feat: musicinfo接口新增musictag参数,用于返回歌曲额外信息
This commit is contained in:
parent
10693e103e
commit
425214d453
46
test/test_music_tags.py
Normal file
46
test/test_music_tags.py
Normal 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))
|
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
# 处理电台列表
|
||||
|
Loading…
Reference in New Issue
Block a user