Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

streams.get_highest_resolution() method doesn't seem to pull the highest resolution #367

Open
mlozier opened this issue Dec 1, 2024 · 3 comments
Labels
enhancement New feature or request

Comments

@mlozier
Copy link

mlozier commented Dec 1, 2024

This project is great! That said, I've noticed that when using the streams.get_highest_resolution() method, the highest resolution doesn't seem to be pulled. What I'm getting, is at best, 480p when a 1080p video is in fact available. Perhaps I'm missing something (an option?). Admittantly, I didn't dig through the source to see if I need to throw an option when using this method to pull down a file in 1080p. Thank you!!

@mlozier mlozier added the enhancement New feature or request label Dec 1, 2024
@rockfarmor
Copy link

I believe that you need to download the video and audio separately, and them combine them. I'm using MoviePy for this, but you could use FFMPEG for it as well.

This snippet gets the highest resolution of the video and downloads it, as well as downloading the audio separatly

yt = YouTube(youtube_url, use_oauth=True, allow_oauth_cache=True)

# Get the highest resolution video stream (without audio)
video_stream = yt.streams.filter(file_extension="mp4", only_video=True).order_by('resolution').desc().first()

# Get the highest quality audio stream
audio_stream = yt.streams.filter(only_audio=True).order_by('abr').desc().first()

if not video_stream or not audio_stream:
        raise Exception('No suitable video or audio streams found.')

# Log the resolution and audio quality
print(f"Downloading video in resolution: {video_stream.resolution}")
print(f"Downloading audio with bitrate: {audio_stream.abr}")

# Download video and audio streams
video_path = video_stream.download(output_path=temp_folder, filename="video.mp4", )
audio_path = audio_stream.download(output_path=temp_folder, filename="audio.mp4")

If you don't want to download 4k videos for example (max res 1080p) you could do something like this:

video_streams = (
        yt.streams.filter(file_extension="mp4", only_video=True, res=["1080p", "720p", "360p", "240p", "144p"])
        .order_by("resolution")
        .desc()
)
        
video_stream = video_streams.first();

@goalie1998
Copy link

By default, get_highest_resolution finds only progressive videos (which in YouTube's case have audio and video streams in one file), which may not be the highest resolution video. Change the parameter to False (get_highest_resolution(False)) to get the highest resolution video regardless of the audio stream. Then if the stream is not progressive (check using not is_progressive or is adaptive), download the audio stream and combine the two however you want.

@valorisa
Copy link

valorisa commented Jan 4, 2025

Here an improving version :

from pytubefix import YouTube
from pytubefix.cli import on_progress
import os
import subprocess

def download_video():
    # Ask the user to provide the YouTube video URL
    url = input("Please enter the YouTube video URL: ")

    try:
        # Create a YouTube object
        yt = YouTube(url, on_progress_callback=on_progress)

        # Display the video title
        print(f"Downloading video: {yt.title}")

        # Get the stream with the highest resolution (may be adaptive)
        video_stream = yt.streams.get_highest_resolution(False)
        print(f"Selected video stream: {video_stream.resolution} ({video_stream.fps}fps)")

        # Check if the stream is adaptive
        if not video_stream.is_progressive:
            # Get the audio stream with the best quality
            audio_stream = yt.streams.filter(only_audio=True).order_by('abr').desc().first()
            print(f"Selected audio stream: {audio_stream.abr}")

            if not audio_stream:
                raise Exception('No suitable audio stream found.')

            # Download the video and audio streams
            video_path = video_stream.download(filename="video.mp4")
            print(f"Video stream downloaded: {video_path}")
            audio_path = audio_stream.download(filename="audio.mp4")
            print(f"Audio stream downloaded: {audio_path}")

            # Combine the video and audio streams with ffmpeg
            output_path = "final_video.mp4"
            subprocess.run([
                'ffmpeg',
                '-i', video_path,
                '-i', audio_path,
                '-c:v', 'copy',
                '-c:a', 'aac',
                '-strict', 'experimental',
                output_path
            ])
            print(f"Combined video saved: {output_path}")

            # Clean up temporary files
            os.remove(video_path)
            os.remove(audio_path)

            print("Download and combination completed!")
        else:
            # Download the progressive stream
            video_stream.download(filename="final_video.mp4")
            print("Download completed!")
    except Exception as e:
        print(f"An error occurred: {e}")

if __name__ == "__main__":
    download_video()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Status: waiting
Development

No branches or pull requests

4 participants