File size: 5,773 Bytes
b02246d
 
 
 
 
65004e0
b02246d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65004e0
b02246d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65004e0
 
 
 
b02246d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
import os
import gradio as gr
from mutagen.mp3 import MP3
from mutagen.flac import FLAC
from mutagen.id3 import USLT, PictureType
from utils import insert_meta, clean_dir, TMP_DIR, EN_US

CACHE_DIR = f"{TMP_DIR}/meta"
ZH2EN = {
    "# 音频 Meta 信息编辑器": "# Music Metadata Editor",
    "上传待编辑音乐 (mp3/flac)": "Upload music (mp3/flac)",
    "编辑文件名 (不含后缀)": "Edit filename (excluding suffix)",
    "请确保文件名有效": "Ensure the filename is valid",
    "编辑歌名": "Edit title",
    "编辑作者": "Edit artist",
    "编辑专辑": "Edit album",
    "编辑歌词": "Edit lyrics",
    "编辑封面 (留空意味着清空)": "Edit cover (leaving blank means deletion)",
    "提交": "Submit",
    "下载输出音频": "Download output audio",
    "状态栏": "Status",
}


def _L(zh_txt: str):
    return ZH2EN[zh_txt] if EN_US else zh_txt


# outer func requires try except
def extract_metadata(file_path: str):
    status = "Success"
    title = fname = artist = album = lyrics = cover = None
    try:
        if not file_path:
            raise ValueError("文件路径为空!")

        fname = os.path.splitext(os.path.basename(file_path))[0]
        file_ext = os.path.splitext(file_path)[1].lower()
        if file_ext == ".mp3":
            title, artist, album, lyrics, cover = extract_mp3_meta(file_path)
        elif file_ext == ".flac":
            title, artist, album, lyrics, cover = extract_flac_meta(file_path)

    except Exception as e:
        status = f"{e}"

    return status, title, fname, artist, album, lyrics, cover


def extract_mp3_meta(file_path):
    title = artist = album = lyrics = cover = None
    audio = MP3(file_path)
    title = audio.get("TIT2")
    artist = audio.get("TPE1")
    album = audio.get("TALB")
    for tag in audio.tags.values():
        if isinstance(tag, USLT):
            lyrics = tag.text

        if tag.FrameID == "APIC":
            cover = f"{CACHE_DIR}/cover.jpg"
            with open(cover, "wb") as img_file:
                img_file.write(tag.data)

    return title, artist, album, lyrics, cover


def extract_flac_meta(file_path):
    title = artist = album = lyrics = cover = None
    audio = FLAC(file_path)
    title = audio.get("TITLE")[0]
    artist = audio.get("ARTIST")[0]
    album = audio.get("ALBUM")[0]
    lyrics = audio.get("LYRICS")[0]
    for picture in audio.pictures:
        if picture.type == PictureType.COVER_FRONT:
            cover = f"{CACHE_DIR}/cover.jpg"
            with open(cover, "wb") as img_file:
                img_file.write(picture.data)

            break

    return title, artist, album, lyrics, cover


# outer func requires try except
def upd_meta(audio_in: str, fname, title, artist, album, lyric, cover):
    status = "Success"
    audio_out = None
    try:
        file_ext = os.path.splitext(audio_in)[1].lower()
        audio_out = insert_meta(
            audio_in,
            title,
            artist,
            album,
            lyric,
            cover,
            f"{CACHE_DIR}/{fname}{file_ext}",
        )

    except Exception as e:
        status = f"{e}"

    return status, audio_out


def clear_inputs():
    status = None
    try:
        clean_dir(CACHE_DIR)
    except Exception as e:
        status = f"{e}"

    return status, None, None, None, None, None, None


def music_meta_editor():
    clean_dir(CACHE_DIR)
    with gr.Blocks() as meta:
        gr.Markdown(_L("# 音频 Meta 信息编辑器"))
        with gr.Row():
            with gr.Column():
                input_audio = gr.Audio(
                    label=_L("上传待编辑音乐 (mp3/flac)"),
                    type="filepath",
                )
                fname = gr.Textbox(
                    label=_L("编辑文件名 (不含后缀)"),
                    placeholder=_L("请确保文件名有效"),
                    interactive=True,
                    show_copy_button=True,
                )
                title = gr.Textbox(
                    label=_L("编辑歌名"),
                    interactive=True,
                    show_copy_button=True,
                )
                artist = gr.Textbox(
                    label=_L("编辑作者"),
                    interactive=True,
                    show_copy_button=True,
                )
                album = gr.Textbox(
                    label=_L("编辑专辑"),
                    interactive=True,
                    show_copy_button=True,
                )
                lyrics = gr.TextArea(
                    label=_L("编辑歌词"),
                    interactive=True,
                    show_copy_button=True,
                )
                cover = gr.Image(
                    label=_L("编辑封面 (留空意味着清空)"),
                    interactive=True,
                    type="filepath",
                )
                submit = gr.Button(_L("提交"))

            with gr.Column():
                status_bar = gr.Textbox(label=_L("状态栏"), show_copy_button=True)
                output_audio = gr.Audio(
                    label=_L("下载输出音频"),
                    show_share_button=False,
                )

        input_audio.upload(
            fn=extract_metadata,
            inputs=input_audio,
            outputs=[status_bar, title, fname, artist, album, lyrics, cover],
        )

        input_audio.clear(
            fn=clear_inputs,
            inputs=None,
            outputs=[status_bar, title, fname, artist, album, lyrics, cover],
        )

        submit.click(
            fn=upd_meta,
            inputs=[input_audio, fname, title, artist, album, lyrics, cover],
            outputs=[status_bar, output_audio],
        )

    return meta