from
tkinter
import
(
Tk,
filedialog,
messagebox,
Label,
Text,
Button,
END,
Scrollbar,
RIGHT,
Y,
)
from
functools
import
partial
import
time
import
os
import
re
import
subprocess
import
json
class
MUSIC_CUE_CUTE_GUI:
def
__init__(
self
, init_window_name):
self
.init_window_name
=
init_window_name
self
.cue_file_path
=
""
self
.wav_file_path
=
""
self
.wav_result_path
=
""
self
.tracks
=
[]
self
.ffmpeg
=
"ffmpeg"
def
reset_params(
self
):
self
.cue_file_path
=
""
self
.wav_file_path
=
""
self
.wav_result_path
=
""
self
.tracks
=
[]
def
set_init_window(
self
):
self
.init_window_name.title(
"CUE音频提取器_v1.0.0"
)
self
.init_window_name.geometry(
"681x681+10+10"
)
self
.cue_file_button
=
Button(
self
.init_window_name,
text
=
"打开CUE文件"
,
bg
=
"lightblue"
,
width
=
16
,
command
=
lambda
:
self
.open_file(
"cue"
),
)
self
.cue_file_button.grid(row
=
0
, column
=
0
)
self
.wav_file_button
=
Button(
self
.init_window_name,
text
=
"打开WAV文件"
,
bg
=
"lightblue"
,
width
=
16
,
command
=
lambda
:
self
.open_file(
"wav"
),
)
self
.wav_file_button.grid(row
=
0
, column
=
1
)
self
.detect_ffmpeg_button
=
Button(
self
.init_window_name,
text
=
"检测ffmpeg环境"
,
bg
=
"lightblue"
,
width
=
16
,
command
=
lambda
:
self
.detect_ffmpeg(),
)
self
.detect_ffmpeg_button.grid(row
=
0
, column
=
2
)
self
.parse_cue_button
=
Button(
self
.init_window_name,
text
=
"读取cue歌曲信息"
,
bg
=
"lightblue"
,
width
=
16
,
command
=
lambda
:
self
.parse_cue(),
)
self
.parse_cue_button.grid(row
=
1
, column
=
0
)
self
.execute_button
=
Button(
self
.init_window_name,
text
=
">> 提取音乐"
,
bg
=
"lightblue"
,
width
=
16
,
command
=
lambda
:
self
.split_audio(),
)
self
.execute_button.grid(row
=
1
, column
=
1
)
self
.result_data_label
=
Label(
self
.init_window_name, text
=
"")
self
.result_data_label.grid(
row
=
2
, column
=
0
, rowspan
=
1
, columnspan
=
5
, sticky
=
"W"
)
self
.result_data_Text
=
Text(
self
.init_window_name)
self
.result_data_Text.grid(row
=
3
, column
=
0
, rowspan
=
5
, columnspan
=
5
)
self
.readme_text
=
Text(
self
.init_window_name, height
=
10
)
self
.readme_text.grid(row
=
9
, column
=
0
, rowspan
=
2
, columnspan
=
5
, sticky
=
"W"
)
self
.readme_text.insert(END,
"使用说明:\n"
)
self
.readme_text.insert(END,
"1. 请先检测ffmpeg环境\n"
)
self
.readme_text.insert(
END,
"2. 选择cue文件,如果wav和cue在同目录且同名,可不用操作wav文件\n"
)
self
.readme_text.insert(END,
"3. 尝试先读取cue文件的歌曲清单,做确认提取音乐\n"
)
self
.readme_text.insert(END,
"4. 执行提取音乐\n"
)
def
detect_ffmpeg(
self
):
try
:
subprocess.run([
self
.ffmpeg,
"-version"
,
">"
,
"/dev/null"
,
"2>&1"
])
messagebox.showinfo(
"ffmpeg检测"
,
"你已正确安装"
)
except
FileNotFoundError:
messagebox.showwarning(
"ffmpeg检测"
,
"你未正确安装,请先安装ffmpeg到系统环境"
)
def
open_file(
self
, t
=
"cue"
):
filetypes
=
[(
"All files"
,
"*.*"
)]
if
t
=
=
"cue"
:
filetypes
=
[(
"Cue files"
,
"*.cue"
)]
elif
t
=
=
"wav"
:
filetypes
=
[(
"Wav files"
,
"*.wav"
)]
print
(filetypes, t,
self
)
file_path
=
filedialog.askopenfilename(
title
=
"选择"
+
t
+
"文件"
, filetypes
=
filetypes
)
if
t
=
=
"cue"
:
self
.cue_file_path
=
file_path
if
self
.wav_file_path
=
=
"":
self
.wav_file_path
=
self
.replace_file_suffix(file_path,
".wav"
)
self
.wav_result_path
=
os.path.dirname(
self
.wav_file_path)
elif
t
=
=
"wav"
:
if
self
.cue_file_path
=
=
"":
self
.cue_file_path
=
self
.replace_file_suffix(file_path,
".cue"
)
self
.wav_file_path
=
file_path
self
.wav_result_path
=
os.path.dirname(
self
.wav_file_path)
self
.print_log(
"你选择了"
+
t
+
"文件: "
+
self
.cue_file_path
+
"\n"
)
self
.print_log(
"系统默认给你选择了"
+
(
"wav"
if
t
=
=
"cue"
else
"cue"
)
+
"文件: "
+
self
.wav_file_path
+
"\n"
,
)
print
(
self
.cue_file_path,
self
.wav_file_path)
def
replace_file_suffix(
self
, file_path, new_suffix):
base_name, ext
=
os.path.splitext(file_path)
if
ext
and
ext[
0
]
=
=
"."
:
new_file_path
=
base_name
+
new_suffix
else
:
new_file_path
=
file_path
+
new_suffix
return
new_file_path
def
parse_cue(
self
):
tracks
=
[]
current_track
=
None
if
self
.cue_file_path
=
=
"":
messagebox.showwarning(
"警告"
,
"请先选择cue文件再来操作"
)
with
open
(
self
.cue_file_path,
"r"
, encoding
=
"GB2312"
) as
file
:
for
line
in
file
:
line
=
line.strip()
if
line.startswith(
"TRACK"
):
if
current_track:
tracks.append(current_track)
match
=
re.match(r
"TRACK (\d+) AUDIO"
, line)
if
match:
track_number
=
int
(match.group(
1
))
current_track
=
{
"number"
: track_number,
"title"
: "",
"start"
:
None
,
}
elif
line.startswith(
"TITLE"
):
title
=
line.split(
'TITLE "'
)[
1
].split(
'"'
)[
0
]
if
current_track:
current_track[
"title"
]
=
title
elif
line.startswith(
"INDEX 01"
):
match
=
re.match(r
"INDEX 01 ((\d+):(\d+):(\d+))"
, line)
if
match:
start_time, minutes, seconds, ms
=
match.groups()
if
current_track:
current_track[
"start"
]
=
minutes
+
":"
+
seconds
+
"."
+
ms
if
current_track:
tracks.append(current_track)
self
.tracks
=
tracks
self
.print_log(
"提取到{}首音乐"
.
format
(
len
(
self
.tracks)))
self
.print_log(
"\n"
.join(
list
(
map
(
lambda
x: json.dumps(x, ensure_ascii
=
False
),
self
.tracks))
)
)
def
split_audio(
self
):
if
len
(
self
.tracks)
=
=
0
:
self
.parse_cue()
if
len
(
self
.tracks)
=
=
0
:
self
.print_log(
"cue音频提起失败"
)
for
i, track
in
enumerate
(
self
.tracks):
start_time
=
track[
"start"
]
output_file
=
(
self
.wav_result_path
+
os.sep
+
track[
"title"
].strip()
+
".wav"
)
if
len
(
self
.tracks)
=
=
i
+
1
:
cuteCmd
=
[
self
.ffmpeg,
"-i"
,
self
.wav_file_path,
"-y"
,
"-ss"
,
start_time,
"-vn"
,
"-acodec"
,
"copy"
,
output_file,
]
else
:
next_track
=
self
.tracks[i
+
1
]
cuteCmd
=
[
self
.ffmpeg,
"-i"
,
self
.wav_file_path,
"-y"
,
"-ss"
,
start_time,
"-to"
,
next_track[
"start"
],
"-vn"
,
"-acodec"
,
"copy"
,
output_file,
]
self
.print_log(i
+
1
+
": "
+
" "
.join(cuteCmd))
subprocess.run(cuteCmd)
self
.print_log(
"cue音频提起完成"
)
self
.reset_params()
def
get_current_time(
self
):
current_time
=
time.strftime(
"%Y-%m-%d %H:%M:%S"
, time.localtime(time.time()))
return
current_time
def
print_log(
self
, text):
self
.result_data_Text.insert(END,
self
.get_current_time()
+
": "
+
text
+
"\n"
)
def
gui_start():
init_window
=
Tk()
MUSIC_CUE_CUTE_GUI(init_window).set_init_window()
init_window.mainloop()
if
__name__
=
=
"__main__"
:
gui_start()