[FEATURE] Automatically handle playlists ordered in reverse

This commit is contained in:
Jesse Bannon 2024-03-25 00:03:38 -07:00
parent f940d3ec3e
commit 052db8704b
4 changed files with 71 additions and 0 deletions

View file

@ -1,11 +1,14 @@
import os
import posixpath
from typing import List
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.types.map import Map
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 ReturnableArgument
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:
@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
def legacy_bracket_safety(value: ReturnableArgument) -> ReturnableArgument:
"""
@ -170,6 +218,7 @@ class CustomFunctions:
Register Custom functions once and only once
"""
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.truncate_filepath_if_too_long)
Functions.register_function(CustomFunctions.to_native_filepath)

View file

View file

View 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