tagreader: Relocate artist/album/title guessing code
Move the code that attempts to fill missing song metadata out of the tagreader worker. In the main process, it will be controllable using settings and calling context. The methods were moved into a new SongPathParser class that checks new settings to determine if action should be taken.
This commit is contained in:
parent
75de59703c
commit
1309c76bec
@ -126,67 +126,8 @@ namespace {
|
||||
const char* kMP4_OriginalYear_ID = "----:com.apple.iTunes:ORIGINAL YEAR";
|
||||
const char* kASF_OriginalDate_ID = "WM/OriginalReleaseTime";
|
||||
const char* kASF_OriginalYear_ID = "WM/OriginalReleaseYear";
|
||||
|
||||
// Helpers for GuessArtistAndTitle()
|
||||
QString WithoutExtension(const QString& s) {
|
||||
if (s.isEmpty()) return s;
|
||||
const int i = s.lastIndexOf('.');
|
||||
if (i < 0) return s;
|
||||
return s.left(i);
|
||||
}
|
||||
|
||||
QString ReplaceUnderscoresWithSpaces(const QString& s) {
|
||||
QString ret(s);
|
||||
ret.replace('_', ' ');
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void TagReader::GuessArtistAndTitle(cpb::tagreader::SongMetadata* song) const {
|
||||
QString artist = QString::fromStdString(song->artist());
|
||||
QString title = QString::fromStdString(song->title());
|
||||
const QString bn = QString::fromStdString(song->basefilename());
|
||||
if (!artist.isEmpty() || !title.isEmpty()) return;
|
||||
if (bn.isEmpty()) return;
|
||||
|
||||
QRegExp rx("^(.*)[\\s_]\\-[\\s_](.*)\\.\\w*$");
|
||||
if (rx.indexIn(bn) >= 0) {
|
||||
artist = rx.cap(1);
|
||||
title = rx.cap(2);
|
||||
} else {
|
||||
title = WithoutExtension(bn);
|
||||
}
|
||||
|
||||
artist = ReplaceUnderscoresWithSpaces(artist);
|
||||
title = ReplaceUnderscoresWithSpaces(title);
|
||||
artist = artist.trimmed();
|
||||
title = title.trimmed();
|
||||
if (!artist.isEmpty()) {
|
||||
song->set_artist(artist.toUtf8().data());
|
||||
}
|
||||
if (!title.isEmpty()) {
|
||||
song->set_title(title.toUtf8().data());
|
||||
}
|
||||
}
|
||||
|
||||
void TagReader::GuessAlbum(const QFileInfo& info,
|
||||
cpb::tagreader::SongMetadata* song) const {
|
||||
QString album = QString::fromStdString(song->album());
|
||||
if (!album.isEmpty()) return;
|
||||
const QString str_dir = info.absoluteDir().absolutePath();
|
||||
if (str_dir.isEmpty()) return;
|
||||
const QFileInfo dir(str_dir);
|
||||
const QString dir_bn = dir.baseName();
|
||||
if (dir_bn.isEmpty()) return;
|
||||
album = ReplaceUnderscoresWithSpaces(dir_bn);
|
||||
album = album.trimmed();
|
||||
if (album.isEmpty()) return;
|
||||
const QString al = album.toLower();
|
||||
if (al == "various" || al == "downloads" || al == "music") return;
|
||||
song->set_album(album.toUtf8().data());
|
||||
}
|
||||
|
||||
TagReader::TagReader()
|
||||
: factory_(new TagLibFileRefFactory), kEmbeddedCover("(embedded)") {}
|
||||
|
||||
@ -233,8 +174,6 @@ void TagReader::ReadFile(const QString& filename,
|
||||
|
||||
// Try fallback -- GME filetypes
|
||||
GME::ReadFile(info, song);
|
||||
GuessArtistAndTitle(song);
|
||||
GuessAlbum(info, song);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -248,8 +187,6 @@ void TagReader::ReadFile(const QString& filename,
|
||||
song->set_track(tag->track());
|
||||
song->set_valid(true);
|
||||
}
|
||||
GuessArtistAndTitle(song);
|
||||
GuessAlbum(info, song);
|
||||
|
||||
QString disc;
|
||||
QString compilation;
|
||||
|
@ -98,6 +98,7 @@ set(SOURCES
|
||||
core/signalchecker.cpp
|
||||
core/song.cpp
|
||||
core/songloader.cpp
|
||||
core/songpathparser.cpp
|
||||
core/stylesheetloader.cpp
|
||||
core/tagreaderclient.cpp
|
||||
core/taskmanager.cpp
|
||||
|
105
src/core/songpathparser.cpp
Normal file
105
src/core/songpathparser.cpp
Normal file
@ -0,0 +1,105 @@
|
||||
/* This file is part of Clementine.
|
||||
Copyright 2021, Jim Broadus <jbroadus@gmail.com>
|
||||
|
||||
Clementine is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Clementine is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "songpathparser.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QSettings>
|
||||
|
||||
#include "core/logging.h"
|
||||
#include "song.h"
|
||||
|
||||
const char* SongPathParser::kSongMetadataSettingsGroup = "SongMetadata";
|
||||
const char* SongPathParser::kGuessMetadataSetting = "guess_metadata";
|
||||
const bool SongPathParser::kGuessMetadataSettingDefault = true;
|
||||
|
||||
SongPathParser::SongPathParser() : guess_metadata_(true) { ReloadSettings(); }
|
||||
|
||||
void SongPathParser::ReloadSettings() {
|
||||
QSettings s;
|
||||
s.beginGroup(kSongMetadataSettingsGroup);
|
||||
guess_metadata_ =
|
||||
s.value(kGuessMetadataSetting, kGuessMetadataSettingDefault).toBool();
|
||||
}
|
||||
|
||||
// Helpers for GuessArtistAndTitle()
|
||||
static QString WithoutExtension(const QString& s) {
|
||||
if (s.isEmpty()) return s;
|
||||
const int i = s.lastIndexOf('.');
|
||||
if (i < 0) return s;
|
||||
return s.left(i);
|
||||
}
|
||||
|
||||
static QString ReplaceUnderscoresWithSpaces(const QString& s) {
|
||||
QString ret(s);
|
||||
ret.replace('_', ' ');
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SongPathParser::GuessArtistAndTitle(Song* song) {
|
||||
qLog(Debug) << "Guess artist and title";
|
||||
QString artist = song->artist();
|
||||
QString title = song->title();
|
||||
const QString bn = song->basefilename();
|
||||
if (!artist.isEmpty() || !title.isEmpty()) return;
|
||||
if (bn.isEmpty()) return;
|
||||
|
||||
QRegExp rx("^(.*)[\\s_]\\-[\\s_](.*)\\.\\w*$");
|
||||
if (rx.indexIn(bn) >= 0) {
|
||||
artist = rx.cap(1);
|
||||
title = rx.cap(2);
|
||||
} else {
|
||||
title = WithoutExtension(bn);
|
||||
}
|
||||
|
||||
artist = ReplaceUnderscoresWithSpaces(artist);
|
||||
title = ReplaceUnderscoresWithSpaces(title);
|
||||
artist = artist.trimmed();
|
||||
title = title.trimmed();
|
||||
if (!artist.isEmpty()) {
|
||||
song->set_artist(artist);
|
||||
}
|
||||
if (!title.isEmpty()) {
|
||||
song->set_title(title);
|
||||
}
|
||||
}
|
||||
|
||||
void SongPathParser::GuessAlbum(const QString& path, Song* song) {
|
||||
qLog(Debug) << "Guess album";
|
||||
QFileInfo info(path);
|
||||
QString album = song->album();
|
||||
if (!album.isEmpty()) return;
|
||||
const QString str_dir = info.absoluteDir().absolutePath();
|
||||
if (str_dir.isEmpty()) return;
|
||||
const QFileInfo dir(str_dir);
|
||||
const QString dir_bn = dir.baseName();
|
||||
if (dir_bn.isEmpty()) return;
|
||||
album = ReplaceUnderscoresWithSpaces(dir_bn);
|
||||
album = album.trimmed();
|
||||
if (album.isEmpty()) return;
|
||||
const QString al = album.toLower();
|
||||
if (al == "various" || al == "downloads" || al == "music") return;
|
||||
song->set_album(album);
|
||||
}
|
||||
|
||||
void SongPathParser::GuessMissingFields(Song* song, QString path) {
|
||||
if (guess_metadata_) {
|
||||
GuessArtistAndTitle(song);
|
||||
GuessAlbum(path, song);
|
||||
}
|
||||
}
|
43
src/core/songpathparser.h
Normal file
43
src/core/songpathparser.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* This file is part of Clementine.
|
||||
Copyright 2021, Jim Broadus <jbroadus@gmail.com>
|
||||
|
||||
Clementine is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Clementine is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CORE_SONGPATHPARSER_H_
|
||||
#define CORE_SONGPATHPARSER_H_
|
||||
|
||||
#include <QString>
|
||||
|
||||
class Song;
|
||||
|
||||
class SongPathParser {
|
||||
public:
|
||||
SongPathParser();
|
||||
|
||||
static const char* kSongMetadataSettingsGroup;
|
||||
static const char* kGuessMetadataSetting;
|
||||
static const bool kGuessMetadataSettingDefault;
|
||||
|
||||
void GuessMissingFields(Song* song, QString path);
|
||||
void ReloadSettings();
|
||||
|
||||
private:
|
||||
void GuessArtistAndTitle(Song* song);
|
||||
void GuessAlbum(const QString& path, Song* song);
|
||||
|
||||
bool guess_metadata_;
|
||||
};
|
||||
|
||||
#endif // CORE_SONGPATHPARSER_H_
|
@ -21,19 +21,24 @@
|
||||
#include "tagreaderclient.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QProcess>
|
||||
#include <QTcpServer>
|
||||
#include <QThread>
|
||||
#include <QUrl>
|
||||
|
||||
#include "player.h"
|
||||
#include "songpathparser.h"
|
||||
|
||||
const char* TagReaderClient::kWorkerExecutableName = "clementine-tagreader";
|
||||
TagReaderClient* TagReaderClient::sInstance = nullptr;
|
||||
|
||||
TagReaderClient::TagReaderClient(QObject* parent)
|
||||
: QObject(parent), worker_pool_(new WorkerPool<HandlerType>(this)) {
|
||||
: QObject(parent),
|
||||
worker_pool_(new WorkerPool<HandlerType>(this)),
|
||||
path_parser_(new SongPathParser()) {
|
||||
sInstance = this;
|
||||
setObjectName("Tag reader client");
|
||||
|
||||
@ -49,6 +54,8 @@ TagReaderClient::TagReaderClient(QObject* parent)
|
||||
SLOT(WorkerFailedToStart()));
|
||||
}
|
||||
|
||||
TagReaderClient::~TagReaderClient() {}
|
||||
|
||||
void TagReaderClient::Start() { worker_pool_->Start(); }
|
||||
|
||||
void TagReaderClient::WorkerFailedToStart() {
|
||||
@ -156,6 +163,7 @@ void TagReaderClient::ReadFileBlocking(const QString& filename, Song* song) {
|
||||
TagReaderReply* reply = ReadFile(filename);
|
||||
if (reply->WaitForFinished()) {
|
||||
song->InitFromProtobuf(reply->message().read_file_response().metadata());
|
||||
path_parser_->GuessMissingFields(song, filename);
|
||||
}
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
@ -21,6 +21,8 @@
|
||||
#ifndef CORE_TAGREADERCLIENT_H_
|
||||
#define CORE_TAGREADERCLIENT_H_
|
||||
|
||||
#include <memory.h>
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
#include "core/messagehandler.h"
|
||||
@ -30,12 +32,14 @@
|
||||
|
||||
class QLocalServer;
|
||||
class QProcess;
|
||||
class SongPathParser;
|
||||
|
||||
class TagReaderClient : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TagReaderClient(QObject* parent = nullptr);
|
||||
virtual ~TagReaderClient();
|
||||
|
||||
typedef AbstractMessageHandler<cpb::tagreader::Message> HandlerType;
|
||||
typedef HandlerType::ReplyType ReplyType;
|
||||
@ -79,6 +83,7 @@ class TagReaderClient : public QObject {
|
||||
|
||||
WorkerPool<HandlerType>* worker_pool_;
|
||||
QList<cpb::tagreader::Message> message_queue_;
|
||||
std::unique_ptr<SongPathParser> path_parser_;
|
||||
};
|
||||
|
||||
typedef TagReaderClient::ReplyType TagReaderReply;
|
||||
|
Loading…
x
Reference in New Issue
Block a user