diff options
author | nathansmith117 <thenathansmithsmith@gmail.com> | 2024-03-27 22:11:09 +0000 |
---|---|---|
committer | nathansmith117 <thenathansmithsmith@gmail.com> | 2024-03-27 22:11:09 +0000 |
commit | ef55effa58ee01089bffb441a65e932393d9facb (patch) | |
tree | 29f65a87c423953b0575b25780bb8432bab09df2 | |
parent | e8bd0e3644070d2ea9f8fc309e725d9b9b3d0bd6 (diff) | |
download | youload-ef55effa58ee01089bffb441a65e932393d9facb.tar.gz youload-ef55effa58ee01089bffb441a65e932393d9facb.tar.bz2 youload-ef55effa58ee01089bffb441a65e932393d9facb.zip |
Working on yt-dlpswitch_to_yt_dlp
-rw-r--r-- | buildozer.spec | 2 | ||||
-rw-r--r-- | requirements.txt | 3 | ||||
-rw-r--r-- | src/model/youload_playlist.py | 65 | ||||
-rw-r--r-- | src/util.py | 7 | ||||
-rw-r--r-- | src/view/app.py | 46 | ||||
-rw-r--r-- | src/view/download_type_chooser.py | 6 | ||||
-rw-r--r-- | src/youload_downloader.py | 63 |
7 files changed, 83 insertions, 109 deletions
diff --git a/buildozer.spec b/buildozer.spec index 56185ae..78a091f 100644 --- a/buildozer.spec +++ b/buildozer.spec @@ -37,7 +37,7 @@ version = 1.2 # (list) Application requirements # comma separated e.g. requirements = sqlite3,kivy -requirements = python3,kivy,pytube,future,ffmpeg,ffmpeg-python +requirements = python3,kivy,yt-dlp # (str) Custom source folders for requirements # Sets custom source for any requirements with recipes diff --git a/requirements.txt b/requirements.txt index 8769e6d..47389c0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,2 @@ kivy -pytube -ffmpeg-python +yt-dlp diff --git a/src/model/youload_playlist.py b/src/model/youload_playlist.py deleted file mode 100644 index 9189522..0000000 --- a/src/model/youload_playlist.py +++ /dev/null @@ -1,65 +0,0 @@ -from pytube import Playlist -import os -import util - -def make_alpha_numeric(string: str) -> str: - return "".join(char for char in string if char.isalnum()) - -class YouLoadPlayList: - """A class for download and handling youtube playlists""" - - DOWNLOAD_TYPES = ["default", "highest", "lowest", "mp3", "720p", "480p", "360p", "240p", "144p"] - DEFAULT_DOWNLOAD_TYPE = "default" - - def __init__(self, link: str): - self.yt_playlist = Playlist(link) - self.video_count = len(self.yt_playlist.videos) - self.folder_name = make_alpha_numeric(self.yt_playlist.title) - self.download_type = self.DEFAULT_DOWNLOAD_TYPE - - def generate_video_info(self, video_num: int) -> str: - """Returns information on video in playlist at 'video_num'""" - - video = self.yt_playlist.videos[video_num] - video_size = video.streams.get_highest_resolution().filesize // 1048576 - return f"Title: {video.title}, Size: {video_size} MB" - - def set_download_directory(self, directory: str) -> None: - """Sets where the playlist folder will be downloaded""" - self.folder_name = os.path.join(directory, make_alpha_numeric(self.yt_playlist.title)) - - def prepare_for_download(self) -> None: - """Gets the playlist ready for download. Creates the output folder and that stuff.""" - os.mkdir(self.folder_name) - - def download_video(self, video_num: int, use_prefix: bool) -> str: - """Download video at 'video_num'""" - video = self.yt_playlist.videos[video_num] - - # Create prefix. - filename_prefix = "" - - if use_prefix: - filename_prefix = str(video_num + 1) + " " - - # Download this fucker. - if self.download_type == "default": - video.streams.first().download(output_path=self.folder_name, filename_prefix=filename_prefix) - elif self.download_type == "highest": - video.streams.get_highest_resolution().download(output_path=self.folder_name, filename_prefix=filename_prefix) - elif self.download_type == "lowest": - video.streams.get_lowest_resolution().download(output_path=self.folder_name, filename_prefix=filename_prefix) - elif self.download_type == "mp3": - file_path = video.streams.first().download(output_path=self.folder_name, filename_prefix=filename_prefix) - - # To mp3. - file_path_mp3 = file_path[:-4] + ".mp3" - util.convert_mp4_to_mp3(file_path, file_path_mp3) - - # Remove mp4 file. - os.remove(file_path) - else: - video.streams.get_by_resolution(self.download_type).download(output_path=self.folder_name, filename_prefix=filename_prefix) - - return f"Title: {video.title}" - diff --git a/src/util.py b/src/util.py index 99c9c03..4b82c77 100644 --- a/src/util.py +++ b/src/util.py @@ -1,9 +1,5 @@ import os -import ffmpeg -import subprocess -from urllib.request import urlretrieve from kivy.utils import platform -from kivy.app import App def get_default_download_dir() -> str: if platform == "android": @@ -11,6 +7,3 @@ def get_default_download_dir() -> str: else: from pathlib import Path return os.path.join(str(Path.home()), "Downloads") - -def convert_mp4_to_mp3(input_file: str, output_file: str) -> None: - ffmpeg.input(input_file).output(output_file).run() diff --git a/src/view/app.py b/src/view/app.py index 5c6ce6f..4b295d2 100644 --- a/src/view/app.py +++ b/src/view/app.py @@ -6,14 +6,21 @@ from kivy.uix.button import Button from kivy.uix.textinput import TextInput from kivy.uix.label import Label from kivy import platform +from kivy.logger import Logger, LOG_LEVELS import threading import traceback -from model.youload_playlist import YouLoadPlayList +import youload_downloader from view.file_chooser import YouloadFileChooser from view.download_type_chooser import YouloadDownloadTypeChooser import util +import sys + +# The logger fucks up yt-dlp. +Logger.setLevel(LOG_LEVELS["critical"]) +sys.stdout = sys.__stdout__ +sys.stderr = sys.__stderr__ class YouloadApp(App): def build(self): @@ -109,42 +116,19 @@ class YouloadApp(App): # Download the videos in a different thread so the ui still works. def download_playlist_thread(self): try: - self.download_status.text = "Fetching playlist" + self.download_status.text = "Downloading" self.submit.text = "Stop" self.is_downloading = True - # Get playlist. - playlist = YouLoadPlayList(self.url) - - # Set directory and other stuff. - playlist.set_download_directory(self.folder_display.text) - playlist.download_type = self.download_type_chooser.current_type - playlist.prepare_for_download() - self.downloads_display.text = f"Downloading to {playlist.folder_name}\n" - - # Download each video - for i in range(playlist.video_count): - # Stop this mother fucker - if self.should_stop_download: - break - - self.download_status.text = f"Downloading {i+1}/{playlist.video_count}" - self.downloads_display.text += playlist.download_video(i, self.do_add_numbers) + "\n" + self.downloads_display = youload_downloader.download_playlist( + self.url_input.text, + self.download_type_chooser.current_type, + self.folder_display.text, + self.do_add_numbers + ) # Complete download. self.download_status.text = "Download complete" - except FileExistsError as e: - self.download_status.text = "Folder already exists" - self.downloads_display.text = repr(e) + "\n" + traceback.format_exc() - print(self.downloads_display.text) - except KeyError as e: - self.download_status.text = "Error getting playlist" - self.downloads_display.text = repr(e) + "\n" + traceback.format_exc() - print(self.downloads_display.text) - except AttributeError as e: - self.download_status.text = "Download type not supported" - self.downloads_display.text = repr(e) + "\n" + traceback.format_exc() - print(self.downloads_display.text) except Exception as e: self.downloads_display.text = repr(e) + "\n" + traceback.format_exc() print(self.downloads_display.text) diff --git a/src/view/download_type_chooser.py b/src/view/download_type_chooser.py index 927d7a4..2f50cff 100644 --- a/src/view/download_type_chooser.py +++ b/src/view/download_type_chooser.py @@ -3,7 +3,7 @@ from kivy.uix.button import Button from kivy.uix.popup import Popup from kivy.uix.boxlayout import BoxLayout -from model.youload_playlist import YouLoadPlayList +import youload_downloader class YouloadDownloadTypeChooser(Popup): @@ -13,10 +13,10 @@ class YouloadDownloadTypeChooser(Popup): self.title = "Download types" layout = BoxLayout(orientation="vertical") - self.current_type = YouLoadPlayList.DEFAULT_DOWNLOAD_TYPE + self.current_type = youload_downloader.DOWNLOAD_TYPES[0] # Add option buttons. - for download_type in YouLoadPlayList.DOWNLOAD_TYPES: + for download_type in youload_downloader.DOWNLOAD_TYPES: item = Button(text=download_type) item.bind(on_press=self.option_button_cb) layout.add_widget(item) diff --git a/src/youload_downloader.py b/src/youload_downloader.py new file mode 100644 index 0000000..5800ed2 --- /dev/null +++ b/src/youload_downloader.py @@ -0,0 +1,63 @@ +import yt_dlp +import os + +DOWNLOAD_TYPES = ["best/mp4", "worst/mp4", "mp3"] + +def get_playlist_name(url: str) -> str: + ydl_opts = { + 'format': 'worstaudio/worst', + "quiet": True, + "simulate": True, + "extract_flat": True, + "force_generic_extractor": True, + } + + with yt_dlp.YoutubeDL(ydl_opts) as ydl: + info = ydl.extract_info(url, download=False) + + if "title" in info: + return info["title"] + else: + return None + + +def playlist_hook(d): + print(d) + +def download_playlist(url: str, download_type: str, directory: str, numbers: bool) -> None: + # Get name and set download directory. + playlist_name = get_playlist_name(url) + + if playlist_name is None: + playlist_name = "playlist" + + download_directory = os.path.join(directory, playlist_name) + os.mkdir(download_directory) + + # Set options. + ydl_opts = {} + format_mask = "%(title)s.%(ext)s" + + if numbers: + format_mask = "%(playlist_index)s %(title)s.%(ext)s" + + if download_type == "mp3": + ydl_opts = { + "paths": {"home": download_directory}, + "outtmpl": {"default": format_mask}, + "progress_hooks": [playlist_hook], + "postprocessors": [{ + "key": "FFmpegExtractAudio", + "preferredcodec": "mp3", + }] + } + else: + ydl_opts = { + "format": download_type, + "paths": {"home": download_directory}, + "outtmpl": {"default": format_mask}, + "progress_hooks": [playlist_hook] + } + + with yt_dlp.YoutubeDL(ydl_opts) as ydl: + ydl.download(url) |