diff --git a/src/ytdl_sub/downloaders/soundcloud/abc.py b/src/ytdl_sub/downloaders/soundcloud/abc.py deleted file mode 100644 index cba3e289..00000000 --- a/src/ytdl_sub/downloaders/soundcloud/abc.py +++ /dev/null @@ -1,65 +0,0 @@ -from abc import ABC -from typing import Generic -from typing import TypeVar - -from ytdl_sub.downloaders.downloader import Downloader -from ytdl_sub.downloaders.downloader import DownloaderValidator -from ytdl_sub.entries.soundcloud import SoundcloudTrack -from ytdl_sub.validators.validators import BoolValidator - - -class SoundcloudDownloaderOptions(DownloaderValidator, ABC): - """ - Abstract source validator for all soundcloud sources. - """ - - _optional_keys = {"skip_premiere_tracks"} - - def __init__(self, name: str, value: dict): - super().__init__(name=name, value=value) - self._skip_premiere_tracks = self._validate_key( - "skip_premiere_tracks", BoolValidator, default=True - ) - - @property - def skip_premiere_tracks(self) -> bool: - """ - Optional. True to skip tracks that require purchasing. False otherwise. Defaults to True. - """ - return self._skip_premiere_tracks.value - - -SoundcloudDownloaderOptionsT = TypeVar( - "SoundcloudDownloaderOptionsT", bound=SoundcloudDownloaderOptions -) - - -class SoundcloudDownloader( - Downloader[SoundcloudDownloaderOptionsT, SoundcloudTrack], - Generic[SoundcloudDownloaderOptionsT], - ABC, -): - """ - Class that handles downloading soundcloud entries via ytdl and converting them into - SoundcloudTrack / SoundcloudAlbumTrack objects - """ - - downloader_entry_type = SoundcloudTrack - - @classmethod - def artist_albums_url(cls, artist_url: str) -> str: - """ - Returns - ------- - Full artist album url - """ - return f"{artist_url}/albums" - - @classmethod - def artist_tracks_url(cls, artist_url: str) -> str: - """ - Returns - ------- - Full artist tracks url - """ - return f"{artist_url}/tracks" diff --git a/src/ytdl_sub/downloaders/soundcloud/albums_and_singles.py b/src/ytdl_sub/downloaders/soundcloud/albums_and_singles.py index 77b264d1..2a669fed 100644 --- a/src/ytdl_sub/downloaders/soundcloud/albums_and_singles.py +++ b/src/ytdl_sub/downloaders/soundcloud/albums_and_singles.py @@ -1,15 +1,17 @@ from typing import Dict from typing import Generator +from ytdl_sub.downloaders.downloader import Downloader +from ytdl_sub.downloaders.downloader import DownloaderValidator from ytdl_sub.downloaders.generic.collection import CollectionDownloader from ytdl_sub.downloaders.generic.collection import CollectionDownloadOptions -from ytdl_sub.downloaders.soundcloud.abc import SoundcloudDownloader -from ytdl_sub.downloaders.soundcloud.abc import SoundcloudDownloaderOptions +from ytdl_sub.entries.entry import Entry from ytdl_sub.entries.soundcloud import SoundcloudTrack from ytdl_sub.validators.url_validator import SoundcloudUsernameUrlValidator +from ytdl_sub.validators.validators import BoolValidator -class SoundcloudAlbumsAndSinglesDownloadOptions(SoundcloudDownloaderOptions): +class SoundcloudAlbumsAndSinglesDownloadOptions(DownloaderValidator): """ Downloads a soundcloud user's entire discography. Groups together album tracks and considers any track not in an album as a single. Also includes any collaboration tracks. @@ -30,12 +32,16 @@ class SoundcloudAlbumsAndSinglesDownloadOptions(SoundcloudDownloaderOptions): """ _required_keys = {"url"} + _optional_keys = {"skip_premiere_tracks"} def __init__(self, name, value): super().__init__(name, value) self._url = self._validate_key( key="url", validator=SoundcloudUsernameUrlValidator ).username_url + self._skip_premiere_tracks = self._validate_key( + "skip_premiere_tracks", BoolValidator, default=True + ) self.collection_validator = CollectionDownloadOptions( name=self._name, @@ -67,6 +73,13 @@ class SoundcloudAlbumsAndSinglesDownloadOptions(SoundcloudDownloaderOptions): }, ) + @property + def skip_premiere_tracks(self) -> bool: + """ + Optional. True to skip tracks that require purchasing. False otherwise. Defaults to True. + """ + return self._skip_premiere_tracks.value + @property def url(self) -> str: """ @@ -76,9 +89,11 @@ class SoundcloudAlbumsAndSinglesDownloadOptions(SoundcloudDownloaderOptions): class SoundcloudAlbumsAndSinglesDownloader( - SoundcloudDownloader[SoundcloudAlbumsAndSinglesDownloadOptions] + Downloader[SoundcloudAlbumsAndSinglesDownloadOptions, SoundcloudTrack] ): downloader_options_type = SoundcloudAlbumsAndSinglesDownloadOptions + downloader_entry_type = SoundcloudTrack + supports_subtitles = False supports_chapters = False @@ -100,6 +115,16 @@ class SoundcloudAlbumsAndSinglesDownloader( }, ) + def _should_skip(self, entry: Entry) -> bool: + if not self.download_options.skip_premiere_tracks: + return False + + for url in [entry.kwargs_get("url", ""), entry.webpage_url]: + if "/preview/" in url: + return True + + return False + def download(self) -> Generator[SoundcloudTrack, None, None]: """ Soundcloud subscription to download albums and tracks as singles. @@ -112,4 +137,7 @@ class SoundcloudAlbumsAndSinglesDownloader( ) for entry in downloader.download(): + if self._should_skip(entry): + continue + yield entry diff --git a/src/ytdl_sub/entries/soundcloud.py b/src/ytdl_sub/entries/soundcloud.py index 0d775c6c..475c63b1 100644 --- a/src/ytdl_sub/entries/soundcloud.py +++ b/src/ytdl_sub/entries/soundcloud.py @@ -1,6 +1,8 @@ from ytdl_sub.entries.entry import Entry from ytdl_sub.entries.variables.soundcloud_variables import SoundcloudVariables +# TODO: Delete since not used + class SoundcloudTrack(SoundcloudVariables, Entry): """ @@ -9,37 +11,3 @@ class SoundcloudTrack(SoundcloudVariables, Entry): """ entry_extractor = "soundcloud" - - def is_premiere(self) -> bool: - """ - Returns whether the entry is a premier track. Check this by seeing if the track's url is - a preview. - """ - return "/preview/" in self.kwargs("url") - - -class SoundcloudAlbumTrack(SoundcloudTrack): - """ - Entry object to represent a Soundcloud track yt-dlp that belongs to an album. - """ - - @property - def track_number(self) -> int: - """Returns the entry's track number""" - return self.kwargs("playlist_index") - - @property - def track_count(self) -> int: - """Returns the entry's total tracks in album""" - return self.kwargs("playlist_count") - - @property - def album(self) -> str: - """Returns the entry's album name, fetched from its internal album""" - return self.kwargs("playlist") - - @property - def album_year(self) -> int: - """Returns the entry's album year, fetched from its internal album""" - # added from parent entry - return self._additional_variables["playlist_max_upload_year"]