Skip to content

Commit

Permalink
fix: playlist download methods.
Browse files Browse the repository at this point in the history
pyutube/cli.py
The handle_playlist function has been modified to check if any videos in the playlist have already been downloaded. If so, it removes them from the download queue.

pyutube/downloader.py
The Downloader class has been modified to handle cases where the specified quality is not available. It now falls back to the best available quality if the specified quality is not found.

requirements.txt
The pytubefix version has been updated from 5.4.2 to 5.6.3.
  • Loading branch information
Hetari committed Jun 17, 2024
1 parent 4b9d45b commit 32030d6
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 15 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Pyutube Changelog

## 1.2.8

- Add: if you download half of the playlist, you can resume the others without having to download them again.
It will check the root directory for the file, and if the playlist folder is found it will see its content and remove all the files that already downloaded from the download queue.

## 1.2.6

- Fix: switch into pytubefix instead of pytube.
Expand Down
76 changes: 66 additions & 10 deletions pyutube/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@

import os
import sys
import re

import typer
import threading
Expand Down Expand Up @@ -190,13 +191,10 @@ def handle_playlist(url: str, path: str):
Returns:
None
"""
def get_title(video):
"""Function to get the title of a YouTube video."""
return video.title

def fetch_title_thread(video):
"""Fetch the title of a YouTube video in a separate thread."""
video_title = video.title
video_title = safe_filename(video.title)
video_id = video.video_id
playlist_videos.append((video_title, video_id))

Expand Down Expand Up @@ -229,19 +227,77 @@ def fetch_title_thread(video):

# Now all video titles are stored in the video_titles list
console.print(f"\nPlaylist title: {title}\n", style="info")
console.print(f"Total videos: {total}\n\n", style="info")
console.print("Chose what video you want to download")

videos_selected = ask_playlist_video_names(playlist_videos)
console.print(f"Total videos: {total}\n", style="info")

os.makedirs(title, exist_ok=True)
new_path = os.path.join(path, title)

# check if there is any video already downloaded in the past
for file in os.listdir(new_path):
for video in playlist_videos:
if file.startswith(video):
playlist_videos.remove(video)
# Exit the inner loop since we found a match
break

if not playlist_videos:
console.print(f"All playlist are already downloaded in this directory, see '{
title}' folder", style="info")
sys.exit()

console.print("Chose what video you want to download")
videos_selected = ask_playlist_video_names(playlist_videos)

for index, video_id in enumerate(videos_selected):
url = f"https://www.youtube.com/watch?v={video_id}"

if index == 0:
quality = download(url, new_path, is_audio, is_playlist=False)
continue

download(url, new_path, is_audio,
quality_choice=quality, is_playlist=False)
quality_choice=quality,
is_playlist=False)


def safe_filename(s: str, max_length: int = 255) -> str:
"""Sanitize a string making it safe to use as a filename.
This function was based off the limitations outlined here:
https://en.wikipedia.org/wiki/Filename.
:param str s:
A string to make safe for use as a file name.
:param int max_length:
The maximum filename character length.
:rtype: str
:returns:
A sanitized string.
"""
# Characters in range 0-31 (0x00-0x1F) are not allowed in ntfs filenames.
ntfs_characters = [chr(i) for i in range(31)]
characters = [
r'"',
r"\#",
r"\$",
r"\%",
r"'",
r"\*",
r"\,",
r"\.",
r"\/",
r"\:",
r'"',
r"\;",
r"\<",
r"\>",
r"\?",
r"\\",
r"\^",
r"\|",
r"\~",
r"\\\\",
]
pattern = "|".join(ntfs_characters + characters)
regex = re.compile(pattern, re.UNICODE)
filename = regex.sub("", s)
return filename[:max_length].rsplit(" ", 0)[0]
11 changes: 10 additions & 1 deletion pyutube/downloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,16 @@ def get_video_streams(self, quality: str, streams: YouTube.streams) -> YouTube:
The video stream with the specified quality,
or the best available stream if no match is found.
"""
return streams.filter(res=quality).first()
s = streams.filter(res=quality).first()

if not s:
available_qualities = [stream.resolution for stream in streams]
available_qualities = list(map(int, available_qualities))
selected_quality = min(available_qualities,
key=lambda x: abs(int(quality) - x))
s = streams.filter(res=str(selected_quality)).first()

return s

@yaspin(
text=colored("Downloading the audio...", "green"),
Expand Down
9 changes: 6 additions & 3 deletions pyutube/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from termcolor import colored


__version__ = "1.2.7"
__version__ = "1.2.8"
__app__ = "pyutube"
ABORTED_PREFIX = "aborted"
CANCEL_PREFIX = "cancel"
Expand Down Expand Up @@ -251,12 +251,14 @@ def ask_rename_file(filename: str) -> str:

def ask_playlist_video_names(videos):
note = colored("NOTE:", "cyan")
select_one = colored("<space>", "red")
select_all = colored("<ctrl+a>", "red")
invert_selection = colored("<ctrl+i>", "red")
restart_selection = colored("<ctrl+r>", "red")

print(
f"{note} Press {select_all} to select all, {invert_selection} to invert selection, and {restart_selection} to restart selection",
f"{note} Press {select_one} to select the videos, {select_all} to select all, {
invert_selection} to invert selection, and {restart_selection} to restart selection",
)
questions = [
inquirer.Checkbox(
Expand Down Expand Up @@ -348,7 +350,8 @@ def check_for_updates() -> None:

if latest_version != __version__:
console.print(
f"👉 A new version of {__app__} is available: {latest_version}. Update it by running [bold red link=https://github.com/Hetari/pyutube]pip install --upgrade {__app__}[/bold red link]",
f"👉 A new version of {__app__} is available: {
latest_version}. Update it by running [bold red link=https://github.com/Hetari/pyutube]pip install --upgrade {__app__}[/bold red link]",
style="warning"
)
else:
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ typer==0.9.0
requests==2.31.0
rich==13.7.1
yaspin==3.0.1
pytubefix==5.4.2
pytubefix==5.6.3
inquirer==3.2.4
termcolor==2.4.0
moviepy==1.0.3

0 comments on commit 32030d6

Please sign in to comment.