diff --git a/README.md b/README.md
index a083a22c..25b903a4 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ A [demo](http://lms.demo.poupon.io) instance is available, with the following li
* Audio transcode for maximum interoperability and low bandwith requirements
* Persistent play queue across sessions
* Subsonic API
-* Album artist
+* Compilation support
* Multi-value tags: artists, genres, ...
* Custom tags (ex: _mood_, _genre_, _albummood_, _albumgrouping_, ...)
* MusicBrainzID support to handle duplicated artist and release names
diff --git a/approot/messages.xml b/approot/messages.xml
index 17d5ded8..20677bc8 100644
--- a/approot/messages.xml
+++ b/approot/messages.xml
@@ -39,9 +39,9 @@
Monthly
Never
Media root directory
-Recommendation engine
-Tags based
-Audio analysis based
+Recommendation engine
+Tags based
+Audio analysis based
Scan complete: {1} total files, {2} additions, {3} updates, {4} deletions, {5} duplicates, {6} errors
Scan launched!
Scan options
diff --git a/approot/messages_fr.xml b/approot/messages_fr.xml
index 2d61dc1d..934cd400 100644
--- a/approot/messages_fr.xml
+++ b/approot/messages_fr.xml
@@ -39,9 +39,9 @@
Tous les mois
Jamais
Dossier racine des fichiers de musique
-Moteur de recommandation
-Basé sur les tags
-Basé sur l'analyse audio
+Moteur de recommandation
+Basé sur les tags
+Basé sur l'analyse audio
Scan terminé : {1} fichiers, {2} ajouts, {3} mises à jour, {4} suppressions, {5} duplicatas, {6} erreurs
Scan lancé !
Options
diff --git a/src/libs/database/impl/Artist.cpp b/src/libs/database/impl/Artist.cpp
index 5d17df1a..b5c6d221 100644
--- a/src/libs/database/impl/Artist.cpp
+++ b/src/libs/database/impl/Artist.cpp
@@ -104,6 +104,21 @@ Artist::getAllOrphans(Session& session)
return std::vector(res.begin(), res.end());
}
+std::vector
+Artist::getAllIdsWithClusters(Session& session, std::optional limit)
+{
+ session.checkSharedLocked();
+
+ Wt::Dbo::collection res = session.getDboSession().query
+ ("SELECT DISTINCT a.id FROM artist a"
+ " INNER JOIN track t ON t.id = t_a_l.track_id INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id"
+ " INNER JOIN track_cluster t_c ON t_c.track_id = t.id")
+ .limit(limit ? static_cast(*limit) : -1);
+
+ return std::vector(res.begin(), res.end());
+}
+
+
static
Wt::Dbo::Query
getQuery(Session& session,
diff --git a/src/libs/database/impl/Release.cpp b/src/libs/database/impl/Release.cpp
index 343a7ce1..7fdd639a 100644
--- a/src/libs/database/impl/Release.cpp
+++ b/src/libs/database/impl/Release.cpp
@@ -252,6 +252,21 @@ Release::getByFilter(Session& session,
return res;
}
+std::vector
+Release::getAllIdsWithClusters(Session& session, std::optional limit)
+{
+ session.checkSharedLocked();
+
+ Wt::Dbo::collection res = session.getDboSession().query
+ ("SELECT DISTINCT r.id FROM release r"
+ " INNER JOIN track t ON t.release_id = r.id"
+ " INNER JOIN track_cluster t_c ON t_c.track_id = t.id")
+ .limit(limit ? static_cast(*limit) : -1);
+
+ return std::vector(res.begin(), res.end());
+}
+
+
std::optional
Release::getTotalTrackNumber(void) const
{
diff --git a/src/libs/database/impl/Session.cpp b/src/libs/database/impl/Session.cpp
index 36750ec7..081fe8a8 100644
--- a/src/libs/database/impl/Session.cpp
+++ b/src/libs/database/impl/Session.cpp
@@ -118,7 +118,7 @@ Session::doDatabaseMigrationIfNeeded()
{
_session.execute("DROP TABLE similarity_settings");
_session.execute("DROP TABLE similarity_settings_feature");
- _session.execute("ALTER TABLE scan_settings ADD similarity_engine_type INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast(ScanSettings::SimilarityEngineType::Clusters)) + ")");
+ _session.execute("ALTER TABLE scan_settings ADD similarity_engine_type INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast(ScanSettings::RecommendationEngineType::Clusters)) + ")");
}
else if (version == 8)
{
diff --git a/src/libs/database/impl/Track.cpp b/src/libs/database/impl/Track.cpp
index a84af8e1..2acff171 100644
--- a/src/libs/database/impl/Track.cpp
+++ b/src/libs/database/impl/Track.cpp
@@ -163,6 +163,19 @@ Track::getAllIdsWithFeatures(Session& session, std::optional limit)
return std::vector(res.begin(), res.end());
}
+std::vector
+Track::getAllIdsWithClusters(Session& session, std::optional limit)
+{
+ session.checkSharedLocked();
+
+ Wt::Dbo::collection res = session.getDboSession().query
+ ("SELECT DISTINCT t.id FROM track t"
+ " INNER JOIN track_cluster t_c ON t_c.track_id = t.id")
+ .limit(limit ? static_cast(*limit) : -1);
+
+ return std::vector(res.begin(), res.end());
+}
+
std::vector
Track::getClusters(void) const
{
@@ -263,7 +276,7 @@ Track::getByFilter(Session& session,
std::vector
Track::getSimilarTracks(Session& session,
- const std::set& tracks,
+ const std::unordered_set& tracks,
std::optional offset,
std::optional size)
{
diff --git a/src/libs/database/include/database/Artist.hpp b/src/libs/database/include/database/Artist.hpp
index 01d261b3..f53082c1 100644
--- a/src/libs/database/include/database/Artist.hpp
+++ b/src/libs/database/include/database/Artist.hpp
@@ -68,6 +68,7 @@ class Artist : public Wt::Dbo::Dbo
static std::vector getAllIds(Session& session);
static std::vector getAllOrphans(Session& session); // No track related
static std::vector getLastAdded(Session& session, Wt::WDateTime after, std::optional size = {});
+ static std::vector getAllIdsWithClusters(Session& session, std::optional limit = {});
// Accessors
const std::string& getName(void) const { return _name; }
diff --git a/src/libs/database/include/database/Release.hpp b/src/libs/database/include/database/Release.hpp
index c0a638f3..695bcdc5 100644
--- a/src/libs/database/include/database/Release.hpp
+++ b/src/libs/database/include/database/Release.hpp
@@ -66,6 +66,7 @@ class Release : public Wt::Dbo::Dbo
std::optional offset,
std::optional size,
bool& moreExpected);
+ static std::vector getAllIdsWithClusters(Session& session, std::optional limit = {});
std::vector> getTracks(const std::set& clusters = std::set()) const;
std::size_t getTracksCount() const;
diff --git a/src/libs/database/include/database/ScanSettings.hpp b/src/libs/database/include/database/ScanSettings.hpp
index 0ce37a49..7151df23 100644
--- a/src/libs/database/include/database/ScanSettings.hpp
+++ b/src/libs/database/include/database/ScanSettings.hpp
@@ -43,7 +43,7 @@ class ScanSettings : public Wt::Dbo::Dbo
};
// Do not modify values (just add)
- enum class SimilarityEngineType
+ enum class RecommendationEngineType
{
Clusters = 0,
Features,
@@ -60,7 +60,7 @@ class ScanSettings : public Wt::Dbo::Dbo
UpdatePeriod getUpdatePeriod() const { return _updatePeriod; }
std::vector> getClusterTypes() const;
std::set getAudioFileExtensions() const;
- SimilarityEngineType getSimilarityEngineType() const { return _similarityEngineType; }
+ RecommendationEngineType getRecommendationEngineType() const { return _recommendationEngineType; }
// Setters
void addAudioFileExtension(const std::filesystem::path& ext);
@@ -68,7 +68,7 @@ class ScanSettings : public Wt::Dbo::Dbo
void setUpdateStartTime(Wt::WTime t) { _startTime = t; }
void setUpdatePeriod(UpdatePeriod p) { _updatePeriod = p; }
void setClusterTypes(Session& session, const std::set& clusterTypeNames);
- void setSimilarityEngineType(SimilarityEngineType type) { _similarityEngineType = type; }
+ void setRecommendationEngineType(RecommendationEngineType type) { _recommendationEngineType = type; }
void incScanVersion();
template
@@ -79,7 +79,7 @@ class ScanSettings : public Wt::Dbo::Dbo
Wt::Dbo::field(a, _startTime, "start_time");
Wt::Dbo::field(a, _updatePeriod, "update_period");
Wt::Dbo::field(a, _audioFileExtensions, "audio_file_extensions");
- Wt::Dbo::field(a, _similarityEngineType,"similarity_engine_type");
+ Wt::Dbo::field(a, _recommendationEngineType,"similarity_engine_type");
Wt::Dbo::hasMany(a, _clusterTypes, Wt::Dbo::ManyToOne, "scan_settings");
}
@@ -89,7 +89,7 @@ class ScanSettings : public Wt::Dbo::Dbo
std::string _mediaDirectory;
Wt::WTime _startTime = Wt::WTime {0,0,0};
UpdatePeriod _updatePeriod {UpdatePeriod::Never};
- SimilarityEngineType _similarityEngineType {SimilarityEngineType::Clusters};
+ RecommendationEngineType _recommendationEngineType {RecommendationEngineType::Clusters};
std::string _audioFileExtensions {".alac .mp3 .ogg .oga .aac .m4a .m4b .flac .wav .wma .aif .aiff .ape .mpc .shn .opus"};
Wt::Dbo::collection> _clusterTypes;
};
diff --git a/src/libs/database/include/database/Track.hpp b/src/libs/database/include/database/Track.hpp
index d3bcd824..24113f21 100644
--- a/src/libs/database/include/database/Track.hpp
+++ b/src/libs/database/include/database/Track.hpp
@@ -22,8 +22,9 @@
#include
#include
#include
-#include
#include
+#include
+#include
#include
#include
@@ -58,7 +59,7 @@ class Track : public Wt::Dbo::Dbo