diff --git a/plugins/music/main.py b/plugins/music/main.py index f227a14..3a71fbd 100644 --- a/plugins/music/main.py +++ b/plugins/music/main.py @@ -70,7 +70,7 @@ class MusicPlugin(MessagePluginInterface): self._commands = self._config.get("Music", {}).get("command", ["点歌", "音乐"]) self.command_format = self._config.get("Music", {}).get("command-format", "点歌 歌曲名") self.enable = self._config.get("Music", {}).get("enable", True) - self.music_api_url = self._config.get("Music", {}).get("music_api_url", "") + self.music_api_url = self._config.get("Music", {}).get("music_api_url", "http://192.168.2.170:5000") self.LOG.debug(f"[{self.name}] 插件初始化完成,指令:{self._commands}") return True @@ -139,57 +139,48 @@ class MusicPlugin(MessagePluginInterface): def _search_song(self, song_name: str) -> Dict[str, Any]: """搜索歌曲信息""" try: - # 使用新的聚合搜索API - api_url = f"{self.music_api_url}".format(song_name=song_name) - self.LOG.info(f"请求歌曲API: {api_url}") - - response = requests.get(api_url, verify=False) - - if response.status_code != 200: - self.LOG.error(f"API 请求失败,状态码: {response.status_code}") + base_url = self.music_api_url.rstrip("/") + search_url = f"{base_url}/Search" + self.LOG.info(f"请求歌曲API: {search_url}") + resp = requests.get(search_url, params={"keywords": song_name}, timeout=10) + if resp.status_code != 200: + self.LOG.error(f"API 请求失败,状态码: {resp.status_code}") return {} - - json_data = response.json() - - # 检查API返回状态 - if json_data.get("code") != 200: - self.LOG.error(f"API 返回错误: {json_data.get('message')}") + search_data = resp.json() + if not search_data.get("success") or search_data.get("status") != 200: + self.LOG.error(f"API 返回错误: {search_data.get('message')}") return {} - - # 从results中获取第一首歌 - song_list = json_data.get("data", {}).get("results", []) - if not song_list or not isinstance(song_list, list) or len(song_list) == 0: + songs = search_data.get("data", []) + if not songs: self.LOG.error(f"未找到歌曲: {song_name}") return {} - - # 获取第一首搜索结果 - first_song = song_list[0] - - # 从API响应中提取所需字段 - result_song_name = first_song.get('name', '') - result_singer_name = first_song.get('artist', '') - play_url = first_song.get('url', '') - singer_pic = first_song.get('pic', '') - data_url = first_song.get('url', '') # 使用相同的URL作为数据链接 - - if not play_url: - self.LOG.error(f"歌曲播放链接为空") + first_song = songs[0] + song_id = str(first_song.get("id", "")) + detail_url = f"{base_url}/Song_V1" + detail_params = {"url": song_id, "level": "standard", "type": "json"} + detail_resp = requests.get(detail_url, params=detail_params, timeout=15) + if detail_resp.status_code != 200: + self.LOG.error(f"详情请求失败,状态码: {detail_resp.status_code}") return {} - - # 获取真实的播放链接(跟随重定向) + detail_data = detail_resp.json() + if not detail_data.get("success") or detail_data.get("status") != 200: + self.LOG.error(f"获取歌曲详情失败: {detail_data.get('message')}") + return {} + song_info = detail_data.get("data", {}) + song_name_res = song_info.get("name", first_song.get("name", "")) + singer_name_res = song_info.get("ar_name", first_song.get("artist_string", first_song.get("artists", ""))) + play_url = song_info.get("url", "") + pic_url = song_info.get("pic", first_song.get("picUrl", "")) + data_url = song_info.get("url", "") real_play_url = self._get_real_url(play_url) real_data_url = self._get_real_url(data_url) - real_singer_pic = self._get_real_url(singer_pic) - - self.LOG.info(f"成功获取歌曲: {result_singer_name} - {result_song_name}") - self.LOG.debug(f"原始URL: {play_url}") - self.LOG.debug(f"真实URL: {real_play_url}") - + real_pic_url = self._get_real_url(pic_url) + self.LOG.info(f"成功获取歌曲: {singer_name_res} - {song_name_res}") return { - "song_name": result_song_name, - "singer_name": result_singer_name, + "song_name": song_name_res, + "singer_name": singer_name_res, "play_url": real_play_url, - "singer_pic": real_singer_pic, + "pic_url": real_pic_url, "data_url": real_data_url } @@ -233,7 +224,7 @@ class MusicPlugin(MessagePluginInterface): song_name = song_info.get("song_name", "") singer_name = song_info.get("singer_name", "") play_url = song_info.get("play_url", "") - singer_pic = song_info.get("singer_pic", "") + singer_pic = song_info.get("pic_url", "") data_url = song_info.get("data_url", "") xml_message = f"{MUSIC_XML}".format(song_name=song_name, singer_name=singer_name, play_url=play_url, data_url=data_url, singer_pic=singer_pic) diff --git a/test/music.py b/test/music.py new file mode 100644 index 0000000..ad324c3 --- /dev/null +++ b/test/music.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +网易云音乐点歌工具 - 字段提取版 +功能:搜索歌曲 → 获取第一首 → 调用 /Song_V1 → 提取点歌所需字段 +""" + +import requests +import json +from urllib.parse import unquote + +BASE_URL = "http://192.168.2.170:5000" + + +def search_and_extract_song(keyword: str = "学不会", level: str = "standard"): + """ + 完整流程: + 1. 调用 /Search 搜索歌曲 + 2. 取第一首歌曲 + 3. 调用 /Song_V1 获取播放链接等详情 + 4. 提取你需要的字段 + + 返回示例: + { + "song_name": "学不会", + "singer_name": "林俊杰", + "play_url": "http://m802.music.126.net/...", + "pic_url": "https://p2.music.126.net/...jpg", + "data_url": "http://m802.music.126.net/...", # 与 play_url 相同 + "lyric": "...", + "song_id": "108134", + "album_name": "学不会" + } + """ + try: + # Step 1: 搜索歌曲 + search_url = f"{BASE_URL}/Search" + params = {"keywords": keyword} + resp = requests.get(search_url, params=params, timeout=10) + resp.raise_for_status() + search_data = resp.json() + + if not search_data.get("success") or search_data.get("status") != 200: + return {"error": f"搜索失败: {search_data.get('message')}"} + + songs = search_data.get("data", []) + if not songs: + return {"error": "没有找到相关歌曲"} + + first_song = songs[0] + song_id = str(first_song.get("id", "")) + + # Step 2: 获取歌曲详细信息(关键) + detail_url = f"{BASE_URL}/Song_V1" + detail_params = { + "url": song_id, + "level": level, # standard / exhigh / lossless + "type": "json" + } + detail_resp = requests.get(detail_url, params=detail_params, timeout=15) + detail_resp.raise_for_status() + detail_data = detail_resp.json() + + if not detail_data.get("success") or detail_data.get("status") != 200: + return {"error": f"获取歌曲详情失败: {detail_data.get('message')}"} + + song_info = detail_data.get("data", {}) + + # Step 3: 提取你需要的字段 + result = { + "song_name": song_info.get("name", first_song.get("name", "")), + "singer_name": song_info.get("ar_name", first_song.get("artist_string", first_song.get("artists", ""))), + "play_url": song_info.get("url", ""), + "pic_url": song_info.get("pic", first_song.get("picUrl", "")), + "data_url": song_info.get("url", ""), # 你要求与 play_url 相同 + "lyric": song_info.get("lyric", ""), + "song_id": song_info.get("id", song_id), + "album_name": song_info.get("al_name", first_song.get("album", "")), + "size": song_info.get("size", "") + } + + # 清理空值 + for key in list(result.keys()): + if result[key] == "": + del result[key] + + return result + + except requests.exceptions.RequestException as e: + return {"error": f"网络请求失败: {str(e)}"} + except Exception as e: + return {"error": f"未知错误: {str(e)}"} + + +def print_song_info(result): + """美化打印结果""" + if "error" in result: + print(f"❌ {result['error']}") + return + + print("\n" + "=" * 60) + print("🎵 点歌信息提取成功") + print("=" * 60) + print(f"歌曲名称 : {result.get('song_name', '未知')}") + print(f"演唱歌手 : {result.get('singer_name', '未知')}") + print(f"专辑名称 : {result.get('album_name', '未知')}") + print(f"歌曲ID : {result.get('song_id', '未知')}") + if result.get("size"): + print(f"文件大小 : {result.get('size')}") + + print(f"\n▶️ 播放地址 (play_url):") + print(result.get("play_url", "无")) + + print(f"\n🖼️ 封面图片 (pic_url):") + print(result.get("pic_url", "无")) + + print(f"\n📁 数据地址 (data_url):") + print(result.get("data_url", "无")) + + if result.get("lyric"): + print(f"\n📝 歌词长度: {len(result['lyric'])} 字符") + print("歌词预览:") + print(result['lyric'][:300] + "..." if len(result['lyric']) > 300 else result['lyric']) + + +# ====================== 主函数 ====================== +if __name__ == "__main__": + print("网易云音乐点歌字段提取工具") + print("输入歌曲名称(回车使用默认“学不会”):") + + keyword = input().strip() + if not keyword: + keyword = "学不会" + + print(f"\n正在搜索: {keyword} ...\n") + + result = search_and_extract_song(keyword=keyword, level="standard") + + print_song_info(result) + + # 如果你想直接得到字典用于你的点歌工具 + # print("\n返回给点歌工具的字典:") + # print(json.dumps(result, ensure_ascii=False, indent=2)) \ No newline at end of file