[BUGFIX] Do not fail with thumbnail issues
This commit is contained in:
parent
a9e6a80111
commit
867f8ff15b
8 changed files with 52 additions and 48 deletions
|
|
@ -34,8 +34,8 @@ from ytdl_sub.entries.variables.kwargs import YTDL_SUB_MATCH_FILTER_REJECT
|
|||
from ytdl_sub.utils.file_handler import FileHandler
|
||||
from ytdl_sub.utils.logger import Logger
|
||||
from ytdl_sub.utils.thumbnail import ThumbnailTypes
|
||||
from ytdl_sub.utils.thumbnail import convert_download_thumbnail
|
||||
from ytdl_sub.utils.thumbnail import download_and_convert_url_thumbnail
|
||||
from ytdl_sub.utils.thumbnail import try_convert_download_thumbnail
|
||||
from ytdl_sub.ytdl_additions.enhanced_download_archive import EnhancedDownloadArchive
|
||||
|
||||
download_logger = Logger.get(name="downloader")
|
||||
|
|
@ -82,8 +82,6 @@ class UrlDownloaderThumbnailPlugin(SourcePluginExtension):
|
|||
|
||||
# If latest entry, always update the thumbnail on each entry
|
||||
if thumbnail_id == ThumbnailTypes.LATEST_ENTRY:
|
||||
# Make sure the entry's thumbnail is converted to jpg
|
||||
convert_download_thumbnail(entry, error_if_not_found=False)
|
||||
|
||||
# always save in dry-run even if it doesn't exist...
|
||||
if self.is_dry_run or os.path.isfile(entry.get_download_thumbnail_path()):
|
||||
|
|
@ -138,8 +136,14 @@ class UrlDownloaderThumbnailPlugin(SourcePluginExtension):
|
|||
|
||||
def modify_entry(self, entry: Entry) -> Optional[Entry]:
|
||||
"""
|
||||
Use the entry to download thumbnails (or move if LATEST_ENTRY)
|
||||
Use the entry to download thumbnails (or move if LATEST_ENTRY).
|
||||
In addition, convert the entry thumbnail to jpg
|
||||
"""
|
||||
# We always convert entry thumbnails to jpgs, and is performed here to be done
|
||||
# as early as possible in the plugin pipeline (downstream plugins depend on it being jpg)
|
||||
if not self.is_dry_run:
|
||||
try_convert_download_thumbnail(entry=entry)
|
||||
|
||||
if entry.kwargs_get(COLLECTION_URL) in self._collection_url_mapping:
|
||||
self._download_url_thumbnails(
|
||||
collection_url=self._collection_url_mapping[entry.kwargs(COLLECTION_URL)],
|
||||
|
|
|
|||
|
|
@ -86,10 +86,12 @@ class YTDLP:
|
|||
If the entry fails to download
|
||||
"""
|
||||
num_tries = 0
|
||||
entry_files_exist = False
|
||||
copied_ytdl_options_overrides = copy.deepcopy(ytdl_options_overrides)
|
||||
|
||||
while not entry_files_exist and num_tries < cls._EXTRACT_ENTRY_NUM_RETRIES:
|
||||
is_downloaded = False
|
||||
entry_dict: Optional[Dict] = None
|
||||
|
||||
while num_tries < cls._EXTRACT_ENTRY_NUM_RETRIES:
|
||||
entry_dict = cls.extract_info(
|
||||
ytdl_options_overrides=copied_ytdl_options_overrides, **kwargs
|
||||
)
|
||||
|
|
@ -115,7 +117,7 @@ class YTDLP:
|
|||
time.sleep(cls._EXTRACT_ENTRY_RETRY_WAIT_SEC)
|
||||
num_tries += 1
|
||||
|
||||
# Remove the download archive so it can retry without thinking its already downloaded,
|
||||
# Remove the download archive to retry without thinking its already downloaded,
|
||||
# even though it is not
|
||||
if "download_archive" in copied_ytdl_options_overrides:
|
||||
del copied_ytdl_options_overrides["download_archive"]
|
||||
|
|
@ -127,6 +129,10 @@ class YTDLP:
|
|||
cls._EXTRACT_ENTRY_NUM_RETRIES,
|
||||
)
|
||||
|
||||
# Still return if the media file downloaded (thumbnail could be missing)
|
||||
if is_downloaded and entry_dict is not None:
|
||||
return entry_dict
|
||||
|
||||
error_dict = {"ytdl_options": ytdl_options_overrides, "kwargs": kwargs}
|
||||
raise FileNotDownloadedException(
|
||||
f"yt-dlp failed to download an entry with these arguments: {error_dict}"
|
||||
|
|
|
|||
|
|
@ -92,6 +92,15 @@ class Entry(EntryVariables, BaseEntry):
|
|||
"""
|
||||
return self.get_ytdlp_download_thumbnail_path() is not None
|
||||
|
||||
@final
|
||||
def is_thumbnail_available(self) -> bool:
|
||||
"""
|
||||
Returns
|
||||
-------
|
||||
True if the thumbnail file exists and is its proper format. False otherwise.
|
||||
"""
|
||||
return os.path.isfile(self.get_download_thumbnail_path())
|
||||
|
||||
@final
|
||||
def is_downloaded(self) -> bool:
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ from ytdl_sub.utils.ffmpeg import FFMPEG
|
|||
from ytdl_sub.utils.file_handler import FileHandler
|
||||
from ytdl_sub.utils.file_handler import FileMetadata
|
||||
from ytdl_sub.utils.logger import Logger
|
||||
from ytdl_sub.utils.thumbnail import convert_download_thumbnail
|
||||
from ytdl_sub.validators.audo_codec_validator import AUDIO_CODEC_EXTS
|
||||
from ytdl_sub.validators.validators import BoolValidator
|
||||
|
||||
|
|
@ -90,10 +89,12 @@ class EmbedThumbnailPlugin(Plugin[EmbedThumbnailOptions]):
|
|||
logger.warning("webm does not support embedded thumbnails, skipping")
|
||||
return None
|
||||
|
||||
if not self.is_dry_run:
|
||||
# convert the entry thumbnail so it is embedded as jpg
|
||||
convert_download_thumbnail(entry=entry)
|
||||
if not entry.is_thumbnail_downloaded():
|
||||
logger.warning(
|
||||
"Cannot embed thumbnail for '%s' because it is not available", entry.title
|
||||
)
|
||||
|
||||
if not self.is_dry_run:
|
||||
if entry.ext in AUDIO_CODEC_EXTS:
|
||||
self._embed_audio_file(entry)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ from ytdl_sub.config.preset_options import OptionsDictValidator
|
|||
from ytdl_sub.entries.entry import Entry
|
||||
from ytdl_sub.utils.file_handler import FileMetadata
|
||||
from ytdl_sub.utils.logger import Logger
|
||||
from ytdl_sub.utils.thumbnail import convert_download_thumbnail
|
||||
from ytdl_sub.validators.audo_codec_validator import AUDIO_CODEC_EXTS
|
||||
from ytdl_sub.validators.strict_dict_validator import StrictDictValidator
|
||||
from ytdl_sub.validators.string_formatter_validators import ListFormatterValidator
|
||||
|
|
@ -162,11 +161,7 @@ class MusicTagsPlugin(Plugin[MusicTagsOptions]):
|
|||
)
|
||||
setattr(audio_file, tag_name, tag_value[0])
|
||||
|
||||
if self.plugin_options.embed_thumbnail:
|
||||
|
||||
# convert the entry thumbnail so it is embedded as jpg
|
||||
convert_download_thumbnail(entry=entry)
|
||||
|
||||
if self.plugin_options.embed_thumbnail and entry.is_thumbnail_available():
|
||||
with open(entry.get_download_thumbnail_path(), "rb") as thumb:
|
||||
mediafile_img = mediafile.Image(
|
||||
data=thumb.read(), desc="cover", type=mediafile.ImageType.front
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import copy
|
||||
import os.path
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
from typing import List
|
||||
|
|
@ -21,7 +20,6 @@ from ytdl_sub.utils.exceptions import ValidationException
|
|||
from ytdl_sub.utils.ffmpeg import FFMPEG
|
||||
from ytdl_sub.utils.file_handler import FileHandler
|
||||
from ytdl_sub.utils.file_handler import FileMetadata
|
||||
from ytdl_sub.utils.thumbnail import convert_download_thumbnail
|
||||
from ytdl_sub.validators.string_select_validator import StringSelectValidator
|
||||
|
||||
|
||||
|
|
@ -184,11 +182,6 @@ class SplitByChaptersPlugin(SplitPlugin[SplitByChaptersOptions]):
|
|||
f"Tried to split '{entry.title}' by chapters but it has no chapters"
|
||||
)
|
||||
|
||||
# convert the entry thumbnail early so we do not have to guess the thumbnail extension
|
||||
# when copying it. Do not error if it's not found, in case thumbnail_name is not set
|
||||
if not self.is_dry_run:
|
||||
convert_download_thumbnail(entry=entry, error_if_not_found=False)
|
||||
|
||||
for idx, title in enumerate(chapters.titles):
|
||||
new_uid = _split_video_uid(source_uid=entry.uid, idx=idx)
|
||||
|
||||
|
|
@ -209,7 +202,7 @@ class SplitByChaptersPlugin(SplitPlugin[SplitByChaptersOptions]):
|
|||
|
||||
# Copy the original vid thumbnail to the working directory with the new uid. This so
|
||||
# downstream logic thinks this split video has its own thumbnail
|
||||
if os.path.isfile(entry.get_download_thumbnail_path()):
|
||||
if entry.is_thumbnail_available():
|
||||
FileHandler.copy(
|
||||
src_file_path=entry.get_download_thumbnail_path(),
|
||||
dst_file_path=Path(self.working_directory)
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ from ytdl_sub.utils.exceptions import ValidationException
|
|||
from ytdl_sub.utils.file_handler import FileHandler
|
||||
from ytdl_sub.utils.file_handler import FileHandlerTransactionLog
|
||||
from ytdl_sub.utils.file_handler import FileMetadata
|
||||
from ytdl_sub.utils.thumbnail import convert_download_thumbnail
|
||||
|
||||
|
||||
def _get_split_plugin(plugins: List[Plugin]) -> Optional[SplitPlugin]:
|
||||
|
|
@ -69,16 +68,11 @@ class SubscriptionDownload(BaseSubscription, ABC):
|
|||
entry=entry,
|
||||
)
|
||||
|
||||
# TODO: see if entry even has a thumbnail
|
||||
if self.output_options.thumbnail_name:
|
||||
if self.output_options.thumbnail_name and entry.is_thumbnail_available():
|
||||
output_thumbnail_name = self.overrides.apply_formatter(
|
||||
formatter=self.output_options.thumbnail_name, entry=entry
|
||||
)
|
||||
|
||||
# We always convert entry thumbnails to jpgs, and is performed here
|
||||
if not dry_run:
|
||||
convert_download_thumbnail(entry=entry)
|
||||
|
||||
# Copy the thumbnails since they could be used later for other things
|
||||
self._enhanced_download_archive.save_file_to_output_directory(
|
||||
file_name=entry.get_download_thumbnail_name(),
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
import logging
|
||||
import os
|
||||
import tempfile
|
||||
from subprocess import CalledProcessError
|
||||
from typing import Optional
|
||||
from urllib.request import urlopen
|
||||
|
||||
from ytdl_sub.entries.entry import Entry
|
||||
from ytdl_sub.utils.ffmpeg import FFMPEG
|
||||
from ytdl_sub.utils.file_handler import FileHandler
|
||||
from ytdl_sub.utils.logger import Logger
|
||||
from ytdl_sub.utils.retry import retry
|
||||
|
||||
|
||||
|
|
@ -13,21 +16,18 @@ class ThumbnailTypes:
|
|||
LATEST_ENTRY = "latest_entry"
|
||||
|
||||
|
||||
def convert_download_thumbnail(entry: Entry, error_if_not_found: bool = True) -> None:
|
||||
logger: logging.Logger = Logger.get("thumbnail")
|
||||
|
||||
|
||||
def try_convert_download_thumbnail(entry: Entry) -> None:
|
||||
"""
|
||||
Converts an entry's downloaded thumbnail into jpg format
|
||||
Converts an entry's downloaded thumbnail into jpg format.
|
||||
Log with a warning if the thumbnail is not found or fails to convert
|
||||
|
||||
Parameters
|
||||
----------
|
||||
entry
|
||||
Entry with the thumbnail
|
||||
error_if_not_found
|
||||
If the thumbnail is not found, error if True.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
Entry thumbnail file not found
|
||||
"""
|
||||
download_thumbnail_path = entry.get_ytdlp_download_thumbnail_path()
|
||||
download_thumbnail_path_as_jpg = entry.get_download_thumbnail_path()
|
||||
|
|
@ -37,14 +37,16 @@ def convert_download_thumbnail(entry: Entry, error_if_not_found: bool = True) ->
|
|||
return
|
||||
|
||||
if not download_thumbnail_path:
|
||||
if error_if_not_found:
|
||||
raise ValueError("Thumbnail not found")
|
||||
return
|
||||
logger.warning("Thumbnail for '%s' was not downloaded", entry.title)
|
||||
|
||||
if not download_thumbnail_path == download_thumbnail_path_as_jpg:
|
||||
try:
|
||||
FFMPEG.run(
|
||||
["-y", "-bitexact", "-i", download_thumbnail_path, download_thumbnail_path_as_jpg]
|
||||
)
|
||||
except CalledProcessError:
|
||||
logger.warning("Failed to convert thumbnail for '%s' to jpg", entry.title)
|
||||
finally:
|
||||
FileHandler.delete(download_thumbnail_path)
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue