From c7e9380fe03160f94431d7bddcde49cfce648856 Mon Sep 17 00:00:00 2001 From: Jesse Bannon Date: Sat, 10 Sep 2022 14:46:03 -0700 Subject: [PATCH] [BACKEND] Refactor entry classes (#228) --- src/ytdl_sub/entries/base_entry.py | 35 +++++++++++ src/ytdl_sub/entries/entry.py | 28 ++++++--- src/ytdl_sub/entries/soundcloud.py | 3 +- .../entries/variables/entry_variables.py | 60 ++++--------------- src/ytdl_sub/entries/youtube.py | 22 +------ 5 files changed, 72 insertions(+), 76 deletions(-) diff --git a/src/ytdl_sub/entries/base_entry.py b/src/ytdl_sub/entries/base_entry.py index 8eb47b1e..e526ae4a 100644 --- a/src/ytdl_sub/entries/base_entry.py +++ b/src/ytdl_sub/entries/base_entry.py @@ -1,7 +1,9 @@ from abc import ABC from typing import Any from typing import Dict +from typing import List from typing import Optional +from typing import final class BaseEntry(ABC): @@ -9,6 +11,9 @@ class BaseEntry(ABC): Abstract entry object to represent anything download from ytdl (playlist metadata, media, etc). """ + # The ytdl extractor type that the entry represents + entry_extractor: str + def __init__(self, entry_dict: Dict, working_directory: str): """ Initialize the entry using ytdl metadata @@ -75,3 +80,33 @@ class BaseEntry(ABC): self._additional_variables = dict(self._additional_variables, **variables_to_add) return self + + def _added_variables(self) -> Dict[str, str]: + """ + Returns + ------- + Dict of variables added to this entry + """ + return self._additional_variables + + @classmethod + def source_variables(cls) -> List[str]: + """ + Returns + ------- + List of all source variables + """ + property_names = [prop for prop in dir(cls) if isinstance(getattr(cls, prop), property)] + return property_names + + @final + def to_dict(self) -> Dict[str, str]: + """ + Returns + ------- + Dictionary containing all variables + """ + source_variable_dict = { + source_var: getattr(self, source_var) for source_var in self.source_variables() + } + return dict(source_variable_dict, **self._added_variables()) diff --git a/src/ytdl_sub/entries/entry.py b/src/ytdl_sub/entries/entry.py index 9298a611..f34bebf3 100644 --- a/src/ytdl_sub/entries/entry.py +++ b/src/ytdl_sub/entries/entry.py @@ -2,11 +2,11 @@ import copy import json import os from pathlib import Path -from typing import Dict from typing import Optional from typing import final from ytdl_sub.entries.base_entry import BaseEntry +from ytdl_sub.entries.variables.entry_variables import BaseEntryVariables from ytdl_sub.entries.variables.entry_variables import EntryVariables from ytdl_sub.validators.audo_codec_validator import AUDIO_CODEC_EXTS @@ -16,9 +16,6 @@ class Entry(EntryVariables, BaseEntry): Entry object to represent a single media object returned from yt-dlp. """ - # The ytdl extractor type that the entry represents - entry_extractor: str - def get_download_file_name(self) -> str: """ Returns @@ -107,11 +104,26 @@ class Entry(EntryVariables, BaseEntry): return file_exists - @final - def to_dict(self) -> Dict[str, str]: + +class ParentEntry(BaseEntryVariables, BaseEntry): + """ + Entry to represent parent entry objects like a Channel or Playlist + """ + + def _get_thumbnail_url(self, thumbnail_id: str) -> Optional[str]: """ + Downloads a specific thumbnail from a YTDL entry's thumbnail list + + Parameters + ---------- + thumbnail_id: + Id of the thumbnail defined in the parent's thumbnail + Returns ------- - The variables in dictionary format + Desired thumbnail url if it exists. None if it does not. """ - return self._to_dict() + for thumbnail in self.kwargs_get("thumbnails", []): + if thumbnail["id"] == thumbnail_id: + return thumbnail["url"] + return None diff --git a/src/ytdl_sub/entries/soundcloud.py b/src/ytdl_sub/entries/soundcloud.py index 7149b39e..1fc2db3d 100644 --- a/src/ytdl_sub/entries/soundcloud.py +++ b/src/ytdl_sub/entries/soundcloud.py @@ -3,6 +3,7 @@ from typing import List from typing import Optional from ytdl_sub.entries.entry import Entry +from ytdl_sub.entries.entry import ParentEntry from ytdl_sub.entries.variables.soundcloud_variables import SoundcloudVariables @@ -84,7 +85,7 @@ class SoundcloudAlbumTrack(SoundcloudTrack): ) -class SoundcloudAlbum(Entry): +class SoundcloudAlbum(ParentEntry): """ Entry object to represent a Soundcloud album. """ diff --git a/src/ytdl_sub/entries/variables/entry_variables.py b/src/ytdl_sub/entries/variables/entry_variables.py index d1883990..9ad22fc4 100644 --- a/src/ytdl_sub/entries/variables/entry_variables.py +++ b/src/ytdl_sub/entries/variables/entry_variables.py @@ -1,7 +1,3 @@ -from typing import Dict -from typing import List -from typing import final - from yt_dlp.utils import sanitize_filename from ytdl_sub.entries.base_entry import BaseEntry @@ -18,7 +14,7 @@ def _pad(num: int, width: int = 2): _days_in_month = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] -class SourceVariables: +class BaseEntryVariables: """ Source variables are ``{variables}`` that contain metadata from downloaded media. These variables can be used with fields that expect @@ -47,38 +43,6 @@ class SourceVariables: """ return self.kwargs("extractor") - def _added_variables(self: BaseEntry) -> Dict[str, str]: - """ - Returns - ------- - Dict of variables added to this entry - """ - return self._additional_variables - - @classmethod - def source_variables(cls) -> List[str]: - """ - Returns - ------- - List of all source variables - """ - property_names = [prop for prop in dir(cls) if isinstance(getattr(cls, prop), property)] - return property_names - - @final - def _to_dict(self) -> Dict[str, str]: - """ - Returns - ------- - Dictionary containing all variables - """ - source_variable_dict = { - source_var: getattr(self, source_var) for source_var in self.source_variables() - } - return dict(source_variable_dict, **self._added_variables()) - - -class EntryVariables(SourceVariables): @property def title(self: BaseEntry) -> str: """ @@ -109,6 +73,18 @@ class EntryVariables(SourceVariables): """ return self.kwargs("webpage_url") + @property + def info_json_ext(self) -> str: + """ + Returns + ------- + str + The "info.json" extension + """ + return "info.json" + + +class EntryVariables(BaseEntryVariables): @property def ext(self: BaseEntry) -> str: """ @@ -314,13 +290,3 @@ class EntryVariables(SourceVariables): The uploaded date formatted as YYYY-MM-DD """ return f"{self.upload_year}-{self.upload_month_padded}-{self.upload_day_padded}" - - @property - def info_json_ext(self) -> str: - """ - Returns - ------- - str - The "info.json" extension - """ - return "info.json" diff --git a/src/ytdl_sub/entries/youtube.py b/src/ytdl_sub/entries/youtube.py index a6f7df87..2bac764e 100644 --- a/src/ytdl_sub/entries/youtube.py +++ b/src/ytdl_sub/entries/youtube.py @@ -1,8 +1,8 @@ import os.path from pathlib import Path -from typing import Optional from ytdl_sub.entries.entry import Entry +from ytdl_sub.entries.entry import ParentEntry from ytdl_sub.entries.variables.youtube_variables import YoutubeVideoVariables @@ -46,27 +46,9 @@ class YoutubePlaylistVideo(YoutubeVideo): return self.kwargs("playlist_count") -class YoutubeChannel(Entry): +class YoutubeChannel(ParentEntry): entry_extractor = "youtube:tab" - def _get_thumbnail_url(self, thumbnail_id: str) -> Optional[str]: - """ - Downloads a specific thumbnail from a YTDL entry's thumbnail list - - Parameters - ---------- - thumbnail_id: - Id of the thumbnail defined in the channel's thumbnail - - Returns - ------- - Desired thumbnail url if it exists. None if it does not. - """ - for thumbnail in self.kwargs("thumbnails"): - if thumbnail["id"] == thumbnail_id: - return thumbnail["url"] - return None - def avatar_thumbnail_url(self) -> str: """ Returns