diff --git a/streamrip/bases.py b/streamrip/bases.py index fd402d0..eadbd0a 100644 --- a/streamrip/bases.py +++ b/streamrip/bases.py @@ -202,6 +202,7 @@ class Track: return False if self.client.source == "qobuz": + assert isinstance(dl_info, dict) # for typing if not self.__validate_qobuz_dl_info(dl_info): click.secho("Track is not available for download", fg="red") return False @@ -211,6 +212,7 @@ class Track: # --------- Download Track ---------- if self.client.source in ("qobuz", "tidal", "deezer"): + assert isinstance(dl_info, dict) logger.debug("Downloadable URL found: %s", dl_info.get("url")) try: tqdm_download( @@ -223,6 +225,7 @@ class Track: return False elif self.client.source == "soundcloud": + assert isinstance(dl_info, dict) self._soundcloud_download(dl_info) else: @@ -403,7 +406,7 @@ class Track: cover_url=cover_url, ) - def tag( + def tag( # noqa self, album_meta: dict = None, cover: Union[Picture, APIC, MP4Cover] = None, @@ -871,7 +874,7 @@ class Tracklist(list): info = cls._parse_get_resp(item, client=client) # equivalent to Album(client=client, **info) - return cls(client=client, **info) + return cls(client=client, **info) # type: ignore @staticmethod def get_cover_obj(cover_path: str, container: str, source: str): diff --git a/streamrip/clients.py b/streamrip/clients.py index 8b52730..51f80bf 100644 --- a/streamrip/clients.py +++ b/streamrip/clients.py @@ -1,5 +1,4 @@ import base64 -from pprint import pprint import hashlib import json import logging diff --git a/streamrip/metadata.py b/streamrip/metadata.py index 7fb7d16..f14a941 100644 --- a/streamrip/metadata.py +++ b/streamrip/metadata.py @@ -1,4 +1,6 @@ """Manages the information that will be embeded in the audio file. """ +from __future__ import annotations + import logging import re from collections import OrderedDict @@ -48,7 +50,10 @@ class TrackMetadata: """ def __init__( - self, track: Optional[dict] = None, album: Optional[dict] = None, source="qobuz" + self, + track: Optional[Union[TrackMetadata, dict]] = None, + album: Optional[Union[TrackMetadata, dict]] = None, + source="qobuz", ): """Creates a TrackMetadata object optionally initialized with dicts returned by the Qobuz API. diff --git a/streamrip/tracklists.py b/streamrip/tracklists.py index 11444fd..307efbd 100644 --- a/streamrip/tracklists.py +++ b/streamrip/tracklists.py @@ -9,7 +9,7 @@ import logging import os import re from tempfile import gettempdir -from typing import Dict, Generator, Iterable, Union, Optional +from typing import Dict, Generator, Iterable, Optional, Union import click from pathvalidate import sanitize_filename @@ -59,6 +59,7 @@ class Album(Tracklist): self.disctotal: int self.tracktotal: int self.albumartist: str + # usually an unpacked TrackMetadata.asdict() self.__dict__.update(kwargs) diff --git a/streamrip/utils.py b/streamrip/utils.py index ab8bb43..d643014 100644 --- a/streamrip/utils.py +++ b/streamrip/utils.py @@ -5,7 +5,7 @@ import os import re import sys from string import Formatter -from typing import Hashable, Optional, Union +from typing import Dict, Hashable, Optional, Union import click import requests @@ -52,6 +52,7 @@ def get_quality(quality_id: int, source: str) -> Union[str, int]: :type source: str :rtype: Union[str, int] """ + q_map: Dict[int, Union[int, str]] if source == "qobuz": q_map = { 1: 5, @@ -89,7 +90,8 @@ def get_quality_id(bit_depth: Optional[int], sampling_rate: Optional[int]): :param sampling_rate: :type sampling_rate: Optional[int] """ - if not (bit_depth or sampling_rate): # is lossy + # XXX: Should `0` quality be supported? + if bit_depth is None or sampling_rate is None: # is lossy return 1 if bit_depth == 16: @@ -266,6 +268,9 @@ def decho(message, fg=None): logger.debug(message) +interpreter_artist_regex = re.compile(r"getSimilarArtist\(\s*'(\w+)'") + + def extract_interpreter_url(url: str) -> str: """Extract artist ID from a Qobuz interpreter url. @@ -275,8 +280,14 @@ def extract_interpreter_url(url: str) -> str: """ session = gen_threadsafe_session({"User-Agent": AGENT}) r = session.get(url) - artist_id = re.search(r"getSimilarArtist\(\s*'(\w+)'", r.text).group(1) - return artist_id + match = interpreter_artist_regex.search(r.text) + if match: + return match.group(1) + + raise Exception( + "Unable to extract artist id from interpreter url. Use a " + "url that contains an artist id." + ) def get_container(quality: int, source: str) -> str: