shell 案例

批量处理处理MP3文件

场景

网站中播放音乐使用的是Aplayer,在构建静态文件时,需要将音乐文件转换为JSON格式,才能在Aplayer中播放。
如以下格式:

1
2
3
4
5
6
7
{
"title": "前前前世",
"author": "RADWIMPS",
"url": "xxxx.mp3",
"pic": "xxxx.jpg",
"lrc": "xxxx.lrc"
}

完整示例写法参考
Linux–Hexo搭建与配置

我的歌单中存了几百首歌,肯定不可能自己全部手动转换,因此写了一个脚本,自动完成。最开始我的源文件都是以“作者-歌曲名”格式保存的,因此很容易根据名字提取。初始版本如下:

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
#!/bin/bash

# 输出文件
output_file="output.txt"

# 清空或新建输出文件
> "$output_file"

# 遍历当前目录的 MP3 文件
for file in *.mp3; do
# 检查文件是否存在
if [[ -f "$file" ]]; then
# 提取作者和歌曲名
author="${file%%-*}" # "-" 前部分
title_with_suffix="${file#*-}" # "-" 后部分
title="${title_with_suffix%%(*}" # 去掉括号和后缀部分

# 生成 JSON 数据
json_entry=$(cat <<EOF
{
"title": "$title",
"author": "$author",
"url": "/music/mp3/$file",
"pic": "/img/top_3.jpg",
"lrc": "/music/lrc/${file%.mp3}.lrc"
},
EOF
)

# 写入输出文件
echo "$json_entry" >> "$output_file"
fi
done

# 删除最后一行的逗号
sed -i '$ s/,$//' "$output_file"

# 包装为 JSON 数组
sed -i '1s/^/[/' "$output_file"
echo "]" >> "$output_file"

echo "处理完成,结果已保存到 $output_file"

上面脚本要求环境很严格,仅能处理以“作者-歌曲名”命名的 MP3 文件,并且只提取作者和歌曲名。之前了解过大部分的mp3文件格式中,会包含歌手、专辑等元数据,所以我想能不能直接从元数据中提取这些信息。

这里使用 ffprobe工具,运行前需要安装 ffprobe。ubuntu 可以使用以下命令安装:

1
sudo apt install ffmpeg

脚本分享

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
#!/bin/bash

# 检查 ffprobe 是否安装
if ! command -v ffprobe &>/dev/null; then
echo "请先安装 ffprobe 工具!"
exit 1
fi

# 输出文件
output_file="output.json"

# 清空或新建输出文件
> "$output_file"

# 遍历当前目录的 MP3 文件
for mp3_file in *.mp3; do
# 检查文件是否存在
if [[ -f "$mp3_file" ]]; then
# 提取信息
artist=$(ffprobe -v error -show_entries format_tags=artist -of default=noprint_wrappers=1:nokey=1 "$mp3_file")
title=$(ffprobe -v error -show_entries format_tags=title -of default=noprint_wrappers=1:nokey=1 "$mp3_file")
album=$(ffprobe -v error -show_entries format_tags=album -of default=noprint_wrappers=1:nokey=1 "$mp3_file")

# 如果某些字段缺失,使用占位符
artist=${artist:-"未知歌手"}
title=${title:-"未知歌名"}
album=${album:-"未知专辑"}

# 生成 JSON 数据
json_entry=$(cat <<EOF
{
"title": "$title",
"author": "$artist",
"url": "/music/mp3/$mp3_file",
"pic": "/img/top_3.jpg",
"lrc": "/music/lrc/$artist-${mp3_file%.mp3}.lrc"
},
EOF
)

# 写入输出文件
echo "$json_entry" >> "$output_file"
fi
done

# 删除最后一行的逗号
sed -i '$ s/,$//' "$output_file"

# 包装为 JSON 数组
sed -i '1s/^/[/' "$output_file"
echo "]" >> "$output_file"

echo "处理完成,结果已保存到 $output_file"