This commit is contained in:
Nathan Thomas 2023-06-20 19:15:58 -07:00
commit fd353d57cc
7 changed files with 83 additions and 39 deletions

BIN
demo/.DS_Store vendored

Binary file not shown.

View file

@ -464,8 +464,15 @@ class ConfigCommand(Command):
import getpass import getpass
import hashlib import hashlib
self._config.file["qobuz"]["email"] = self.ask("Qobuz email:") self._config.file["qobuz"]["use_auth_token"] = self.confirm("Use Qobuz auth token to authenticate?", default=False)
self._config.file["qobuz"]["password"] = hashlib.md5(
if self._config.file["qobuz"]["use_auth_token"]:
self._config.file["qobuz"]["email_or_userid"] = self.ask("Qobuz user id:")
self._config.file["qobuz"]["password_or_token"] = getpass.getpass("Qobuz auth token (won't show on screen): ")
self._config.save()
else:
self._config.file["qobuz"]["email_or_userid"] = self.ask("Qobuz email:")
self._config.file["qobuz"]["password_or_token"] = hashlib.md5(
getpass.getpass("Qobuz password (won't show on screen): ").encode() getpass.getpass("Qobuz password (won't show on screen): ").encode()
).hexdigest() ).hexdigest()
self._config.save() self._config.save()

View file

@ -172,8 +172,9 @@ class Config:
def qobuz_creds(self): def qobuz_creds(self):
"""Return a QobuzClient compatible dict of credentials.""" """Return a QobuzClient compatible dict of credentials."""
return { return {
"email": self.file["qobuz"]["email"], "use_auth_token": self.file["qobuz"]["use_auth_token"],
"pwd": self.file["qobuz"]["password"], "email_or_userid": self.file["qobuz"]["email_or_userid"],
"password_or_token": self.file["qobuz"]["password_or_token"],
"app_id": self.file["qobuz"]["app_id"], "app_id": self.file["qobuz"]["app_id"],
"secrets": self.file["qobuz"]["secrets"], "secrets": self.file["qobuz"]["secrets"],
} }

View file

@ -20,9 +20,12 @@ quality = 3
# This will download booklet pdfs that are included with some albums # This will download booklet pdfs that are included with some albums
download_booklets = true download_booklets = true
email = "" # Authenticate to Qobuz using auth token? Value can be true/false only
# This is an md5 hash of the plaintext password use_auth_token = false
password = "" # Enter your userid if the above use_auth_token is set to true, else enter your email
email_or_userid = ""
# Enter your auth token if the above use_auth_token is set to true, else enter the md5 hash of your plaintext password
password_or_token = ""
# Do not change # Do not change
app_id = "" app_id = ""
# Do not change # Do not change
@ -157,7 +160,6 @@ restrict_characters = false
# Setting this to false may cause downloads to fail on some systems # Setting this to false may cause downloads to fail on some systems
truncate = true truncate = true
# Last.fm playlists are downloaded by searching for the titles of the tracks # Last.fm playlists are downloaded by searching for the titles of the tracks
[lastfm] [lastfm]
# The source on which to search for the tracks. # The source on which to search for the tracks.

View file

@ -878,13 +878,29 @@ class RipCore(list):
:type source: str :type source: str
""" """
if source == "qobuz": if source == "qobuz":
secho("Enter Qobuz email:", fg="green") secho("Use Qobuz auth token to authenticate? (yes/no)", fg="green")
self.config.file[source]["email"] = input() use_auth_token = re.match("(?i)^y", input()) is not None
self.config.file[source]["use_auth_token"] = use_auth_token
if use_auth_token:
secho("Enter Qobuz user id:", fg="green")
self.config.file[source]["email_or_userid"] = input()
secho("Enter Qobuz token (will not show on screen):", fg="green")
self.config.file[source]["password_or_token"] = getpass(prompt="")
self.config.save()
secho( secho(
"Enter Qobuz password (will not show on screen):", f'Credentials saved to config file at "{self.config._path}"',
fg="green", fg="green",
) )
self.config.file[source]["password"] = md5( else:
secho("Enter Qobuz email:", fg="green")
self.config.file[source]["email_or_userid"] = input()
secho("Enter Qobuz password (will not show on screen):", fg="green")
self.config.file[source]["password_or_token"] = md5(
getpass(prompt="").encode("utf-8") getpass(prompt="").encode("utf-8")
).hexdigest() ).hexdigest()

View file

@ -6,6 +6,9 @@ from typing import Tuple
from streamrip.constants import AGENT from streamrip.constants import AGENT
from streamrip.utils import gen_threadsafe_session from streamrip.utils import gen_threadsafe_session
interpreter_artist_id_regex = re.compile(
r"https?://www\.qobuz\.com/\w\w-\w\w/interpreter/[-\w]+/(?P<artistId>[0-9]+)"
)
interpreter_artist_regex = re.compile(r"getSimilarArtist\(\s*'(\w+)'") interpreter_artist_regex = re.compile(r"getSimilarArtist\(\s*'(\w+)'")
@ -13,9 +16,14 @@ def extract_interpreter_url(url: str) -> str:
"""Extract artist ID from a Qobuz interpreter url. """Extract artist ID from a Qobuz interpreter url.
:param url: Urls of the form "https://www.qobuz.com/us-en/interpreter/{artist}/download-streaming-albums" :param url: Urls of the form "https://www.qobuz.com/us-en/interpreter/{artist}/download-streaming-albums"
or "https://www.qobuz.com/us-en/interpreter/the-last-shadow-puppets/{artistId}}"
:type url: str :type url: str
:rtype: str :rtype: str
""" """
url_match = interpreter_artist_id_regex.search(url)
if url_match:
return url_match.group("artistId")
session = gen_threadsafe_session({"User-Agent": AGENT}) session = gen_threadsafe_session({"User-Agent": AGENT})
r = session.get(url) r = session.get(url)
match = interpreter_artist_regex.search(r.text) match = interpreter_artist_regex.search(r.text)

View file

@ -117,9 +117,10 @@ class QobuzClient(Client):
:param kwargs: app_id: str, secrets: list, return_secrets: bool :param kwargs: app_id: str, secrets: list, return_secrets: bool
""" """
secho(f"Logging into {self.source}", fg="green") secho(f"Logging into {self.source}", fg="green")
email: str = kwargs["email"] use_auth_token: bool = kwargs["use_auth_token"]
pwd: str = kwargs["pwd"] email_or_userid: str = kwargs["email_or_userid"]
if not email or not pwd: password_or_token: str = kwargs["password_or_token"]
if not email_or_userid or not password_or_token:
raise MissingCredentials raise MissingCredentials
if self.logged_in: if self.logged_in:
@ -138,7 +139,7 @@ class QobuzClient(Client):
) )
self._validate_secrets() self._validate_secrets()
self._api_login(email, pwd) self._api_login(use_auth_token, email_or_userid, password_or_token)
logger.debug("Logged into Qobuz") logger.debug("Logged into Qobuz")
logger.debug("Qobuz client is ready to use") logger.debug("Qobuz client is ready to use")
@ -342,17 +343,26 @@ class QobuzClient(Client):
return self._gen_pages(epoint, params) return self._gen_pages(epoint, params)
def _api_login(self, email: str, pwd: str): def _api_login(self, use_auth_token: bool, email_or_userid: str, password_or_token: str):
"""Log into the api to get the user authentication token. """Log into the api to get the user authentication token.
:param email: :param use_auth_token:
:type email: str :type use_auth_token: bool
:param pwd: :param email_or_userid:
:type pwd: str :type email_or_userid: str
:param password_or_token:
:type password_or_token: str
""" """
if use_auth_token:
params = { params = {
"email": email, "user_id": email_or_userid,
"password": pwd, "user_auth_token": password_or_token,
"app_id": self.app_id,
}
else:
params = {
"email": email_or_userid,
"password": password_or_token,
"app_id": self.app_id, "app_id": self.app_id,
} }
epoint = "user/login" epoint = "user/login"