feat: musicinfo接口新增musictag参数,用于返回歌曲额外信息

This commit is contained in:
涵曦 2024-09-21 21:18:27 +08:00
parent 10693e103e
commit 425214d453
4 changed files with 197 additions and 3 deletions

46
test/test_music_tags.py Normal file
View File

@ -0,0 +1,46 @@
import traceback
from xiaomusic.const import (
SUPPORT_MUSIC_TYPE,
)
from xiaomusic.utils import (
get_audio_metadata,
traverse_music_directory,
)
# title 标题
# artist 艺术家
# album 影集
# year 年
# genre 性
# picture 图片
# lyrics 歌词
async def test_one_music(filename):
# 获取播放时长
try:
metadata = get_audio_metadata(filename)
if metadata:
lyrics = metadata.get("lyrics")
if lyrics:
print(f"歌曲 : {filename}{lyrics}")
except Exception as e:
print(f"歌曲 : {filename} no tag {e}")
traceback.print_exc()
async def main(directory):
# 获取所有歌曲文件
local_musics = traverse_music_directory(directory, 10, [], SUPPORT_MUSIC_TYPE)
print(local_musics)
for _, files in local_musics.items():
for file in files:
await test_one_music(file)
if __name__ == "__main__":
import asyncio
directory = "./music" # 替换为你的音乐目录路径
asyncio.run(main(directory))

View File

@ -227,13 +227,18 @@ async def musiclist(Verifcation=Depends(verification)):
@app.get("/musicinfo")
async def musicinfo(name: str, Verifcation=Depends(verification)):
async def musicinfo(
name: str, musictag: bool = False, Verifcation=Depends(verification)
):
url = xiaomusic.get_music_url(name)
return {
info = {
"ret": "OK",
"name": name,
"url": url,
}
if musictag:
info["tags"] = xiaomusic.get_music_tags(name)
return info
@app.get("/curplaylist")

View File

@ -2,6 +2,7 @@
from __future__ import annotations
import asyncio
import base64
import copy
import difflib
import json
@ -20,8 +21,13 @@ from urllib.parse import urlparse
import aiohttp
import mutagen
from mutagen.id3 import ID3
from mutagen.flac import FLAC
from mutagen.id3 import APIC, ID3
from mutagen.monkeysaudio import MonkeysAudio
from mutagen.mp3 import MP3
from mutagen.mp4 import MP4
from mutagen.oggvorbis import OggVorbis
from mutagen.wave import WAVE
from requests.utils import cookiejar_from_dict
from xiaomusic.const import SUPPORT_MUSIC_TYPE
@ -441,3 +447,131 @@ def chinese_to_number(chinese):
result += num
num = 0
return result
def get_audio_metadata(file_path):
if file_path.endswith(".mp3"):
return get_mp3_metadata(file_path)
elif file_path.endswith(".flac"):
return get_flac_metadata(file_path)
elif file_path.endswith(".wav"):
return get_wav_metadata(file_path)
elif file_path.endswith(".ape"):
return get_ape_metadata(file_path)
elif file_path.endswith(".ogg"):
return get_ogg_metadata(file_path)
elif file_path.endswith(".m4a"):
return get_m4a_metadata(file_path)
else:
raise ValueError("Unsupported file type")
def get_mp3_metadata(file_path):
audio = MP3(file_path, ID3=ID3)
tags = audio.tags
if tags is None:
return None
metadata = {
"title": tags.get("TIT2", [""])[0] if "TIT2" in tags else "",
"artist": tags.get("TPE1", [""])[0] if "TPE1" in tags else "",
"album": tags.get("TALB", [""])[0] if "TALB" in tags else "",
"year": tags.get("TDRC", [""])[0] if "TDRC" in tags else "",
"genre": tags.get("TCON", [""])[0] if "TCON" in tags else "",
"picture": "",
"lyrics": "",
}
for tag in tags.values():
if isinstance(tag, APIC):
metadata["picture"] = base64.b64encode(tag.data).decode("utf-8")
break
lyrics = tags.getall("USLT")
if lyrics:
metadata["lyrics"] = lyrics[0]
return metadata
def get_flac_metadata(file_path):
audio = FLAC(file_path)
metadata = {
"title": audio.get("title", [""])[0],
"artist": audio.get("artist", [""])[0],
"album": audio.get("album", [""])[0],
"year": audio.get("date", [""])[0],
"genre": audio.get("genre", [""])[0],
"picture": "",
"lyrics": "",
}
if audio.pictures:
picture = audio.pictures[0]
metadata["picture"] = base64.b64encode(picture.data).decode("utf-8")
if "lyrics" in audio:
metadata["lyrics"] = audio["lyrics"][0]
return metadata
def get_wav_metadata(file_path):
audio = WAVE(file_path)
metadata = {
"title": audio.get("TIT2", [""])[0],
"artist": audio.get("TPE1", [""])[0],
"album": audio.get("TALB", [""])[0],
"year": audio.get("TDRC", [""])[0],
"genre": audio.get("TCON", [""])[0],
"picture": "",
"lyrics": "",
}
return metadata
def get_ape_metadata(file_path):
audio = MonkeysAudio(file_path)
metadata = {
"title": audio.get("TIT2", [""])[0],
"artist": audio.get("TPE1", [""])[0],
"album": audio.get("TALB", [""])[0],
"year": audio.get("TDRC", [""])[0],
"genre": audio.get("TCON", [""])[0],
"picture": "",
"lyrics": "",
}
return metadata
def get_ogg_metadata(file_path):
audio = OggVorbis(file_path)
metadata = {
"title": audio.get("title", [""])[0],
"artist": audio.get("artist", [""])[0],
"album": audio.get("album", [""])[0],
"year": audio.get("date", [""])[0],
"genre": audio.get("genre", [""])[0],
"picture": "",
"lyrics": "",
}
return metadata
def get_m4a_metadata(file_path):
audio = MP4(file_path)
metadata = {
"title": audio.tags.get("\xa9nam", [""])[0],
"artist": audio.tags.get("\xa9ART", [""])[0],
"album": audio.tags.get("\xa9alb", [""])[0],
"year": audio.tags.get("\xa9day", [""])[0],
"genre": audio.tags.get("\xa9gen", [""])[0],
"picture": "",
"lyrics": "",
}
if "covr" in audio.tags:
cover = audio.tags["covr"][0]
metadata["picture"] = base64.b64encode(cover).decode("utf-8")
return metadata

View File

@ -41,6 +41,7 @@ from xiaomusic.utils import (
deepcopy_data_no_sensitive_info,
find_best_match,
fuzzyfinder,
get_audio_metadata,
get_local_music_duration,
get_web_music_duration,
is_mp3,
@ -68,6 +69,7 @@ class XiaoMusic:
self.music_list = {} # 播放列表 key 为目录名, value 为 play_list
self.devices = {} # key 为 did
self.running_task = []
self.all_music_tags = {} # 歌曲额外信息
# 初始化配置
self.init_config()
@ -389,6 +391,9 @@ class XiaoMusic:
self.log.warning(f"获取歌曲时长失败 {name} {url}")
return sec, url
def get_music_tags(self, name):
return self.all_music_tags.get(name, {})
def get_music_url(self, name):
if self.is_web_music(name):
url = self.all_music[name]
@ -432,6 +437,7 @@ class XiaoMusic:
# 获取目录下所有歌曲,生成随机播放列表
def _gen_all_music_list(self):
self.all_music = {}
self.all_music_tags = {}
all_music_by_dir = {}
local_musics = traverse_music_directory(
self.music_path,
@ -455,6 +461,7 @@ class XiaoMusic:
filename = os.path.basename(file)
(name, _) = os.path.splitext(filename)
self.all_music[name] = file
self.all_music_tags[name] = get_audio_metadata(file)
all_music_by_dir[dir_name][name] = True
self.log.debug(f"_gen_all_music_list {name}:{dir_name}:{file}")
@ -516,6 +523,8 @@ class XiaoMusic:
if (not name) or (not url):
continue
self.all_music[name] = url
# TODO: 网络歌曲获取歌曲额外信息
# self.all_music_tags[name] = get_audio_metadata(url)
one_music_list.append(name)
# 处理电台列表