0 缘起
起源是看到站内这一篇分享
作者此前已经在用Jellyfin进行电影、电视剧、动漫的管理,找到音流之后发现音流支持Jellyfin作为服务端
并进一步发现Jellyfin甚至支持管理书籍(后话挖坑)。本着能用就不部署多余服务的想法,我就先开始了基于Jellyfin的音乐管理折腾,目前来看结果满足我日常使用
1 使用工具
1、Jellyfin(简单介绍部署,重点在踩坑)
2、音乐标签(刮削下载音乐的歌词、封面等)
3、音流(作为客户端播放刮削好的歌曲)
4、python(生成满足Jellyfin要求的目录结构)
2 Jellyfin部署
玩NAS的朋友可以直接跳过
2.1a 威联通(QNAP)
我在住处用的威联通,在威联通的NAS上部署,直接下载对应QPKG文件即可(需要魔法Releases · pdulvp/jellyfin-qnap (github.com))
2.1b 自建NAS
我一般使用docker-compose部署nyanmisaka大神做的可以直接硬件解码的版本
version: '3'
services:
jellyfin:
image: nyanmisaka/jellyfin
container_name: jellyfin
group_add:
- "105"
devices:
- /dev/dri:/dev/dri #添加显卡
volumes:
- {your_config_path}:/config #配置文件
- {your_cache_path}:/cache #缓存
- {your_media_path}:/media #媒体目录
ports:
- 8096:8096 #可以自定义端口
restart: unless-stopped
docker的安装以及镜像加速不是重点就不讲了
2.2 添加音乐媒体库
这里笔者已经添加了,仅作演示,进入控制台后选择添加媒体库,如果是docker-compose部署的话,映射的media目录应当是根目录,如果是威联通qpkg安装则需要自行查找对应目录(都点开瞅瞅)
首先选择内容类型为音乐,显示名称是媒体库的名称,可以随便起,但自建nas可能没有中文字库,需要自行解决。最后就是文件夹右边的加号需要点击添加自己的音乐目录。后续所有维持默认即可
3 音流
插一句题外话,域名填充其实是很多客户端软件让人困惑的地方,能对Jellyfin的默认端口进行适配感觉音流的作者还是很为普通用户考虑的
但此时你得到的是没有歌词,没有封面的一个音乐库,能听,但是差点感觉
4 音乐标签:为音乐添加内嵌歌词与专辑封面
此刻就不得不提到根据音流支持列表得知的消息,音乐文件可以内嵌歌词,一番搜索后寻找到音乐标签软件,可以批量刮削音乐的歌词、专辑封面等信息
开发者在博客园开放了软件下载
此处笔者简单进行使用介绍,大致流程是添加音乐文件根目录(如果包含子目录注意勾选)
添加完成后选择自动匹配
选择你需要的元信息
在一段时间等待后会提醒匹配完成,点击保存标签你就可以在Jellyfin中看到海报墙了
但笔者在此还遇到专辑无法识别、音流中可以显示歌词但不显示专辑封面的问题,为此通过排查发现是Jellyfin无法识别专辑,而音流在2024-04-08 V1.2.7的更新中看起来改成了只获取音乐专辑封面。原因和表征符合,那接下来就是解决问题
5 Jellyfin专辑识别
最初笔者以为Jellyfin使用歌曲元数据(音乐标签)进行专辑识别,因此特地进行了专辑匹配,但并未奏效,经过搜索发现在Jellyfin的文档中提到Jellyfin的专辑识别依靠文件夹而非音乐标签
而我的音乐文件此前是使用网易云音乐批量下载到一个目录下没有任何子目录,所以无法识别专辑但一个个手动创建专辑也比较麻烦,并且有些专辑名称是“精选国语23”、“精选国语45”等,十分难以辨认是什么歌,因此笔者计划以每一首歌作为一个目录以歌曲名称命名。此处需要用到python和音乐标签。最初的歌曲命名是“歌手 歌名.扩展名”的结构,使用空格提取会遇到歌名中包含空格而无法完全自动化,因此需要使用音乐的标签进行重命名。
最初因为可以批量改名,本想直接添加“\”符号改名到专辑名称,但会将“\”变成“;”而无法实现,因此只能使用别的工具,作者常用python因此使用python进行
import os
import shutil
def organize_music_files(root_directory):
for root, dirs, files in os.walk(root_directory):
for file in files:
file_path = os.path.join(root, file)
if file.endswith(('.mp3', '.flac','.wav')):#如果有其他格式音乐文件自行添加,不涉及任何文件内容修改,因此可以适配任何格式
try:
file_name = os.path.splitext(file)[0]
infom = file_name.split('=') #如果前文没有使用等号请自行更改
album_name = infom[1].strip()
album_directory = os.path.join(root_directory, album_name)
if not os.path.exists(album_directory):
os.makedirs(album_directory)
new_file_name = file_name.replace('=', '-')+os.path.splitext(file)[1]
destination_path = os.path.join(album_directory, new_file_name)
shutil.move(file_path, destination_path)
except:
print(f"Error processing file: {file}")
continue
if __name__ == '__main__':
# 调用函数,指定根目录
root_directory = r"your_media_path"
organize_music_files(root_directory)
等程序运行结束后在Jellyfin中重新扫描媒体库,你就可以得到封面歌词都匹配的播放器了
6 最终成果与遗留问题
遗留问题
通过对比可以发现iOS端很好匹配了歌曲名称和歌词,但安卓端显示的确实是“专辑”名称,并且歌词也无法匹配到。并且经过排查Jellyfin本身也是在专辑界面显示专辑名称,于是这个事情便变得吊诡起来,来自同一个服务端的数据,在同一个开发者的跨平台app上有不同表现,极大可能是Flutter本身在双端的实现上有差异,只能期待作者后续可以打补丁了。
但作者还是觉得Jellyfin也很神奇,专辑存在与否的识别通过是否存在目录达成,但专辑名称与封面又会读取音乐标签,为什么不直接读取音乐标签进行专辑聚合,也让用户免受满足目录结构的苦。