kwargs almost gone

This commit is contained in:
Jesse Bannon 2023-12-13 10:50:12 -08:00
parent 88df1c736f
commit c3c2f03319
5 changed files with 80 additions and 345 deletions

View file

@ -1,5 +1,4 @@
from abc import ABC from abc import ABC
from datetime import datetime
from pathlib import Path from pathlib import Path
from typing import Any from typing import Any
from typing import Dict from typing import Dict
@ -8,233 +7,15 @@ from typing import Type
from typing import TypeVar from typing import TypeVar
from typing import final from typing import final
from yt_dlp.utils import sanitize_filename from ytdl_sub.entries.script.variable_definitions import VARIABLES
from ytdl_sub.entries.script.variable_definitions import VariableDefinitions
from ytdl_sub.entries.variables.kwargs import DESCRIPTION
from ytdl_sub.entries.variables.kwargs import EPOCH
from ytdl_sub.entries.variables.kwargs import EXTRACTOR
from ytdl_sub.entries.variables.kwargs import IE_KEY
from ytdl_sub.entries.variables.kwargs import TITLE
from ytdl_sub.entries.variables.kwargs import UID
from ytdl_sub.entries.variables.kwargs import UPLOADER
from ytdl_sub.entries.variables.kwargs import UPLOADER_ID
from ytdl_sub.entries.variables.kwargs import UPLOADER_URL
from ytdl_sub.entries.variables.kwargs import WEBPAGE_URL
# pylint: disable=no-member
def _sanitize_plex(string: str) -> str:
out = ""
for char in string:
match char:
case "0":
out += ""
case "1":
out += ""
case "2":
out += ""
case "3":
out += ""
case "4":
out += ""
case "5":
out += ""
case "6":
out += ""
case "7":
out += ""
case "8":
out += ""
case "9":
out += ""
case _:
out += char
return out
class BaseEntryVariables:
"""
Source variables are ``{variables}`` that contain metadata from downloaded media.
These variables can be used with fields that expect
:class:`~ytdl_sub.validators.string_formatter_validators.StringFormatterValidator`,
but not
:class:`~ytdl_sub.validators.string_formatter_validators.OverridesStringFormatterValidator`.
"""
@property
def uid(self: "BaseEntry") -> str:
"""
Returns
-------
str
The entry's unique ID
"""
return str(self.kwargs(UID))
@property
def uid_sanitized(self: "BaseEntry") -> str:
"""
Returns
-------
str
The sanitized uid of the entry, which is safe to use for Unix and Windows file names.
"""
return sanitize_filename(self.uid)
@property
def uid_sanitized_plex(self: "BaseEntry") -> str:
"""
Returns
-------
str
The sanitized uid with additional sanitizing for Plex. Replaces numbers with
fixed-width numbers so Plex does not recognize them as season or episode numbers.
"""
return _sanitize_plex(self.uid_sanitized)
@property
def extractor(self: "BaseEntry") -> str:
"""
Returns
-------
str
The ytdl extractor name
"""
# pylint: disable=line-too-long
# Taken from https://github.com/yt-dlp/yt-dlp/blob/e6ab678e36c40ded0aae305bbb866cdab554d417/yt_dlp/YoutubeDL.py#L3514
# pylint: enable=line-too-long
return self.kwargs_get(EXTRACTOR) or self.kwargs(IE_KEY)
@property
def epoch(self: "BaseEntry") -> int:
"""
Returns
-------
int
The unix epoch of when the metadata was scraped by yt-dlp.
"""
return self.kwargs(EPOCH)
@property
def epoch_date(self: "BaseEntry") -> str:
"""
Returns
-------
str
The epoch's date, in YYYYMMDD format.
"""
return datetime.utcfromtimestamp(self.epoch).strftime("%Y%m%d")
@property
def epoch_hour(self: "BaseEntry") -> str:
"""
Returns
-------
str
The epoch's hour, padded
"""
return datetime.utcfromtimestamp(self.epoch).strftime("%H")
@property
def title(self: "BaseEntry") -> str:
"""
Returns
-------
str
The title of the entry. If a title does not exist, returns its unique ID.
"""
return self.kwargs_get(TITLE, self.uid)
@property
def title_sanitized(self) -> str:
"""
Returns
-------
str
The sanitized title of the entry, which is safe to use for Unix and Windows file names.
"""
return sanitize_filename(self.title)
@property
def title_sanitized_plex(self) -> str:
"""
Returns
-------
str
The sanitized title with additional sanitizing for Plex. Replaces numbers with
fixed-width numbers so Plex does not recognize them as season or episode numbers.
"""
return _sanitize_plex(self.title_sanitized)
@property
def webpage_url(self: "BaseEntry") -> str:
"""
Returns
-------
str
The url to the webpage.
"""
return self.kwargs(WEBPAGE_URL)
@property
def info_json_ext(self) -> str:
"""
Returns
-------
str
The "info.json" extension
"""
return "info.json"
@property
def description(self: "BaseEntry") -> str:
"""
Returns
-------
str
The description if it exists. Otherwise, returns an emtpy string.
"""
return self.kwargs_get(DESCRIPTION, "")
@property
def uploader_id(self: "BaseEntry") -> str:
"""
Returns
-------
str
The uploader id if it exists, otherwise return the unique ID.
"""
return self.kwargs_get(UPLOADER_ID, self.uid)
@property
def uploader(self: "BaseEntry") -> str:
"""
Returns
-------
str
The uploader if it exists, otherwise return the uploader ID.
"""
return self.kwargs_get(UPLOADER, self.uploader_id)
@property
def uploader_url(self: "BaseEntry") -> str:
"""
Returns
-------
str
The uploader url if it exists, otherwise returns the webpage_url.
"""
return self.kwargs_get(UPLOADER_URL, self.webpage_url)
# pylint: enable=no-member
v: VariableDefinitions = VARIABLES
TBaseEntry = TypeVar("TBaseEntry", bound="BaseEntry") TBaseEntry = TypeVar("TBaseEntry", bound="BaseEntry")
class BaseEntry(BaseEntryVariables, ABC): class BaseEntry(ABC):
""" """
Abstract entry object to represent anything download from ytdl (playlist metadata, media, etc). Abstract entry object to represent anything download from ytdl (playlist metadata, media, etc).
""" """
@ -255,6 +36,52 @@ class BaseEntry(BaseEntryVariables, ABC):
self._additional_variables: Dict[str, str | int] = {} self._additional_variables: Dict[str, str | int] = {}
@property
def uid(self: "BaseEntry") -> str:
"""
Returns
-------
str
The entry's unique ID
"""
return str(self.kwargs(v.uid.metadata_key))
@property
def extractor(self: "BaseEntry") -> str:
"""
The ytdl extractor name
"""
# pylint: disable=line-too-long
# Taken from https://github.com/yt-dlp/yt-dlp/blob/e6ab678e36c40ded0aae305bbb866cdab554d417/yt_dlp/YoutubeDL.py#L3514
# pylint: enable=line-too-long
return self.kwargs_get(v.extractor_key.metadata_key) or self.kwargs(v.ie_key.metadata_key)
@property
def title(self: "BaseEntry") -> str:
"""
The title of the entry. If a title does not exist, returns its unique ID.
"""
return self.kwargs_get(v.title.metadata_key, self.uid)
@property
def webpage_url(self: "BaseEntry") -> str:
"""
The url to the webpage.
"""
return self.kwargs(v.webpage_url.metadata_key)
@property
def info_json_ext(self) -> str:
"""The "info.json" extension"""
return "info.json"
@property
def uploader_id(self: "BaseEntry") -> str:
"""
The uploader id if it exists, otherwise return the unique ID.
"""
return self.kwargs_get(v.uploader_id.metadata_key, self.uid)
def kwargs_contains(self, key: str) -> bool: def kwargs_contains(self, key: str) -> bool:
"""Returns whether internal kwargs contains the specified key""" """Returns whether internal kwargs contains the specified key"""
return key in self._kwargs return key in self._kwargs

View file

@ -36,7 +36,7 @@ class SiblingMetadata(MetadataVariable):
pass pass
class _Variables: class VariableDefinitions:
@property @property
def entry_metadata(self) -> Metadata: def entry_metadata(self) -> Metadata:
""" """
@ -69,16 +69,6 @@ class _Variables:
""" """
return MetadataVariable(metadata_key="id", variable_name="uid") return MetadataVariable(metadata_key="id", variable_name="uid")
@property
def uid_sanitized(self) -> Variable:
"""
Returns
-------
str
The sanitized uid of the entry, which is safe to use for Unix and Windows file names.
"""
return Variable("uid_sanitized")
@property @property
def uid_sanitized_plex(self) -> Variable: def uid_sanitized_plex(self) -> Variable:
""" """
@ -90,6 +80,16 @@ class _Variables:
""" """
return Variable("uid_sanitized_plex") return Variable("uid_sanitized_plex")
@property
def ie_key(self) -> MetadataVariable:
"""
Returns
-------
str
The info-extractor key
"""
return MetadataVariable(metadata_key="ie_key", variable_name="ie_key")
@property @property
def extractor_key(self) -> MetadataVariable: def extractor_key(self) -> MetadataVariable:
""" """
@ -150,16 +150,6 @@ class _Variables:
""" """
return MetadataVariable(variable_name="title", metadata_key="title") return MetadataVariable(variable_name="title", metadata_key="title")
@property
def title_sanitized(self) -> Variable:
"""
Returns
-------
str
The sanitized title of the entry, which is safe to use for Unix and Windows file names.
"""
return Variable("title_sanitized")
@property @property
def title_sanitized_plex(self) -> Variable: def title_sanitized_plex(self) -> Variable:
""" """
@ -242,16 +232,6 @@ class _Variables:
""" """
return MetadataVariable("source_title", metadata_key=self.title.metadata_key) return MetadataVariable("source_title", metadata_key=self.title.metadata_key)
@property
def source_title_sanitized(self) -> Variable:
"""
Returns
-------
str
The source title, sanitized
"""
return Variable("source_title_sanitized")
@property @property
def source_uid(self) -> MetadataVariable: def source_uid(self) -> MetadataVariable:
""" """
@ -335,16 +315,6 @@ class _Variables:
""" """
return MetadataVariable(variable_name="playlist_title", metadata_key="playlist_title") return MetadataVariable(variable_name="playlist_title", metadata_key="playlist_title")
@property
def playlist_title_sanitized(self) -> Variable:
"""
Returns
-------
str
The playlist name, sanitized
"""
return Variable("playlist_title_sanitized")
@property @property
def playlist_index(self) -> MetadataVariable: def playlist_index(self) -> MetadataVariable:
""" """
@ -498,16 +468,6 @@ class _Variables:
""" """
return MetadataVariable("playlist_uploader", metadata_key=self.uploader.metadata_key) return MetadataVariable("playlist_uploader", metadata_key=self.uploader.metadata_key)
@property
def playlist_uploader_sanitized(self) -> Variable:
"""
Returns
-------
str
The playlist uploader, sanitized.
"""
return Variable("playlist_uploader_sanitized")
@property @property
def playlist_uploader_url(self) -> MetadataVariable: def playlist_uploader_url(self) -> MetadataVariable:
""" """
@ -560,16 +520,6 @@ class _Variables:
""" """
return MetadataVariable(variable_name="creator", metadata_key="creator") return MetadataVariable(variable_name="creator", metadata_key="creator")
@property
def creator_sanitized(self) -> Variable:
"""
Returns
-------
str
The creator name, sanitized
"""
return Variable("creator_sanitized")
@property @property
def channel(self) -> MetadataVariable: def channel(self) -> MetadataVariable:
""" """
@ -580,16 +530,6 @@ class _Variables:
""" """
return MetadataVariable(variable_name="channel", metadata_key="channel") return MetadataVariable(variable_name="channel", metadata_key="channel")
@property
def channel_sanitized(self) -> Variable:
"""
Returns
-------
str
The channel name, sanitized.
"""
return Variable("channel_sanitized")
@property @property
def channel_id(self) -> MetadataVariable: def channel_id(self) -> MetadataVariable:
""" """
@ -1051,4 +991,4 @@ class _Variables:
# Singleton to use externally # Singleton to use externally
VARIABLES = _Variables() VARIABLES: VariableDefinitions = VariableDefinitions()

View file

@ -6,23 +6,22 @@ from typing import Set
import mergedeep import mergedeep
from ytdl_sub.entries.script.custom_functions import CustomFunctions from ytdl_sub.entries.script.custom_functions import CustomFunctions
from ytdl_sub.entries.script.variable_definitions import VARIABLES as v from ytdl_sub.entries.script.variable_definitions import VARIABLES
from ytdl_sub.entries.script.variable_definitions import Metadata from ytdl_sub.entries.script.variable_definitions import Metadata
from ytdl_sub.entries.script.variable_definitions import MetadataVariable from ytdl_sub.entries.script.variable_definitions import MetadataVariable
from ytdl_sub.entries.script.variable_definitions import Variable from ytdl_sub.entries.script.variable_definitions import Variable
from ytdl_sub.entries.script.variable_definitions import VariableDefinitions
############################################################################################### ###############################################################################################
# Helpers # Helpers
v: VariableDefinitions = VARIABLES
def pad_int(key: Variable, pad: int) -> str: def pad_int(key: Variable, pad: int) -> str:
return f"{{%pad_zero({key.variable_name}, {pad})}}" return f"{{%pad_zero({key.variable_name}, {pad})}}"
def sanitized(key: Variable) -> str:
return f"{{%sanitize({key.variable_name})}}"
def sanitized_plex(key: Variable) -> str: def sanitized_plex(key: Variable) -> str:
return f"{{%sanitize_plex_episode({key.variable_name})}}" return f"{{%sanitize_plex_episode({key.variable_name})}}"
@ -130,6 +129,7 @@ ENTRY_DEFAULT_VARIABLES: Dict[MetadataVariable, str] = {
v.title: entry_get_str(v.title, v.uid), v.title: entry_get_str(v.title, v.uid),
v.extractor: entry_get_str(v.extractor, v.extractor_key), v.extractor: entry_get_str(v.extractor, v.extractor_key),
v.description: entry_get_str(v.description, ""), v.description: entry_get_str(v.description, ""),
v.ie_key: entry_get_str(v.ie_key, v.extractor_key),
v.uploader_id: entry_get_str(v.uploader_id, v.uid), v.uploader_id: entry_get_str(v.uploader_id, v.uid),
v.uploader: entry_get_str(v.uploader, v.uploader_id), v.uploader: entry_get_str(v.uploader, v.uploader_id),
v.uploader_url: entry_get_str(v.uploader_url, v.webpage_url), v.uploader_url: entry_get_str(v.uploader_url, v.webpage_url),
@ -157,19 +157,14 @@ ENTRY_INJECTED_VARIABLES: Dict[Variable, str] = {
} }
ENTRY_DERIVED_VARIABLES: Dict[Variable, str] = { ENTRY_DERIVED_VARIABLES: Dict[Variable, str] = {
v.uid_sanitized: sanitized(v.uid),
v.uid_sanitized_plex: sanitized_plex(v.uid), v.uid_sanitized_plex: sanitized_plex(v.uid),
v.title_sanitized: sanitized(v.title),
v.title_sanitized_plex: sanitized_plex(v.title), v.title_sanitized_plex: sanitized_plex(v.title),
v.epoch_date: f"{{%datetime_strftime({v.epoch.variable_name}, '%Y%m%d')}}", v.epoch_date: f"{{%datetime_strftime({v.epoch.variable_name}, '%Y%m%d')}}",
v.epoch_hour: f"{{%datetime_strftime({v.epoch.variable_name}, '%H')}}", v.epoch_hour: f"{{%datetime_strftime({v.epoch.variable_name}, '%H')}}",
v.channel_sanitized: sanitized(v.channel),
v.creator_sanitized: sanitized(v.creator),
v.download_index_padded6: pad_int(v.download_index, 6), v.download_index_padded6: pad_int(v.download_index, 6),
v.upload_date_index_padded: pad_int(v.upload_date_index, 2), v.upload_date_index_padded: pad_int(v.upload_date_index, 2),
v.upload_date_index_reversed: f"{{%sub(100, {v.upload_date_index.variable_name})}}", v.upload_date_index_reversed: f"{{%sub(100, {v.upload_date_index.variable_name})}}",
v.upload_date_index_reversed_padded: pad_int(v.upload_date_index_reversed, 2), v.upload_date_index_reversed_padded: pad_int(v.upload_date_index_reversed, 2),
v.playlist_title_sanitized: sanitized(v.playlist_title),
v.playlist_index_reversed: f"{{%sub({v.playlist_count.variable_name}, {v.playlist_index.variable_name}, -1)}}", v.playlist_index_reversed: f"{{%sub({v.playlist_count.variable_name}, {v.playlist_index.variable_name}, -1)}}",
v.playlist_index_padded: pad_int(v.playlist_index, 2), v.playlist_index_padded: pad_int(v.playlist_index, 2),
v.playlist_index_reversed_padded: pad_int(v.playlist_index_reversed, 2), v.playlist_index_reversed_padded: pad_int(v.playlist_index_reversed, 2),
@ -226,10 +221,6 @@ PLAYLIST_VARIABLES: Dict[Variable, str] = {
v.playlist_uploader_url: playlist_get_str(v.playlist_uploader_url, v.playlist_webpage_url), v.playlist_uploader_url: playlist_get_str(v.playlist_uploader_url, v.playlist_webpage_url),
} }
PLAYLIST_DERIVED_VARIABLES: Dict[Variable, str] = {
v.playlist_uploader_sanitized: sanitized(v.playlist_uploader),
}
SOURCE_VARIABLES: Dict[Variable, str] = { SOURCE_VARIABLES: Dict[Variable, str] = {
v.source_uid: source_get_str(v.source_uid, v.playlist_uid), v.source_uid: source_get_str(v.source_uid, v.playlist_uid),
@ -244,7 +235,6 @@ SOURCE_VARIABLES: Dict[Variable, str] = {
} }
SOURCE_DERIVED_VARIABLES: Dict[Variable, str] = { SOURCE_DERIVED_VARIABLES: Dict[Variable, str] = {
v.source_title_sanitized: sanitized(v.source_title),
v.source_index_padded: pad_int(v.source_index, 2), v.source_index_padded: pad_int(v.source_index, 2),
} }
@ -282,7 +272,6 @@ mergedeep.merge(
SIBLING_VARIABLES, SIBLING_VARIABLES,
SIBLING_DERIVED_VARIABLES, SIBLING_DERIVED_VARIABLES,
PLAYLIST_VARIABLES, PLAYLIST_VARIABLES,
PLAYLIST_DERIVED_VARIABLES,
SOURCE_VARIABLES, SOURCE_VARIABLES,
SOURCE_DERIVED_VARIABLES, SOURCE_DERIVED_VARIABLES,
) )

View file

@ -18,19 +18,3 @@ def _(key: str, backend: bool = False) -> str:
CHAPTERS = _("chapters", backend=True) CHAPTERS = _("chapters", backend=True)
YTDL_SUB_CUSTOM_CHAPTERS = _("ytdl_sub_custom_chapters", backend=True) YTDL_SUB_CUSTOM_CHAPTERS = _("ytdl_sub_custom_chapters", backend=True)
UID = _("id")
EXTRACTOR = _("extractor")
EXTRACTOR_KEY = _("extractor_key")
IE_KEY = _("ie_key")
EPOCH = _("epoch")
CHANNEL = _("channel")
CHANNEL_ID = _("channel_id")
CREATOR = _("creator")
TITLE = _("title")
DESCRIPTION = _("description")
WEBPAGE_URL = _("webpage_url")
RELEASE_DATE = _("release_date")
UPLOAD_DATE = _("upload_date")
UPLOADER = _("uploader")
UPLOADER_ID = _("uploader_id")
UPLOADER_URL = _("uploader_url")

View file

@ -12,15 +12,10 @@ from resources import copy_file_fixture
from ytdl_sub.config.config_file import ConfigFile from ytdl_sub.config.config_file import ConfigFile
from ytdl_sub.downloaders.url.downloader import MultiUrlDownloader from ytdl_sub.downloaders.url.downloader import MultiUrlDownloader
from ytdl_sub.downloaders.ytdlp import YTDLP from ytdl_sub.downloaders.ytdlp import YTDLP
from ytdl_sub.entries.script.variable_definitions import VARIABLES as v from ytdl_sub.entries.script.variable_definitions import VARIABLES
from ytdl_sub.entries.variables.kwargs import DESCRIPTION from ytdl_sub.entries.script.variable_definitions import VariableDefinitions
from ytdl_sub.entries.variables.kwargs import EPOCH
from ytdl_sub.entries.variables.kwargs import EXTRACTOR v: VariableDefinitions = VARIABLES
from ytdl_sub.entries.variables.kwargs import EXTRACTOR_KEY
from ytdl_sub.entries.variables.kwargs import TITLE
from ytdl_sub.entries.variables.kwargs import UID
from ytdl_sub.entries.variables.kwargs import UPLOAD_DATE
from ytdl_sub.entries.variables.kwargs import WEBPAGE_URL
@pytest.fixture @pytest.fixture
@ -59,19 +54,19 @@ def mock_entry_dict_factory(mock_downloaded_file_path) -> Callable:
is_extracted_audio: bool = False, is_extracted_audio: bool = False,
) -> Dict: ) -> Dict:
entry_dict = { entry_dict = {
UID: uid, v.uid.metadata_key: uid,
EPOCH: 1596878400, v.epoch.metadata_key: 1596878400,
v.playlist_title.metadata_key: playlist_title, v.playlist_title.metadata_key: playlist_title,
v.playlist_index.metadata_key: playlist_index, v.playlist_index.metadata_key: playlist_index,
v.playlist_count.metadata_key: playlist_count, v.playlist_count.metadata_key: playlist_count,
EXTRACTOR: "mock-entry-dict", v.extractor.metadata_key: "mock-entry-dict",
EXTRACTOR_KEY: "mock-extractor-key", v.extractor_key.metadata_key: "mock-extractor-key",
TITLE: f"Mock Entry {uid}", v.title.metadata_key: f"Mock Entry {uid}",
"ext": "mp4", v.ext.metadata_key: "mp4",
UPLOAD_DATE: upload_date, v.upload_date.metadata_key: upload_date,
WEBPAGE_URL: f"https://{uid}.com", v.webpage_url.metadata_key: f"https://{uid}.com",
v.playlist_metadata.metadata_key: {"thumbnails": []}, v.playlist_metadata.metadata_key: {"thumbnails": []},
DESCRIPTION: "The Description", v.description.metadata_key: "The Description",
} }
if is_youtube_channel: if is_youtube_channel: