feat: tag 信息支持写入到歌曲文件 see #266

This commit is contained in:
涵曦 2024-12-06 22:55:14 +08:00
parent 2c5b7b7f26
commit 48a8bf3325
4 changed files with 140 additions and 2 deletions

View File

@ -168,6 +168,9 @@ class Config:
enable_yt_dlp_cookies: bool = (
os.getenv("XIAOMUSIC_ENABLE_YT_DLP_COOKIES", "false").lower() == "true"
)
enable_save_tag: bool = (
os.getenv("XIAOMUSIC_ENABLE_SAVE_TAG", "false").lower() == "true"
)
get_ask_by_mina: bool = (
os.getenv("XIAOMUSIC_GET_ASK_BY_MINA", "false").lower() == "true"
)

View File

@ -198,6 +198,12 @@ var vConsole = new window.VConsole();
<option value="false" selected>false</option>
</select>
<label for="enable_save_tag">启用ID3标签写入文件:</label>
<select id="enable_save_tag">
<option value="true">true</option>
<option value="false" selected>false</option>
</select>
<label for="get_ask_by_mina">特殊型号获取对话记录:</label>
<select id="get_ask_by_mina">
<option value="true">true</option>

View File

@ -27,7 +27,19 @@ import aiohttp
import mutagen
from mutagen.asf import ASF
from mutagen.flac import FLAC
from mutagen.id3 import APIC, ID3, Encoding, TextFrame, TimeStampTextFrame
from mutagen.id3 import (
APIC,
ID3,
TALB,
TCON,
TDRC,
TIT2,
TPE1,
USLT,
Encoding,
TextFrame,
TimeStampTextFrame,
)
from mutagen.mp3 import MP3
from mutagen.mp4 import MP4
from mutagen.oggvorbis import OggVorbis
@ -568,6 +580,16 @@ class Metadata:
picture: str = ""
lyrics: str = ""
def __init__(self, info=None):
if info:
self.title = info.get("title", "")
self.artist = info.get("artist", "")
self.album = info.get("album", "")
self.year = info.get("year", "")
self.genre = info.get("genre", "")
self.picture = info.get("picture", "")
self.lyrics = info.get("lyrics", "")
def _get_alltag_value(tags, k):
v = tags.getall(k)
@ -731,6 +753,110 @@ def extract_audio_metadata(file_path, save_root):
return asdict(metadata)
def set_music_tag_to_file(file_path, info):
audio = mutagen.File(file_path, easy=True)
if audio is None:
log.error(f"Unable to open file {file_path}")
return "Unable to open file"
if isinstance(audio, MP3):
_set_mp3_tags(audio, info)
elif isinstance(audio, FLAC):
_set_flac_tags(audio, info)
elif isinstance(audio, MP4):
_set_mp4_tags(audio, info)
elif isinstance(audio, OggVorbis):
_set_ogg_tags(audio, info)
elif isinstance(audio, ASF):
_set_asf_tags(audio, info)
elif isinstance(audio, WAVE):
_set_wave_tags(audio, info)
else:
log.error(f"Unsupported file type for {file_path}")
return "Unsupported file type"
try:
audio.save()
log.info(f"Tags saved successfully to {file_path}")
return "OK"
except Exception as e:
log.exception(f"Error saving tags: {e}")
return "Error saving tags"
def _set_mp3_tags(audio, info):
audio["TIT2"] = TIT2(encoding=3, text=info.title)
audio["TPE1"] = TPE1(encoding=3, text=info.artist)
audio["TALB"] = TALB(encoding=3, text=info.album)
audio["TDRC"] = TDRC(encoding=3, text=info.year)
audio["TCON"] = TCON(encoding=3, text=info.genre)
if info.lyrics:
audio["USLT"] = USLT(encoding=3, lang="eng", text=info.lyrics)
if info.picture:
with open(info.picture, "rb") as img_file:
image_data = img_file.read()
audio["APIC"] = APIC(
encoding=3, mime="image/jpeg", type=3, desc="Cover", data=image_data
)
def _set_flac_tags(audio, info):
audio["TITLE"] = info.title
audio["ARTIST"] = info.artist
audio["ALBUM"] = info.album
audio["DATE"] = info.year
audio["GENRE"] = info.genre
if info.lyrics:
audio["LYRICS"] = info.lyrics
if info.picture:
with open(info.picture, "rb") as img_file:
image_data = img_file.read()
audio.add_picture(image_data)
def _set_mp4_tags(audio, info):
audio["\xa9nam"] = info.title
audio["\xa9ART"] = info.artist
audio["\xa9alb"] = info.album
audio["\xa9day"] = info.year
audio["\xa9gen"] = info.genre
if info.picture:
with open(info.picture, "rb") as img_file:
image_data = img_file.read()
audio["covr"] = [image_data]
def _set_ogg_tags(audio, info):
audio["TITLE"] = info.title
audio["ARTIST"] = info.artist
audio["ALBUM"] = info.album
audio["DATE"] = info.year
audio["GENRE"] = info.genre
if info.lyrics:
audio["LYRICS"] = info.lyrics
if info.picture:
with open(info.picture, "rb") as img_file:
image_data = img_file.read()
audio["metadata_block_picture"] = base64.b64encode(image_data).decode()
def _set_asf_tags(audio, info):
audio["Title"] = info.title
audio["Author"] = info.artist
audio["WM/AlbumTitle"] = info.album
audio["WM/Year"] = info.year
audio["WM/Genre"] = info.genre
if info.picture:
with open(info.picture, "rb") as img_file:
image_data = img_file.read()
audio["WM/Picture"] = image_data
def _set_wave_tags(audio, info):
audio["Title"] = info.title
audio["Artist"] = info.artist
# 下载播放列表
async def download_playlist(config, url, dirname):
title = f"{dirname}/%(title)s.%(ext)s"

View File

@ -52,6 +52,7 @@ from xiaomusic.utils import (
parse_cookie_string,
parse_str_to_dict,
save_picture_by_base64,
set_music_tag_to_file,
traverse_music_directory,
try_add_access_control_param,
)
@ -477,11 +478,13 @@ class XiaoMusic:
tags["year"] = info.year
tags["genre"] = info.genre
tags["lyrics"] = info.lyrics
file_path = self.all_music[name]
if info.picture:
file_path = self.all_music[name]
tags["picture"] = save_picture_by_base64(
info.picture, self.config.picture_cache_path, file_path
)
if self.config.enable_save_tag and (not self.is_web_music(name)):
set_music_tag_to_file(file_path, Metadata(tags))
self.all_music_tags[name] = tags
self.try_save_tag_cache()
return "OK"