Misc fixes related to search

This commit is contained in:
Nathan Thomas 2023-12-22 23:25:43 -08:00
parent 8c9673a067
commit a515b9c1fd
6 changed files with 55 additions and 26 deletions

View File

@ -181,6 +181,7 @@ class DeezerClient(Client):
)
dl_info["url"] = url
logger.debug("dz track info: %s", track_info)
return DeezerDownloadable(self.session, dl_info)
def _get_encrypted_file_url(
@ -212,5 +213,6 @@ class DeezerClient(Client):
path = binascii.hexlify(
AES.new(b"jo6aey6haid2Teih", AES.MODE_ECB).encrypt(info_bytes),
).decode("utf-8")
return f"https://e-cdns-proxy-{track_hash[0]}.dzcdn.net/mobile/1/{path}"
url = f"https://e-cdns-proxy-{track_hash[0]}.dzcdn.net/mobile/1/{path}"
logger.debug("Encrypted file path %s", url)
return url

View File

@ -36,7 +36,7 @@ class SoundcloudClient(Client):
async def login(self):
self.session = await self.get_session()
client_id, app_version = self.config.client_id, self.config.app_version
if not client_id or not app_version or not (await self._announce()):
if not client_id or not app_version or not (await self._announce_success()):
client_id, app_version = await self._refresh_tokens()
# update file and session configs and save to disk
cf = self.global_config.file.soundcloud
@ -54,13 +54,14 @@ class SoundcloudClient(Client):
"""Fetch metadata for an item in Soundcloud API.
Args:
----
item_id (str): Plain soundcloud item ID (e.g 1633786176)
media_type (str): track or playlist
Returns:
-------
API response.
API response. The item IDs for the tracks in the playlist are modified to
include resolution status.
"""
if media_type == "track":
# parse custom id that we injected
@ -227,12 +228,15 @@ class SoundcloudClient(Client):
async with self.session.get(url, params=_params, headers=headers) as resp:
return await resp.content.read(), resp.status
async def _resolve_url(self, url: str) -> dict:
async def resolve_url(self, url: str) -> dict:
resp, status = await self._api_request("resolve", params={"url": url})
assert status == 200
if resp["kind"] == "track":
resp["id"] = self._get_custom_id(resp)
return resp
async def _announce(self):
async def _announce_success(self):
url = f"{BASE}/announcements"
_, status = await self._request_body(url)
return status == 200

View File

@ -39,7 +39,7 @@ class ArtistSummary(Summary):
return "artist"
def summarize(self) -> str:
return self.name
return clean(self.name)
def preview(self) -> str:
return f"{self.num_albums} Albums\n\nID: {self.id}"
@ -73,7 +73,8 @@ class TrackSummary(Summary):
return "track"
def summarize(self) -> str:
return f"{self.name} by {self.artist}"
# This char breaks the menu for some reason
return f"{clean(self.name)} by {clean(self.artist)}"
def preview(self) -> str:
return f"Released on:\n{self.date_released}\n\nID: {self.id}"
@ -119,7 +120,7 @@ class AlbumSummary(Summary):
return "album"
def summarize(self) -> str:
return f"{self.name} by {self.artist}"
return f"{clean(self.name)} by {clean(self.artist)}"
def preview(self) -> str:
return f"Date released:\n{self.date_released}\n\n{self.num_tracks} Tracks\n\nID: {self.id}"
@ -188,11 +189,14 @@ class PlaylistSummary(Summary):
description: str
def summarize(self) -> str:
return f"{self.name} by {self.creator}"
name = clean(self.name)
creator = clean(self.creator)
return f"{name} by {creator}"
def preview(self) -> str:
desc = clean(self.description, trunc=False)
wrapped = "\n".join(
textwrap.wrap(self.description, os.get_terminal_size().columns - 4 or 70),
textwrap.wrap(desc, os.get_terminal_size().columns - 4 or 70),
)
return f"{self.num_tracks} tracks\n\nDescription:\n{wrapped}\n\nID: {self.id}"
@ -214,6 +218,7 @@ class PlaylistSummary(Summary):
item.get("tracks_count")
or item.get("nb_tracks")
or item.get("numberOfTracks")
or len(item.get("tracks", []))
or -1
)
description = item.get("description") or "No description"
@ -273,3 +278,11 @@ class SearchResults:
assert ind is not None
i = int(ind.group(0))
return self.results[i - 1].preview()
def clean(s: str, trunc=True) -> str:
s = s.replace("|", "").replace("\n", "")
if trunc:
max_chars = 50
return s[:max_chars]
return s

View File

@ -25,8 +25,6 @@ class ProgressManager:
BarColumn(bar_width=None),
"[progress.percentage]{task.percentage:>3.1f}%",
"",
# DownloadColumn(),
# "•",
TransferSpeedColumn(),
"",
TimeRemainingColumn(),

View File

@ -36,8 +36,14 @@ def coro(f):
"--config-path",
default=DEFAULT_CONFIG_PATH,
help="Path to the configuration file",
type=click.Path(readable=True, writable=True),
)
@click.option(
"-f",
"--folder",
help="The folder to download items into.",
type=click.Path(file_okay=False, dir_okay=True),
)
@click.option("-f", "--folder", help="The folder to download items into.")
@click.option(
"-ndb",
"--no-db",
@ -46,11 +52,14 @@ def coro(f):
is_flag=True,
)
@click.option(
"-q", "--quality", help="The maximum quality allowed to download", type=int
"-q",
"--quality",
help="The maximum quality allowed to download",
type=click.IntRange(min=0, max=4),
)
@click.option(
"-c",
"--convert",
"--codec",
help="Convert the downloaded files to an audio codec (ALAC, FLAC, MP3, AAC, or OGG)",
)
@click.option(
@ -66,7 +75,7 @@ def coro(f):
is_flag=True,
)
@click.pass_context
def rip(ctx, config_path, folder, no_db, quality, convert, no_progress, verbose):
def rip(ctx, config_path, folder, no_db, quality, codec, no_progress, verbose):
"""Streamrip: the all in one music downloader."""
global logger
logging.basicConfig(
@ -112,7 +121,8 @@ def rip(ctx, config_path, folder, no_db, quality, convert, no_progress, verbose)
return
# set session config values to command line args
c.session.database.downloads_enabled = not no_db
if no_db:
c.session.database.downloads_enabled = False
if folder is not None:
c.session.downloads.folder = folder
@ -122,10 +132,10 @@ def rip(ctx, config_path, folder, no_db, quality, convert, no_progress, verbose)
c.session.deezer.quality = quality
c.session.soundcloud.quality = quality
if convert is not None:
if codec is not None:
c.session.conversion.enabled = True
assert convert.upper() in ("ALAC", "FLAC", "OGG", "MP3", "AAC")
c.session.conversion.codec = convert.upper()
assert codec.upper() in ("ALAC", "FLAC", "OGG", "MP3", "AAC")
c.session.conversion.codec = codec.upper()
if no_progress:
c.session.cli.progress_bars = False
@ -147,7 +157,9 @@ async def url(ctx, urls):
@rip.command()
@click.argument("path", required=True)
@click.argument(
"path", required=True, type=click.Path(file_okay=True, dir_okay=False, exists=True)
)
@click.pass_context
@coro
async def file(ctx, path):
@ -275,7 +287,7 @@ async def search(ctx, first, source, media_type, query):
"""Search for content using a specific source.
Example:
-------
rip search qobuz album 'rumours'
"""
with ctx.obj["config"] as cfg:

View File

@ -140,7 +140,7 @@ class SoundcloudURL(URL):
config: Config,
db: Database,
) -> Pending:
resolved = await client._resolve_url(self.url)
resolved = await client.resolve_url(self.url)
media_type = resolved["kind"]
item_id = str(resolved["id"])
if media_type == "track":