Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
nathom committed Jun 29, 2021
2 parents d979ed3 + 6380f07 commit 70a0928
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 45 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "streamrip"
version = "0.6.4"
version = "0.6.5"
description = "A fast, all-in-one music ripper for Qobuz, Deezer, Tidal, and SoundCloud"
authors = ["nathom <[email protected]>"]
license = "GPL-3.0-only"
Expand Down
2 changes: 1 addition & 1 deletion streamrip/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""streamrip: the all in one music downloader."""

__version__ = "0.6.4"
__version__ = "0.6.5"
1 change: 0 additions & 1 deletion streamrip/bases.py
Original file line number Diff line number Diff line change
Expand Up @@ -842,7 +842,6 @@ def download(self, **kwargs):

if kwargs.get("concurrent_downloads", True):
# Tidal errors out with unlimited concurrency
# max_workers = 15 if self.client.source == "tidal" else 90
with concurrent.futures.ThreadPoolExecutor(15) as executor:
futures = [executor.submit(target, item, **kwargs) for item in self]
try:
Expand Down
2 changes: 1 addition & 1 deletion streamrip/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ def download(self):
if not (isinstance(item, Tracklist) and item.loaded):
logger.debug("Loading metadata")
try:
item.load_meta()
item.load_meta(**arguments)
except NonStreamable:
click.secho(f"{item!s} is not available, skipping.", fg="red")
continue
Expand Down
23 changes: 4 additions & 19 deletions streamrip/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
TRACK_KEYS,
)
from .exceptions import InvalidContainerError, InvalidSourceError
from .utils import get_quality_id, safe_get, tidal_cover_url
from .utils import get_quality_id, safe_get, tidal_cover_url, get_cover_urls

logger = logging.getLogger("streamrip")

Expand Down Expand Up @@ -151,8 +151,7 @@ def add_album_meta(self, resp: dict):

# Non-embedded information
self.version = resp.get("version")
self.cover_urls = OrderedDict(resp["image"])
self.cover_urls["original"] = self.cover_urls["large"].replace("600", "org")
self.cover_urls = get_cover_urls(resp, self.__source)
self.streamable = resp.get("streamable", False)
self.bit_depth = resp.get("maximum_bit_depth")
self.sampling_rate = resp.get("maximum_sampling_rate")
Expand All @@ -177,13 +176,7 @@ def add_album_meta(self, resp: dict):
# non-embedded
self.explicit = resp.get("explicit", False)
# 80, 160, 320, 640, 1280
uuid = resp.get("cover")
self.cover_urls = OrderedDict(
{
sk: tidal_cover_url(uuid, size)
for sk, size in zip(COVER_SIZES, (160, 320, 640, 1280))
}
)
self.cover_urls = get_cover_urls(resp, self.__source)
self.streamable = resp.get("allowStreaming", False)

if q := resp.get("audioQuality"): # for album entries in single tracks
Expand All @@ -205,15 +198,7 @@ def add_album_meta(self, resp: dict):
self.explicit = bool(resp.get("parental_warning"))
self.quality = 2
self.bit_depth = 16
self.cover_urls = OrderedDict(
{
sk: resp.get(rk) # size key, resp key
for sk, rk in zip(
COVER_SIZES,
("cover", "cover_medium", "cover_large", "cover_xl"),
)
}
)
self.cover_urls = get_cover_urls(resp, self.__source)
self.sampling_rate = 44100
self.streamable = True

Expand Down
40 changes: 19 additions & 21 deletions streamrip/tracklists.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from .metadata import TrackMetadata
from .utils import (
clean_format,
get_cover_urls,
get_container,
get_stats_from_quality,
safe_get,
Expand Down Expand Up @@ -68,7 +69,7 @@ def __init__(self, client: Client, **kwargs):
self.loaded = False
self.downloaded = False

def load_meta(self):
def load_meta(self, **kwargs):
"""Load detailed metadata from API using the id."""
assert hasattr(self, "id"), "id must be set to load metadata"
resp = self.client.get(self.id, media_type="album")
Expand Down Expand Up @@ -220,7 +221,7 @@ def _load_tracks(self, resp):
This uses a classmethod to convert an item into a Track object, which
stores the metadata inside a TrackMetadata object.
"""
logging.debug(f"Loading {self.tracktotal} tracks to album")
logging.debug("Loading %d tracks to album", self.tracktotal)
for track in _get_tracklist(resp, self.client.source):
if track.get("type") == "Music Video":
self.append(Video.from_album_meta(track, self.client))
Expand All @@ -238,7 +239,13 @@ def _get_formatter(self) -> dict:
"""
fmt = {key: self.get(key) for key in ALBUM_KEYS}

stats = get_stats_from_quality(self.quality)
stats = tuple(
min(bd, sr)
for bd, sr in zip(
(self.meta.bit_depth, self.meta.sampling_rate),
get_stats_from_quality(self.quality),
)
)

# The quality chosen is not the maximum available quality
if stats != (fmt.get("sampling_rate"), fmt.get("bit_depth")):
Expand Down Expand Up @@ -338,6 +345,7 @@ def __init__(self, client: Client, **kwargs):
:type album_id: Union[str, int]
:param kwargs:
"""
self.name: str
self.client = client

for k, v in kwargs.items():
Expand Down Expand Up @@ -373,7 +381,7 @@ def load_meta(self, **kwargs):
self._load_tracks(**kwargs)
self.loaded = True

def _load_tracks(self, new_tracknumbers: bool = True):
def _load_tracks(self, new_tracknumbers: bool = True, **kwargs):
"""Parse the tracklist returned by the API.
:param new_tracknumbers: replace tracknumber tag with playlist position
Expand All @@ -386,9 +394,6 @@ def _load_tracks(self, new_tracknumbers: bool = True):

tracklist = self.meta["tracks"]["items"]

def gen_cover(track):
return track["album"]["image"]["small"]

def meta_args(track):
return {"track": track, "album": track["album"]}

Expand All @@ -399,10 +404,6 @@ def meta_args(track):

tracklist = self.meta["tracks"]

def gen_cover(track):
cover_url = tidal_cover_url(track["album"]["cover"], 640)
return cover_url

def meta_args(track):
return {
"track": track,
Expand All @@ -416,18 +417,12 @@ def meta_args(track):

tracklist = self.meta["tracks"]

def gen_cover(track):
return track["album"]["cover_medium"]

elif self.client.source == "soundcloud":
self.name = self.meta["title"]
# self.image = self.meta.get("artwork_url").replace("large", "t500x500")
self.creator = self.meta["user"]["username"]
tracklist = self.meta["tracks"]

def gen_cover(track):
return track["artwork_url"].replace("large", "t500x500")

else:
raise NotImplementedError

Expand All @@ -443,13 +438,16 @@ def gen_cover(track):
# tracknumber tags might cause conflicts if the playlist files are
# inside of a library folder
meta = TrackMetadata(track=track, source=self.client.source)
cover_url = get_cover_urls(track["album"], self.client.source)[
kwargs.get("embed_cover_size", "large")
]

self.append(
Track(
self.client,
id=track.get("id"),
meta=meta,
cover_url=gen_cover(track),
cover_url=cover_url,
part_of_tracklist=True,
)
)
Expand Down Expand Up @@ -484,7 +482,7 @@ def _download_item(self, item: Track, **kwargs) -> bool: # type: ignore
if self.downloaded and self.client.source != "deezer":
item.tag(embed_cover=kwargs.get("embed_cover", True))

if playlist_to_album and self.client.source == "deezer":
if self.downloaded and playlist_to_album and self.client.source == "deezer":
# Because Deezer tracks come pre-tagged, the `set_playlist_to_album`
# option is never set. Here, we manually do this
from mutagen.flac import FLAC
Expand Down Expand Up @@ -584,7 +582,7 @@ def __init__(self, client: Client, **kwargs):

self.loaded = False

def load_meta(self):
def load_meta(self, **kwargs):
"""Send an API call to get album info based on id."""
self.meta = self.client.get(self.id, media_type="artist")
self._load_albums()
Expand Down Expand Up @@ -857,7 +855,7 @@ def __hash__(self):
class Label(Artist):
"""Represents a downloadable Label."""

def load_meta(self):
def load_meta(self, **kwargs):
"""Load metadata given an id."""
assert self.client.source == "qobuz", "Label source must be qobuz"

Expand Down
32 changes: 31 additions & 1 deletion streamrip/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@
import re
from string import Formatter
from typing import Dict, Hashable, Optional, Tuple, Union
from collections import OrderedDict

import click
import requests
from pathvalidate import sanitize_filename
from requests.packages import urllib3
from tqdm import tqdm

from .constants import AGENT, TIDAL_COVER_URL
from .constants import AGENT, TIDAL_COVER_URL, COVER_SIZES
from .exceptions import InvalidQuality, InvalidSourceError, NonStreamable

urllib3.disable_warnings()
Expand Down Expand Up @@ -382,3 +383,32 @@ def get_container(quality: int, source: str) -> str:
return "AAC"

return "MP3"


def get_cover_urls(resp: dict, source: str) -> dict:
if source == "qobuz":
cover_urls = OrderedDict(resp["image"])
cover_urls["original"] = cover_urls["large"].replace("600", "org")
return cover_urls

if source == "tidal":
uuid = resp["cover"]
return OrderedDict(
{
sk: tidal_cover_url(uuid, size)
for sk, size in zip(COVER_SIZES, (160, 320, 640, 1280))
}
)

if source == "deezer":
return OrderedDict(
{
sk: resp.get(rk) # size key, resp key
for sk, rk in zip(
COVER_SIZES,
("cover", "cover_medium", "cover_large", "cover_xl"),
)
}
)

raise InvalidSourceError(source)

0 comments on commit 70a0928

Please sign in to comment.