feat: add sjmusic player support

This commit is contained in:
Harold
2026-04-24 20:52:59 +08:00
parent 3cb2b9e9fc
commit 04c3e45a88
2 changed files with 108 additions and 1 deletions
+18
View File
@@ -213,6 +213,24 @@ class TestSJMusicSpider(unittest.TestCase):
self.assertEqual(playlist_vod["vod_play_url"], "安静$music:401#晴天$music:402")
self.assertEqual(singer_vod["vod_play_url"], "青花瓷$music:501#稻香$music:502")
def test_player_content_maps_music_and_mv_ids(self):
song = self.spider.playerContent("世纪音乐", "music:123", {})
mv = self.spider.playerContent("世纪音乐", "vplay:456:1080", {})
self.assertEqual(song["parse"], 0)
self.assertEqual(song["url"], "https://www.4c44.com/data/down.php?ac=music&id=123")
self.assertEqual(mv["url"], "https://www.4c44.com/data/down.php?ac=vplay&id=456&q=1080")
def test_player_content_returns_empty_url_for_invalid_id(self):
self.assertEqual(self.spider.playerContent("世纪音乐", "bad", {})["url"], "")
@patch.object(Spider, "fetch")
def test_filters_include_singer_mv_and_playlist_groups(self, mock_fetch):
mock_fetch.return_value = SimpleNamespace(status_code=200, text=HOME_HTML)
filters = self.spider.homeContent(False)["filters"]
self.assertEqual([item["key"] for item in filters["singer"]], ["sex", "area", "char"])
self.assertEqual([item["key"] for item in filters["mv"]], ["area", "type", "sort"])
self.assertEqual([item["key"] for item in filters["playlist"]], ["lang", "style"])
if __name__ == "__main__":
unittest.main()
+90 -1
View File
@@ -72,7 +72,70 @@ class Spider(BaseSpider):
return text.split(marker, 1)[1].split(".html", 1)[0].split("/", 1)[0]
def _build_filters(self):
return {"singer": [], "mv": [], "playlist": []}
return {
"singer": [
{
"key": "sex",
"name": "性别",
"value": [
{"n": "女歌手", "v": "girl"},
{"n": "男歌手", "v": "male"},
{"n": "乐队组合", "v": "band"},
],
},
{
"key": "area",
"name": "地区",
"value": [
{"n": "华语", "v": "huayu"},
{"n": "欧美", "v": "oumei"},
{"n": "韩国", "v": "hanguo"},
{"n": "日本", "v": "riben"},
],
},
{
"key": "char",
"name": "字母",
"value": [{"n": "全部", "v": "index"}],
},
],
"mv": [
{
"key": "area",
"name": "地区",
"value": [{"n": "全部地区", "v": "index"}],
},
{
"key": "type",
"name": "类型",
"value": [{"n": "全部类型", "v": "index"}],
},
{
"key": "sort",
"name": "排序",
"value": [
{"n": "最新", "v": "new"},
{"n": "最热", "v": "hot"},
{"n": "上升最快", "v": "rise"},
],
},
],
"playlist": [
{
"key": "lang",
"name": "语种",
"value": [{"n": "全部语种", "v": "index"}],
},
{
"key": "style",
"name": "风格",
"value": [
{"n": "流行", "v": "liuxing"},
{"n": "摇滚", "v": "yaogun"},
],
},
],
}
def _parse_home_items(self, html):
root = self._load_html(html)
@@ -125,6 +188,15 @@ class Spider(BaseSpider):
return f"vplay:{value}:1080"
return ""
def _decode_play_id(self, play_id):
raw = str(play_id or "").strip()
if raw.startswith("music:"):
return "music", raw.split(":", 1)[1], "0"
if raw.startswith("vplay:"):
_, mv_id, quality = raw.split(":", 2)
return "vplay", mv_id, quality
return "", "", ""
def _parse_list_cards(self, html, expected_prefixes):
root = self._load_html(html)
items = []
@@ -285,3 +357,20 @@ class Spider(BaseSpider):
]
}
return {"list": []}
def playerContent(self, flag, id, vipFlags):
kind, value, quality = self._decode_play_id(id)
if kind == "music":
url = f"{self.host}/data/down.php?ac=music&id={value}"
elif kind == "vplay":
url = f"{self.host}/data/down.php?ac=vplay&id={value}&q={quality}"
else:
url = ""
return {
"parse": 0,
"url": url,
"header": {
"User-Agent": self.headers["User-Agent"],
"Referer": self.host + "/",
},
}