mirror of
https://github.com/nathom/streamrip.git
synced 2025-05-13 14:44:49 -04:00
Make Deezer/Deezloader transitions smoother
This commit is contained in:
parent
96b15d9917
commit
aac254516f
5 changed files with 1273 additions and 1253 deletions
|
@ -38,12 +38,20 @@ refresh_token = ""
|
||||||
# in again using `rip config --tidal`
|
# in again using `rip config --tidal`
|
||||||
token_expiry = ""
|
token_expiry = ""
|
||||||
|
|
||||||
# Doesn't require login
|
|
||||||
[deezer]
|
[deezer]
|
||||||
# 0, 1, or 2
|
# 0, 1, or 2
|
||||||
|
# This only applies to paid Deezer subscriptions. Those using deezloader
|
||||||
|
# are automatically limited to quality = 1
|
||||||
quality = 2
|
quality = 2
|
||||||
use_deemix_server = true
|
# An authentication cookie that allows streamrip to use your Deezer account
|
||||||
|
# See [ADD LINK] for instructions on how to find this
|
||||||
arl = ""
|
arl = ""
|
||||||
|
# This allows for free 320kbps MP3 downloads from Deezer
|
||||||
|
# If an arl is provided, deezloader is never used
|
||||||
|
use_deezloader = true
|
||||||
|
# This warns you when the paid deezer account is not logged in and rip falls
|
||||||
|
# back to deezloader, which is unreliable
|
||||||
|
deezloader_warnings = true
|
||||||
|
|
||||||
[soundcloud]
|
[soundcloud]
|
||||||
# Only 0 is available for now
|
# Only 0 is available for now
|
||||||
|
|
77
rip/core.py
77
rip/core.py
|
@ -35,6 +35,7 @@ from streamrip.clients import (
|
||||||
)
|
)
|
||||||
from .config import Config
|
from .config import Config
|
||||||
from streamrip.constants import MEDIA_TYPES
|
from streamrip.constants import MEDIA_TYPES
|
||||||
|
from streamrip.utils import set_progress_bar_theme, TQDM_DEFAULT_THEME
|
||||||
from .constants import (
|
from .constants import (
|
||||||
URL_REGEX,
|
URL_REGEX,
|
||||||
SOUNDCLOUD_URL_REGEX,
|
SOUNDCLOUD_URL_REGEX,
|
||||||
|
@ -56,7 +57,12 @@ from streamrip.exceptions import (
|
||||||
NoResultsFound,
|
NoResultsFound,
|
||||||
ParsingError,
|
ParsingError,
|
||||||
)
|
)
|
||||||
from .utils import extract_deezer_dynamic_link, extract_interpreter_url
|
from .utils import (
|
||||||
|
extract_deezer_dynamic_link,
|
||||||
|
extract_interpreter_url,
|
||||||
|
)
|
||||||
|
from .exceptions import DeezloaderFallback
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger("streamrip")
|
logger = logging.getLogger("streamrip")
|
||||||
|
|
||||||
|
@ -191,8 +197,6 @@ class RipCore(list):
|
||||||
:param item_id:
|
:param item_id:
|
||||||
:type item_id: str
|
:type item_id: str
|
||||||
"""
|
"""
|
||||||
self.assert_creds(source)
|
|
||||||
|
|
||||||
client = self.get_client(source)
|
client = self.get_client(source)
|
||||||
|
|
||||||
if media_type not in MEDIA_TYPES:
|
if media_type not in MEDIA_TYPES:
|
||||||
|
@ -340,8 +344,11 @@ class RipCore(list):
|
||||||
"""
|
"""
|
||||||
client = self.clients[source]
|
client = self.clients[source]
|
||||||
if not client.logged_in:
|
if not client.logged_in:
|
||||||
self.assert_creds(source)
|
try:
|
||||||
self.login(client)
|
self.login(client)
|
||||||
|
except DeezloaderFallback:
|
||||||
|
client = self.clients["deezloader"]
|
||||||
|
|
||||||
return client
|
return client
|
||||||
|
|
||||||
def login(self, client):
|
def login(self, client):
|
||||||
|
@ -350,16 +357,27 @@ class RipCore(list):
|
||||||
:param client:
|
:param client:
|
||||||
"""
|
"""
|
||||||
creds = self.config.creds(client.source)
|
creds = self.config.creds(client.source)
|
||||||
|
if client.source == "deezer" and creds["arl"] == "":
|
||||||
|
if self.config.session["deezer"]["deezloader_warnings"]:
|
||||||
|
click.secho(
|
||||||
|
"Falling back to Deezloader (max 320kbps MP3). If you have a subscription, run ",
|
||||||
|
nl=False,
|
||||||
|
fg="yellow",
|
||||||
|
)
|
||||||
|
click.secho("rip config --deezer ", nl=False, bold=True)
|
||||||
|
click.secho("to download FLAC files.\n\n", fg="yellow")
|
||||||
|
raise DeezloaderFallback
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
client.login(**creds)
|
client.login(**creds)
|
||||||
break
|
break
|
||||||
except AuthenticationError:
|
except AuthenticationError:
|
||||||
click.secho("Invalid credentials, try again.")
|
click.secho("Invalid credentials, try again.", fg="yellow")
|
||||||
self.prompt_creds(client.source)
|
self.prompt_creds(client.source)
|
||||||
creds = self.config.creds(client.source)
|
creds = self.config.creds(client.source)
|
||||||
except MissingCredentials:
|
except MissingCredentials:
|
||||||
logger.debug("Credentials are missing. Prompting..")
|
logger.debug("Credentials are missing. Prompting..", fg="yellow")
|
||||||
self.prompt_creds(client.source)
|
self.prompt_creds(client.source)
|
||||||
creds = self.config.creds(client.source)
|
creds = self.config.creds(client.source)
|
||||||
|
|
||||||
|
@ -571,13 +589,6 @@ class RipCore(list):
|
||||||
else page["albums"]["items"]
|
else page["albums"]["items"]
|
||||||
)
|
)
|
||||||
for i, item in enumerate(tracklist):
|
for i, item in enumerate(tracklist):
|
||||||
if item_id := str(item["id"]) in self.db:
|
|
||||||
click.secho(
|
|
||||||
f"ID {item_id} already logged in database. Skipping.",
|
|
||||||
fg="magenta",
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
|
|
||||||
yield MEDIA_CLASS[ # type: ignore
|
yield MEDIA_CLASS[ # type: ignore
|
||||||
media_type if media_type != "featured" else "album"
|
media_type if media_type != "featured" else "album"
|
||||||
].from_api(item, client)
|
].from_api(item, client)
|
||||||
|
@ -811,8 +822,20 @@ class RipCore(list):
|
||||||
fg="green",
|
fg="green",
|
||||||
)
|
)
|
||||||
elif source == "deezer":
|
elif source == "deezer":
|
||||||
click.secho("Enter Deezer ARL: ", fg="green")
|
click.secho(
|
||||||
self.config.file["deezer"]["arl"] = input()
|
"If you're not sure how to find the ARL cookie, see the instructions at ",
|
||||||
|
italic=True,
|
||||||
|
nl=False,
|
||||||
|
dim=True,
|
||||||
|
)
|
||||||
|
click.secho(
|
||||||
|
"https://github.com/nathom/streamrip/wiki/Finding-your-Deezer-ARL-Cookie",
|
||||||
|
underline=True,
|
||||||
|
italic=True,
|
||||||
|
fg="blue",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.config.file["deezer"]["arl"] = input(click.style("ARL: ", fg="green"))
|
||||||
self.config.save()
|
self.config.save()
|
||||||
click.secho(
|
click.secho(
|
||||||
f'Credentials saved to config file at "{self.config._path}"',
|
f'Credentials saved to config file at "{self.config._path}"',
|
||||||
|
@ -821,28 +844,6 @@ class RipCore(list):
|
||||||
else:
|
else:
|
||||||
raise Exception
|
raise Exception
|
||||||
|
|
||||||
def assert_creds(self, source: str):
|
|
||||||
"""Ensure that the credentials for `source` are valid.
|
|
||||||
|
|
||||||
:param source:
|
|
||||||
:type source: str
|
|
||||||
"""
|
|
||||||
assert source in (
|
|
||||||
"qobuz",
|
|
||||||
"tidal",
|
|
||||||
"deezer",
|
|
||||||
"soundcloud",
|
|
||||||
), f"Invalid source {source}"
|
|
||||||
|
|
||||||
if source == "soundcloud":
|
|
||||||
return
|
|
||||||
|
|
||||||
if source == "qobuz" and (
|
|
||||||
self.config.file[source]["email"] is None
|
|
||||||
or self.config.file[source]["password"] is None
|
|
||||||
):
|
|
||||||
self.prompt_creds(source)
|
|
||||||
|
|
||||||
def _config_updating_message(self):
|
def _config_updating_message(self):
|
||||||
click.secho(
|
click.secho(
|
||||||
"Updating config file... Some settings may be lost. Please run the "
|
"Updating config file... Some settings may be lost. Please run the "
|
||||||
|
|
2
rip/exceptions.py
Normal file
2
rip/exceptions.py
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
class DeezloaderFallback(Exception):
|
||||||
|
pass
|
2421
streamrip/clients.py
2421
streamrip/clients.py
File diff suppressed because it is too large
Load diff
|
@ -280,12 +280,20 @@ class Track(Media):
|
||||||
try:
|
try:
|
||||||
download_url = dl_info["url"]
|
download_url = dl_info["url"]
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
|
if restrictions := dl_info["restrictions"]:
|
||||||
|
# Turn CamelCase code into a readable sentence
|
||||||
|
words = re.findall(r"([A-Z][a-z]+)", restrictions[0]["code"])
|
||||||
|
raise NonStreamable(
|
||||||
|
words[0] + " " + " ".join(map(str.lower, words[1:])) + "."
|
||||||
|
)
|
||||||
|
|
||||||
click.secho(f"Panic: {e} dl_info = {dl_info}", fg="red")
|
click.secho(f"Panic: {e} dl_info = {dl_info}", fg="red")
|
||||||
|
raise NonStreamable
|
||||||
|
|
||||||
_quick_download(download_url, self.path, desc=self._progress_desc)
|
_quick_download(download_url, self.path, desc=self._progress_desc)
|
||||||
|
|
||||||
elif isinstance(self.client, DeezloaderClient):
|
elif isinstance(self.client, DeezloaderClient):
|
||||||
tqdm_download(dl_info["url"], self.path, desc=self._progress_desc)
|
_quick_download(dl_info["url"], self.path, desc=self._progress_desc)
|
||||||
|
|
||||||
elif self.client.source == "deezer":
|
elif self.client.source == "deezer":
|
||||||
# We can only find out if the requested quality is available
|
# We can only find out if the requested quality is available
|
||||||
|
@ -1205,7 +1213,8 @@ class Tracklist(list):
|
||||||
"""
|
"""
|
||||||
click.secho(
|
click.secho(
|
||||||
f"\n\nDownloading {self.title} ({self.__class__.__name__})\n",
|
f"\n\nDownloading {self.title} ({self.__class__.__name__})\n",
|
||||||
fg="blue",
|
fg="magenta",
|
||||||
|
bold=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -1345,7 +1354,6 @@ class Album(Tracklist, Media):
|
||||||
# Generate the folder name
|
# Generate the folder name
|
||||||
self.folder_format = kwargs.get("folder_format", FOLDER_FORMAT)
|
self.folder_format = kwargs.get("folder_format", FOLDER_FORMAT)
|
||||||
self.quality = min(kwargs.get("quality", 3), self.client.max_quality)
|
self.quality = min(kwargs.get("quality", 3), self.client.max_quality)
|
||||||
print(f"{self.quality=} {self.client.max_quality = }")
|
|
||||||
|
|
||||||
self.folder = self._get_formatted_folder(
|
self.folder = self._get_formatted_folder(
|
||||||
kwargs.get("parent_folder", "StreamripDownloads"), self.quality
|
kwargs.get("parent_folder", "StreamripDownloads"), self.quality
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue