from typing import Dict from typing import List from typing import Optional from ytdl_sub.downloaders.downloader import Downloader from ytdl_sub.downloaders.downloader import DownloaderValidator from ytdl_sub.downloaders.generic.collection_validator import CollectionValidator from ytdl_sub.validators.string_formatter_validators import OverridesStringFormatterValidator from ytdl_sub.validators.url_validator import YoutubeChannelUrlValidator class YoutubeChannelDownloaderOptions(DownloaderValidator): """ Downloads all videos from a youtube channel. Usage: .. code-block:: yaml presets: my_example_preset: youtube: # required download_strategy: "channel" channel_url: "UCsvn_Po0SmunchJYtttWpOxMg" # optional channel_avatar_path: "poster.jpg" channel_banner_path: "fanart.jpg" """ _required_keys = {"channel_url"} _optional_keys = { "channel_avatar_path", "channel_banner_path", } def __init__(self, name, value): super().__init__(name, value) self._channel_url = self._validate_key( "channel_url", YoutubeChannelUrlValidator ).channel_url self._channel_avatar_path = self._validate_key_if_present( "channel_avatar_path", OverridesStringFormatterValidator ) self._channel_banner_path = self._validate_key_if_present( "channel_banner_path", OverridesStringFormatterValidator ) @property def collection_validator(self) -> CollectionValidator: """Download from the channel url""" playlist_thumbnails: List[Dict] = [] if self._channel_avatar_path: playlist_thumbnails.append( { "name": self._channel_avatar_path.format_string, "uid": "avatar_uncropped", } ) if self._channel_banner_path: playlist_thumbnails.append( { "name": self._channel_banner_path.format_string, "uid": "banner_uncropped", } ) return CollectionValidator( name=self._name, value={ "urls": [ { "url": self.channel_url, "playlist_thumbnails": playlist_thumbnails, "variables": {"playlist_size": "{playlist_count}"}, } ] }, ) @property def channel_url(self) -> str: """ Required. The channel's url, i.e. ``https://www.youtube.com/channel/UCsvn_Po0SmunchJYOWpOxMg``. URLs with ``/username`` or ``/c`` are valid to use. """ return self._channel_url @property def channel_avatar_path(self) -> Optional[OverridesStringFormatterValidator]: """ Optional. Path to store the channel's avatar thumbnail image to. """ return self._channel_avatar_path @property def channel_banner_path(self) -> Optional[OverridesStringFormatterValidator]: """ Optional. Path to store the channel's banner image to. """ return self._channel_banner_path class YoutubeChannelDownloader(Downloader[YoutubeChannelDownloaderOptions]): downloader_options_type = YoutubeChannelDownloaderOptions # pylint: disable=line-too-long @classmethod def ytdl_option_defaults(cls) -> Dict: """ Default `ytdl_options`_ for ``channel`` .. code-block:: yaml ytdl_options: ignoreerrors: True # ignore errors like hidden videos, age restriction, etc break_on_existing: True # stop downloads (newest to oldest) if a video is already downloaded """ return dict( super().ytdl_option_defaults(), **{ "break_on_existing": True, }, ) # pylint: enable=line-too-long