[BACKEND] Remove individual_download parameter from youtube channel + playlist (#119)
This commit is contained in:
parent
72442ab846
commit
d292ab0510
4 changed files with 19 additions and 71 deletions
|
|
@ -15,7 +15,6 @@ from ytdl_sub.utils.thumbnail import convert_url_thumbnail
|
||||||
from ytdl_sub.validators.date_range_validator import DateRangeValidator
|
from ytdl_sub.validators.date_range_validator import DateRangeValidator
|
||||||
from ytdl_sub.validators.string_formatter_validators import OverridesStringFormatterValidator
|
from ytdl_sub.validators.string_formatter_validators import OverridesStringFormatterValidator
|
||||||
from ytdl_sub.validators.url_validator import YoutubeChannelUrlValidator
|
from ytdl_sub.validators.url_validator import YoutubeChannelUrlValidator
|
||||||
from ytdl_sub.validators.validators import BoolValidator
|
|
||||||
from ytdl_sub.ytdl_additions.enhanced_download_archive import EnhancedDownloadArchive
|
from ytdl_sub.ytdl_additions.enhanced_download_archive import EnhancedDownloadArchive
|
||||||
|
|
||||||
logger = Logger.get()
|
logger = Logger.get()
|
||||||
|
|
@ -49,7 +48,6 @@ class YoutubeChannelDownloaderOptions(YoutubeDownloaderOptions, DateRangeValidat
|
||||||
"after",
|
"after",
|
||||||
"channel_avatar_path",
|
"channel_avatar_path",
|
||||||
"channel_banner_path",
|
"channel_banner_path",
|
||||||
"download_individually",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, name, value):
|
def __init__(self, name, value):
|
||||||
|
|
@ -64,9 +62,6 @@ class YoutubeChannelDownloaderOptions(YoutubeDownloaderOptions, DateRangeValidat
|
||||||
self._channel_banner_path = self._validate_key_if_present(
|
self._channel_banner_path = self._validate_key_if_present(
|
||||||
"channel_banner_path", OverridesStringFormatterValidator
|
"channel_banner_path", OverridesStringFormatterValidator
|
||||||
)
|
)
|
||||||
self._download_individually = self._validate_key_if_present(
|
|
||||||
"download_individually", BoolValidator, default=True
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def channel_url(self) -> str:
|
def channel_url(self) -> str:
|
||||||
|
|
@ -91,15 +86,6 @@ class YoutubeChannelDownloaderOptions(YoutubeDownloaderOptions, DateRangeValidat
|
||||||
"""
|
"""
|
||||||
return self._channel_banner_path
|
return self._channel_banner_path
|
||||||
|
|
||||||
@property
|
|
||||||
def download_individually(self) -> Optional[bool]:
|
|
||||||
"""
|
|
||||||
Optional. Downloads files from the channel individually instead of in bulk. Setting to True
|
|
||||||
is safer when downloading large amounts of videos in case an error occurs. Downloading by
|
|
||||||
bulk (by setting to False) can increase speeds. Defaults to True.
|
|
||||||
"""
|
|
||||||
return self._download_individually.value
|
|
||||||
|
|
||||||
|
|
||||||
class YoutubeChannelDownloader(YoutubeDownloader[YoutubeChannelDownloaderOptions, YoutubeVideo]):
|
class YoutubeChannelDownloader(YoutubeDownloader[YoutubeChannelDownloaderOptions, YoutubeVideo]):
|
||||||
downloader_options_type = YoutubeChannelDownloaderOptions
|
downloader_options_type = YoutubeChannelDownloaderOptions
|
||||||
|
|
@ -155,26 +141,26 @@ class YoutubeChannelDownloader(YoutubeDownloader[YoutubeChannelDownloaderOptions
|
||||||
"""
|
"""
|
||||||
ytdl_options_overrides = {}
|
ytdl_options_overrides = {}
|
||||||
|
|
||||||
# If downloading individually, dry-run the entire channel download first, this will get the
|
|
||||||
# videos that will be downloaded. Afterwards, download each video one-by-one
|
|
||||||
if self.download_options.download_individually:
|
|
||||||
ytdl_options_overrides["skip_download"] = True
|
|
||||||
ytdl_options_overrides["writethumbnail"] = False
|
|
||||||
|
|
||||||
# If a date range is specified when download a YT channel, add it into the ytdl options
|
# If a date range is specified when download a YT channel, add it into the ytdl options
|
||||||
source_date_range = self.download_options.get_date_range()
|
source_date_range = self.download_options.get_date_range()
|
||||||
if source_date_range:
|
if source_date_range:
|
||||||
ytdl_options_overrides["daterange"] = source_date_range
|
ytdl_options_overrides["daterange"] = source_date_range
|
||||||
|
|
||||||
|
# dry-run the entire channel download first, this will get the
|
||||||
|
# videos that will be downloaded. Afterwards, download each video one-by-one
|
||||||
entry_dicts = self.extract_info_via_info_json(
|
entry_dicts = self.extract_info_via_info_json(
|
||||||
ytdl_options_overrides=ytdl_options_overrides, url=self.download_options.channel_url
|
ytdl_options_overrides=dict(
|
||||||
|
{"skip_download": True, "write_thumbnail": False}, **ytdl_options_overrides
|
||||||
|
),
|
||||||
|
url=self.download_options.channel_url,
|
||||||
)
|
)
|
||||||
self.channel = self._get_channel_from_entry_dicts(entry_dicts=entry_dicts)
|
self.channel = self._get_channel_from_entry_dicts(entry_dicts=entry_dicts)
|
||||||
|
|
||||||
for entry_dict in entry_dicts:
|
for entry_dict in entry_dicts:
|
||||||
if entry_dict.get("extractor") == "youtube":
|
if entry_dict.get("extractor") == "youtube":
|
||||||
# Only do the individual download if it is not dry-run and downloading individually
|
# Only do the individual download if it is not dry-run
|
||||||
if not self.is_dry_run and self.download_options.download_individually:
|
# TODO: Respect the Reject/Exist exceptions
|
||||||
|
if not self.is_dry_run:
|
||||||
ytdl_options_overrides["playlist_items"] = str(entry_dict.get("playlist_index"))
|
ytdl_options_overrides["playlist_items"] = str(entry_dict.get("playlist_index"))
|
||||||
_ = self.extract_info(
|
_ = self.extract_info(
|
||||||
ytdl_options_overrides={
|
ytdl_options_overrides={
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,10 @@
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from ytdl_sub.downloaders.youtube.abc import YoutubeDownloader
|
from ytdl_sub.downloaders.youtube.abc import YoutubeDownloader
|
||||||
from ytdl_sub.downloaders.youtube.abc import YoutubeDownloaderOptions
|
from ytdl_sub.downloaders.youtube.abc import YoutubeDownloaderOptions
|
||||||
from ytdl_sub.entries.youtube import YoutubePlaylistVideo
|
from ytdl_sub.entries.youtube import YoutubePlaylistVideo
|
||||||
from ytdl_sub.validators.url_validator import YoutubePlaylistUrlValidator
|
from ytdl_sub.validators.url_validator import YoutubePlaylistUrlValidator
|
||||||
from ytdl_sub.validators.validators import BoolValidator
|
|
||||||
|
|
||||||
|
|
||||||
class YoutubePlaylistDownloaderOptions(YoutubeDownloaderOptions):
|
class YoutubePlaylistDownloaderOptions(YoutubeDownloaderOptions):
|
||||||
|
|
@ -28,16 +26,12 @@ class YoutubePlaylistDownloaderOptions(YoutubeDownloaderOptions):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_required_keys = {"playlist_url"}
|
_required_keys = {"playlist_url"}
|
||||||
_optional_keys = {"download_individually"}
|
|
||||||
|
|
||||||
def __init__(self, name, value):
|
def __init__(self, name, value):
|
||||||
super().__init__(name, value)
|
super().__init__(name, value)
|
||||||
self._playlist_url = self._validate_key(
|
self._playlist_url = self._validate_key(
|
||||||
"playlist_url", YoutubePlaylistUrlValidator
|
"playlist_url", YoutubePlaylistUrlValidator
|
||||||
).playlist_url
|
).playlist_url
|
||||||
self._download_individually = self._validate_key_if_present(
|
|
||||||
"download_individually", BoolValidator, default=True
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def playlist_url(self) -> str:
|
def playlist_url(self) -> str:
|
||||||
|
|
@ -47,15 +41,6 @@ class YoutubePlaylistDownloaderOptions(YoutubeDownloaderOptions):
|
||||||
"""
|
"""
|
||||||
return self._playlist_url
|
return self._playlist_url
|
||||||
|
|
||||||
@property
|
|
||||||
def download_individually(self) -> Optional[bool]:
|
|
||||||
"""
|
|
||||||
Optional. Downloads files from the playlist individually instead of in bulk. Setting to True
|
|
||||||
is safer when downloading large amounts of videos in case an error occurs. Downloading by
|
|
||||||
bulk (by setting to False) can increase speeds. Defaults to True.
|
|
||||||
"""
|
|
||||||
return self._download_individually.value
|
|
||||||
|
|
||||||
|
|
||||||
class YoutubePlaylistDownloader(
|
class YoutubePlaylistDownloader(
|
||||||
YoutubeDownloader[YoutubePlaylistDownloaderOptions, YoutubePlaylistVideo]
|
YoutubeDownloader[YoutubePlaylistDownloaderOptions, YoutubePlaylistVideo]
|
||||||
|
|
@ -84,25 +69,24 @@ class YoutubePlaylistDownloader(
|
||||||
|
|
||||||
def download(self) -> Generator[YoutubePlaylistVideo, None, None]:
|
def download(self) -> Generator[YoutubePlaylistVideo, None, None]:
|
||||||
"""
|
"""
|
||||||
Downloads all videos in a Youtube playlist
|
Downloads all videos in a Youtube playlist.
|
||||||
|
|
||||||
|
Dry-run the entire playlist download first. This will get the videos that will be
|
||||||
|
downloaded. Afterwards, download each video one-by-one
|
||||||
"""
|
"""
|
||||||
ytdl_options_overrides = {}
|
|
||||||
|
|
||||||
# If downloading individually, dry-run the entire channel download first, this will get the
|
|
||||||
# videos that will be downloaded. Afterwards, download each video one-by-one
|
|
||||||
if self.download_options.download_individually:
|
|
||||||
ytdl_options_overrides["skip_download"] = True
|
|
||||||
ytdl_options_overrides["writethumbnail"] = False
|
|
||||||
|
|
||||||
entry_dicts = self.extract_info_via_info_json(
|
entry_dicts = self.extract_info_via_info_json(
|
||||||
ytdl_options_overrides=ytdl_options_overrides, url=self.download_options.playlist_url
|
ytdl_options_overrides={
|
||||||
|
"skip_download": True,
|
||||||
|
"writethumbnail": False,
|
||||||
|
},
|
||||||
|
url=self.download_options.playlist_url,
|
||||||
)
|
)
|
||||||
|
|
||||||
for entry_dict in entry_dicts:
|
for entry_dict in entry_dicts:
|
||||||
if entry_dict.get("extractor") == "youtube":
|
if entry_dict.get("extractor") == "youtube":
|
||||||
|
|
||||||
# Only do the individual download if it is not dry-run and downloading individually
|
# Only do the individual download if it is not dry-run and downloading individually
|
||||||
if not self.is_dry_run and self.download_options.download_individually:
|
if not self.is_dry_run:
|
||||||
_ = self.extract_info(
|
_ = self.extract_info(
|
||||||
ytdl_options_overrides={
|
ytdl_options_overrides={
|
||||||
"playlist_items": str(entry_dict.get("playlist_index")),
|
"playlist_items": str(entry_dict.get("playlist_index")),
|
||||||
|
|
|
||||||
|
|
@ -225,7 +225,6 @@ class TestChannelAsKodiTvShow:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@pytest.mark.parametrize("dry_run", [True, False])
|
@pytest.mark.parametrize("dry_run", [True, False])
|
||||||
@pytest.mark.parametrize("download_individually", [True, False])
|
|
||||||
def test_full_channel_download(
|
def test_full_channel_download(
|
||||||
self,
|
self,
|
||||||
channel_subscription_generator,
|
channel_subscription_generator,
|
||||||
|
|
@ -233,10 +232,7 @@ class TestChannelAsKodiTvShow:
|
||||||
expected_full_channel_download,
|
expected_full_channel_download,
|
||||||
output_directory,
|
output_directory,
|
||||||
dry_run,
|
dry_run,
|
||||||
download_individually,
|
|
||||||
):
|
):
|
||||||
channel_preset_dict["youtube"]["download_individually"] = download_individually
|
|
||||||
|
|
||||||
full_channel_subscription = channel_subscription_generator(preset_dict=channel_preset_dict)
|
full_channel_subscription = channel_subscription_generator(preset_dict=channel_preset_dict)
|
||||||
transaction_log = full_channel_subscription.download(dry_run=dry_run)
|
transaction_log = full_channel_subscription.download(dry_run=dry_run)
|
||||||
assert_transaction_log_matches(
|
assert_transaction_log_matches(
|
||||||
|
|
@ -248,7 +244,6 @@ class TestChannelAsKodiTvShow:
|
||||||
expected_full_channel_download.assert_files_exist(relative_directory=output_directory)
|
expected_full_channel_download.assert_files_exist(relative_directory=output_directory)
|
||||||
|
|
||||||
@pytest.mark.parametrize("dry_run", [True, False])
|
@pytest.mark.parametrize("dry_run", [True, False])
|
||||||
@pytest.mark.parametrize("download_individually", [True, False])
|
|
||||||
def test_recent_channel_download(
|
def test_recent_channel_download(
|
||||||
self,
|
self,
|
||||||
channel_subscription_generator,
|
channel_subscription_generator,
|
||||||
|
|
@ -256,10 +251,7 @@ class TestChannelAsKodiTvShow:
|
||||||
expected_recent_channel_download,
|
expected_recent_channel_download,
|
||||||
output_directory,
|
output_directory,
|
||||||
dry_run,
|
dry_run,
|
||||||
download_individually,
|
|
||||||
):
|
):
|
||||||
recent_channel_preset_dict["youtube"]["download_individually"] = download_individually
|
|
||||||
|
|
||||||
recent_channel_subscription = channel_subscription_generator(
|
recent_channel_subscription = channel_subscription_generator(
|
||||||
preset_dict=recent_channel_preset_dict
|
preset_dict=recent_channel_preset_dict
|
||||||
)
|
)
|
||||||
|
|
@ -291,7 +283,6 @@ class TestChannelAsKodiTvShow:
|
||||||
)
|
)
|
||||||
|
|
||||||
@pytest.mark.parametrize("dry_run", [True, False])
|
@pytest.mark.parametrize("dry_run", [True, False])
|
||||||
@pytest.mark.parametrize("download_individually", [True, False])
|
|
||||||
def test_recent_channel_download__no_vids_in_range(
|
def test_recent_channel_download__no_vids_in_range(
|
||||||
self,
|
self,
|
||||||
channel_subscription_generator,
|
channel_subscription_generator,
|
||||||
|
|
@ -299,9 +290,7 @@ class TestChannelAsKodiTvShow:
|
||||||
expected_recent_channel_no_vids_in_range_download,
|
expected_recent_channel_no_vids_in_range_download,
|
||||||
output_directory,
|
output_directory,
|
||||||
dry_run,
|
dry_run,
|
||||||
download_individually,
|
|
||||||
):
|
):
|
||||||
recent_channel_preset_dict["youtube"]["download_individually"] = download_individually
|
|
||||||
recent_channel_preset_dict["youtube"]["after"] = "21000101"
|
recent_channel_preset_dict["youtube"]["after"] = "21000101"
|
||||||
|
|
||||||
recent_channel_no_vids_in_range_subscription = channel_subscription_generator(
|
recent_channel_no_vids_in_range_subscription = channel_subscription_generator(
|
||||||
|
|
@ -321,7 +310,6 @@ class TestChannelAsKodiTvShow:
|
||||||
)
|
)
|
||||||
|
|
||||||
@pytest.mark.parametrize("dry_run", [True, False])
|
@pytest.mark.parametrize("dry_run", [True, False])
|
||||||
@pytest.mark.parametrize("download_individually", [True, False])
|
|
||||||
def test_rolling_recent_channel_download(
|
def test_rolling_recent_channel_download(
|
||||||
self,
|
self,
|
||||||
channel_subscription_generator,
|
channel_subscription_generator,
|
||||||
|
|
@ -331,13 +319,7 @@ class TestChannelAsKodiTvShow:
|
||||||
expected_rolling_recent_channel_download,
|
expected_rolling_recent_channel_download,
|
||||||
output_directory,
|
output_directory,
|
||||||
dry_run,
|
dry_run,
|
||||||
download_individually,
|
|
||||||
):
|
):
|
||||||
recent_channel_preset_dict["youtube"]["download_individually"] = download_individually
|
|
||||||
rolling_recent_channel_preset_dict["youtube"][
|
|
||||||
"download_individually"
|
|
||||||
] = download_individually
|
|
||||||
|
|
||||||
recent_channel_subscription = channel_subscription_generator(
|
recent_channel_subscription = channel_subscription_generator(
|
||||||
preset_dict=recent_channel_preset_dict
|
preset_dict=recent_channel_preset_dict
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,6 @@ class TestPlaylistAsKodiMusicVideo:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@pytest.mark.parametrize("dry_run", [True, False])
|
@pytest.mark.parametrize("dry_run", [True, False])
|
||||||
@pytest.mark.parametrize("download_individually", [True, False])
|
|
||||||
def test_playlist_download(
|
def test_playlist_download(
|
||||||
self,
|
self,
|
||||||
music_video_config,
|
music_video_config,
|
||||||
|
|
@ -100,10 +99,7 @@ class TestPlaylistAsKodiMusicVideo:
|
||||||
expected_playlist_download,
|
expected_playlist_download,
|
||||||
output_directory,
|
output_directory,
|
||||||
dry_run,
|
dry_run,
|
||||||
download_individually,
|
|
||||||
):
|
):
|
||||||
playlist_preset_dict["youtube"]["download_individually"] = download_individually
|
|
||||||
|
|
||||||
playlist_subscription = Subscription.from_dict(
|
playlist_subscription = Subscription.from_dict(
|
||||||
config=music_video_config,
|
config=music_video_config,
|
||||||
preset_name="music_video_playlist_test",
|
preset_name="music_video_playlist_test",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue