[BUGFIX] Properly handle UIDs that have misbehaving chars that get sanitized (#870)

Should hopefuly fix both:
- https://github.com/jmbannon/ytdl-sub/issues/843
- https://github.com/jmbannon/ytdl-sub/issues/867

Various sites have unique IDs with characters that get sanitized (i.e. `/`, `:`). `ytdl-sub` was not using sanitized UIDs when looking for files, and would throw an error saying download was missing. This should resolve that issue.
This commit is contained in:
Jesse Bannon 2024-01-04 15:01:17 -08:00 committed by GitHub
parent b3d298b664
commit 2dbe426ced
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 35 additions and 14 deletions

View file

@ -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":

View file

@ -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:
"""

View file

@ -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

View file

@ -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

View file

@ -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(),