Fix error when maintain_download_archive=False, improve error message (#39)

This commit is contained in:
Jesse Bannon 2022-05-20 14:41:05 -07:00 committed by GitHub
parent 0e8ea1f9b6
commit de5dade937
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 94 additions and 25 deletions

View file

@ -26,17 +26,37 @@ presets:
year: "{album_year}" year: "{album_year}"
genre: "{genre}" genre: "{genre}"
music_videos: yt_music_video:
# A single YouTube video is our source/download strategy. However, this
# can be overwritten to download music videos from a "playlist", as we
# will see in a preset below
youtube: youtube:
download_strategy: "video"
# For advanced YTDL users only.
# It is wise to leave ignoreerrors=True to avoid errors for things
# like age-restricted videos in case you have not set your cookie.
ytdl_options: ytdl_options:
ignoreerrors: True ignoreerrors: True
# For each video downloaded, set the file and thumbnail name here.
# We set both with {music_video_name}, which is a variable we define in
# the overrides section further below to represent consistent naming format.
output_options: output_options:
file_name: "{sanitized_artist} - {sanitized_title}.{ext}" output_directory: "{music_video_directory}/{sanitized_artist}"
thumbnail_name: "{sanitized_artist} - {sanitized_title}.jpg" file_name: "{music_video_name}.{ext}"
thumbnail_name: "{music_video_name}.jpg"
# Always convert the video thumbnail to jpg
# TODO: always convert all thumbnails to jpg in code
convert_thumbnail: convert_thumbnail:
to: "jpg" to: "jpg"
# For each video downloaded, add a music video NFO file for it. Populate it
# with tags that Kodi will read and use to display it in the music or music
# videos section.
nfo_tags: nfo_tags:
nfo_name: "{sanitized_artist} - {sanitized_title}.nfo" nfo_name: "{music_video_name}.nfo"
nfo_root: "musicvideo" nfo_root: "musicvideo"
tags: tags:
artist: "{artist}" artist: "{artist}"
@ -44,6 +64,33 @@ presets:
album: "Music Videos" album: "Music Videos"
year: "{upload_year}" year: "{upload_year}"
# Overrides is a section where we can define our own variables, and use them in
# any other section. We define our music video directory and episode file name
# here, which gets reused above for the video, thumbnail, and NFO file.
overrides:
music_video_directory: "path/to/Music Videos"
music_video_name: "{sanitized_artist} - {sanitized_title}"
# It is not always ideal to download all of an artist's music videos.
# Maybe you only like one song of theirs. We can reuse our preset above
# to download a single video instead.
yt_music_video_playlist:
preset: "yt_music_video"
youtube:
download_strategy: "playlist"
# Setting maintain_download_archive=True is generally a good thing to enable
# with playlists and channels because it will store previously downloaded
# video ids to tell YTDL not to re-download them on a successive invocation.
output_options:
maintain_download_archive: True
# Setting break_on_existing=True is also a good thing anytime you are using
# a download archive, because it will tell the downloader to stop trying
# to download videos that have already been downloaded.
ytdl_options:
break_on_existing: True
yt_channel: yt_channel:
youtube: youtube:
download_strategy: "channel" download_strategy: "channel"

View file

@ -58,9 +58,9 @@ def _download_subscription_from_cli(config: ConfigFile, extra_args: List[str]) -
subscription.download() subscription.download()
def main(): def _main():
""" """
Entrypoint for ytdl-subscribe Entrypoint for ytdl-sub, without the error handling
""" """
# If no args are provided, print help and exit # If no args are provided, print help and exit
if len(sys.argv) < 2: if len(sys.argv) < 2:
@ -80,18 +80,26 @@ def main():
logger.info("Download complete!") logger.info("Download complete!")
if __name__ == "__main__": def main():
"""
Entrypoint for ytdl-sub
"""
try: try:
main() _main()
except ValidationException as validation_exception: except ValidationException as validation_exception:
logger.error(validation_exception) logger.error(validation_exception)
sys.exit(1) sys.exit(1)
except Exception as exc: # pylint: disable=broad-except except Exception: # pylint: disable=broad-except
logger.exception( logger.exception("An uncaught error occurred:")
"A fatal error occurred. Please copy and paste the stacktrace above and make a Github " logger.error(
"issue at https://github.com/jmbannon/ytdl-subscribe/issues with your config and " "Please copy and paste the stacktrace above and make a Github "
"command/subscription yaml file to reproduce. Thanks for trying ytdl-subscribe!" "issue at https://github.com/jmbannon/ytdl-sub/issues with your config and "
"command/subscription yaml file to reproduce. Thanks for trying ytdl-sub!"
) )
sys.exit(1) sys.exit(1)
sys.exit(0) sys.exit(0)
if __name__ == "__main__":
main()

View file

@ -1,5 +1,6 @@
from abc import ABC from abc import ABC
from typing import Generic from typing import Generic
from typing import Optional
from typing import Type from typing import Type
from typing import TypeVar from typing import TypeVar
from typing import final from typing import final
@ -33,7 +34,7 @@ class Plugin(Generic[PluginOptionsT], ABC):
plugin_options: PluginOptionsT, plugin_options: PluginOptionsT,
output_directory: str, output_directory: str,
overrides: Overrides, overrides: Overrides,
enhanced_download_archive: EnhancedDownloadArchive, enhanced_download_archive: Optional[EnhancedDownloadArchive],
): ):
self.plugin_options = plugin_options self.plugin_options = plugin_options
self.output_directory = output_directory self.output_directory = output_directory
@ -46,6 +47,7 @@ class Plugin(Generic[PluginOptionsT], ABC):
def archive_entry_file_name(self, entry: Entry, relative_file_path: str) -> None: def archive_entry_file_name(self, entry: Entry, relative_file_path: str) -> None:
""" """
Adds an entry and a file name that belongs to it into the archive mapping. Adds an entry and a file name that belongs to it into the archive mapping.
If maintain_download_archive is False for the subscription, this method will do nothing.
Parameters Parameters
---------- ----------
@ -54,9 +56,10 @@ class Plugin(Generic[PluginOptionsT], ABC):
relative_file_path: relative_file_path:
The name of the file path relative to the output directory The name of the file path relative to the output directory
""" """
self.__enhanced_download_archive.mapping.add_entry( if self.__enhanced_download_archive:
entry=entry, entry_file_path=relative_file_path self.__enhanced_download_archive.mapping.add_entry(
) entry=entry, entry_file_path=relative_file_path
)
def post_process_entry(self, entry: Entry): def post_process_entry(self, entry: Entry):
""" """

View file

@ -131,12 +131,17 @@ class Subscription:
""" """
return self.overrides.apply_formatter(formatter=self.output_options.output_directory) return self.overrides.apply_formatter(formatter=self.output_options.output_directory)
def _copy_file_to_output_directory(self, source_file_path: str, output_file_name: str): def _copy_file_to_output_directory(
self, entry: Entry, source_file_path: str, output_file_name: str
):
""" """
Helper function to move a file from the working directory to the output directory. Helper function to move a file from the working directory to the output directory.
Will add it to the download archive mapping if the archive is being maintained.
Parameters Parameters
---------- ----------
entry:
Entry that the file belongs to
source_file_path: source_file_path:
Path to the source file Path to the source file
output_file_name: output_file_name:
@ -146,6 +151,9 @@ class Subscription:
os.makedirs(os.path.dirname(destination_file_path), exist_ok=True) os.makedirs(os.path.dirname(destination_file_path), exist_ok=True)
copyfile(source_file_path, destination_file_path) copyfile(source_file_path, destination_file_path)
if self.output_options.maintain_download_archive:
self._enhanced_download_archive.mapping.add_entry(entry, output_file_name)
def _copy_entry_files_to_output_directory(self, entry: Entry): def _copy_entry_files_to_output_directory(self, entry: Entry):
""" """
Helper function to move the media file and optionally thumbnail file to the output directory Helper function to move the media file and optionally thumbnail file to the output directory
@ -160,23 +168,22 @@ class Subscription:
output_file_name = self.overrides.apply_formatter( output_file_name = self.overrides.apply_formatter(
formatter=self.output_options.file_name, entry=entry formatter=self.output_options.file_name, entry=entry
) )
self._enhanced_download_archive.mapping.add_entry(entry, output_file_name)
self._copy_file_to_output_directory( self._copy_file_to_output_directory(
source_file_path=entry.get_download_file_path(), output_file_name=output_file_name entry=entry,
source_file_path=entry.get_download_file_path(),
output_file_name=output_file_name,
) )
if self.output_options.thumbnail_name: if self.output_options.thumbnail_name:
output_thumbnail_name = self.overrides.apply_formatter( output_thumbnail_name = self.overrides.apply_formatter(
formatter=self.output_options.thumbnail_name, entry=entry formatter=self.output_options.thumbnail_name, entry=entry
) )
self._enhanced_download_archive.mapping.add_entry(entry, output_thumbnail_name)
self._copy_file_to_output_directory( self._copy_file_to_output_directory(
entry=entry,
source_file_path=entry.get_download_thumbnail_path(), source_file_path=entry.get_download_thumbnail_path(),
output_file_name=output_thumbnail_name, output_file_name=output_thumbnail_name,
) )
self._enhanced_download_archive.mapping.add_entry(entry, output_file_name)
@contextlib.contextmanager @contextlib.contextmanager
def _prepare_working_directory(self): def _prepare_working_directory(self):
""" """
@ -221,7 +228,9 @@ class Subscription:
plugin_options=plugin_options, plugin_options=plugin_options,
output_directory=self.output_directory, output_directory=self.output_directory,
overrides=self.overrides, overrides=self.overrides,
enhanced_download_archive=self._enhanced_download_archive, enhanced_download_archive=self._enhanced_download_archive
if self.output_options.maintain_download_archive
else None,
) )
plugins.append(plugin) plugins.append(plugin)
@ -238,7 +247,9 @@ class Subscription:
working_directory=self.working_directory, working_directory=self.working_directory,
download_options=self.downloader_options, download_options=self.downloader_options,
ytdl_options=self.ytdl_options.dict, ytdl_options=self.ytdl_options.dict,
download_archive_file_name=self._enhanced_download_archive.archive_file_name, download_archive_file_name=self._enhanced_download_archive.archive_file_name
if self.output_options.maintain_download_archive
else None,
) )
entries = downloader.download() entries = downloader.download()