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`
|
||||
token_expiry = ""
|
||||
|
||||
# Doesn't require login
|
||||
[deezer]
|
||||
# 0, 1, or 2
|
||||
# This only applies to paid Deezer subscriptions. Those using deezloader
|
||||
# are automatically limited to quality = 1
|
||||
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 = ""
|
||||
# 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]
|
||||
# Only 0 is available for now
|
||||
|
|
75
rip/core.py
75
rip/core.py
|
@ -35,6 +35,7 @@ from streamrip.clients import (
|
|||
)
|
||||
from .config import Config
|
||||
from streamrip.constants import MEDIA_TYPES
|
||||
from streamrip.utils import set_progress_bar_theme, TQDM_DEFAULT_THEME
|
||||
from .constants import (
|
||||
URL_REGEX,
|
||||
SOUNDCLOUD_URL_REGEX,
|
||||
|
@ -56,7 +57,12 @@ from streamrip.exceptions import (
|
|||
NoResultsFound,
|
||||
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")
|
||||
|
||||
|
@ -191,8 +197,6 @@ class RipCore(list):
|
|||
:param item_id:
|
||||
:type item_id: str
|
||||
"""
|
||||
self.assert_creds(source)
|
||||
|
||||
client = self.get_client(source)
|
||||
|
||||
if media_type not in MEDIA_TYPES:
|
||||
|
@ -340,8 +344,11 @@ class RipCore(list):
|
|||
"""
|
||||
client = self.clients[source]
|
||||
if not client.logged_in:
|
||||
self.assert_creds(source)
|
||||
try:
|
||||
self.login(client)
|
||||
except DeezloaderFallback:
|
||||
client = self.clients["deezloader"]
|
||||
|
||||
return client
|
||||
|
||||
def login(self, client):
|
||||
|
@ -350,16 +357,27 @@ class RipCore(list):
|
|||
:param client:
|
||||
"""
|
||||
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:
|
||||
try:
|
||||
client.login(**creds)
|
||||
break
|
||||
except AuthenticationError:
|
||||
click.secho("Invalid credentials, try again.")
|
||||
click.secho("Invalid credentials, try again.", fg="yellow")
|
||||
self.prompt_creds(client.source)
|
||||
creds = self.config.creds(client.source)
|
||||
except MissingCredentials:
|
||||
logger.debug("Credentials are missing. Prompting..")
|
||||
logger.debug("Credentials are missing. Prompting..", fg="yellow")
|
||||
self.prompt_creds(client.source)
|
||||
creds = self.config.creds(client.source)
|
||||
|
||||
|
@ -571,13 +589,6 @@ class RipCore(list):
|
|||
else page["albums"]["items"]
|
||||
)
|
||||
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
|
||||
media_type if media_type != "featured" else "album"
|
||||
].from_api(item, client)
|
||||
|
@ -811,8 +822,20 @@ class RipCore(list):
|
|||
fg="green",
|
||||
)
|
||||
elif source == "deezer":
|
||||
click.secho("Enter Deezer ARL: ", fg="green")
|
||||
self.config.file["deezer"]["arl"] = input()
|
||||
click.secho(
|
||||
"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()
|
||||
click.secho(
|
||||
f'Credentials saved to config file at "{self.config._path}"',
|
||||
|
@ -821,28 +844,6 @@ class RipCore(list):
|
|||
else:
|
||||
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):
|
||||
click.secho(
|
||||
"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
|
|
@ -1036,8 +1036,9 @@ class TidalClient(Client):
|
|||
|
||||
params["countryCode"] = self.country_code
|
||||
params["limit"] = 100
|
||||
r = self.session.get(f"{TIDAL_BASE}/{path}", params=params).json()
|
||||
return r
|
||||
r = self.session.get(f"{TIDAL_BASE}/{path}", params=params)
|
||||
r.raise_for_status()
|
||||
return r.json()
|
||||
|
||||
def _get_video_stream_url(self, video_id: str) -> str:
|
||||
"""Get the HLS video stream url.
|
||||
|
|
|
@ -280,12 +280,20 @@ class Track(Media):
|
|||
try:
|
||||
download_url = dl_info["url"]
|
||||
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")
|
||||
raise NonStreamable
|
||||
|
||||
_quick_download(download_url, self.path, desc=self._progress_desc)
|
||||
|
||||
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":
|
||||
# We can only find out if the requested quality is available
|
||||
|
@ -1205,7 +1213,8 @@ class Tracklist(list):
|
|||
"""
|
||||
click.secho(
|
||||
f"\n\nDownloading {self.title} ({self.__class__.__name__})\n",
|
||||
fg="blue",
|
||||
fg="magenta",
|
||||
bold=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
|
@ -1345,7 +1354,6 @@ class Album(Tracklist, Media):
|
|||
# Generate the folder name
|
||||
self.folder_format = kwargs.get("folder_format", FOLDER_FORMAT)
|
||||
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(
|
||||
kwargs.get("parent_folder", "StreamripDownloads"), self.quality
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue