perf: parallelize lrclib search queries
This commit is contained in:
@@ -9,6 +9,7 @@ Used when metadata is incomplete (no album or duration) but title is available.
|
|||||||
Selects the best match by duration when track length is known.
|
Selects the best match by duration when track length is known.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
import httpx
|
import httpx
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
@@ -80,29 +81,35 @@ class LrclibSearchFetcher(BaseFetcher):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
async with httpx.AsyncClient(timeout=HTTP_TIMEOUT) as client:
|
async with httpx.AsyncClient(timeout=HTTP_TIMEOUT) as client:
|
||||||
for params in queries:
|
|
||||||
|
async def _query(params: dict[str, str]) -> tuple[list[dict], bool]:
|
||||||
url = f"{LRCLIB_SEARCH_URL}?{urlencode(params)}"
|
url = f"{LRCLIB_SEARCH_URL}?{urlencode(params)}"
|
||||||
logger.debug(f"LRCLIB-search: query {params}")
|
logger.debug(f"LRCLIB-search: query {params}")
|
||||||
resp = await client.get(url, headers={"User-Agent": UA_LRX})
|
try:
|
||||||
|
resp = await client.get(url, headers={"User-Agent": UA_LRX})
|
||||||
|
except httpx.HTTPError as e:
|
||||||
|
logger.error(f"LRCLIB-search: HTTP error: {e}")
|
||||||
|
return [], True
|
||||||
if resp.status_code != 200:
|
if resp.status_code != 200:
|
||||||
logger.error(f"LRCLIB-search: API returned {resp.status_code}")
|
logger.error(f"LRCLIB-search: API returned {resp.status_code}")
|
||||||
had_error = True
|
return [], True
|
||||||
continue
|
|
||||||
|
|
||||||
data = resp.json()
|
data = resp.json()
|
||||||
if not isinstance(data, list):
|
if not isinstance(data, list):
|
||||||
continue
|
return [], False
|
||||||
|
return [item for item in data if isinstance(item, dict)], False
|
||||||
|
|
||||||
for item in data:
|
all_results = await asyncio.gather(*(_query(p) for p in queries))
|
||||||
if not isinstance(item, dict):
|
|
||||||
continue
|
for items, err in all_results:
|
||||||
item_id = item.get("id")
|
if err:
|
||||||
if item_id is not None and item_id in seen_ids:
|
had_error = True
|
||||||
continue
|
for item in items:
|
||||||
if item_id is not None:
|
item_id = item.get("id")
|
||||||
seen_ids.add(item_id)
|
if item_id is not None and item_id in seen_ids:
|
||||||
candidates.append(item)
|
continue
|
||||||
|
if item_id is not None:
|
||||||
|
seen_ids.add(item_id)
|
||||||
|
candidates.append(item)
|
||||||
|
|
||||||
if not candidates:
|
if not candidates:
|
||||||
if had_error:
|
if had_error:
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "lrx-cli"
|
name = "lrx-cli"
|
||||||
version = "0.4.2"
|
version = "0.4.3"
|
||||||
description = "Fetch line-synced lyrics for your music player."
|
description = "Fetch line-synced lyrics for your music player."
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
|
|||||||
Reference in New Issue
Block a user