From dfb307f43686879b08f435ed4a1bb3385093f423 Mon Sep 17 00:00:00 2001 From: Cloud Date: Sat, 1 Aug 2026 22:54:53 +0800 Subject: [PATCH] fix: ensure directories exist before use and update cover metadata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Pre-create config/cache/database directories using QDir::mkpath() to fix build on MSYS2 where directories may not exist yet - Simplify directory creation logic in MusicSettings - Emit metaChanged signal when cover is ready for current playing media - Fetch latest cover/lyric metadata from database in getActivateMeta() fix: 确保目录在使用前已创建,并修复封面元数据更新 - 使用 QDir::mkpath() 预创建配置/缓存/数据库目录, 修复 MSYS2 构建时目录不存在的问题 - 简化 MusicSettings 中的目录创建逻辑 - 当前播放歌曲的封面就绪时发送 metaChanged 信号 - 在 getActivateMeta() 中从数据库获取最新的封面和歌词路径 --- src/libdmusic/core/audioanalysis.cpp | 165 +++++++++++---------------- src/libdmusic/core/datamanager.cpp | 2 + src/libdmusic/core/musicsettings.cpp | 11 +- src/libdmusic/global.cpp | 2 + src/libdmusic/player/vlcplayer.cpp | 2 +- src/libdmusic/presenter.cpp | 21 +++- 6 files changed, 94 insertions(+), 109 deletions(-) diff --git a/src/libdmusic/core/audioanalysis.cpp b/src/libdmusic/core/audioanalysis.cpp index 0e11940f0..0dd020b2c 100644 --- a/src/libdmusic/core/audioanalysis.cpp +++ b/src/libdmusic/core/audioanalysis.cpp @@ -188,7 +188,7 @@ bool AudioAnalysis::parseFileTagCodec(DMusic::MediaMeta &meta) QString detectCodec; auto mediaPath = QStringToTString(meta.localPath); #ifdef _WIN32 - TagLib::FileRef f(meta->localPath.toStdWString().c_str()); + TagLib::FileRef f(meta.localPath.toStdWString().c_str()); #else TagLib::FileRef f(meta.localPath.toStdString().c_str()); #endif @@ -451,16 +451,8 @@ void AudioAnalysis::parseMetaCover(DMusic::MediaMeta &meta) QString path = meta.localPath; QString imagesDirPath = tmpPath + "/images"; QString imageName = hash + ".jpg"; + QDir().mkpath(imagesDirPath); QDir imageDir(imagesDirPath); - if (!imageDir.exists()) { - qCDebug(dmMusic) << "Creating images directory:" << imagesDirPath; - bool isExists = imageDir.cdUp(); - isExists &= imageDir.mkdir("images"); - isExists &= imageDir.cd("images"); - if (!isExists) { - qCWarning(dmMusic) << "Failed to create images directory:" << imagesDirPath; - } - } QByteArray byteArray; if (!tmpPath.isEmpty() && !hash.isEmpty()) { @@ -661,96 +653,87 @@ QImage AudioAnalysis::getMetaCoverImage(DMusic::MediaMeta meta) void AudioAnalysis::parseMetaLyrics(DMusic::MediaMeta &meta) { qCDebug(dmMusic) << "Parsing lyrics for file:" << meta.localPath << "hash:" << meta.hash; + QString tmpPath = DmGlobal::cachePath(); QString hash = meta.hash; QString path = meta.localPath; - QString lyricDirPath = QDir::cleanPath(tmpPath + QDir::separator() + "lyrics"); + + // --- 目录准备 --- + QString lyricDirPath = tmpPath + "/lyrics"; QString lyricName = hash + ".lrc"; - const QString lyricRootPath = QFileInfo(lyricDirPath).absoluteFilePath(); - const QString lyricFilePath = QFileInfo(QDir::cleanPath(lyricRootPath + QDir::separator() + lyricName)).absoluteFilePath(); - const QString lyricRootPrefix = lyricRootPath.endsWith(QDir::separator()) ? lyricRootPath : lyricRootPath + QDir::separator(); - if (!lyricFilePath.startsWith(lyricRootPrefix)) { - qCWarning(dmMusic) << "Rejected unsafe lyrics path:" << lyricFilePath - << "root:" << lyricRootPath - << "hash:" << hash; + QString lyricPath = lyricDirPath + "/" + lyricName; + QDir().mkpath(lyricDirPath); + QDir lyricDir(lyricDirPath); + + // 歌词文件已存在,直接使用缓存 + if (lyricDir.exists(lyricName)) { + qCDebug(dmMusic) << "Lyrics file already exists, skipping parsing:" << lyricName; + meta.lyricPath = lyricPath; return; } - QDir lyricDir(lyricRootPath); - if (!lyricDir.exists()) { - qCDebug(dmMusic) << "Creating lyrics directory:" << lyricRootPath; - if (!QDir().mkpath(lyricRootPath)) { - qCWarning(dmMusic) << "Failed to create lyrics directory:" << lyricRootPath; - return; - } + if (path.isEmpty()) { + qCWarning(dmMusic) << "Path is empty, cannot parse lyrics for:" << hash; + return; } - if (!tmpPath.isEmpty() && !hash.isEmpty()) { - // 歌词文件存在,停止解析 - if (lyricDir.exists(lyricName)) { - qCDebug(dmMusic) << "Lyrics file already exists, skipping parsing:" << lyricName; - meta.lyricPath = lyricFilePath; // backfill for DB/persistence - return; - } - - if (!path.isEmpty()) { - QFile lyric(lyricFilePath); - TagLib::MPEG::File f(path.toStdString().c_str()); - QString lyricStr = ""; - - // 检查音乐文件 - if (f.isValid()) { - // 音乐文件不一定存在ID3v2Tag - if (f.ID3v2Tag() != nullptr) { - // 先获取同步歌词 - TagLib::ID3v2::FrameList syltFrames = f.ID3v2Tag()->frameListMap()["SYLT"]; - if (!syltFrames.isEmpty()) { - qCDebug(dmMusic) << "Found synchronized lyrics in file:" << path; - TagLib::ID3v2::SynchronizedLyricsFrame *frame = dynamic_cast(syltFrames.front()); - if (frame) { - TagLib::ID3v2::SynchronizedLyricsFrame::SynchedTextList synchedTextList = frame->synchedText(); - for (unsigned int i = 0; i < synchedTextList.size(); i++){ - QString time = QDateTime::fromMSecsSinceEpoch(synchedTextList[i].time).toString("mm:ss.zzz"); - QString text = TStringToQString(synchedTextList[i].text).trimmed(); - lyricStr.append(QString("[%1]%2\n").arg(time).arg(text)); - } - } - } + // --- 单次 TagLib 打开,提取歌词 --- + QFile lyric(lyricPath); + TagLib::MPEG::File f(path.toStdString().c_str()); + QString lyricStr; - // 没获取到歌词,获取非同步歌词 - if (lyricStr.isEmpty()) { - TagLib::ID3v2::FrameList usltFrames = f.ID3v2Tag()->frameListMap()["USLT"]; - if (!usltFrames.isEmpty()) { - qCDebug(dmMusic) << "Found unsynchronized lyrics in file:" << path; - TagLib::ID3v2::UnsynchronizedLyricsFrame *frame = dynamic_cast(usltFrames.front()); - if (frame) { - lyricStr = TStringToQString(frame->text()); - } - } - } + if (!f.isValid()) { + qCWarning(dmMusic) << "Invalid MPEG file for lyrics extraction:" << path; + return; + } - if (!lyricStr.isEmpty()) { - if (lyric.open(QIODevice::WriteOnly)) { - lyric.write(lyricStr.toUtf8()); - meta.lyricPath = lyricFilePath; // backfill for DB/persistence - qCInfo(dmMusic) << "Successfully extracted and saved lyrics for file:" << path; - } else { - qCWarning(dmMusic) << "Failed to open lyrics file for writing:" << lyricName; - } - lyric.close(); - } else { - qCDebug(dmMusic) << "No lyrics found in file:" << path; - } - } else { - qCDebug(dmMusic) << "No ID3v2 tag found for lyrics extraction:" << path; + if (f.ID3v2Tag() != nullptr) { + // 先尝试同步歌词 + TagLib::ID3v2::FrameList syltFrames = f.ID3v2Tag()->frameListMap()["SYLT"]; + if (!syltFrames.isEmpty()) { + qCDebug(dmMusic) << "Found synchronized lyrics in file:" << path; + TagLib::ID3v2::SynchronizedLyricsFrame *frame = + dynamic_cast(syltFrames.front()); + if (frame) { + TagLib::ID3v2::SynchronizedLyricsFrame::SynchedTextList synchedTextList = frame->synchedText(); + for (unsigned int i = 0; i < synchedTextList.size(); i++) { + QString time = QDateTime::fromMSecsSinceEpoch(synchedTextList[i].time).toString("mm:ss.zzz"); + QString text = TStringToQString(synchedTextList[i].text).trimmed(); + lyricStr.append(QString("[%1]%2\n").arg(time).arg(text)); } + } + } - f.clear(); - } else { - qCWarning(dmMusic) << "Invalid MPEG file for lyrics extraction:" << path; + // 没获取到歌词,获取非同步歌词 + if (lyricStr.isEmpty()) { + TagLib::ID3v2::FrameList usltFrames = f.ID3v2Tag()->frameListMap()["USLT"]; + if (!usltFrames.isEmpty()) { + qCDebug(dmMusic) << "Found unsynchronized lyrics in file:" << path; + TagLib::ID3v2::UnsynchronizedLyricsFrame *frame = + dynamic_cast(usltFrames.front()); + if (frame) { + lyricStr = TStringToQString(frame->text()); + } } } + } else { + qCDebug(dmMusic) << "No ID3v2 tag found for lyrics extraction:" << path; } + + if (!lyricStr.isEmpty()) { + if (lyric.open(QIODevice::WriteOnly)) { + lyric.write(lyricStr.toUtf8()); + meta.lyricPath = lyricPath; + qCInfo(dmMusic) << "Successfully extracted and saved lyrics for file:" << path; + } else { + qCWarning(dmMusic) << "Failed to open lyrics file for writing:" << lyricName; + } + lyric.close(); + } else { + qCDebug(dmMusic) << "No lyrics found in file:" << path; + } + + f.clear(); } void AudioAnalysis::startRecorder() @@ -854,24 +837,14 @@ void AudioAnalysis::parseMetaCoverAndLyrics(DMusic::MediaMeta &meta) QString imagesDirPath = tmpPath + "/images"; QString imageName = hash + ".jpg"; QString coverPath = imagesDirPath + "/" + imageName; + QDir().mkpath(imagesDirPath); QDir imageDir(imagesDirPath); - if (!imageDir.exists()) { - bool ok = imageDir.cdUp() && imageDir.mkdir("images") && imageDir.cd("images"); - if (!ok) { - qCWarning(dmMusic) << "Failed to create images directory:" << imagesDirPath; - } - } QString lyricDirPath = tmpPath + "/lyrics"; QString lyricName = hash + ".lrc"; QString lyricPath = lyricDirPath + "/" + lyricName; + QDir().mkpath(lyricDirPath); QDir lyricDir(lyricDirPath); - if (!lyricDir.exists()) { - bool ok = lyricDir.cdUp() && lyricDir.mkdir("lyrics") && lyricDir.cd("lyrics"); - if (!ok) { - qCWarning(dmMusic) << "Failed to create lyrics directory:" << lyricDirPath; - } - } bool coverCached = QFile::exists(coverPath); bool lyricsCached = QFile::exists(lyricPath); diff --git a/src/libdmusic/core/datamanager.cpp b/src/libdmusic/core/datamanager.cpp index 7c29330f3..59d40e9c3 100644 --- a/src/libdmusic/core/datamanager.cpp +++ b/src/libdmusic/core/datamanager.cpp @@ -6,6 +6,7 @@ #include "datamanager.h" #include +#include #include #include #include @@ -2888,6 +2889,7 @@ void DataManager::initPlaylist() "rejected to prevent path traversal, falling back to default."; dbPath = DmGlobal::cachePath() + "/mediameta.sqlite"; } + QDir().mkpath(QFileInfo(dbPath).absolutePath()); qCDebug(dmMusic) << "Opening database at:" << dbPath; m_data->m_database = QSqlDatabase::addDatabase("QSQLITE"); m_data->m_database.setDatabaseName(dbPath); diff --git a/src/libdmusic/core/musicsettings.cpp b/src/libdmusic/core/musicsettings.cpp index 4a27df037..d5fbbdb47 100644 --- a/src/libdmusic/core/musicsettings.cpp +++ b/src/libdmusic/core/musicsettings.cpp @@ -58,16 +58,7 @@ void MusicSettings::ensureDefaultCover() { auto coverPath = DmGlobal::cachePath() + "/images/default_cover.png"; if (!QFile::exists(coverPath)) { - QDir imageDir(DmGlobal::cachePath() + "/images"); - if (!imageDir.exists()) { - qCDebug(dmMusic) << "Creating images directory"; - bool isExists = imageDir.cdUp(); - isExists &= imageDir.mkdir("images"); - isExists &= imageDir.cd("images"); - if (!isExists) { - qCWarning(dmMusic) << "Failed to create images directory"; - } - } + QDir().mkpath(DmGlobal::cachePath() + "/images"); qCDebug(dmMusic) << "Creating default cover image"; QImage defaultImg(":/data/default_cover.png"); defaultImg = defaultImg.scaled(430, 430, Qt::KeepAspectRatio, Qt::SmoothTransformation); diff --git a/src/libdmusic/global.cpp b/src/libdmusic/global.cpp index 6a9c32a80..ad515b331 100644 --- a/src/libdmusic/global.cpp +++ b/src/libdmusic/global.cpp @@ -50,6 +50,8 @@ void DmGlobal::initPath() userConfigPath = DStandardPaths::writableLocation(QStandardPaths::AppConfigLocation); userCachePath = DStandardPaths::writableLocation(QStandardPaths::CacheLocation); userMusicPath = DStandardPaths::writableLocation(QStandardPaths::MusicLocation); + QDir().mkpath(userConfigPath); + QDir().mkpath(userCachePath); qCDebug(dmMusic) << "Paths initialized - config:" << userConfigPath << "cache:" << userCachePath << "music:" << userMusicPath; } diff --git a/src/libdmusic/player/vlcplayer.cpp b/src/libdmusic/player/vlcplayer.cpp index 4d8f160b8..835713c65 100644 --- a/src/libdmusic/player/vlcplayer.cpp +++ b/src/libdmusic/player/vlcplayer.cpp @@ -89,7 +89,7 @@ void VlcPlayer::init() qCDebug(dmMusic) << "Current track playback ended"; emit end(); }); - connect(m_qvplayer, &SdlPlayer::audioDataReady, this, &PlayerBase::audioDataReady); + //connect(m_qvplayer, &SdlPlayer::audioDataReady, this, &PlayerBase::audioDataReady); initCdaThread(); } } diff --git a/src/libdmusic/presenter.cpp b/src/libdmusic/presenter.cpp index 381ff3bdc..3ac29194d 100644 --- a/src/libdmusic/presenter.cpp +++ b/src/libdmusic/presenter.cpp @@ -348,13 +348,30 @@ void Presenter::setActivateMeta(const QString &metaHash) QImage Presenter::getActivateMetImage() { qCDebug(dmMusic) << "Getting active media cover image"; - return AudioAnalysis::getMetaCoverImage(m_data->m_playerEngine->getMediaMeta()); + DMusic::MediaMeta meta = m_data->m_playerEngine->getMediaMeta(); + if (!meta.hash.isEmpty()) { + DMusic::MediaMeta latestMeta = m_data->m_dataManager->metaFromHash(meta.hash); + if (!latestMeta.hash.isEmpty()) { + meta.hasimage = latestMeta.hasimage; + meta.coverUrl = latestMeta.coverUrl; + } + } + return AudioAnalysis::getMetaCoverImage(meta); } QVariantMap Presenter::getActivateMeta() { qCDebug(dmMusic) << "Getting active media meta"; - return Utils::metaToVariantMap(m_data->m_playerEngine->getMediaMeta()); + DMusic::MediaMeta meta = m_data->m_playerEngine->getMediaMeta(); + if (!meta.hash.isEmpty()) { + DMusic::MediaMeta latestMeta = m_data->m_dataManager->metaFromHash(meta.hash); + if (!latestMeta.hash.isEmpty()) { + meta.coverUrl = latestMeta.coverUrl; + meta.hasimage = latestMeta.hasimage; + meta.lyricPath = latestMeta.lyricPath; + } + } + return Utils::metaToVariantMap(meta); } QVariant Presenter::getPlaybackStatus()