diff --git a/src/ytdl_sub/downloaders/info_json/info_json_downloader.py b/src/ytdl_sub/downloaders/info_json/info_json_downloader.py index 509a4f8d..71f3c996 100644 --- a/src/ytdl_sub/downloaders/info_json/info_json_downloader.py +++ b/src/ytdl_sub/downloaders/info_json/info_json_downloader.py @@ -152,7 +152,9 @@ class InfoJsonDownloader(SourcePlugin[InfoJsonDownloaderOptions]): for file_name in entry_file_names: ext = get_file_extension(file_name) file_path = Path(self.output_directory) / file_name - working_directory_file_path = Path(self.working_directory) / f"{entry.uid}.{ext}" + working_directory_file_path = Path(self.working_directory) / entry.base_filename( + ext=ext + ) # NFO files will always get rewritten, so ignore if ext == "nfo": diff --git a/src/ytdl_sub/entries/base_entry.py b/src/ytdl_sub/entries/base_entry.py index c4243d63..6b056900 100644 --- a/src/ytdl_sub/entries/base_entry.py +++ b/src/ytdl_sub/entries/base_entry.py @@ -8,6 +8,8 @@ from typing import Type from typing import TypeVar from typing import final +from yt_dlp.utils import sanitize_filename + from ytdl_sub.entries.script.variable_definitions import VARIABLES from ytdl_sub.entries.script.variable_definitions import VariableDefinitions @@ -45,6 +47,19 @@ class BaseEntry(ABC): """ return str(self._kwargs[v.uid.metadata_key]) + @property + def uid_sanitized(self) -> str: + """ + Sanitized version, used in filenames + """ + return sanitize_filename(self.uid) + + def base_filename(self, ext: str): + """ + The base filename of all yt-dlp downloaded entry files + """ + return f"{self.uid_sanitized}.{ext}" + @property def download_archive_extractor(self) -> str: """ @@ -124,7 +139,7 @@ class BaseEntry(ABC): ------- The download info json's file name """ - return f"{self.uid}.{self.info_json_ext}" + return self.base_filename(ext=self.info_json_ext) def get_download_info_json_path(self) -> str: """ diff --git a/src/ytdl_sub/entries/entry.py b/src/ytdl_sub/entries/entry.py index c7442992..1d684c5b 100644 --- a/src/ytdl_sub/entries/entry.py +++ b/src/ytdl_sub/entries/entry.py @@ -113,7 +113,8 @@ class Entry(BaseEntry, Scriptable): """ ext = self.try_get(v.ext, str) or self._kwargs[v.ext.metadata_key] for possible_ext in [ext, "mkv"]: - file_path = str(Path(self.working_directory()) / f"{self.uid}.{possible_ext}") + file_name = self.base_filename(ext=possible_ext) + file_path = str(Path(self.working_directory()) / file_name) if os.path.isfile(file_path): return possible_ext @@ -125,7 +126,7 @@ class Entry(BaseEntry, Scriptable): ------- The entry's file name """ - return f"{self.uid}.{self.ext}" + return self.base_filename(ext=self.ext) def get_download_file_path(self) -> str: """Returns the entry's file path to where it was downloaded""" @@ -137,7 +138,7 @@ class Entry(BaseEntry, Scriptable): ------- The download thumbnail's file name """ - return f"{self.uid}.{self.get(v.thumbnail_ext, str)}" + return self.base_filename(ext=self.get(v.thumbnail_ext, str)) def get_download_thumbnail_path(self) -> str: """Returns the entry's thumbnail's file path to where it was downloaded""" @@ -155,7 +156,10 @@ class Entry(BaseEntry, Scriptable): possible_thumbnail_exts.add(thumbnail["url"].split(".")[-1]) for ext in possible_thumbnail_exts: - possible_thumbnail_path = str(Path(self.working_directory()) / f"{self.uid}.{ext}") + possible_thumbnail_filename = self.base_filename(ext=ext) + possible_thumbnail_path = str( + Path(self.working_directory()) / possible_thumbnail_filename + ) if os.path.isfile(possible_thumbnail_path): return possible_thumbnail_path @@ -202,7 +206,7 @@ class Entry(BaseEntry, Scriptable): # HACK: yt-dlp does not record extracted/converted extensions anywhere. If the file is not # found, try it using all possible extensions if not file_exists: - for ext in AUDIO_CODEC_EXTS.union(VIDEO_CODEC_EXTS): + for ext in AUDIO_CODEC_EXTS | VIDEO_CODEC_EXTS: if os.path.isfile(self.get_download_file_path().removesuffix(self.ext) + ext): file_exists = True break diff --git a/src/ytdl_sub/plugins/subtitles.py b/src/ytdl_sub/plugins/subtitles.py index 9c53a9bd..0e74d448 100644 --- a/src/ytdl_sub/plugins/subtitles.py +++ b/src/ytdl_sub/plugins/subtitles.py @@ -208,7 +208,6 @@ class SubtitlesPlugin(Plugin[SubtitleOptions]): file_metadata = FileMetadata(f"Embedded subtitles with lang(s) {', '.join(langs)}") if self.plugin_options.subtitles_name: for lang in langs: - subtitle_file_name = f"{entry.uid}.{lang}.{self.plugin_options.subtitles_type}" output_subtitle_file_name = self.overrides.apply_formatter( formatter=self.plugin_options.subtitles_name, entry=entry, @@ -216,7 +215,9 @@ class SubtitlesPlugin(Plugin[SubtitleOptions]): ) self.save_file( - file_name=subtitle_file_name, + file_name=entry.base_filename( + ext=f"{lang}.{self.plugin_options.subtitles_type}" + ), output_file_name=output_subtitle_file_name, entry=entry, ) @@ -225,9 +226,8 @@ class SubtitlesPlugin(Plugin[SubtitleOptions]): # Can happen for both file and embedded subs for lang in langs: for possible_ext in SUBTITLE_EXTENSIONS: - possible_subs_file = ( - Path(self.working_directory) / f"{entry.uid}.{lang}.{possible_ext}" - ) + possible_subs_filename = entry.base_filename(ext=f"{lang}.{possible_ext}") + possible_subs_file = Path(self.working_directory) / possible_subs_filename FileHandler.delete(possible_subs_file) return file_metadata diff --git a/src/ytdl_sub/subscriptions/subscription_ytdl_options.py b/src/ytdl_sub/subscriptions/subscription_ytdl_options.py index 14916c2e..d4ca2edf 100644 --- a/src/ytdl_sub/subscriptions/subscription_ytdl_options.py +++ b/src/ytdl_sub/subscriptions/subscription_ytdl_options.py @@ -56,8 +56,8 @@ class SubscriptionYTDLOptions: ytdl-options to apply to every run no matter what """ ytdl_options = { - # Download all files in the format of {id}.{ext} - "outtmpl": str(Path(self._working_directory) / "%(id)s.%(ext)s"), + # Download all files in the format of {id}.{ext}, where id is sanitized + "outtmpl": str(Path(self._working_directory) / "%(id)S.%(ext)s"), # Always write thumbnails "writethumbnail": True, "ffmpeg_location": FFMPEG.ffmpeg_path(),