diff --git a/src/collection/collectionmodel.cpp b/src/collection/collectionmodel.cpp index 0009fcb3..895a9faf 100644 --- a/src/collection/collectionmodel.cpp +++ b/src/collection/collectionmodel.cpp @@ -1681,7 +1681,7 @@ QString CollectionModel::PrettyYearAlbum(const int year, const QString &album) { QString CollectionModel::PrettyAlbumDisc(const QString &album, const int disc) { - if (disc <= 0 || album.contains(Song::kAlbumRemoveDisc)) return TextOrUnknown(album); + if (disc <= 0 || Song::AlbumContainsDisc(album)) return TextOrUnknown(album); else return TextOrUnknown(album) + " - (Disc " + QString::number(disc) + ")"; } @@ -1693,7 +1693,7 @@ QString CollectionModel::PrettyYearAlbumDisc(const int year, const QString &albu if (year <= 0) str = TextOrUnknown(album); else str = QString::number(year) + " - " + TextOrUnknown(album); - if (!album.contains(Song::kAlbumRemoveDisc) && disc > 0) str += " - (Disc " + QString::number(disc) + ")"; + if (!Song::AlbumContainsDisc(album) && disc > 0) str += " - (Disc " + QString::number(disc) + ")"; return str; diff --git a/src/core/song.cpp b/src/core/song.cpp index b5630e59..97123d4e 100644 --- a/src/core/song.cpp +++ b/src/core/song.cpp @@ -167,9 +167,20 @@ const QString Song::kFtsColumnSpec = Song::kFtsColumns.join(", "); const QString Song::kFtsBindSpec = Utilities::Prepend(":", Song::kFtsColumns).join(", "); const QString Song::kFtsUpdateSpec = Utilities::Updateify(Song::kFtsColumns).join(", "); -const QRegularExpression Song::kAlbumRemoveDisc(" ?-? ((\\(|\\[)?)(Disc|CD) ?([0-9]{1,2})((\\)|\\])?)$", QRegularExpression::CaseInsensitiveOption); -const QRegularExpression Song::kAlbumRemoveMisc(" ?-? ((\\(|\\[)?)(Remastered|([0-9]{1,4}) *Remaster|Explicit) ?((\\)|\\])?)$", QRegularExpression::CaseInsensitiveOption); -const QRegularExpression Song::kTitleRemoveMisc(" ?-? ((\\(|\\[)?)(Remastered|Remastered Version|([0-9]{1,4}) *Remaster) ?((\\)|\\])?)$", QRegularExpression::CaseInsensitiveOption); +const Song::RegularExpressionList Song::kAlbumDisc = Song::RegularExpressionList() + << QRegularExpression("\\s+-*\\s*(Disc|CD)\\s*([0-9]{1,2})$", QRegularExpression::CaseInsensitiveOption) + << QRegularExpression("\\s+-*\\s*\\(\\s*(Disc|CD)\\s*([0-9]{1,2})\\)$", QRegularExpression::CaseInsensitiveOption) + << QRegularExpression("\\s+-*\\s*\\[\\s*(Disc|CD)\\s*([0-9]{1,2})\\]$", QRegularExpression::CaseInsensitiveOption); + +const Song::RegularExpressionList Song::kAlbumMisc = Song::RegularExpressionList() + << QRegularExpression("\\s+-*\\s*(Remastered|([0-9]{1,4})\\s*Remaster|Explicit)\\s*$", QRegularExpression::CaseInsensitiveOption) + << QRegularExpression("\\s+-*\\s*\\(\\s*(Remastered|([0-9]{1,4})\\s*Remaster|Explicit)\\s*\\)\\s*$", QRegularExpression::CaseInsensitiveOption) + << QRegularExpression("\\s+-*\\s*\\[\\s*(Remastered|([0-9]{1,4})\\s*Remaster|Explicit)\\s*\\]\\s*$", QRegularExpression::CaseInsensitiveOption); + +const Song::RegularExpressionList Song::kTitleMisc = Song::RegularExpressionList() + << QRegularExpression("\\s+-*\\s*(Remastered|Remastered Version|([0-9]{1,4})\\s*Remaster)\\s*$", QRegularExpression::CaseInsensitiveOption) + << QRegularExpression("\\s+-*\\s*\\(\\s*(Remastered|Remastered Version|([0-9]{1,4})\\s*Remaster)\\s*\\)\\s*$", QRegularExpression::CaseInsensitiveOption) + << QRegularExpression("\\s+-*\\s*\\[\\s*(Remastered|Remastered Version|([0-9]{1,4})\\s*Remaster)\\s*\\]\\s*$", QRegularExpression::CaseInsensitiveOption); const QStringList Song::kArticles = QStringList() << "the " << "a " << "an "; @@ -1843,3 +1854,53 @@ size_t HashSimilar(const Song &song) { // Should compare the same fields as function IsSimilar return qHash(song.title().toLower()) ^ qHash(song.artist().toLower()) ^ qHash(song.album().toLower()); } + +bool Song::ContainsRegexList(const QString &str, const RegularExpressionList ®ex_list) { + + for (const QRegularExpression ®ex : regex_list) { + if (str.contains(regex)) return true; + } + + return false; + +} + +QString Song::StripRegexList(QString str, const RegularExpressionList ®ex_list) { + + for (const QRegularExpression ®ex : regex_list) { + str = str.remove(regex); + } + + return str; + +} + +bool Song::AlbumContainsDisc(const QString &album) { + + return ContainsRegexList(album, kAlbumDisc); + +} + +QString Song::AlbumRemoveDisc(const QString &album) { + + return StripRegexList(album, kAlbumDisc); + +} + +QString Song::AlbumRemoveMisc(const QString &album) { + + return StripRegexList(album, kAlbumMisc); + +} + +QString Song::AlbumRemoveDiscMisc(const QString &album) { + + return StripRegexList(album, RegularExpressionList() << kAlbumDisc << kAlbumMisc); + +} + +QString Song::TitleRemoveMisc(const QString &title) { + + return StripRegexList(title, kTitleMisc); + +} diff --git a/src/core/song.h b/src/core/song.h index 76b57118..8fcc2ea6 100644 --- a/src/core/song.h +++ b/src/core/song.h @@ -123,9 +123,10 @@ class Song { static const QString kFtsBindSpec; static const QString kFtsUpdateSpec; - static const QRegularExpression kAlbumRemoveDisc; - static const QRegularExpression kAlbumRemoveMisc; - static const QRegularExpression kTitleRemoveMisc; + using RegularExpressionList = QList; + static const RegularExpressionList kAlbumDisc; + static const RegularExpressionList kAlbumMisc; + static const RegularExpressionList kTitleMisc; static const QStringList kArticles; @@ -443,6 +444,14 @@ class Song { // It is more efficient to use IsOnSameAlbum, but this function can be used when you need to hash the key to do fast lookups. QString AlbumKey() const; + static bool ContainsRegexList(const QString &str, const RegularExpressionList ®ex_list); + static QString StripRegexList(QString str, const RegularExpressionList ®ex_list); + static bool AlbumContainsDisc(const QString &album); + static QString AlbumRemoveDisc(const QString &album); + static QString AlbumRemoveMisc(const QString &album); + static QString AlbumRemoveDiscMisc(const QString &album); + static QString TitleRemoveMisc(const QString &title); + private: struct Private; diff --git a/src/covermanager/albumcoverchoicecontroller.cpp b/src/covermanager/albumcoverchoicecontroller.cpp index 6c3c1691..246a69bb 100644 --- a/src/covermanager/albumcoverchoicecontroller.cpp +++ b/src/covermanager/albumcoverchoicecontroller.cpp @@ -333,7 +333,7 @@ AlbumCoverImageResult AlbumCoverChoiceController::SearchForImage(Song *song) { if (!song->url().isValid() || !song->url().isLocalFile() || song->effective_albumartist().isEmpty() || song->album().isEmpty()) return AlbumCoverImageResult(); QString album = song->effective_album(); - album = album.remove(Song::kAlbumRemoveDisc).remove(Song::kAlbumRemoveMisc); + album = Song::AlbumRemoveDiscMisc(album); // Get something sensible to stick in the search box return cover_searcher_->Exec(song->effective_albumartist(), album); diff --git a/src/covermanager/albumcoverfetcher.cpp b/src/covermanager/albumcoverfetcher.cpp index 0f16452c..d416a88f 100644 --- a/src/covermanager/albumcoverfetcher.cpp +++ b/src/covermanager/albumcoverfetcher.cpp @@ -66,9 +66,7 @@ quint64 AlbumCoverFetcher::FetchAlbumCover(const QString &artist, const QString CoverSearchRequest request; request.id = ++next_id_; request.artist = artist; - request.album = album; - request.album = request.album.remove(Song::kAlbumRemoveDisc); - request.album = request.album.remove(Song::kAlbumRemoveMisc); + request.album = Song::AlbumRemoveDiscMisc(album); request.title = title; request.search = false; request.batch = batch; @@ -83,9 +81,7 @@ quint64 AlbumCoverFetcher::SearchForCovers(const QString &artist, const QString CoverSearchRequest request; request.id = ++next_id_; request.artist = artist; - request.album = album; - request.album = request.album.remove(Song::kAlbumRemoveDisc); - request.album = request.album.remove(Song::kAlbumRemoveMisc); + request.album = Song::AlbumRemoveDiscMisc(album); request.title = title; request.search = true; request.batch = false; diff --git a/src/covermanager/deezercoverprovider.cpp b/src/covermanager/deezercoverprovider.cpp index 2a003e1c..ebc902cd 100644 --- a/src/covermanager/deezercoverprovider.cpp +++ b/src/covermanager/deezercoverprovider.cpp @@ -265,12 +265,9 @@ void DeezerCoverProvider::HandleSearchReply(QNetworkReply *reply, const int id) } QString album = obj_album["title"].toString(); - album = album.remove(Song::kAlbumRemoveDisc); - album = album.remove(Song::kAlbumRemoveMisc); - CoverProviderSearchResult cover_result; cover_result.artist = artist; - cover_result.album = album; + cover_result.album = Song::AlbumRemoveDiscMisc(album); bool have_cover = false; QList> cover_sizes = QList>() << qMakePair(QString("cover_xl"), QSize(1000, 1000)) diff --git a/src/covermanager/qobuzcoverprovider.cpp b/src/covermanager/qobuzcoverprovider.cpp index 11157417..b987b9ea 100644 --- a/src/covermanager/qobuzcoverprovider.cpp +++ b/src/covermanager/qobuzcoverprovider.cpp @@ -262,12 +262,9 @@ void QobuzCoverProvider::HandleSearchReply(QNetworkReply *reply, const int id) { } QUrl cover_url(obj_image["large"].toString()); - album = album.remove(Song::kAlbumRemoveDisc); - album = album.remove(Song::kAlbumRemoveMisc); - CoverProviderSearchResult cover_result; cover_result.artist = artist; - cover_result.album = album; + cover_result.album = Song::AlbumRemoveDiscMisc(album); cover_result.image_url = cover_url; cover_result.image_size = QSize(600, 600); results << cover_result; diff --git a/src/covermanager/tidalcoverprovider.cpp b/src/covermanager/tidalcoverprovider.cpp index e5bd189e..bf0fb73a 100644 --- a/src/covermanager/tidalcoverprovider.cpp +++ b/src/covermanager/tidalcoverprovider.cpp @@ -241,15 +241,11 @@ void TidalCoverProvider::HandleSearchReply(QNetworkReply *reply, const int id) { continue; } QString album = obj_album["title"].toString(); - QString cover = obj_album["cover"].toString(); - - album = album.remove(Song::kAlbumRemoveDisc); - album = album.remove(Song::kAlbumRemoveMisc); - cover = cover.replace("-", "/"); + QString cover = obj_album["cover"].toString().replace("-", "/"); CoverProviderSearchResult cover_result; cover_result.artist = artist; - cover_result.album = album; + cover_result.album = Song::AlbumRemoveDiscMisc(album); cover_result.number = ++i; QList> cover_sizes = QList>() << qMakePair(QString("1280x1280"), QSize(1280, 1280)) diff --git a/src/lyrics/lyricsfetcher.cpp b/src/lyrics/lyricsfetcher.cpp index 9e65dbd7..616006b9 100644 --- a/src/lyrics/lyricsfetcher.cpp +++ b/src/lyrics/lyricsfetcher.cpp @@ -53,10 +53,8 @@ quint64 LyricsFetcher::Search(const QString &effective_albumartist, const QStrin LyricsSearchRequest search_request; search_request.albumartist = effective_albumartist; search_request.artist = artist; - search_request.album = album; - search_request.album.remove(Song::kAlbumRemoveMisc); - search_request.title = title; - search_request.title.remove(Song::kTitleRemoveMisc); + search_request.album = Song::AlbumRemoveDiscMisc(album); + search_request.title = Song::TitleRemoveMisc(title); Request request; request.id = ++next_id_; diff --git a/src/qobuz/qobuzrequest.cpp b/src/qobuz/qobuzrequest.cpp index 62f7366c..9b3eb02a 100644 --- a/src/qobuz/qobuzrequest.cpp +++ b/src/qobuz/qobuzrequest.cpp @@ -1189,7 +1189,7 @@ void QobuzRequest::ParseSong(Song &song, const QJsonObject &json_obj, const Arti url.setScheme(url_handler_->scheme()); url.setPath(song_id); - title.remove(Song::kTitleRemoveMisc); + title = Song::TitleRemoveMisc(title); //qLog(Debug) << "id" << song_id << "track" << track << "title" << title << "album" << album << "album artist" << album_artist << cover_url << streamable << url; diff --git a/src/scrobbler/scrobblerservice.cpp b/src/scrobbler/scrobblerservice.cpp index 20512e63..5fafde72 100644 --- a/src/scrobbler/scrobblerservice.cpp +++ b/src/scrobbler/scrobblerservice.cpp @@ -50,14 +50,14 @@ bool ScrobblerService::ExtractJsonObj(const QByteArray &data, QJsonObject &json_ } -QString ScrobblerService::StripAlbum(QString album) const { +QString ScrobblerService::StripAlbum(const QString &album) const { - return album.remove(Song::kAlbumRemoveDisc).remove(Song::kAlbumRemoveMisc); + return Song::AlbumRemoveDisc(album); } -QString ScrobblerService::StripTitle(QString title) const { +QString ScrobblerService::StripTitle(const QString &title) const { - return title.remove(Song::kTitleRemoveMisc); + return Song::TitleRemoveMisc(title); } diff --git a/src/scrobbler/scrobblerservice.h b/src/scrobbler/scrobblerservice.h index ea1daed7..b7b4ccd8 100644 --- a/src/scrobbler/scrobblerservice.h +++ b/src/scrobbler/scrobblerservice.h @@ -61,8 +61,8 @@ class ScrobblerService : public QObject { bool ExtractJsonObj(const QByteArray &data, QJsonObject &json_obj, QString &error_description); - QString StripAlbum(QString album) const; - QString StripTitle(QString title) const; + QString StripAlbum(const QString &album) const; + QString StripTitle(const QString &title) const; public slots: virtual void Submit() = 0; diff --git a/src/tidal/tidalrequest.cpp b/src/tidal/tidalrequest.cpp index 64bb939c..182df339 100644 --- a/src/tidal/tidalrequest.cpp +++ b/src/tidal/tidalrequest.cpp @@ -1129,7 +1129,7 @@ void TidalRequest::ParseSong(Song &song, const QJsonObject &json_obj, const Arti } } - title.remove(Song::kTitleRemoveMisc); + title = Song::TitleRemoveMisc(title); //qLog(Debug) << "id" << song_id << "track" << track << "disc" << disc << "title" << title << "album" << album << "album artist" << album_artist << "artist" << artist << cover << allow_streaming << url; diff --git a/src/utilities/coverutils.cpp b/src/utilities/coverutils.cpp index dc7a3b6b..9a5bba5e 100644 --- a/src/utilities/coverutils.cpp +++ b/src/utilities/coverutils.cpp @@ -152,7 +152,7 @@ QString CoverUtils::CoverFilenameFromSource(const Song::Source source, const QUr QString CoverUtils::CoverFilenameFromVariable(const CoverOptions &options, const QString &artist, QString album, const QString &extension) { - album = album.remove(Song::kAlbumRemoveDisc); + album = Song::AlbumRemoveDisc(album); QString filename(options.cover_pattern); filename.replace("%albumartist", artist);