mirror of
https://github.com/nathom/streamrip.git
synced 2025-05-13 06:34:45 -04:00
Add Deezer support for rip discover
This commit is contained in:
parent
87c6894386
commit
22d2a649ce
6 changed files with 70 additions and 19 deletions
50
rip/cli.py
50
rip/cli.py
|
@ -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,21 +198,46 @@ 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 chosen_list not in QOBUZ_FEATURED_KEYS:
|
if source == "qobuz":
|
||||||
|
from streamrip.constants import QOBUZ_FEATURED_KEYS
|
||||||
|
|
||||||
|
if chosen_list not in QOBUZ_FEATURED_KEYS:
|
||||||
|
self.line(
|
||||||
|
f'<error>Error: list "{chosen_list}" not available</error>'
|
||||||
|
)
|
||||||
|
self.line(self.help)
|
||||||
|
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(
|
self.line(
|
||||||
f'<error>Error: list "{chosen_list}" not available</error>'
|
"<error>Invalid source. Choose either <cmd>qobuz</cmd> or <cmd>deezer</cmd></error>"
|
||||||
)
|
)
|
||||||
self.line(self.help)
|
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
config = Config()
|
config = 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):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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":
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue