Add Deezer support for rip discover

This commit is contained in:
Nathan Thomas 2021-08-19 18:13:05 -07:00
parent 87c6894386
commit 22d2a649ce
6 changed files with 70 additions and 19 deletions

View file

@ -169,11 +169,12 @@ class SearchCommand(Command):
class DiscoverCommand(Command): class DiscoverCommand(Command):
""" """
Browse and download items in interactive mode (Qobuz only). Browse and download items in interactive mode (Qobuz and Deezer only).
discover discover
{--s|scrape : Download all of the items in the list} {--scrape : Download all of the items in the list}
{--m|max-items=50 : The number of items to fetch} {--m|max-items=50 : The number of items to fetch}
{--s|source=qobuz : The source to download from (<cmd>qobuz</cmd> or <cmd>deezer</cmd>)}
{list=ideal-discography : The list to fetch} {list=ideal-discography : The list to fetch}
""" """
@ -182,7 +183,7 @@ class DiscoverCommand(Command):
"$ <cmd>rip discover</cmd>\n\n" "$ <cmd>rip discover</cmd>\n\n"
"Browse the best-sellers list\n" "Browse the best-sellers list\n"
"$ <cmd>rip discover best-sellers</cmd>\n\n" "$ <cmd>rip discover best-sellers</cmd>\n\n"
"Available options for <info>list</info>:\n\n" "Available options for Qobuz <info>list</info>:\n\n"
" • most-streamed\n" " • most-streamed\n"
" • recent-releases\n" " • recent-releases\n"
" • best-sellers\n" " • best-sellers\n"
@ -197,22 +198,47 @@ class DiscoverCommand(Command):
" • universal-classic\n" " • universal-classic\n"
" • universal-jazz\n" " • universal-jazz\n"
" • universal-jeunesse\n" " • universal-jeunesse\n"
" • universal-chanson\n" " • universal-chanson\n\n"
"Browse the Deezer editorial releases list\n"
"$ <cmd>rip discover --source deezer</cmd>\n\n"
"Browse the Deezer charts\n"
"$ <cmd>rip discover --source deezer charts</cmd>\n\n"
"Available options for Deezer <info>list</info>:\n\n"
" • releases\n"
" • charts\n"
" • selection\n"
) )
def handle(self): def handle(self):
from streamrip.constants import QOBUZ_FEATURED_KEYS source = self.option("source")
chosen_list = self.argument("list")
scrape = self.option("scrape") scrape = self.option("scrape")
chosen_list = self.argument("list")
max_items = self.option("max-items") max_items = self.option("max-items")
if source == "qobuz":
from streamrip.constants import QOBUZ_FEATURED_KEYS
if chosen_list not in QOBUZ_FEATURED_KEYS: if chosen_list not in QOBUZ_FEATURED_KEYS:
self.line( self.line(
f'<error>Error: list "{chosen_list}" not available</error>' f'<error>Error: list "{chosen_list}" not available</error>'
) )
self.line(self.help) self.line(self.help)
return 1 return 1
elif source == "deezer":
from streamrip.constants import DEEZER_FEATURED_KEYS
if chosen_list not in DEEZER_FEATURED_KEYS:
self.line(
f'<error>Error: list "{chosen_list}" not available</error>'
)
self.line(self.help)
return 1
else:
self.line(
"<error>Invalid source. Choose either <cmd>qobuz</cmd> or <cmd>deezer</cmd></error>"
)
return 1
config = Config() config = Config()
core = RipCore(config) core = RipCore(config)
@ -223,12 +249,14 @@ class DiscoverCommand(Command):
return 0 return 0
if core.interactive_search( if core.interactive_search(
chosen_list, "qobuz", "featured", limit=int(max_items) chosen_list, source, "featured", limit=int(max_items)
): ):
core.download() core.download()
else: else:
self.line("<error>No items chosen, exiting.</error>") self.line("<error>No items chosen, exiting.</error>")
return 0
class LastfmCommand(Command): class LastfmCommand(Command):
""" """

View file

@ -654,6 +654,8 @@ class RipCore(list):
client = self.get_client(source) client = self.get_client(source)
results = client.search(query, media_type) results = client.search(query, media_type)
if media_type == "featured":
media_type = "album"
if isinstance(results, Generator): # QobuzClient if isinstance(results, Generator): # QobuzClient
for page in results: for page in results:
@ -670,11 +672,11 @@ class RipCore(list):
if i >= limit - 1: if i >= limit - 1:
return return
else: else:
logger.debug("Not generator")
items = ( items = (
results.get("data") results.get("data")
or results.get("items") or results.get("items")
or results.get("collection") or results.get("collection")
or results.get("albums", {}).get("data", False)
) )
if items is None: if items is None:
raise NoResultsFound(query) raise NoResultsFound(query)

View file

@ -499,7 +499,19 @@ class DeezerClient(Client):
""" """
# TODO: use limit parameter # TODO: use limit parameter
try: try:
search_function = getattr(self.client.api, f"search_{media_type}") if media_type == "featured":
if query:
print(query)
search_function = getattr(
self.client.api, f"get_editorial_{query}"
)
else:
search_function = self.client.api.get_editorial_releases
else:
search_function = getattr(
self.client.api, f"search_{media_type}"
)
except AttributeError: except AttributeError:
raise Exception raise Exception

View file

@ -152,6 +152,7 @@ TIDAL_Q_MAP = {
} }
DEEZER_MAX_Q = 6 DEEZER_MAX_Q = 6
DEEZER_FEATURED_KEYS = {"releases", "charts", "selection"}
AVAILABLE_QUALITY_IDS = (0, 1, 2, 3, 4) AVAILABLE_QUALITY_IDS = (0, 1, 2, 3, 4)
DEEZER_FORMATS = { DEEZER_FORMATS = {
"AAC_64", "AAC_64",

View file

@ -303,9 +303,11 @@ class Track(Media):
url_id = self.id url_id = self.id
try: try:
print(url_id)
print(self.quality)
dl_info = self.client.get_file_url(url_id, self.quality) dl_info = self.client.get_file_url(url_id, self.quality)
except Exception as e: except Exception as e:
# raise NonStreamable(repr(e)) logger.debug(repr(e))
raise NonStreamable(e) raise NonStreamable(e)
if self.client.source == "qobuz": if self.client.source == "qobuz":

View file

@ -103,12 +103,17 @@ class DownloadStream:
assert isinstance(self.id, str), self.id assert isinstance(self.id, str), self.id
blowfish_key = self._generate_blowfish_key(self.id) blowfish_key = self._generate_blowfish_key(self.id)
decryptor = self._create_deezer_decryptor(blowfish_key) # decryptor = self._create_deezer_decryptor(blowfish_key)
CHUNK_SIZE = 2048 * 3
return ( return (
(decryptor.decrypt(chunk[:2048]) + chunk[2048:]) # (decryptor.decrypt(chunk[:2048]) + chunk[2048:])
# (self._decrypt_chunk(blowfish_key, chunk[:2048]) + chunk[2048:]) (
if len(chunk) >= 2048 else chunk self._decrypt_chunk(blowfish_key, chunk[:2048])
for chunk in self.request.iter_content(2048 * 3) + chunk[2048:]
)
if len(chunk) >= 2048
else chunk
for chunk in self.request.iter_content(CHUNK_SIZE)
) )
return self.request.iter_content(chunk_size=1024) return self.request.iter_content(chunk_size=1024)
@ -155,6 +160,7 @@ class DownloadStream:
return Blowfish.new( return Blowfish.new(
key, key,
Blowfish.MODE_CBC, Blowfish.MODE_CBC,
b"\x00\x01\x02\x03\x04\x05\x06\x07",
).decrypt(data) ).decrypt(data)