[FEATURE] download_reverse in URL download strategy (#531)
* [FEATURE] download_reverse in URL download strategy * doc fix
This commit is contained in:
parent
bc90348bf0
commit
f42973cf2f
4 changed files with 40 additions and 12 deletions
|
|
@ -63,7 +63,7 @@ download strategy has its own set of parameters.
|
||||||
url
|
url
|
||||||
'''
|
'''
|
||||||
.. autoclass:: ytdl_sub.downloaders.generic.url.UrlDownloadOptions()
|
.. autoclass:: ytdl_sub.downloaders.generic.url.UrlDownloadOptions()
|
||||||
:members: url, playlist_thumbnails, source_thumbnails
|
:members: url, playlist_thumbnails, source_thumbnails, download_reverse
|
||||||
:member-order: bysource
|
:member-order: bysource
|
||||||
|
|
||||||
multi_url
|
multi_url
|
||||||
|
|
|
||||||
|
|
@ -476,10 +476,14 @@ class Downloader(DownloadArchiver, Generic[DownloaderOptionsT], ABC):
|
||||||
|
|
||||||
return entry
|
return entry
|
||||||
|
|
||||||
def _download_entries(self, entries: List[Entry]) -> Generator[Entry, None, None]:
|
def _download_entries(
|
||||||
# Download entries in reverse order since they are scraped in the opposite direction.
|
self, url_validator: UrlValidator, entries: List[Entry]
|
||||||
# Helps deal with break_on_existing
|
) -> Generator[Entry, None, None]:
|
||||||
for entry in reversed(entries):
|
entries_to_iterate = entries
|
||||||
|
if url_validator.download_reverse:
|
||||||
|
entries_to_iterate = reversed(entries)
|
||||||
|
|
||||||
|
for entry in entries_to_iterate:
|
||||||
self._url_state.entries_downloaded += 1
|
self._url_state.entries_downloaded += 1
|
||||||
|
|
||||||
if self._is_downloaded(entry):
|
if self._is_downloaded(entry):
|
||||||
|
|
@ -500,13 +504,19 @@ class Downloader(DownloadArchiver, Generic[DownloaderOptionsT], ABC):
|
||||||
yield self._download_entry(entry)
|
yield self._download_entry(entry)
|
||||||
self._mark_downloaded(entry)
|
self._mark_downloaded(entry)
|
||||||
|
|
||||||
def _download_parent_entry(self, parent: EntryParent) -> Generator[Entry, None, None]:
|
def _download_parent_entry(
|
||||||
for entry_child in self._download_entries(parent.entry_children()):
|
self, url_validator: UrlValidator, parent: EntryParent
|
||||||
|
) -> Generator[Entry, None, None]:
|
||||||
|
for entry_child in self._download_entries(
|
||||||
|
url_validator=url_validator, entries=parent.entry_children()
|
||||||
|
):
|
||||||
yield entry_child
|
yield entry_child
|
||||||
|
|
||||||
# Recursion the parent's parent entries
|
# Recursion the parent's parent entries
|
||||||
for parent_child in reversed(parent.parent_children()):
|
for parent_child in reversed(parent.parent_children()):
|
||||||
for entry_child in self._download_parent_entry(parent=parent_child):
|
for entry_child in self._download_parent_entry(
|
||||||
|
url_validator=url_validator, parent=parent_child
|
||||||
|
):
|
||||||
yield entry_child
|
yield entry_child
|
||||||
|
|
||||||
def _set_collection_variables(self, collection_url: UrlValidator, entry: Entry | EntryParent):
|
def _set_collection_variables(self, collection_url: UrlValidator, entry: Entry | EntryParent):
|
||||||
|
|
@ -554,6 +564,7 @@ class Downloader(DownloadArchiver, Generic[DownloaderOptionsT], ABC):
|
||||||
|
|
||||||
def _download(
|
def _download(
|
||||||
self,
|
self,
|
||||||
|
url_validator: UrlValidator,
|
||||||
parents: List[EntryParent],
|
parents: List[EntryParent],
|
||||||
orphans: List[Entry],
|
orphans: List[Entry],
|
||||||
) -> Generator[Entry, None, None]:
|
) -> Generator[Entry, None, None]:
|
||||||
|
|
@ -563,10 +574,12 @@ class Downloader(DownloadArchiver, Generic[DownloaderOptionsT], ABC):
|
||||||
# Delete info json files afterwards so other collection URLs do not use them
|
# Delete info json files afterwards so other collection URLs do not use them
|
||||||
with self._separate_download_archives(clear_info_json_files=True):
|
with self._separate_download_archives(clear_info_json_files=True):
|
||||||
for parent in parents:
|
for parent in parents:
|
||||||
for entry_child in self._download_parent_entry(parent=parent):
|
for entry_child in self._download_parent_entry(
|
||||||
|
url_validator=url_validator, parent=parent
|
||||||
|
):
|
||||||
yield entry_child
|
yield entry_child
|
||||||
|
|
||||||
for orphan in self._download_entries(orphans):
|
for orphan in self._download_entries(url_validator=url_validator, entries=orphans):
|
||||||
yield orphan
|
yield orphan
|
||||||
|
|
||||||
def download(
|
def download(
|
||||||
|
|
@ -585,7 +598,9 @@ class Downloader(DownloadArchiver, Generic[DownloaderOptionsT], ABC):
|
||||||
download_logger.info(
|
download_logger.info(
|
||||||
"Beginning downloads for %s", self.overrides.apply_formatter(collection_url.url)
|
"Beginning downloads for %s", self.overrides.apply_formatter(collection_url.url)
|
||||||
)
|
)
|
||||||
for entry in self._download(parents=parents, orphans=orphan_entries):
|
for entry in self._download(
|
||||||
|
url_validator=collection_url, parents=parents, orphans=orphan_entries
|
||||||
|
):
|
||||||
# Update thumbnails in case of last_entry
|
# Update thumbnails in case of last_entry
|
||||||
self._download_url_thumbnails(collection_url=collection_url, entry=entry)
|
self._download_url_thumbnails(collection_url=collection_url, entry=entry)
|
||||||
yield entry
|
yield entry
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ class UrlDownloadOptions(UrlValidator, DownloaderValidator):
|
||||||
uid: "avatar_uncropped"
|
uid: "avatar_uncropped"
|
||||||
- name: "fanart.jpg"
|
- name: "fanart.jpg"
|
||||||
uid: "banner_uncropped"
|
uid: "banner_uncropped"
|
||||||
|
download_reverse: True
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ from ytdl_sub.validators.strict_dict_validator import StrictDictValidator
|
||||||
from ytdl_sub.validators.string_formatter_validators import DictFormatterValidator
|
from ytdl_sub.validators.string_formatter_validators import DictFormatterValidator
|
||||||
from ytdl_sub.validators.string_formatter_validators import OverridesStringFormatterValidator
|
from ytdl_sub.validators.string_formatter_validators import OverridesStringFormatterValidator
|
||||||
from ytdl_sub.validators.string_formatter_validators import StringFormatterValidator
|
from ytdl_sub.validators.string_formatter_validators import StringFormatterValidator
|
||||||
|
from ytdl_sub.validators.validators import BoolValidator
|
||||||
from ytdl_sub.validators.validators import ListValidator
|
from ytdl_sub.validators.validators import ListValidator
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -41,7 +42,7 @@ class UrlThumbnailListValidator(ListValidator[UrlThumbnailValidator]):
|
||||||
|
|
||||||
class UrlValidator(StrictDictValidator):
|
class UrlValidator(StrictDictValidator):
|
||||||
_required_keys = {"url"}
|
_required_keys = {"url"}
|
||||||
_optional_keys = {"variables", "source_thumbnails", "playlist_thumbnails"}
|
_optional_keys = {"variables", "source_thumbnails", "playlist_thumbnails", "download_reverse"}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def partial_validate(cls, name: str, value: Any) -> None:
|
def partial_validate(cls, name: str, value: Any) -> None:
|
||||||
|
|
@ -67,6 +68,9 @@ class UrlValidator(StrictDictValidator):
|
||||||
self._playlist_thumbnails = self._validate_key_if_present(
|
self._playlist_thumbnails = self._validate_key_if_present(
|
||||||
key="playlist_thumbnails", validator=UrlThumbnailListValidator, default=[]
|
key="playlist_thumbnails", validator=UrlThumbnailListValidator, default=[]
|
||||||
)
|
)
|
||||||
|
self._download_reverse = self._validate_key(
|
||||||
|
key="download_reverse", validator=BoolValidator, default=True
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def url(self) -> OverridesStringFormatterValidator:
|
def url(self) -> OverridesStringFormatterValidator:
|
||||||
|
|
@ -134,6 +138,14 @@ class UrlValidator(StrictDictValidator):
|
||||||
"""
|
"""
|
||||||
return self._source_thumbnails
|
return self._source_thumbnails
|
||||||
|
|
||||||
|
@property
|
||||||
|
def download_reverse(self) -> bool:
|
||||||
|
"""
|
||||||
|
Optional. Whether to download entries in the reverse order of the metadata downloaded.
|
||||||
|
Defaults to True.
|
||||||
|
"""
|
||||||
|
return self._download_reverse.value
|
||||||
|
|
||||||
|
|
||||||
class UrlListValidator(ListValidator[UrlValidator]):
|
class UrlListValidator(ListValidator[UrlValidator]):
|
||||||
_inner_list_type = UrlValidator
|
_inner_list_type = UrlValidator
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue