点歌功能再次优化
This commit is contained in:
@@ -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)
|
||||
|
||||
143
test/music.py
Normal file
143
test/music.py
Normal file
@@ -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))
|
||||
Reference in New Issue
Block a user