本文最后更新于 2022-01-30 12:27:09
前言
一个月黑风高的晚上,结束了一天的紧张工作(摸鱼)后打算在睡前听一会网抑云音乐。刚要打开播放器的时候突然想到之前看到的深度音乐的截图,决定试用一下。
将下载好的音乐导入深度音乐后点击播放,兴冲冲的打开歌词显示,大大的“没有找到歌词”映入眼帘
不对呀,我记得我下载歌曲的时候明明勾选了嵌入歌词的。掏出祖传的 ffprobe
查看了一下,发现确实是有歌词的。看来是深度音乐不支持了。与其慢慢等官方实现,不如自己动手、丰衣足食。
思路
既然知道歌词已经写到歌曲中了。就先看看写到了歌曲的什么位置,打开 洛雪音乐助手 的源码,全局搜索 lyrics
,找到如下代码:
1 2 3 4 5 6 7 8 9 10 11 12
|
const handleWriteMeta = (meta, filePath) => { if (meta.lyrics) { meta.unsynchronisedLyrics = { language: 'zho', text: meta.lyrics, } delete meta.lyrics } NodeID3.write(meta, filePath) }
|
根据代码我们可以知道歌词被写入到 ID3 标签中的 unsynchronisedLyrics
中。Google 了一下,发现这个是 ID3v2 标准专门用来存储文本歌词的,而洛雪音乐助手写入的是 lrc 格式的歌词,所以我们只需要读取这个属性中内容,直接提供给深度音乐显示就可以了。
开发
歌词的提取我们可以参考深度音乐对歌曲封面图的处理方法:添加歌曲后开始读取歌词,读取到歌词后,写入缓存文件夹里的 lyrics 文件夹。播放时先使用原来的逻辑获取歌曲同目录下同名歌词文件,如果没找到就去缓存文件夹里 lyrics 文件夹中查找歌词文件,如果还没找到再显示“没有找到歌词”。
核心代码如下,代码参考了 Stack Overflow 的一个回答 和 TagLib 文档
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
|
#include <taglib/mpegfile.h> #include <taglib/id3v2tag.h> #include <taglib/id3v2frame.h> #include <taglib/unsynchronizedlyricsframe.h>
void MetaDetector::getLyricData(const QString &path, const QString &tmpPath, const QString &hash) { QString lyricsDirPath = tmpPath + "/lyrics"; QString lyricName = hash + ".lrc"; QDir lyricsDir(lyricsDirPath); if (!lyricsDir.exists()) { bool isExists = lyricsDir.cdUp(); isExists &= lyricsDir.mkdir("lyrics"); isExists &= lyricsDir.cd("lyrics"); }
if (!path.isEmpty() && !tmpPath.isEmpty() && !hash.isEmpty()) { if (!lyricsDir.exists(lyricName)) { QFile lyric(lyricsDirPath + "/" + lyricName);
TagLib::MPEG::File f1(path.toStdString().c_str()); TagLib::ID3v2::FrameList frames = f1.ID3v2Tag()->frameListMap()["USLT"]; if (!frames.isEmpty()) { TagLib::ID3v2::UnsynchronizedLyricsFrame *frame = dynamic_cast<TagLib::ID3v2::UnsynchronizedLyricsFrame *>(frames.front()); if (frame) { if (lyric.open(QIODevice::WriteOnly)) { QString str = TStringToQString(frame->text()); lyric.write(str.toUtf8()); } lyric.close(); } } } }
return; }
|
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
|
void MusicLyricWidget::onMusicPlayed(MediaMeta meta) { Q_UNUSED(meta) QFileInfo fileInfo(Player::getInstance()->getActiveMeta().localPath); QString lrcPath = fileInfo.dir().path() + QDir::separator() + fileInfo.completeBaseName() + ".lrc"; QFile file(lrcPath); if (!file.exists()) { MediaMeta meta = Player::getInstance()->getActiveMeta(); QFileInfo lyricInfo(Global::cacheDir() + "/lyrics/" + meta.hash + ".lrc"); if (!lyricInfo.exists()) { m_nolyric->show(); m_lyricview->hide(); } else { m_nolyric->hide(); m_lyricview->show(); m_lyricview->getFromFile(lyricInfo.filePath()); } } else { m_nolyric->hide(); m_lyricview->show(); m_lyricview->getFromFile(lrcPath); } }
|
完整代码见:https://github.com/linuxdeepin/deepin-music/pull/111/
后记
本次修改只实现了对 ID3v2 标签中非同步歌词的读取。至于另一种同步歌词,手头上没有测试文件,就暂时搁置,以后有时间再来实现。
参考