
——历时近十年探索后找到的最佳实践
核心问题:
1. 如何评价自己对某一歌曲的喜欢程度?
2. 如何根据对歌曲的评价建立播放列表?
a) 如何使得歌曲播放率与其评价呈正相关?
b) 如何确保曲库中不会出现被遗忘的歌曲?
3. 如何对歌曲的增加、删除及修改进行跟踪?
其他问题:
1. 「艺术家」和「专辑艺术家」应该填什么?
2. 多名「艺术家」应该如何分隔?
3. 歌曲应该如何分组与排序?
4. 如何高效地检索外文歌曲?
先说明一下,本文是建立在本地播放器上的,要求读者本身对本地播放器的功能——尤其是音乐库、播放列表、智能播放列表、排序、分组等概念有一定了解。
后文所说的操作都是建立在AIMP之上,用到的都是相对比较基础的功能。如果你对音乐管理有一定基础,在了解本文的核心思想后,使用其他本地播放器如foobar2000应该也能轻松实现(可能要借助插件)。如果实现不了,说明你的本地播放器是个five,建议更换。
如何评价自己对一首歌的喜欢程度?
这是最根本的问题,它决定了歌曲的去留以及播放率。这个问题花了我近十年的时间,才在最近半年找到较好的实践。我本在半年前就想着写这篇文章,但想看一下这个实践能否经得起时间的检验。当然,它成功了,也就有了这篇文章。
先说结论:无论是借助算法实现的自动评分,还是借助个人标准建立的手动评分,都是不可取的。接下来我会对原因进行阐述,并非重点,可以跳过。
自动评分的弊端
首先要明白,「喜欢程度」是一个非常主观的概念,妄图通过评分算法来解决,至少在目前来看效果很不理想。
简单介绍一下AIMP内置的歌曲评价系统:记录所有歌曲在一段时间内的回放完成次数,得到最大回放次数,每首歌曲的自动评分为该曲的回放次数与最大回放次数之比乘以5。其中「一段时间」的时长以及「回放完成」的定义都可以设置。
表面问题1:实践中某段时间总会有几首特别喜欢的歌曲,所以会出现一首歌5分,五六首歌3到4分,其他几百首歌在1分以下的尴尬情况。这个问题很好解决,写个插件对最终结果作一个对数校正就好。
表面问题2:算法过于简单,没有考虑「主动点击播放某一首歌」「还没有播放结束就主动点击下一首」这些用户行为。同上,写个插件自己编个算法就好。
但是,其实即使真的写了这么一个插件也不管用。因为本质问题是:曲库实在太大了,这种自动评分需要极长的时间才能得到较为合理的结果。我每隔一段时间都会清理以及不那么常听的歌曲,即使有这样的习惯,曲库还是常年在维持在250首以上,相信大部分人的曲库远比我的庞大,那问题就更严重了。即使是AIMP内置的这个最简单的算法,自动评分的响应速度也足以令人捉鸡。
尽管将评分统计的时间范围限制得比较小(如两周)可以解决响应问题,结果就是曲库中大部分的歌曲都变为0分。因为在短短两周时间内绝不可能使得曲库中的文件都得到一定数量的播放,根本无法满足统计数据的客观性。
自动评分响应速度不足的带来问题远比想象中麻烦,没有切身体验是不可能理解的。不过,我对自动评分还是充满期望的,相信总有一天这个问题能在AI的帮助下彻底解决。
手动评分的弊端
既然自动评分算法行不通,那还是回归手动评分吧。然而,这是一个比自动评分更大的坑。首先,这个极其主观的评分标准到底如何确定?
一开始,我建立了一套个人的评分标准,尝试去解构每一首歌,然后得到一个「客观」评分。这是最愚蠢的做法,极其浪费时间,而且得出来的分数跟实际的喜欢程度偏差极大。总有一些曲子,分数非常高但你就是不喜欢;另一些曲子,分数不怎么高却一次又一次被手动单曲循环。
针对前面的问题我在客观评分以外加入主观评分的规则,尝试进行修正。效果说实话还说得过去,也痛苦地用了好几年。
如前面所说,这套评分方式准确度还是说得过去的,但有两个致命缺陷:
1. 评分时间长,每一次评分至少要花掉一到两天的时间,期间需要花费大量时间将每首歌的片段听个几次,与同等级的曲子对比、与上下两个等级的曲子对比,最终得到一个相对靠谱的评分。其中最难确定的,就是介于两个等级之间的曲子如何判断,评着评着标准必然会不自觉改变,又得重新评一遍。
2. 每隔一段时间,总会有曲子的「喜欢程度」会发生变动。大家可以回想一下,自己有没有曾经非常喜欢、现在放到却直接跳过的歌曲,这种最极端的情况充分说明了喜欢程度的变动性极大。只需过个半年,再回过头来看曾经极其准确的几百首歌的评分,你会发现又得重新评分了。之前我在自动评分一章说过评分响应速度的问题,本质上也是这点造成的。
后来我意识到前面评分标准的问题,终于想通了:必须要在潜意识里将评分认为是一种主观的行为,评分的唯一标准应该是对某首歌曲的第一直觉。于是对评分标准进行重修,前后经历了两种实践。
第一种实践,给1到5星分别划分标准:1-经常会主动跳过;2-偶尔会主动跳过;3-大部分情况下不会主动跳过;4-偶尔会主动点击播放;5-经常会主动点击播放。
第二种实践,所有歌曲评为3星,在听的时候如果感觉明显高于当前播放列表的平均水平就上调,明显低于当前播放列表平均水平就下调。
其中,第二种实践就是我在没有抛弃歌曲评分之前,找到的较好的实践。不需要浪费太多额外时间评分,准确度也高。但缺点还是有的,主观评分就意味着要动脑,就必然会遇到纠结是否调整评分的时候。
基于评分的智能播放列表的弊端
在还没有抛弃歌曲评分的时候,我会根据评分来建立多个智能播放列表,分别对应自动评分或手动评分高于某一分值的歌曲。这其实没能从本质上解决我前面所说的两个问题:1. 如何让播放率与评价呈现正相关?2. 如何确保不会出现被遗忘的歌曲?
第一个问题还能算有点解决的意思,高评分的歌曲会在更多播放列表中出现,但高评分和低评分歌曲的播放比例不能进行很好的控制。第二个问题就完全解决不了了,因为你总会偏向于播放高评分的列表,最低档的列表几乎不会去碰,到最后曲库中就会出现很多永远也不会被播放,同时又不舍得删的歌曲。
由此可见,进行歌曲评分本身不仅会带来巨大的人力投入,也无法很好地对评分进行简单的应用。我知道foobar2000借助sql插件可以很好地利用上评分,但这已背离简单化的要旨了。
标记及基于标记的智能播放列表
首先要引入歌曲评分的替代品:标记(TAG)。
建立一个符合要求的智能列表,只需要将歌曲分为两类:第一类是希望频繁播放的,第二类是不希望频繁播放的。先把问题简化,建立一个只含第一类歌曲的智能播放列表。
其实第一类歌曲无外乎几种(仅为个人观点,请根据自己需求扩充):1. 最近加入曲库的新歌曲;2. 自己非常喜欢的歌曲;3. 临时选拔的歌曲(本来在第二类中,但播放到的时候觉得可以就手动修改标记,将其临时选拔加入到第一类中,如果以后又播放到觉得不OK就移除标记几其回归到第二类)。
通过AIMP的歌曲标记功能,可以很轻松地给这些歌曲添加对应的标记。我用的是:!new(一段时间后要手动移除标签),!top,!pick。当然标记功能本身远不止这里所说的用法,用来标记纯音乐、语种等都是很好用的。
理论说明已经完成,下面介绍具体的实践方式。其中第一种能实现非常精细的控制,但较为复杂,且设定好后还需定期手动操作,不推荐;第一种需要借助AIMP插件,虽控制力稍显不足且有一点BUG,但自动化程度极高,简单易用,推荐使用。
复杂方式(不推荐)
按下面的设置就能从音乐库建立一个只含第一类歌曲的智能播放列表:

只含第一类歌曲的智能播放列表设置
这个智能播放列表实际上不会用来播放,而是用来确定第一类歌曲的数量。然后再建立一个同时包含两类歌曲,且可以控制两类歌曲比例的智能播放列表:

能调整两类歌曲比例的智能播放列表设置
这个看起来比较复杂的智能播放列表就是我们实际播放的列表。
相较之前的设置,多加了一个关于最后回放的过滤器,时间设为「今天」就行了。需要每隔一段时间(半年左右)要更新一下「今天」的日期,否则第二类歌曲入不敷出。这个过滤器会将「很久没有播放过」的第二类歌曲也包含进来,并且在其播放过一次之后就将其移除出播放列表。
这里的「最大曲目数」用于控制第一类与第二类之间的比例。先观察之前建立的只含第一类歌曲的列表,记录第一类歌曲的数量,再配合这个「最大曲目数」就能达成准确的比例控制。假设第一类歌曲数是100,这里设为160,那么两类歌曲的播放比例就是100:(160-100)=5:3。
此外,还需巧用「排序方式」来设定两类歌曲优先度,所以不能给歌曲添加其他无关的标记,否则会影响智能播放列表的建立。AIMP在这里功能确实不足,如果可以设置多重排序也就没有这种限制了。
最大的缺陷是,在一个更新周期内,第二类歌曲只有一次被播放到的机会。不过既然已经是第二类歌曲了,竞争者这么多没能被加上!pick标记,只能怪自身素质不行了。
简单方式(推荐)
原理本质上跟复杂方式一下,只是利用 Advanced Shuffle (https://www.aimp.ru/?do=catalog&rec_id=388) 插件简化过程,而非靠奇技淫巧来实现以上功能。

Advanced Shuffle
按上图所示,则AIMP会在所有播放列表(除排除列表外)间不重复随机切换,单个列表中的歌曲同样会采用不重复随机方式切换。注意,必须将AIMP的「随机播放」关闭才能生效。
显然,只要分别为第一类歌曲、第二类歌曲各建立一个智能播放列表,那么AIMP就会在这两个列表间跳跃播放,每个列表的播放率各为50%。这个比例显然是失衡的,所以需要采取一点变化:
1. 第一个智能播放列表,包含整个曲库。

整个曲库
2. 第二个智能播放列表,包含第一类歌曲。

第一类歌曲
3. 第三个智能播放列表,包含离最后一次播放时间最久的歌曲。
其实在 AIMP4 及以前的版本,智能播放列表功能还不是很完善,LastPlay 列表的实现还是需要点奇技淫巧的,但 AIMP5 的改动使得 LastPlay 列表的实现变得非常简单。
注意:【选项->播放器->自动化->关于删除播放文件】需要设置为「什么也不做」。视【选项->播放器->音乐库->回放核算】的设置而定,歌曲会在播放到 X% 时被标记为已播放状态,从而被自动移除出 LastPlay 列表,从而触发「关于删除播放文件」的操作。
LastPlay 列表具体设置如下。

如此设置后,以三次播放为一个循环,每个循环必然会包含「曲库中任意一首歌曲」「第一类歌曲之一」「很久没有播放过的歌曲之一」。这一比例肯定不是最好的,但个人用下来感觉已经足够舒服了。当然还可以添加更多播放列表来调整播放比例,但想做到复杂方式那种精细的比例控制还是洗洗睡吧。
这种方式并非没有缺陷,基本上都是 Advanced Shuffle 插件的BUG:
1. 「上一首」失效,点击会跳转到随机歌曲。这一缺陷,建议通过 AIMP History (https://www.aimp.ru/?do=catalog&rec_id=705) 播放历史插件来弥补。
2. 播放较长时间后会出问题(不会报错弹框),只能重启AIMP。不过时间较长,大概一个多星期一次,不是像我这样几个月关一次机的用户应该大概遇不到这个问题。
3. 每次建立播放列表(包括临时列表)后,需要手动设置将其加入排除,或尽快将其关闭,否则会加入到循环中。
如何对歌曲增加、删除、修改的详情进行跟踪?
1. 修改播放器的曲目列表导出设置,将有必要进行跟踪的元数据都列出。可读性不是关键,详细即可,反正diff的时候能认出来元数据分别是什么即可。

曲目列表导出设置
参考配置:
%Title - %FileName Artist[%Artist] AlbumArtist[%IF(%AlbumArtist,%AlbumArtist,%Artist)] Year[%Year] Album[%Album] Track[%TrackNumber] Disk[%DiskNumber] Composer[%Composer] Lyricist[%Lyricist] Publisher[%Publisher] Genre[%Genre] Encode[%E] SampleRate[%SampleRate] BitRate[%Bitrate] Channels[%Channels] Duration[%Duration] Comment[%Comment]
2. 从音乐库建立一个包含所有歌曲的智能播放列表。智能播放列表的排序、分组(后文会对排序及分组的最佳实践作介绍)等固定好之后不好修改,保证以后每次导出按同一规则。
3. 按前面的规则导出从上述智能播放列表导出曲目列表,格式使用Text Document [Unicode]。
4. 在导出文件后,推荐使用以下两种方式之一进行跟踪:
a) 首选方案:使用git对导出文件进行跟踪,以后无论是音乐的增加、删除还是元信息的修改历史都能如指掌。(顺便一提,如果打算直接对音乐文件进行跟踪,强烈建议SVN而不是git)
b) 备选方案:如果你不会使用git,可以导出文件名后跟上日期(如Music-20190401.txt、Music-20201024.txt等),单独建立目录统一保存(可借助网盘备份)。在有需要时使用文本比较工具进行比较即可。
「艺术家」和「专辑艺术家」应该填什么?
很多歌曲都缺失专辑艺术家,甚至很多官方发行的数字版都缺少这项数据。如果这张专辑的艺术家跟其中所有歌曲的艺术家都一样,那倒能理解,这也是最常见的一种情况。所以AIMP在某些情况下(具体是哪些情况很复杂,最好是假装不知道这点来编写宏)读取不到专辑艺术家时,会读取出艺术家。
简而言之,专辑艺术家的核心在于「这张专辑到底是以什么名义发行的」。如果一个音乐文件的元数据里有这项,那基本不会出错。
艺术家则不然,大家对于这个概念的理解千差万别,即使是官方发行的数字版,里面填写的内容也是采取各种不统一的标准。我自己对「艺术家」的定义,在这几年里也发生过数次改变,在此对一些关键点提一下个人目前的看法:
1. 一般:有歌手填歌手,纯音乐填作曲家。(编曲放哪里也是一个很值得探究的问题,这里就不展开了) 2. VOCALOID:作曲 + 虚拟歌姬 3. 古典音乐:作曲 + 演奏 4. 若官方发行版填写的艺术家不符合规则,具体情况具体分析。 a) 官方硬将专辑艺术家填到艺术家处,且有明显不尊重歌手/作曲家的嫌疑,修正之。比如很多游戏或电影的OST。 b) 官方出于某种合理的考虑不按规则填写,尊重之。像某些歌曲中演唱的部分只是一种辅助,艺术家填作曲家无可厚非。 5. 专辑以A的名义发行,其中某首歌曲是B歌唱/作曲。 a) 如果A是一个真正意义上的组合,且B是组合成员,那么艺术家填A。 b) 如果A是一个真正意义上的组合,且B不是组合成员,那么艺术家填B。 c) 如果A是一个「伪组合」,那么无论B是否组合成员,艺术家填B。 d) 如果A与B构成某个组合,艺术家依然填B。
其中, 「伪组合」指的是临时性合作,并且发布时以类似于「A×B」这种形式署名的情况,如「T.M.Revolution×水樹奈々」、「水樹奈々×T.M.Revolution」这种。
而「组合」在本文中是个很宽泛的概念,比如后文将会提到的「Symholic」,早期成员严格来说只有Paspal一人,而且本身发行专辑的形式也与传统意义上的音乐团体有着很大不同,虽然会造成一点分析上的麻烦,但不妨碍我们对此问题的讨论。事实上正是因为这种麻烦更能说明问题,才挑选其作为典型例子
好像很绕的样子,下面以叶月相关的几首歌为例,看一下艺术家该怎么填(应该包括最复杂的几种情况了)。后面格式表示的意思是「[专辑艺术家] 艺术家 :: 标题」。
1. [清風明月] 清風明月 :: 宵闇花火 instrumental 所在专辑以「清風明月」名义发布,作为伴奏(纯音)其作曲是组合成员「Drop」,因此艺术家填「清風明月」。 2. [Symholic] 葉月ゆら :: 鮮血の斉唱 所在专辑以「Symholic」名义发布,歌手「葉月ゆら」并非组合成员,因此艺术家填「葉月ゆら」。 3. [葉月ゆら×藤田真梨] 葉月ゆら :: 魔女の卵 所在专辑以「葉月ゆら×藤田真梨」名义发布,但这是一个伪组合,因此艺术家填歌手「葉月ゆら」。 4. [葉月ゆら] Drop :: Veritas 所在专辑以「葉月ゆら」名义发布,作为纯音其作曲是「Drop」。尽管「清風明月≈葉月ゆら+Drop」,但艺术家依然填「Drop」。
但这仍未彻底解决问题,在「B是A组合的成员」这点上依然会横生枝节。
还是以Symholic为例,这是本来是一个以Paspal为核心的「组合」,大概在2018年狛茉璃奈以Lalue的名义加入Symholic。
1. 我们假设Paspal与Lalue的地位不对等,有绝对的主次之分。在这种情况下应该将Lalue作为组合成员,还是将其作为Symholic的合作者?我的答案是依然作为组合成员。(这里假设是为了保证例子的统一,其实用Beyond作为例子更好)
[Symholic] Symholic :: Angelology 所在专辑以「Symholic」名义发布,歌手「Lalue」是组合成员,因此艺术家填「Symholic」。
2. 在狛茉璃奈加入Symholic之前与之合作的歌曲中,应该将其视作合作者。
[Symholic] 小松菜 :: 風に乗せた逃飛行 所在专辑以「Symholic」名义发布,歌手「小松菜」其实就是狛茉璃奈(也就是「Lalue」),但她在当时还不是组合成员,因此艺术家填「小松菜」。 重点: a) Lalue只是狛茉璃奈在作为Symholic成员时的名义,既然作为非组合成员当然是使用自身的名义「小松菜」。 b) 狛茉璃奈在现在已经不再使用「小松菜」这个名字了,但艺术家依然填当时的旧名,遵循「从旧原则」。
3. 在Symholic与其他歌手合作的歌曲中,存在多名演唱者,其中狛茉璃奈在艺术家中应该以「Symholic」的名义存在。如果其他演唱者属于另外的组合,那艺术家的填写要根据该专辑是与该歌手本人的合作还是与其组合的合作来定。
[Symholic] 葉月ゆら×Symholic :: Maisery a) 所在专辑以「Symholic」名义发布。 b) 歌手之一「狛茉璃奈」是组合成员,艺术家填「Symholic」。 c) 歌手之一「葉月ゆら」是以个人名义参与(与其牵涉的其他组合无关),艺术家填「葉月ゆら」。
存在多个「艺术家」时,应该如何分隔?
大部分音乐格式,对于多个艺术家会使用【;】作为分隔符,唯独MP3使用【/】。其实大部分格式使用【;】是有深刻意义的,参考AIMP社区当年对这个问题的讨论:https://www.aimp.ru/forum/index.php?topic=49623.0。
这种不统一会造成一个问题,如果两首歌都是A和B合作,FLAC格式的艺术家是「A;B」,MP3的格式是「A/B」,在排序和分组时会造成一点影响。总之,在排序之前需要先文本替换,保证分隔符一致再处理。
%Replace(%Artist,/,;)
而对于分组,则还需进一步处理,否则无论显示为「A;B」还是「A/B」都不是很好看。推荐写成「A×B」这种较为常见的形式,当然也可以按个人喜好使用其他分隔符。
%Replace(%Replace(%IF(%AlbumArtist,%AlbumArtist,%Artist),;,×),/,×)
歌曲应该如何分组与排序?
如果对这方面没有要求,使用简单的「艺术家-标题」排序都没问题。但如果要追求完美,这个问题没有想象中那么简单,有些本地播放器甚至内置了这样的错误排序逻辑:「艺术家-年份-DiskNumber-TrackNumber」——看似正确反而是最大的错误。
正确而合理的逻辑只有两种:「专辑艺术家-年份-DiskNumber-TrackNumber」或「年份-专辑艺术家-DiskNumber-TrackNumber」。原因是什么,经过前面「专辑艺术家」和「艺术家」的讨论后,应该不需要再解释了。
但实践中问题不止于此,很多歌曲的元信息里不会填专辑艺术家。如果是这种情况,而艺术家又有多个人,就又要考虑之前所说的多艺术家问题了。
总之,直接给参考配置吧。逻辑是,如果有专辑艺术家就用专辑艺术家参加一级排序,否则使用艺术家代替。但无论如何,都要对潜在的艺术家分隔符进行统一处理;尤其是分组涉及到最终界面上的显示,建议全替换为「×」保证风格的统一。
排序: <Album> %Replace(%IF(%AlbumArtist,%AlbumArtist,%Artist),/,;) - %Year - %Album - %DiskNumber - %TrackNumber 分组: %Replace(%Replace(%IF(%AlbumArtist,%AlbumArtist,%Artist),;,×),/,×)
这里面%Replace的嵌套方式是有讲究的,跟AIMP关于专辑艺术家的机制(其实算BUG)有关,也必须要将「自动合并相似类别」勾选上,否则会出现一些小问题。



顺便再分享一下我自己在AIMP上的一些UI设置,也是为了方便以后换电脑之后的重新设置。
信息条:
第一行: %IF(%AlbumArtist,%IFEqual(%AlbumArtist,%Replace(%Replace(%R,;,×),/,×),,[%AlbumArtist] ),)%Replace(%Replace(%R,;,×),/,×) :: %T%IFEqual(%Title,%FileName,, (%FileName)) 第二行: [%E] <%H, %B, %C, %S>%IF(%Album, | %Album%IF(%TrackNumber, %IF(%DiskNumber,%DiskNumber,)#%TrackNumber,),)%IF(%Year, @ %Year,)

列表外观:
第一行: %Title%IFEqual(%Title,%FileName,, (%FileName)) 第二行: %IF(%TrackNumber,%TrackNumber. ,)%Replace(%Replace(%R,;,×),/,×)%IF(%Album, [%Album],)%IF(%Year, <%Year>,)

静态标签模板:
第一行: %T%IFEqual(%Title,%FileName,, (%FileName)) 第二行: %Replace(%Replace(%Artist,;,×),/,×) %IFEqual(%Composer,%Lyricist,%IF(%Composer, [M · L] %Composer,),%IF(%Composer, [M] %Composer,)%IF(%Lyricist, [L] %Lyricist,)) 第三行: %IF(%TrackNumber,%IF(%DiskNumber,%DiskNumber-,)%TrackNumber. ,)%Replace(%Replace(%IF(%AlbumArtist,%AlbumArtist,%R) ,;,×),/,×)%IF(%Album,[%Album] ,)%IF(%Year,<%Year>,) 第四行: %Replace(%Replace(%R ,;,×),/,×)%IF(%Album,[%Album] ,)%IF(%Year,<%Year>,) 第五行: %E, %H, %B, %C, %S

如何高效地检索外文歌曲?
主要是针对小语种、特别是有特殊字母的歌曲。只需将文件名一律改成中文译名,并调整播放列表的显示设置(采用我前面给出的列表格式就行了),让播放列表的界面显示中显示出文件名,便可使用其译名进行检索。
当然大部分歌曲是没有公认的中文译名的,配合DeepL自行发挥呗。