From f3274693bb2eacee9551e2633cc4feeb58a9094d Mon Sep 17 00:00:00 2001 From: nathom Date: Mon, 5 Apr 2021 17:42:24 -0700 Subject: [PATCH] Soundcloud downloads working --- streamrip/clients.py | 17 +++++------------ streamrip/config.py | 3 +++ streamrip/constants.py | 5 +++-- streamrip/core.py | 20 ++++++++++++++------ streamrip/downloader.py | 18 ++++++++---------- streamrip/metadata.py | 10 +--------- 6 files changed, 34 insertions(+), 39 deletions(-) diff --git a/streamrip/clients.py b/streamrip/clients.py index e6f6cb9..67c45c9 100644 --- a/streamrip/clients.py +++ b/streamrip/clients.py @@ -656,14 +656,7 @@ class TidalClient(ClientInterface): class SoundCloudClient(ClientInterface): source = "soundcloud" max_quality = 0 - - def __init__(self): - self.session = requests.Session() - self.session.headers.update( - { - "User-Agent": AGENT, - } - ) + logged_in = True def login(self): raise NotImplementedError @@ -671,10 +664,10 @@ class SoundCloudClient(ClientInterface): def get(self, id, media_type="track"): assert media_type in ("track", "playlist"), f"{media_type} not supported" - if media_type == "track": - resp, _ = self._get(f"{media_type}s/{id}") - elif "http" in id: + if "http" in str(id): resp, _ = self._get(f"resolve?url={id}") + elif media_type == "track": + resp, _ = self._get(f"{media_type}s/{id}") else: raise Exception(id) @@ -716,7 +709,7 @@ class SoundCloudClient(ClientInterface): url = f"{SOUNDCLOUD_BASE}/{path}" logger.debug(f"Fetching url {url}") - r = self.session.get(url, params=params) + r = requests.get(url, params=params) if resp_obj: return r diff --git a/streamrip/config.py b/streamrip/config.py index 9b4a524..4915aa4 100644 --- a/streamrip/config.py +++ b/streamrip/config.py @@ -54,6 +54,9 @@ class Config: "deezer": { "quality": 2, }, + "soundcloud": { + "quality": 0, + }, "database": {"enabled": True, "path": None}, "conversion": { "enabled": False, diff --git a/streamrip/constants.py b/streamrip/constants.py index 31f689c..ee1fe1c 100644 --- a/streamrip/constants.py +++ b/streamrip/constants.py @@ -135,13 +135,14 @@ FOLDER_FORMAT = ( TRACK_FORMAT = "{tracknumber}. {artist} - {title}" URL_REGEX = ( - r"https:\/\/(?:www|open|play|listen)?\.?(\w+)\.com(?:(?:\/(track|playlist|album|" + r"https:\/\/(?:www|open|play|listen)?\.?(qobuz|tidal|deezer)\.com(?:(?:\/(track|playlist|album|" r"artist|label))|(?:\/[-\w]+?))+\/([-\w]+)" ) -SOUNDCLOUD_URL_REGEX = r"https://soundcloud.com/[-\w:]+" +SOUNDCLOUD_URL_REGEX = r"https://soundcloud.com/[-\w:/]+" SOUNDCLOUD_CLIENT_ID = "a3e059563d7fd3372b49b37f00a00bcf" TIDAL_MAX_Q = 7 DEEZER_MAX_Q = 6 AVAILABLE_QUALITY_IDS = (0, 1, 2, 3, 4) +MEDIA_TYPES = ("track", "album", "artist", "label", "playlist") diff --git a/streamrip/core.py b/streamrip/core.py index 545b3e8..13e6349 100644 --- a/streamrip/core.py +++ b/streamrip/core.py @@ -1,4 +1,5 @@ import logging +from pprint import pprint import os import re import sys @@ -11,7 +12,7 @@ import click from .clients import DeezerClient, QobuzClient, SoundCloudClient, TidalClient from .config import Config -from .constants import CONFIG_PATH, DB_PATH, SOUNDCLOUD_URL_REGEX, URL_REGEX +from .constants import (CONFIG_PATH, DB_PATH, SOUNDCLOUD_URL_REGEX, URL_REGEX, MEDIA_TYPES) from .db import MusicDB from .downloader import Album, Artist, Label, Playlist, Track from .exceptions import AuthenticationError, ParsingError @@ -127,6 +128,11 @@ class MusicDL(list): client = self.get_client(source) + if media_type not in MEDIA_TYPES: + if 'playlist' in media_type: # for SoundCloud + media_type = 'playlist' + + assert media_type in MEDIA_TYPES, media_type item = MEDIA_CLASS[media_type](client=client, id=item_id) self.append(item) @@ -209,12 +215,14 @@ class MusicDL(list): :raises exceptions.ParsingError """ - parsed = self.url_parse.findall(url) + parsed = self.url_parse.findall(url) # Qobuz, Tidal, Dezer soundcloud_urls = self.soundcloud_url_parse.findall(url) - if len(soundcloud_urls) > 0: - parsed.extend( - self.clients["soundcloud"].resolve(u) for u in soundcloud_urls - ) + soundcloud_items = [self.clients["soundcloud"].get(u) for u in soundcloud_urls] + + parsed.extend( + ("soundcloud", item["kind"], url) + for item, url in zip(soundcloud_items, soundcloud_urls) + ) logger.debug(f"Parsed urls: {parsed}") diff --git a/streamrip/downloader.py b/streamrip/downloader.py index 1714d63..889f6e3 100644 --- a/streamrip/downloader.py +++ b/streamrip/downloader.py @@ -121,7 +121,6 @@ class Track: assert hasattr(self, "id"), "id must be set before loading metadata" self.resp = self.client.get(self.id, media_type="track") - pprint(self.resp) self.meta = TrackMetadata( track=self.resp, source=self.client.source ) # meta dict -> TrackMetadata object @@ -133,7 +132,7 @@ class Track: elif self.client.source == "deezer": self.cover_url = self.resp["album"]["cover_medium"] elif self.client.source == "soundcloud": - self.cover_url = self.resp["artwork_url"].replace("large", "t500x500") + self.cover_url = (self.resp["artwork_url"] or self.resp['user'].get("avatar_url")).replace("large", "t500x500") else: raise InvalidSourceError(self.client.source) except KeyError: @@ -169,7 +168,7 @@ class Track: :type progress_bar: bool """ # args override attributes - self.quality = min((quality or self.quality), self.client.max_quality) + self.quality = min(quality, self.client.max_quality) self.folder = parent_folder or self.folder self.file_format = kwargs.get("track_format", TRACK_FORMAT) @@ -194,6 +193,7 @@ class Track: return False if hasattr(self, "cover_url"): # only for playlists and singles + logger.debug("Downloading cover") self.download_cover() if self.client.source == "soundcloud": @@ -203,7 +203,7 @@ class Track: dl_info = self.client.get_file_url(url_id, self.quality) - temp_file = os.path.join(gettempdir(), f"~{self.id}_{quality}.tmp") + temp_file = os.path.join(gettempdir(), f"~{hash(self.id)}_{quality}.tmp") logger.debug("Temporary file path: %s", temp_file) if self.client.source == "qobuz": @@ -240,7 +240,7 @@ class Track: [ "ffmpeg", "-i", - dl_info, + dl_info['url'], "-c", "copy", "-y", @@ -288,7 +288,7 @@ class Track: assert hasattr(self, "cover_url"), "must set cover_url attribute" - self.cover_path = os.path.join(self.folder, f"cover{hash(self.meta.album)}.jpg") + self.cover_path = os.path.join(self.folder, f"cover{hash(self.cover_url)}.jpg") logger.debug(f"Downloading cover from {self.cover_url}") click.secho(f"\nDownloading cover art for {self!s}", fg="blue") @@ -1019,7 +1019,7 @@ class Playlist(Tracklist): self.name = self.meta["name"] tracklist = self.meta["tracks"]["items"] - def gen_cover(track): # ? + def gen_cover(track): return track["album"]["image"]["small"] def meta_args(track): @@ -1047,7 +1047,6 @@ class Playlist(Tracklist): return track["album"]["cover_medium"] elif self.client.source == "soundcloud": - pprint(self.meta) self.name = self.meta["title"] tracklist = self.meta["tracks"] @@ -1126,7 +1125,6 @@ class Playlist(Tracklist): :param client: :type client: ClientInterface """ - print(item.keys()) if client.source == "qobuz": return { "name": item["name"], @@ -1223,7 +1221,7 @@ class Artist(Tracklist): def download( self, - parent_folder: str = "Downloads", + parent_folder: str = "StreamripDownloads", filters: Optional[Tuple] = None, no_repeats: bool = False, quality: int = 6, diff --git a/streamrip/metadata.py b/streamrip/metadata.py index b021e1e..99bfc7a 100644 --- a/streamrip/metadata.py +++ b/streamrip/metadata.py @@ -154,22 +154,14 @@ class TrackMetadata: elif self.__source == "soundcloud": self.title = track["title"].strip() - print(f"{self.title=}") self.genre = track["genre"] - print(f"{self.genre=}") self.artist = track["user"]["username"] self.albumartist = self.artist - print(f"{self.artist=}") self.year = track["created_at"][:4] - print(f"{self.year=}") self.label = track["label_name"] - print(f"{self.label=}") - self.comment = track["description"] - print(f"{self.comment=}") + self.description = track["description"] self.tracknumber = 0 - print(f"{self.tracknumber=}") self.tracktotal = 0 - print(f"{self.tracktotal=}") else: raise ValueError(self.__source)