Fix error when maintain_download_archive=False, improve error message (#39)
This commit is contained in:
parent
0e8ea1f9b6
commit
de5dade937
4 changed files with 94 additions and 25 deletions
55
config.yaml
55
config.yaml
|
|
@ -26,17 +26,37 @@ presets:
|
|||
year: "{album_year}"
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
file_name: "{sanitized_artist} - {sanitized_title}.{ext}"
|
||||
thumbnail_name: "{sanitized_artist} - {sanitized_title}.jpg"
|
||||
output_directory: "{music_video_directory}/{sanitized_artist}"
|
||||
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:
|
||||
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_name: "{sanitized_artist} - {sanitized_title}.nfo"
|
||||
nfo_name: "{music_video_name}.nfo"
|
||||
nfo_root: "musicvideo"
|
||||
tags:
|
||||
artist: "{artist}"
|
||||
|
|
@ -44,6 +64,33 @@ presets:
|
|||
album: "Music Videos"
|
||||
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:
|
||||
youtube:
|
||||
download_strategy: "channel"
|
||||
|
|
|
|||
|
|
@ -58,9 +58,9 @@ def _download_subscription_from_cli(config: ConfigFile, extra_args: List[str]) -
|
|||
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 len(sys.argv) < 2:
|
||||
|
|
@ -80,18 +80,26 @@ def main():
|
|||
logger.info("Download complete!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
def main():
|
||||
"""
|
||||
Entrypoint for ytdl-sub
|
||||
"""
|
||||
try:
|
||||
main()
|
||||
_main()
|
||||
except ValidationException as validation_exception:
|
||||
logger.error(validation_exception)
|
||||
sys.exit(1)
|
||||
except Exception as exc: # pylint: disable=broad-except
|
||||
logger.exception(
|
||||
"A fatal error occurred. Please copy and paste the stacktrace above and make a Github "
|
||||
"issue at https://github.com/jmbannon/ytdl-subscribe/issues with your config and "
|
||||
"command/subscription yaml file to reproduce. Thanks for trying ytdl-subscribe!"
|
||||
except Exception: # pylint: disable=broad-except
|
||||
logger.exception("An uncaught error occurred:")
|
||||
logger.error(
|
||||
"Please copy and paste the stacktrace above and make a Github "
|
||||
"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(0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
from abc import ABC
|
||||
from typing import Generic
|
||||
from typing import Optional
|
||||
from typing import Type
|
||||
from typing import TypeVar
|
||||
from typing import final
|
||||
|
|
@ -33,7 +34,7 @@ class Plugin(Generic[PluginOptionsT], ABC):
|
|||
plugin_options: PluginOptionsT,
|
||||
output_directory: str,
|
||||
overrides: Overrides,
|
||||
enhanced_download_archive: EnhancedDownloadArchive,
|
||||
enhanced_download_archive: Optional[EnhancedDownloadArchive],
|
||||
):
|
||||
self.plugin_options = plugin_options
|
||||
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:
|
||||
"""
|
||||
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
|
||||
----------
|
||||
|
|
@ -54,9 +56,10 @@ class Plugin(Generic[PluginOptionsT], ABC):
|
|||
relative_file_path:
|
||||
The name of the file path relative to the output directory
|
||||
"""
|
||||
self.__enhanced_download_archive.mapping.add_entry(
|
||||
entry=entry, entry_file_path=relative_file_path
|
||||
)
|
||||
if self.__enhanced_download_archive:
|
||||
self.__enhanced_download_archive.mapping.add_entry(
|
||||
entry=entry, entry_file_path=relative_file_path
|
||||
)
|
||||
|
||||
def post_process_entry(self, entry: Entry):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -131,12 +131,17 @@ class Subscription:
|
|||
"""
|
||||
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.
|
||||
Will add it to the download archive mapping if the archive is being maintained.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
entry:
|
||||
Entry that the file belongs to
|
||||
source_file_path:
|
||||
Path to the source file
|
||||
output_file_name:
|
||||
|
|
@ -146,6 +151,9 @@ class Subscription:
|
|||
os.makedirs(os.path.dirname(destination_file_path), exist_ok=True)
|
||||
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):
|
||||
"""
|
||||
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(
|
||||
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(
|
||||
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:
|
||||
output_thumbnail_name = self.overrides.apply_formatter(
|
||||
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(
|
||||
entry=entry,
|
||||
source_file_path=entry.get_download_thumbnail_path(),
|
||||
output_file_name=output_thumbnail_name,
|
||||
)
|
||||
|
||||
self._enhanced_download_archive.mapping.add_entry(entry, output_file_name)
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _prepare_working_directory(self):
|
||||
"""
|
||||
|
|
@ -221,7 +228,9 @@ class Subscription:
|
|||
plugin_options=plugin_options,
|
||||
output_directory=self.output_directory,
|
||||
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)
|
||||
|
|
@ -238,7 +247,9 @@ class Subscription:
|
|||
working_directory=self.working_directory,
|
||||
download_options=self.downloader_options,
|
||||
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()
|
||||
|
|
|
|||
Loading…
Reference in a new issue