feat: tag 信息支持写入到歌曲文件 see #266
This commit is contained in:
parent
2c5b7b7f26
commit
48a8bf3325
@ -168,6 +168,9 @@ class Config:
|
|||||||
enable_yt_dlp_cookies: bool = (
|
enable_yt_dlp_cookies: bool = (
|
||||||
os.getenv("XIAOMUSIC_ENABLE_YT_DLP_COOKIES", "false").lower() == "true"
|
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 = (
|
get_ask_by_mina: bool = (
|
||||||
os.getenv("XIAOMUSIC_GET_ASK_BY_MINA", "false").lower() == "true"
|
os.getenv("XIAOMUSIC_GET_ASK_BY_MINA", "false").lower() == "true"
|
||||||
)
|
)
|
||||||
|
@ -198,6 +198,12 @@ var vConsole = new window.VConsole();
|
|||||||
<option value="false" selected>false</option>
|
<option value="false" selected>false</option>
|
||||||
</select>
|
</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>
|
<label for="get_ask_by_mina">特殊型号获取对话记录:</label>
|
||||||
<select id="get_ask_by_mina">
|
<select id="get_ask_by_mina">
|
||||||
<option value="true">true</option>
|
<option value="true">true</option>
|
||||||
|
@ -27,7 +27,19 @@ import aiohttp
|
|||||||
import mutagen
|
import mutagen
|
||||||
from mutagen.asf import ASF
|
from mutagen.asf import ASF
|
||||||
from mutagen.flac import FLAC
|
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.mp3 import MP3
|
||||||
from mutagen.mp4 import MP4
|
from mutagen.mp4 import MP4
|
||||||
from mutagen.oggvorbis import OggVorbis
|
from mutagen.oggvorbis import OggVorbis
|
||||||
@ -568,6 +580,16 @@ class Metadata:
|
|||||||
picture: str = ""
|
picture: str = ""
|
||||||
lyrics: 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):
|
def _get_alltag_value(tags, k):
|
||||||
v = tags.getall(k)
|
v = tags.getall(k)
|
||||||
@ -731,6 +753,110 @@ def extract_audio_metadata(file_path, save_root):
|
|||||||
return asdict(metadata)
|
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):
|
async def download_playlist(config, url, dirname):
|
||||||
title = f"{dirname}/%(title)s.%(ext)s"
|
title = f"{dirname}/%(title)s.%(ext)s"
|
||||||
|
@ -52,6 +52,7 @@ from xiaomusic.utils import (
|
|||||||
parse_cookie_string,
|
parse_cookie_string,
|
||||||
parse_str_to_dict,
|
parse_str_to_dict,
|
||||||
save_picture_by_base64,
|
save_picture_by_base64,
|
||||||
|
set_music_tag_to_file,
|
||||||
traverse_music_directory,
|
traverse_music_directory,
|
||||||
try_add_access_control_param,
|
try_add_access_control_param,
|
||||||
)
|
)
|
||||||
@ -477,11 +478,13 @@ class XiaoMusic:
|
|||||||
tags["year"] = info.year
|
tags["year"] = info.year
|
||||||
tags["genre"] = info.genre
|
tags["genre"] = info.genre
|
||||||
tags["lyrics"] = info.lyrics
|
tags["lyrics"] = info.lyrics
|
||||||
|
file_path = self.all_music[name]
|
||||||
if info.picture:
|
if info.picture:
|
||||||
file_path = self.all_music[name]
|
|
||||||
tags["picture"] = save_picture_by_base64(
|
tags["picture"] = save_picture_by_base64(
|
||||||
info.picture, self.config.picture_cache_path, file_path
|
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.all_music_tags[name] = tags
|
||||||
self.try_save_tag_cache()
|
self.try_save_tag_cache()
|
||||||
return "OK"
|
return "OK"
|
||||||
|
Loading…
Reference in New Issue
Block a user