Files
musicdl-catalog-sync-suite/catalog-sync/musicdl/catalogsync/collectors/qq.py
T

105 lines
3.7 KiB
Python

from __future__ import annotations
import requests
from ..models import PlaylistCandidate
from .base import BaseCollector
PLAYLIST_SQUARE_URL = "https://c.y.qq.com/splcloud/fcgi-bin/fcg_get_diss_by_tag.fcg"
TOPLIST_URL = "https://c.y.qq.com/v8/fcg-bin/fcg_myqq_toplist.fcg"
def _extract_collected_song_count(entry: dict) -> int | None:
for key in ("songnum", "song_num", "songCount", "song_count", "trackCount", "track_count"):
value = entry.get(key)
if isinstance(value, bool):
continue
if isinstance(value, (int, float)):
return int(value)
if isinstance(value, str) and value.strip().isdigit():
return int(value.strip())
return None
def parse_playlist_square_payload(payload: dict) -> list[PlaylistCandidate]:
items: list[PlaylistCandidate] = []
for entry in payload.get("data", {}).get("list", []) or []:
remote_id = str(entry.get("dissid", "")).strip()
if not remote_id:
continue
creator = entry.get("creator") or {}
items.append(
PlaylistCandidate(
platform="qq",
pool_kind="playlist_square",
remote_id=remote_id,
name=entry.get("dissname") or remote_id,
url=f"https://y.qq.com/n/ryqq/playlist/{remote_id}",
cover_url=entry.get("imgurl"),
creator_name=creator.get("name"),
play_count=entry.get("listennum"),
collected_song_count=_extract_collected_song_count(entry),
)
)
return items
def parse_toplist_payload(payload: dict) -> list[PlaylistCandidate]:
items: list[PlaylistCandidate] = []
for entry in payload.get("data", {}).get("topList", []) or []:
remote_id = str(entry.get("id", "")).strip()
if not remote_id:
continue
items.append(
PlaylistCandidate(
platform="qq",
pool_kind="toplist",
remote_id=remote_id,
name=entry.get("topTitle") or remote_id,
url=f"https://y.qq.com/n/ryqq/toplist/{remote_id}",
cover_url=entry.get("picUrl"),
play_count=entry.get("listenCount"),
collected_song_count=_extract_collected_song_count(entry),
parse_strategy="qq_toplist",
)
)
return items
class QQCollector(BaseCollector):
def __init__(self, headers: dict[str, str] | None = None, session: requests.Session | None = None):
super().__init__(headers=headers or {"User-Agent": "Mozilla/5.0"}, session=session or requests.Session())
self.headers.update({"Referer": "https://y.qq.com/", "Origin": "https://y.qq.com/"})
def collect_playlist_square(
self,
category_id: int = 10000000,
sort_id: int = 5,
page: int = 1,
page_size: int = 30,
) -> list[PlaylistCandidate]:
params = {
"picmid": "1",
"rnd": "0.1",
"g_tk": "732560869",
"loginUin": "0",
"hostUin": "0",
"format": "json",
"inCharset": "utf8",
"outCharset": "utf-8",
"notice": "0",
"platform": "yqq.json",
"needNewCode": "0",
"categoryId": str(category_id),
"sortId": str(sort_id),
"sin": str(max(page - 1, 0) * page_size),
"ein": str(max(page, 1) * page_size - 1),
}
response = self.get(PLAYLIST_SQUARE_URL, params=params)
return parse_playlist_square_payload(response.json())
def collect_toplist(self) -> list[PlaylistCandidate]:
response = self.get(TOPLIST_URL, params={"format": "json"})
return parse_toplist_payload(response.json())