1
0
mirror of https://github.com/hanxi/xiaomusic.git synced 2026-06-01 12:15:48 +08:00
Files
xiaomusic/xiaomusic/js_adapter.py
2026-01-17 20:25:20 +08:00

235 lines
8.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
JS 插件适配器
将 MusicFree JS 插件的数据格式转换为 xiaomusic 接口规范
"""
import logging
class JSAdapter:
"""JS 插件数据适配器"""
def __init__(self, xiaomusic):
self.xiaomusic = xiaomusic
self.log = logging.getLogger(__name__)
def format_search_results(
self, plugin_results: list[dict], plugin_name: str
) -> list[str]:
"""格式化搜索结果为 xiaomusic 格式,返回 ID 列表"""
formatted_ids = []
for item in plugin_results:
if not isinstance(item, dict):
self.log.warning(f"Invalid item format in plugin {plugin_name}: {item}")
continue
# 构造符合 xiaomusic 格式的音乐项
music_id = self._generate_music_id(
plugin_name, item.get("id", ""), item.get("songmid", "")
)
music_item = {
"id": music_id,
"title": item.get("title", item.get("name", "")),
"artist": self._extract_artists(item),
"album": item.get("album", item.get("albumName", "")),
"source": "online",
"plugin_name": plugin_name,
"original_data": item,
"duration": item.get("duration", 0),
"cover": item.get(
"artwork", item.get("cover", item.get("albumPic", ""))
),
"url": item.get("url", ""),
"lyric": item.get("lyric", item.get("lrc", "")),
"quality": item.get("quality", ""),
}
# 添加到 all_music 字典中
self.xiaomusic.music_library.all_music[music_id] = music_item
formatted_ids.append(music_id)
return formatted_ids
def format_media_source_result(
self, media_source_result: dict, music_item: dict
) -> dict:
"""格式化媒体源结果"""
if not media_source_result:
return {}
formatted = {
"url": media_source_result.get("url", ""),
"headers": media_source_result.get("headers", {}),
"userAgent": media_source_result.get(
"userAgent", media_source_result.get("user_agent", "")
),
}
return formatted
def format_lyric_result(self, lyric_result: dict) -> str:
"""格式化歌词结果为 lrc 格式字符串"""
if not lyric_result:
return ""
# 获取原始歌词和翻译
raw_lrc = lyric_result.get("rawLrc", lyric_result.get("raw_lrc", ""))
translation = lyric_result.get("translation", "")
# 如果有翻译,合并歌词和翻译
if translation and raw_lrc:
# 这里可以实现歌词和翻译的合并逻辑
return f"{raw_lrc}\n{translation}"
return raw_lrc or translation or ""
def format_album_info_result(self, album_info_result: dict) -> dict:
"""格式化专辑信息结果"""
if not album_info_result:
return {}
album_item = album_info_result.get("albumItem", {})
formatted = {
"isEnd": album_info_result.get("isEnd", True),
"musicList": self.format_search_results(
album_info_result.get("musicList", []), "album"
),
"albumItem": {
"title": album_item.get("title", ""),
"artist": album_item.get("artist", ""),
"cover": album_item.get("cover", ""),
"description": album_item.get("description", ""),
},
}
return formatted
def format_music_sheet_info_result(self, music_sheet_result: dict) -> dict:
"""格式化音乐单信息结果"""
if not music_sheet_result:
return {}
sheet_item = music_sheet_result.get("sheetItem", {})
formatted = {
"isEnd": music_sheet_result.get("isEnd", True),
"musicList": self.format_search_results(
music_sheet_result.get("musicList", []), "playlist"
),
"sheetItem": {
"title": sheet_item.get("title", ""),
"cover": sheet_item.get("cover", ""),
"description": sheet_item.get("description", ""),
},
}
return formatted
def format_artist_works_result(self, artist_works_result: dict) -> dict:
"""格式化艺术家作品结果"""
if not artist_works_result:
return {}
formatted = {
"isEnd": artist_works_result.get("isEnd", True),
"data": self.format_search_results(
artist_works_result.get("data", []), "artist"
),
}
return formatted
def format_top_lists_result(self, top_lists_result: list[dict]) -> list[dict]:
"""格式化榜单列表结果"""
if not top_lists_result:
return []
formatted = []
for group in top_lists_result:
formatted_group = {"title": group.get("title", ""), "data": []}
for item in group.get("data", []):
formatted_item = {
"id": item.get("id", ""),
"title": item.get("title", ""),
"description": item.get("description", ""),
"coverImg": item.get("coverImg", item.get("cover", "")),
}
formatted_group["data"].append(formatted_item)
formatted.append(formatted_group)
return formatted
def format_top_list_detail_result(self, top_list_detail_result: dict) -> dict:
"""格式化榜单详情结果"""
if not top_list_detail_result:
return {}
formatted = {
"isEnd": top_list_detail_result.get("isEnd", True),
"musicList": self.format_search_results(
top_list_detail_result.get("musicList", []), "toplist"
),
"topListItem": top_list_detail_result.get("topListItem", {}),
}
return formatted
def _generate_music_id(
self, plugin_name: str, item_id: str, fallback_id: str = ""
) -> str:
"""生成唯一音乐ID"""
if item_id:
return f"online_{plugin_name}_{item_id}"
else:
# 如果没有 id尝试使用其他标识符
return f"online_{plugin_name}_{fallback_id}"
def _extract_artists(self, item: dict) -> str:
"""提取艺术家信息"""
# 尝试多种可能的艺术家字段
artist_fields = ["artist", "artists", "singer", "author", "creator", "singers"]
for field in artist_fields:
if field not in item:
continue
value = item[field]
if isinstance(value, list):
# 如果是艺术家列表,连接为字符串
artists = []
for artist in value:
if isinstance(artist, dict):
artists.append(artist.get("name", str(artist)))
else:
artists.append(str(artist))
return ", ".join(artists)
elif isinstance(value, dict):
# 如果是艺术家对象
return value.get("name", str(value))
elif value:
return str(value)
# 如果没有找到艺术家信息,返回默认值
return "未知艺术家"
def convert_music_item_for_plugin(self, music_item: dict) -> dict:
"""将 xiaomusic 音乐项转换为插件兼容格式"""
# 如果原始数据存在,优先使用原始数据
if isinstance(music_item, dict) and "original_data" in music_item:
return music_item["original_data"]
# 否则构造一个基本的音乐项
converted = {
"id": music_item.get("id", ""),
"title": music_item.get("title", ""),
"artist": music_item.get("artist", ""),
"album": music_item.get("album", ""),
"url": music_item.get("url", ""),
"duration": music_item.get("duration", 0),
"artwork": music_item.get("cover", ""),
"lyric": music_item.get("lyric", ""),
"quality": music_item.get("quality", ""),
}
return converted