Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 69 additions & 96 deletions src/libdmusic/core/audioanalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()) {
Expand Down Expand Up @@ -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<TagLib::ID3v2::SynchronizedLyricsFrame *>(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<TagLib::ID3v2::UnsynchronizedLyricsFrame *>(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<TagLib::ID3v2::SynchronizedLyricsFrame *>(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<TagLib::ID3v2::UnsynchronizedLyricsFrame *>(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()
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions src/libdmusic/core/datamanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@

#include "datamanager.h"

#include <QFileInfo>

Check warning on line 8 in src/libdmusic/core/datamanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QFileInfo> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QDir>

Check warning on line 9 in src/libdmusic/core/datamanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QDir> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QDirIterator>

Check warning on line 10 in src/libdmusic/core/datamanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QDirIterator> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QDateTime>

Check warning on line 11 in src/libdmusic/core/datamanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QDateTime> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QStandardPaths>

Check warning on line 12 in src/libdmusic/core/datamanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QStandardPaths> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QThread>
#include <QUuid>
#include <QSqlDatabase>
Expand Down Expand Up @@ -2888,6 +2889,7 @@
"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);
Expand Down
11 changes: 1 addition & 10 deletions src/libdmusic/core/musicsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions src/libdmusic/global.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion src/libdmusic/player/vlcplayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
Expand Down
21 changes: 19 additions & 2 deletions src/libdmusic/presenter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Loading