[FEATURE] Automatically handle playlists ordered in reverse
This commit is contained in:
parent
f940d3ec3e
commit
052db8704b
4 changed files with 71 additions and 0 deletions
|
|
@ -1,11 +1,14 @@
|
||||||
import os
|
import os
|
||||||
import posixpath
|
import posixpath
|
||||||
|
from typing import List
|
||||||
|
|
||||||
from yt_dlp.utils import sanitize_filename
|
from yt_dlp.utils import sanitize_filename
|
||||||
|
|
||||||
|
from ytdl_sub.downloaders.ytdlp import YTDLP
|
||||||
from ytdl_sub.script.functions import Functions
|
from ytdl_sub.script.functions import Functions
|
||||||
from ytdl_sub.script.types.map import Map
|
from ytdl_sub.script.types.map import Map
|
||||||
from ytdl_sub.script.types.resolvable import AnyArgument
|
from ytdl_sub.script.types.resolvable import AnyArgument
|
||||||
|
from ytdl_sub.script.types.resolvable import Boolean
|
||||||
from ytdl_sub.script.types.resolvable import Integer
|
from ytdl_sub.script.types.resolvable import Integer
|
||||||
from ytdl_sub.script.types.resolvable import ReturnableArgument
|
from ytdl_sub.script.types.resolvable import ReturnableArgument
|
||||||
from ytdl_sub.script.types.resolvable import String
|
from ytdl_sub.script.types.resolvable import String
|
||||||
|
|
@ -21,6 +24,51 @@ _days_in_month = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
||||||
|
|
||||||
|
|
||||||
class CustomFunctions:
|
class CustomFunctions:
|
||||||
|
@staticmethod
|
||||||
|
def is_playlist_ordered_by_newest(url: String) -> Boolean:
|
||||||
|
"""
|
||||||
|
Queries a playlist-based URL using yt-dlp to see if it is ordered from newest
|
||||||
|
(lower playlist number) to oldest.
|
||||||
|
"""
|
||||||
|
info_only_kwargs = {
|
||||||
|
"skip_download": True,
|
||||||
|
"writethumbnail": False,
|
||||||
|
"writeinfojson": False,
|
||||||
|
"ignoreerrors": True,
|
||||||
|
"extract_flat": "discard",
|
||||||
|
"playlist_items": "0:5",
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
url_info = YTDLP.extract_info(
|
||||||
|
ytdl_options_overrides=info_only_kwargs,
|
||||||
|
url=url.value,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
not isinstance(url_info, dict)
|
||||||
|
or not isinstance(url_info.get("entries"), list)
|
||||||
|
or not len(url_info["entries"])
|
||||||
|
):
|
||||||
|
return Boolean(False)
|
||||||
|
|
||||||
|
upload_dates: List[str] = []
|
||||||
|
for entry in url_info["entries"]:
|
||||||
|
if entry.get("uploader_id") and entry.get("url"):
|
||||||
|
full_entry = YTDLP.extract_info(
|
||||||
|
ytdl_options_overrides=info_only_kwargs, url=entry.get("url")
|
||||||
|
)
|
||||||
|
if isinstance(full_entry.get("upload_date"), str):
|
||||||
|
upload_dates.append(full_entry["upload_date"])
|
||||||
|
|
||||||
|
for idx in range(1, len(upload_dates)):
|
||||||
|
if upload_dates[idx - 1] < upload_dates[idx]:
|
||||||
|
return Boolean(False)
|
||||||
|
|
||||||
|
return Boolean(True)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
return Boolean(False)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def legacy_bracket_safety(value: ReturnableArgument) -> ReturnableArgument:
|
def legacy_bracket_safety(value: ReturnableArgument) -> ReturnableArgument:
|
||||||
"""
|
"""
|
||||||
|
|
@ -170,6 +218,7 @@ class CustomFunctions:
|
||||||
Register Custom functions once and only once
|
Register Custom functions once and only once
|
||||||
"""
|
"""
|
||||||
if not Functions.is_built_in("sanitize"):
|
if not Functions.is_built_in("sanitize"):
|
||||||
|
Functions.register_function(CustomFunctions.is_playlist_ordered_by_newest)
|
||||||
Functions.register_function(CustomFunctions.legacy_bracket_safety)
|
Functions.register_function(CustomFunctions.legacy_bracket_safety)
|
||||||
Functions.register_function(CustomFunctions.truncate_filepath_if_too_long)
|
Functions.register_function(CustomFunctions.truncate_filepath_if_too_long)
|
||||||
Functions.register_function(CustomFunctions.to_native_filepath)
|
Functions.register_function(CustomFunctions.to_native_filepath)
|
||||||
|
|
|
||||||
0
tests/e2e/entries/__init__.py
Normal file
0
tests/e2e/entries/__init__.py
Normal file
0
tests/e2e/entries/script/__init__.py
Normal file
0
tests/e2e/entries/script/__init__.py
Normal file
22
tests/e2e/entries/script/test_custom_functions.py
Normal file
22
tests/e2e/entries/script/test_custom_functions.py
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
from unit.script.conftest import single_variable_output
|
||||||
|
|
||||||
|
|
||||||
|
class TestCustomFunctions:
|
||||||
|
def test_is_playlist_ordered_by_newest_true(self):
|
||||||
|
assert (
|
||||||
|
single_variable_output(
|
||||||
|
"{%is_playlist_ordered_by_newest('https://www.youtube.com/playlist?list=PL5BC0FC26BECA5A35')}"
|
||||||
|
)
|
||||||
|
is True
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_is_playlist_ordered_by_newest_false(self):
|
||||||
|
assert (
|
||||||
|
single_variable_output(
|
||||||
|
"{%is_playlist_ordered_by_newest('https://www.youtube.com/playlist?list=PL2KvlCGf4yFftX466OnFS8wvuSosBfUgm')}"
|
||||||
|
)
|
||||||
|
is False
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_is_playlist_ordered_by_newest_defaults_false(self):
|
||||||
|
assert single_variable_output("{%is_playlist_ordered_by_newest('aaaaaa')}") is False
|
||||||
Loading…
Reference in a new issue