[WIP] Added Artist/ReleaseInfo

This commit is contained in:
emeric
2019-01-23 13:22:43 +01:00
parent b76c60f437
commit 3e142b5507
77 changed files with 2706 additions and 716 deletions
+6
View File
@@ -199,6 +199,12 @@ Artist::getReleases(const std::set<IdType>& clusterIds) const
return std::vector< Wt::Dbo::ptr<Release> > (res.begin(), res.end());
}
std::vector<Wt::Dbo::ptr<Track>>
Artist::getTracks() const
{
return std::vector<Wt::Dbo::ptr<Track>>(_tracks.begin(), _tracks.end());
}
std::vector<std::vector<Wt::Dbo::ptr<Cluster>>>
Artist::getClusterGroups(std::vector<ClusterType::pointer> clusterTypes, std::size_t size) const
{
+1
View File
@@ -65,6 +65,7 @@ class Artist : public Wt::Dbo::Dbo<Artist>
// Get the releases that have at least one track for this artist that belongs to optional cluster filters
std::vector<Wt::Dbo::ptr<Release>> getReleases(const std::set<IdType>& clusterIds = std::set<IdType>()) const;
std::vector<Wt::Dbo::ptr<Track>> getTracks() const;
// Get the cluster of the tracks made by this artist
// Each clusters are grouped by cluster type, sorted by the number of occurence
+2 -2
View File
@@ -37,7 +37,7 @@ class ScanSettings;
class Cluster : public Wt::Dbo::Dbo<Cluster>
{
public:
typedef Wt::Dbo::ptr<Cluster> pointer;
using pointer = Wt::Dbo::ptr<Cluster>;
Cluster();
Cluster(Wt::Dbo::ptr<ClusterType> type, std::string name);
@@ -50,7 +50,7 @@ class Cluster : public Wt::Dbo::Dbo<Cluster>
static pointer create(Wt::Dbo::Session& session, Wt::Dbo::ptr<ClusterType> type, std::string name);
// Accessors
const std::string& getName(void) const { return _name; }
const std::string& getName() const { return _name; }
Wt::Dbo::ptr<ClusterType> getType() const { return _clusterType; }
std::size_t getCount() const { return _tracks.size(); }
std::vector<Wt::Dbo::ptr<Track>> getTracks(int offset, int limit) const;
+12 -2
View File
@@ -35,10 +35,12 @@
#include "Artist.hpp"
#include "Cluster.hpp"
#include "TrackList.hpp"
#include "Release.hpp"
#include "ScanSettings.hpp"
#include "SimilaritySettings.hpp"
#include "Track.hpp"
#include "TrackList.hpp"
#include "TrackFeature.hpp"
namespace Database {
@@ -104,8 +106,11 @@ Handler::Handler(Wt::Dbo::SqlConnectionPool& connectionPool)
_session.mapClass<TrackListEntry>("tracklist_entry");
_session.mapClass<Release>("release");
_session.mapClass<Track>("track");
_session.mapClass<TrackFeature>("track_feature");
_session.mapClass<TrackFeatureType>("track_feature_type");
_session.mapClass<ScanSettings>("scan_settings");
_session.mapClass<SimilaritySettings>("similarity_settings");
_session.mapClass<AuthInfo>("auth_info");
_session.mapClass<AuthInfo::AuthIdentityType>("auth_identity");
@@ -129,13 +134,18 @@ Handler::Handler(Wt::Dbo::SqlConnectionPool& connectionPool)
// Indexes
_session.execute("CREATE INDEX IF NOT EXISTS track_path_idx ON track(file_path)");
_session.execute("CREATE INDEX IF NOT EXISTS track_name_idx ON track(name)");
_session.execute("CREATE INDEX IF NOT EXISTS artist_name_idx ON artist(name)");
_session.execute("CREATE INDEX IF NOT EXISTS release_name_idx ON release(name)");
_session.execute("CREATE INDEX IF NOT EXISTS track_artist_idx ON track(artist_id)");
_session.execute("CREATE INDEX IF NOT EXISTS track_release_idx ON track(release_id)");
_session.execute("CREATE INDEX IF NOT EXISTS cluster_name_idx ON cluster(name)");
_session.execute("CREATE INDEX IF NOT EXISTS cluster_type_name_idx ON cluster_type(name)");
_session.execute("CREATE INDEX IF NOT EXISTS tracklist_name ON tracklist(name)");
_session.execute("CREATE INDEX IF NOT EXISTS tracklist_name_idx ON tracklist(name)");
_session.execute("CREATE INDEX IF NOT EXISTS track_feature_type_name_idx ON track_feature_type(name)");
_session.execute("CREATE INDEX IF NOT EXISTS track_feature_type_idx ON track_feature(type_id)");
_session.execute("CREATE INDEX IF NOT EXISTS track_feature_track_idx ON track_feature(track_id)");
_session.execute("CREATE INDEX IF NOT EXISTS track_feature_type_track_idx ON track_feature(type_id, track_id)");
}
_users = new UserDatabase(_session);
+5 -4
View File
@@ -45,7 +45,7 @@ namespace Database {
ScanSettings::pointer
ScanSettings::get(Wt::Dbo::Session& session)
{
ScanSettings::pointer settings = session.find<ScanSettings>();
pointer settings = session.find<ScanSettings>();
if (!settings)
{
settings = session.add(std::make_unique<ScanSettings>());
@@ -81,16 +81,17 @@ ScanSettings::setClusterTypes(const std::set<std::string>& clusterTypeNames)
assert(session());
// Create any missing cluster type
for (auto clusterTypeName : clusterTypeNames)
for (const auto& clusterTypeName : clusterTypeNames)
{
auto clusterType = ClusterType::getByName(*session(), clusterTypeName);
if (!clusterType)
{
LMS_LOG(DB, INFO) << "Creating cluster type " << clusterTypeName;
clusterType = ClusterType::create(*session(), clusterTypeName);
_clusterTypes.insert(clusterType);
needRescan = true;
}
_clusterTypes.insert(clusterType);
}
// Delete no longer existing cluster types
@@ -101,7 +102,6 @@ ScanSettings::setClusterTypes(const std::set<std::string>& clusterTypeNames)
{
LMS_LOG(DB, INFO) << "Deleting cluster type " << clusterType->getName();
clusterType.remove();
needRescan = true;
}
}
@@ -109,5 +109,6 @@ ScanSettings::setClusterTypes(const std::set<std::string>& clusterTypeNames)
_scanVersion += 1;
}
} // namespace Database
+1 -2
View File
@@ -27,6 +27,7 @@
namespace Database {
class ClusterType;
class ScanSettings : public Wt::Dbo::Dbo<ScanSettings>
{
public:
@@ -39,8 +40,6 @@ class ScanSettings : public Wt::Dbo::Dbo<ScanSettings>
Monthly
};
ScanSettings() {}
static pointer get(Wt::Dbo::Session& session);
// Getters
+130
View File
@@ -0,0 +1,130 @@
/*
* Copyright (C) 2018 Emeric Poupon
*
* This file is part of LMS.
*
* LMS 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.
*
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include "SimilaritySettings.hpp"
#include "utils/Logger.hpp"
#include "utils/Utils.hpp"
#include "TrackFeature.hpp"
namespace {
std::set<std::string> defaultTrackFeaturesNames =
{
"lowlevel.average_loudness",
"lowlevel.barkbands_flatness_db.mean",
"lowlevel.dissonance.mean",
"lowlevel.dynamic_complexity",
"lowlevel.hfc.mean", // GOOD
"lowlevel.melbands_crest.mean",
"lowlevel.melbands_kurtosis.mean",
"lowlevel.melbands_skewness.mean",
"lowlevel.melbands_spread.mean",
"lowlevel.pitch_salience.mean",
"lowlevel.pitch_salience.var",
"lowlevel.silence_rate_30dB.mean",
"lowlevel.silence_rate_60dB.mean",
"lowlevel.spectral_centroid.mean",
"lowlevel.spectral_complexity.mean",
"lowlevel.spectral_decrease.mean",
"lowlevel.spectral_energy.mean",
"lowlevel.spectral_energyband_high.mean",
"lowlevel.spectral_energyband_low.mean",
"lowlevel.spectral_energyband_middle_high.mean",
"lowlevel.spectral_energyband_middle_low.mean",
"lowlevel.spectral_entropy.mean",
"lowlevel.spectral_flux.mean",
"lowlevel.spectral_kurtosis.mean",
"lowlevel.spectral_rms.mean",
"lowlevel.spectral_skewness.mean",
"lowlevel.spectral_spread.mean",
"lowlevel.spectral_strongpeak.mean",
"lowlevel.zerocrossingrate.mean",
"rhythm.beats_loudness.mean", // BAD
"rhythm.bpm",
"tonal.chords_changes_rate", // OK
"tonal.chords_number_rate", // BAD
"tonal.chords_strength.mean", // OK
"tonal.hpcp_entropy.mean", // GOOD
};
} // namespace
namespace Database {
SimilaritySettings::pointer
SimilaritySettings::get(Wt::Dbo::Session& session)
{
pointer settings = session.find<SimilaritySettings>();
if (!settings)
{
settings = session.add(std::make_unique<SimilaritySettings>());
settings.modify()->setTrackFeatureTypes(defaultTrackFeaturesNames);
}
return settings;
}
std::vector<Wt::Dbo::ptr<TrackFeatureType>>
SimilaritySettings::getTrackFeatureTypes() const
{
return std::vector<Wt::Dbo::ptr<TrackFeatureType>>(_trackFeatureTypes.begin(), _trackFeatureTypes.end());
}
void
SimilaritySettings::setTrackFeatureTypes(const std::set<std::string>& featuresNames)
{
bool needRescan = false;
assert(session());
// Create any missing feature type
for (const auto& featureName : featuresNames)
{
auto featureType = TrackFeatureType::getByName(*session(), featureName);
if (!featureType)
{
LMS_LOG(DB, INFO) << "Creating feature type " << featureName;
featureType = TrackFeatureType::create(*session(), featureName);
_trackFeatureTypes.insert(featureType);
needRescan = true;
}
}
// Delete no longer existing feature type
for (auto trackFeatureType : _trackFeatureTypes)
{
if (std::none_of(featuresNames.begin(), featuresNames.end(),
[trackFeatureType](const std::string& name) { return name == trackFeatureType->getName(); }))
{
LMS_LOG(DB, INFO) << "Deleting track feature type " << trackFeatureType->getName();
trackFeatureType.remove();
}
}
if (needRescan)
_scanVersion += 1;
}
} // namespace Database
+66
View File
@@ -0,0 +1,66 @@
/*
* Copyright (C) 2018 Emeric Poupon
*
* This file is part of LMS.
*
* LMS 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.
*
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <Wt/Dbo/Dbo.h>
namespace Database {
class TrackFeature;
class TrackFeatureType;
class SimilaritySettings : public Wt::Dbo::Dbo<SimilaritySettings>
{
public:
using pointer = Wt::Dbo::ptr<SimilaritySettings>;
static pointer get(Wt::Dbo::Session& session);
std::size_t getVersion() const { return _scanVersion; }
std::vector<Wt::Dbo::ptr<TrackFeatureType>> getTrackFeatureTypes() const;
void setTrackFeatureTypes(const std::set<std::string>& featureTypeNames);
void setNetworkData(std::string data) { _refFeaturesData = data; }
const std::string& getNetworkData() const { return _refFeaturesData; }
void setNormalizationData(std::string data) { _normalizationData = data; }
const std::string& getNormalizationData() const { return _normalizationData; }
template<class Action>
void persist(Action& a)
{
Wt::Dbo::field(a, _scanVersion, "settings_version");
Wt::Dbo::field(a, _normalizationData, "normalization_data");
Wt::Dbo::field(a, _refFeaturesData, "ref_features_data");
Wt::Dbo::hasMany(a, _trackFeatureTypes, Wt::Dbo::ManyToOne, "similarity_settings");
}
private:
int _scanVersion = 0;
std::string _normalizationData;
std::string _refFeaturesData;
Wt::Dbo::collection<Wt::Dbo::ptr<TrackFeatureType>> _trackFeatureTypes;
};
} // namespace Database
+38
View File
@@ -26,6 +26,7 @@
#include "Artist.hpp"
#include "Cluster.hpp"
#include "Release.hpp"
#include "TrackFeature.hpp"
#include "SqlQuery.hpp"
namespace Database {
@@ -107,6 +108,25 @@ Track::getLastAdded(Wt::Dbo::Session& session, Wt::WDateTime after, int limit)
return std::vector<pointer>(res.begin(), res.end());
}
std::vector<Track::pointer>
Track::getAllWithMBIDAndMissingFeatures(Wt::Dbo::Session& session)
{
Wt::Dbo::collection<pointer> res = session.query<pointer>
("SELECT t FROM track t")
.where("LENGTH(t.mbid) > 0")
.where("NOT EXISTS (SELECT * FROM track_feature t_f WHERE t_f.track_id = t.id)");
return std::vector<pointer>(res.begin(), res.end());
}
std::vector<Track::pointer>
Track::getAllWithFeatures(Wt::Dbo::Session& session)
{
Wt::Dbo::collection<pointer> res = session.query<pointer>
("SELECT t FROM track t")
.where("EXISTS (SELECT * from track_feature t_f WHERE t_f.track_id = t.id)");
return std::vector<pointer>(res.begin(), res.end());
}
std::vector<Cluster::pointer>
Track::getClusters(void) const
{
@@ -115,6 +135,12 @@ Track::getClusters(void) const
return clusters;
}
bool
Track::hasTrackFeatures() const
{
return !_trackFeatures.empty();
}
static
Wt::Dbo::Query< Track::pointer >
getQuery(Wt::Dbo::Session& session,
@@ -236,6 +262,18 @@ Track::getCopyrightURL() const
return _copyrightURL != "" ? boost::make_optional<std::string>(_copyrightURL) : boost::none;
}
Wt::Dbo::ptr<TrackFeature>
Track::getTrackFeature(Wt::Dbo::ptr<TrackFeatureType> type) const
{
assert(self());
assert(IdIsValid(self()->id()));
assert(session());
return session()->find<TrackFeature>()
.where("type_id = ?").bind(type.id())
.where("track_id = ?").bind(self()->id());
}
std::vector<std::vector<Cluster::pointer>>
Track::getClusterGroups(std::vector<ClusterType::pointer> clusterTypes, std::size_t size) const
{
+17 -3
View File
@@ -36,15 +36,17 @@ namespace Database {
class Artist;
class Cluster;
class ClusterType;
class TrackListEntry;
class Release;
class TrackFeature;
class TrackFeatureType;
class TrackListEntry;
class TrackStats;
class Track : public Wt::Dbo::Dbo<Track>
{
public:
typedef Wt::Dbo::ptr<Track> pointer;
using pointer = Wt::Dbo::ptr<Track>;
Track() {}
Track(const boost::filesystem::path& p);
@@ -68,6 +70,8 @@ class Track : public Wt::Dbo::Dbo<Track>
static std::vector<pointer> getMBIDDuplicates(Wt::Dbo::Session& session);
static std::vector<pointer> getChecksumDuplicates(Wt::Dbo::Session& session);
static std::vector<pointer> getLastAdded(Wt::Dbo::Session& session, Wt::WDateTime after, int size = 1);
static std::vector<pointer> getAllWithMBIDAndMissingFeatures(Wt::Dbo::Session& session); // nested transaction
static std::vector<pointer> getAllWithFeatures(Wt::Dbo::Session& session); // nested transaction
// Create utility
static pointer create(Wt::Dbo::Session& session, const boost::filesystem::path& p);
@@ -76,7 +80,8 @@ class Track : public Wt::Dbo::Dbo<Track>
static void removeClusters(std::string type);
// Accessors
void setScanVersion(std::size_t version) {_scanVersion = version; }
void setScanVersion(std::size_t version) { _scanVersion = version; }
void setSimilarityScanVersion(std::size_t version) { _similarityScanVersion = version; }
void setTrackNumber(int num) { _trackNumber = num; }
void setTotalTrackNumber(int num) { _totalTrackNumber = num; }
void setDiscNumber(int num) { _discNumber = num; }
@@ -96,8 +101,10 @@ class Track : public Wt::Dbo::Dbo<Track>
void setArtist(Wt::Dbo::ptr<Artist> artist) { _artist = artist; }
void setRelease(Wt::Dbo::ptr<Release> release) { _release = release; }
void eraseClusters() { _clusters.clear(); }
void eraseFeatures() { _trackFeatures.clear(); }
std::size_t getScanVersion() const { return _scanVersion; }
std::size_t getSimilarityScanVersion() const { return _similarityScanVersion; }
boost::optional<std::size_t> getTrackNumber() const;
boost::optional<std::size_t> getTotalTrackNumber() const;
boost::optional<std::size_t> getDiscNumber() const;
@@ -117,6 +124,9 @@ class Track : public Wt::Dbo::Dbo<Track>
Wt::Dbo::ptr<Artist> getArtist() const { return _artist; }
Wt::Dbo::ptr<Release> getRelease() const { return _release; }
std::vector<Wt::Dbo::ptr<Cluster>> getClusters() const;
std::vector<Wt::Dbo::ptr<TrackFeature>> getTrackFeatures() const; // ordered by feature's name
bool hasTrackFeatures() const;
Wt::Dbo::ptr<TrackFeature> getTrackFeature(Wt::Dbo::ptr<TrackFeatureType> type) const;
std::vector<std::vector<Wt::Dbo::ptr<Cluster>>> getClusterGroups(std::vector<Wt::Dbo::ptr<ClusterType>> clusterTypes, std::size_t size) const;
@@ -124,6 +134,7 @@ class Track : public Wt::Dbo::Dbo<Track>
void persist(Action& a)
{
Wt::Dbo::field(a, _scanVersion, "scan_version");
Wt::Dbo::field(a, _similarityScanVersion, "similarity_version");
Wt::Dbo::field(a, _trackNumber, "track_number");
Wt::Dbo::field(a, _totalTrackNumber, "total_track_number");
Wt::Dbo::field(a, _discNumber, "disc_number");
@@ -145,6 +156,7 @@ class Track : public Wt::Dbo::Dbo<Track>
Wt::Dbo::belongsTo(a, _artist, "artist", Wt::Dbo::OnDeleteCascade);
Wt::Dbo::hasMany(a, _clusters, Wt::Dbo::ManyToMany, "track_cluster", "", Wt::Dbo::OnDeleteCascade);
Wt::Dbo::hasMany(a, _playlistEntries, Wt::Dbo::ManyToOne, "track");
Wt::Dbo::hasMany(a, _trackFeatures, Wt::Dbo::ManyToOne, "track");
}
private:
@@ -154,6 +166,7 @@ class Track : public Wt::Dbo::Dbo<Track>
static const std::size_t _maxCopyrightURLLength = 128;
int _scanVersion = 0;
int _similarityScanVersion = 0;
int _trackNumber = 0;
int _totalTrackNumber = 0;
int _discNumber = 0;
@@ -178,6 +191,7 @@ class Track : public Wt::Dbo::Dbo<Track>
Wt::Dbo::ptr<Release> _release;
Wt::Dbo::collection<Wt::Dbo::ptr<Cluster>> _clusters;
Wt::Dbo::collection<Wt::Dbo::ptr<TrackListEntry>> _playlistEntries;
Wt::Dbo::collection<Wt::Dbo::ptr<TrackFeature>> _trackFeatures;
};
+58
View File
@@ -0,0 +1,58 @@
/*
* Copyright (C) 2018 Emeric Poupon
*
* This file is part of LMS.
*
* LMS 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.
*
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include "TrackFeature.hpp"
#include "SimilaritySettings.hpp"
#include "Track.hpp"
namespace Database {
TrackFeatureType::TrackFeatureType(std::string name)
: _name(name)
{
}
TrackFeatureType::pointer
TrackFeatureType::getByName(Wt::Dbo::Session& session, std::string name)
{
return session.find<TrackFeatureType>().where("name = ?").bind(name);
}
TrackFeatureType::pointer
TrackFeatureType::create(Wt::Dbo::Session& session, std::string name)
{
return session.add(std::make_unique<TrackFeatureType>(name));
}
TrackFeature::TrackFeature(Wt::Dbo::ptr<TrackFeatureType> type, Wt::Dbo::ptr<Track> track, double value)
: _type(type),
_track(track),
_value(value)
{
}
TrackFeature::pointer
TrackFeature::create(Wt::Dbo::Session& session, Wt::Dbo::ptr<TrackFeatureType> type, Wt::Dbo::ptr<Track> track, double value)
{
return session.add(std::make_unique<TrackFeature>(type, track, value));
}
} // namespace Database
+97
View File
@@ -0,0 +1,97 @@
/*
* Copyright (C) 2018 Emeric Poupon
*
* This file is part of LMS.
*
* LMS 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.
*
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
#include <Wt/Dbo/Dbo.h>
#include "Types.hpp"
namespace Database {
class Track;
class SimilaritySettings;
class TrackFeatureType : public Wt::Dbo::Dbo<TrackFeatureType>
{
public:
using pointer = Wt::Dbo::ptr<TrackFeatureType>;
TrackFeatureType() = default;
TrackFeatureType(std::string name);
// Find utility
static pointer getByName(Wt::Dbo::Session& session, std::string name);
// Create utility
static pointer create(Wt::Dbo::Session& session, std::string name);
// Accessors
const std::string& getName() const { return _name; }
template<class Action>
void persist(Action& a)
{
Wt::Dbo::field(a, _name, "name");
Wt::Dbo::belongsTo(a, _similaritySettings, "similarity_settings", Wt::Dbo::OnDeleteCascade);
}
private:
std::string _name;
Wt::Dbo::ptr<SimilaritySettings> _similaritySettings;
};
class TrackFeature : public Wt::Dbo::Dbo<TrackFeature>
{
public:
using pointer = Wt::Dbo::ptr<TrackFeature>;
TrackFeature() = default;
TrackFeature(Wt::Dbo::ptr<TrackFeatureType> type, Wt::Dbo::ptr<Track> track, double value);
// Create utility
static pointer create(Wt::Dbo::Session& session, Wt::Dbo::ptr<TrackFeatureType> type, Wt::Dbo::ptr<Track> track, double value);
Wt::Dbo::ptr<TrackFeatureType> getType() const { return _type; }
double getValue() const { return _value; }
template<class Action>
void persist(Action& a)
{
Wt::Dbo::field(a, _value, "value");
Wt::Dbo::belongsTo(a, _type, "type", Wt::Dbo::OnDeleteCascade);
Wt::Dbo::belongsTo(a, _track, "track", Wt::Dbo::OnDeleteCascade);
}
private:
Wt::Dbo::ptr<TrackFeatureType> _type;
Wt::Dbo::ptr<Track> _track;
double _value = 0.;
};
} // namespace database