diff --git a/fastanime/Utility/downloader/downloader.py b/fastanime/Utility/downloader/downloader.py index 745fc09..d140e4f 100644 --- a/fastanime/Utility/downloader/downloader.py +++ b/fastanime/Utility/downloader/downloader.py @@ -1,8 +1,14 @@ import logging +import os +import shutil +import subprocess +import tempfile from queue import Queue from threading import Thread import yt_dlp +from rich import print +from rich.prompt import Confirm from yt_dlp.utils import sanitize_filename logger = logging.getLogger(__name__) @@ -39,6 +45,9 @@ class YtDLPDownloader: verbose=False, headers={}, sub="", + merge=False, + clean=True, + prompt=True, ): """Helper function that downloads anime given url and path details @@ -64,8 +73,82 @@ class YtDLPDownloader: urls = [url] if sub: urls.append(sub) - with yt_dlp.YoutubeDL(ydl_opts) as ydl: - ydl.download(urls) + vid_path = "" + sub_path = "" + for i, url in enumerate(urls): + with yt_dlp.YoutubeDL(ydl_opts) as ydl: + info = ydl.extract_info(url, download=True) + if not info: + continue + if i == 0: + vid_path = info["requested_downloads"][0]["filepath"] + else: + sub_path = info["requested_downloads"][0]["filepath"] + if sub_path and vid_path and merge: + self.merge_subtitles(vid_path, sub_path, clean, prompt) + + def merge_subtitles(self, video_path, sub_path, clean, prompt): + # Extract the directory and filename + video_dir = os.path.dirname(video_path) + video_name = os.path.basename(video_path) + video_name, _ = os.path.splitext(video_name) + video_name += ".mkv" + + FFMPEG_EXECUTABLE = shutil.which("ffmpeg") + if not FFMPEG_EXECUTABLE: + print("[yellow bold]WARNING: [/]FFmpeg not found") + return + # Create a temporary directory + with tempfile.TemporaryDirectory() as temp_dir: + # Temporary output path in the temporary directory + temp_output_path = os.path.join(temp_dir, video_name) + # FFmpeg command to merge subtitles + command = [ + FFMPEG_EXECUTABLE, + "-hide_banner", + "-i", + video_path, + "-i", + sub_path, + "-c", + "copy", + "-map", + "0", + "-map", + "1", + temp_output_path, + ] + + # Run the command + try: + subprocess.run(command, check=True) + + # Move the file back to the original directory with the original name + final_output_path = os.path.join(video_dir, video_name) + + if os.path.exists(final_output_path): + if not prompt or Confirm.ask( + f"File exists({final_output_path}) would you like to overwrite it", + default=True, + ): + # move file to dest + os.remove(final_output_path) + shutil.move(temp_output_path, final_output_path) + else: + shutil.move(temp_output_path, final_output_path) + # clean up + if clean: + print("[cyan]Cleaning original files...[/]") + os.remove(video_path) + os.remove(sub_path) + + print( + f"[green bold]Subtitles merged successfully.[/] Output file: {final_output_path}" + ) + except subprocess.CalledProcessError as e: + print(f"[red bold]Error[/] during merging subtitles: {e}") + except Exception as e: + print(f"[red bold]An error[/] occurred: {e}") # WARN: May remove this legacy functionality def download_file(self, url: str, title, silent=True): diff --git a/fastanime/cli/commands/download.py b/fastanime/cli/commands/download.py index e003330..1bfb730 100644 --- a/fastanime/cli/commands/download.py +++ b/fastanime/cli/commands/download.py @@ -1,4 +1,3 @@ -import time from typing import TYPE_CHECKING import click @@ -41,6 +40,28 @@ if TYPE_CHECKING: default=True, ) @click.option("--verbose", "-v", is_flag=True, help="Download verbosely (everywhere)") +@click.option( + "--merge", "-m", is_flag=True, help="Merge the subfile with video using ffmpeg" +) +@click.option( + "--clean/--no-clean", + "-c/-C", + type=bool, + help="After merging delete the original files", + default=True, +) +@click.option( + "--wait-time", + "-w", + type=int, + help="The amount of time to wait after downloading is complete before the screen is completely cleared", + default=10, +) +@click.option( + "--prompt/--no-prompt", + help="Dont prompt for anything instead just do the best thing", + default=False, +) @click.pass_obj def download( config: "Config", @@ -49,7 +70,13 @@ def download( force_unknown_ext, silent, verbose, + merge, + clean, + wait_time, + prompt, ): + import time + from rich import print from rich.progress import Progress from thefuzz import fuzz @@ -83,7 +110,16 @@ def download( print("Search results failed") input("Enter to retry") download( - config, anime_title, episode_range, force_unknown_ext, silent, verbose + config, + anime_title, + episode_range, + force_unknown_ext, + silent, + verbose, + merge, + clean, + wait_time, + prompt, ) return search_results = search_results["results"] @@ -119,7 +155,16 @@ def download( print("Sth went wring anime no found") input("Enter to continue...") download( - config, anime_title, episode_range, force_unknown_ext, silent, verbose + config, + anime_title, + episode_range, + force_unknown_ext, + silent, + verbose, + merge, + clean, + wait_time, + prompt, ) return @@ -223,7 +268,7 @@ def download( ) downloader._download_file( link, - anime["title"], + search_result, episode_title, download_dir, silent, @@ -232,10 +277,14 @@ def download( verbose, headers=provider_headers, sub=subtitles[0]["url"] if subtitles else "", + merge=merge, + clean=clean, + prompt=prompt, ) except Exception as e: print(e) time.sleep(1) print("Continuing...") print("Done Downloading") + time.sleep(wait_time) exit_app()