diff --git a/TODO b/TODO
index 15b32001..d55ee917 100644
--- a/TODO
+++ b/TODO
@@ -12,6 +12,8 @@
- handle access rights problems (instead of aborting)
- add a global play counter for tracks. This will help people to spot most popular files
- Use the WServer::post method to notify the end of the database scan? (with results?)
+- Make clusters based on different metadata (albumgrouping, genre, mood, etc.). Make it configurable somewhere as it is very difficult to handle them all?
+- Use albumartist when available (useful for compilations)
[Metadata]
- WMA covers: add support
@@ -31,6 +33,8 @@
- Add a hint for the user to get the nature of tag (created from genre ? created from audio features?)
- Implement a play queue
- Implement a decent player
+ - Tags cloud for artist/release
+ - Dedicate a color for each tag type
[REST API]
- Make a dedicated REST API. Maybe use the SubSonic API or Ampache API?
diff --git a/src/Makefile.am b/src/Makefile.am
index 54f36b85..7842e2dd 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -15,14 +15,12 @@ lms_SOURCES = \
$(srcdir)/database/SqlQuery.cpp \
$(srcdir)/database/Track.cpp \
$(srcdir)/database/User.cpp \
- $(srcdir)/database/updater/DatabaseUpdater.cpp \
- $(srcdir)/database/updater/DatabaseFeatureExtractor.cpp \
- $(srcdir)/database/updater/DatabaseHighLevelCluster.cpp \
$(srcdir)/feature/FeatureExtractor.cpp \
$(srcdir)/feature/FeatureStore.cpp \
$(srcdir)/image/Image.cpp \
$(srcdir)/metadata/AvFormat.cpp \
$(srcdir)/metadata/TagLibParser.cpp \
+ $(srcdir)/scanner/MediaScanner.cpp \
$(srcdir)/ui/ArtistView.cpp \
$(srcdir)/ui/ArtistsView.cpp \
$(srcdir)/ui/Explore.cpp \
diff --git a/src/database/DatabaseHandler.cpp b/src/database/DatabaseHandler.cpp
index 85164449..c063bbf0 100644
--- a/src/database/DatabaseHandler.cpp
+++ b/src/database/DatabaseHandler.cpp
@@ -17,6 +17,8 @@
* along with LMS. If not, see .
*/
+#include
+
#include
#include
@@ -83,22 +85,25 @@ Handler::Handler(Wt::Dbo::SqlConnectionPool& connectionPool)
_session.mapClass("artist");
_session.mapClass("cluster");
- _session.mapClass("track");
+ _session.mapClass("cluster_type");
+ _session.mapClass("media_directory");
_session.mapClass("playlist");
_session.mapClass("playlist_entry");
_session.mapClass("release");
- _session.mapClass("media_directory");
_session.mapClass("setting");
+ _session.mapClass("track");
- _session.mapClass("user");
_session.mapClass("auth_info");
_session.mapClass("auth_identity");
_session.mapClass("auth_token");
+ _session.mapClass("user");
try {
Wt::Dbo::Transaction transaction(_session);
_session.createTables();
+
+ LMS_LOG(DB, INFO) << "Tables created";
}
catch(std::exception& e) {
LMS_LOG(DB, ERROR) << "Cannot create tables: " << e.what();
@@ -108,21 +113,17 @@ Handler::Handler(Wt::Dbo::SqlConnectionPool& connectionPool)
Wt::Dbo::Transaction transaction(_session);
// Indexes
- _session.execute("PRAGMA journal_mode=WAL");
+ // _session.execute("PRAGMA journal_mode=WAL");
_session.execute("CREATE INDEX IF NOT EXISTS track_path_idx ON track(file_path)");
_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_type_idx ON cluster(type)");
+ _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)");
+ // TODO move this
// Default values
- if (!Setting::exists(_session, "audio_file_extensions"))
- Setting::setString(_session, "audio_file_extensions", ".mp3 .ogg .oga .aac .m4a .flac .wav .wma .aif .aiff .ape .mpc .shn" );
-
- if (!Setting::exists(_session, "video_file_extensions"))
- Setting::setString(_session, "video_file_extensions", ".flv .avi .mpg .mpeg .mp4 .m4v .mkv .mov .wmv .ogv .divx .m2ts");
-
if (!Setting::exists(_session, "tags_highlevel_acousticbrainz"))
Setting::setBool(_session, "tags_highlevel_acousticbrainz", true);
@@ -184,7 +185,7 @@ Handler::createConnectionPool(boost::filesystem::path p)
Wt::Dbo::backend::Sqlite3 *connection = new Wt::Dbo::backend::Sqlite3(p.string());
- connection->executeSql("pragma journal_mode=WAL");
+// connection->executeSql("pragma journal_mode=WAL");
connection->setProperty("show-queries", "true");
return new Wt::Dbo::FixedSqlConnectionPool(connection, 1);
diff --git a/src/database/DatabaseHandler.hpp b/src/database/DatabaseHandler.hpp
index 6b07984e..28f5600a 100644
--- a/src/database/DatabaseHandler.hpp
+++ b/src/database/DatabaseHandler.hpp
@@ -21,6 +21,7 @@
#define DATABASE_HANDLER_HPP
#include
+#include
#include
#include
diff --git a/src/database/MediaDirectory.cpp b/src/database/MediaDirectory.cpp
index cd2a0cc2..88b30e88 100644
--- a/src/database/MediaDirectory.cpp
+++ b/src/database/MediaDirectory.cpp
@@ -23,16 +23,15 @@
namespace Database {
-MediaDirectory::MediaDirectory(boost::filesystem::path p, Type type)
-: _type(type),
- _path(stringTrimEnd(p.string(), "/\\"))
+MediaDirectory::MediaDirectory(boost::filesystem::path p)
+: _path(stringTrimEnd(p.string(), "/\\"))
{
}
MediaDirectory::pointer
-MediaDirectory::create(Wt::Dbo::Session& session, boost::filesystem::path p, Type type)
+MediaDirectory::create(Wt::Dbo::Session& session, boost::filesystem::path p)
{
- return session.add( new MediaDirectory( p, type ) );
+ return session.add( new MediaDirectory(p) );
}
void
@@ -50,20 +49,6 @@ MediaDirectory::getAll(Wt::Dbo::Session& session)
return std::vector(res.begin(), res.end());
}
-std::vector
-MediaDirectory::getByType(Wt::Dbo::Session& session, Type type)
-{
- Wt::Dbo::collection< MediaDirectory::pointer > res = session.find().where("type = ?").bind (type);
-
- return std::vector(res.begin(), res.end());
-}
-
-MediaDirectory::pointer
-MediaDirectory::get(Wt::Dbo::Session& session, boost::filesystem::path p, Type type)
-{
- return session.find().where("path = ?").where("type = ?").bind( p.string()).bind(type);
-}
-
boost::filesystem::path
MediaDirectory::getPath(void) const
{
diff --git a/src/database/MediaDirectory.hpp b/src/database/MediaDirectory.hpp
index e00892dd..3bc2e497 100644
--- a/src/database/MediaDirectory.hpp
+++ b/src/database/MediaDirectory.hpp
@@ -31,39 +31,29 @@ namespace Database {
class MediaDirectory
{
public:
-
typedef Wt::Dbo::ptr pointer;
- enum Type {
- Audio = 1,
- };
-
MediaDirectory() {}
- MediaDirectory(boost::filesystem::path p, Type type);
+ MediaDirectory(boost::filesystem::path p);
// Accessors
- static pointer create(Wt::Dbo::Session& session, boost::filesystem::path p, Type type);
+ static pointer create(Wt::Dbo::Session& session, boost::filesystem::path p);
static std::vector getAll(Wt::Dbo::Session& session);
- static std::vector getByType(Wt::Dbo::Session& session, Type type);
- static pointer get(Wt::Dbo::Session& session, boost::filesystem::path p, Type type);
static void eraseAll(Wt::Dbo::Session& session);
+ static void eraseByPath(Wt::Dbo::Session& session, boost::filesystem::path p);
- Type getType(void) const { return _type; }
boost::filesystem::path getPath(void) const;
template
void persist(Action& a)
{
- Wt::Dbo::field(a, _type, "type");
Wt::Dbo::field(a, _path, "path");
}
private:
- Type _type;
std::string _path;
-
};
} // namespace Database
diff --git a/src/database/Track.cpp b/src/database/Track.cpp
index 5853a293..d913980f 100644
--- a/src/database/Track.cpp
+++ b/src/database/Track.cpp
@@ -224,44 +224,24 @@ Cluster::Cluster()
{
}
-Cluster::Cluster(std::string type, std::string name)
-:
-_type( std::string(type, 0, _maxTypeLength)),
-_name( std::string(name, 0, _maxNameLength))
+Cluster::Cluster(Wt::Dbo::ptr type, std::string name)
+ : _name(std::string(name, 0, _maxNameLength)),
+ _clusterType(type)
{
}
-Wt::Dbo::collection
-Cluster::getAll(Wt::Dbo::Session& session)
-{
- return session.find();
-}
-
Cluster::pointer
-Cluster::get(Wt::Dbo::Session& session, std::string type, std::string name)
-{
- // TODO use like search
- return session.find().where("type = ?").where("name = ?").bind( std::string(type, 0, _maxTypeLength)).bind( std::string(name, 0, _maxNameLength));
-}
-
-std::vector
-Cluster::getByType(Wt::Dbo::Session& session, std::string type)
-{
- Wt::Dbo::collection res = session.find().where("type = ?").bind( std::string(type, 0, _maxTypeLength)).orderBy("name");
- return std::vector(res.begin(), res.end());
-}
-
-Cluster::pointer
-Cluster::create(Wt::Dbo::Session& session, std::string type, std::string name)
+Cluster::create(Wt::Dbo::Session& session, Wt::Dbo::ptr type, std::string name)
{
return session.add(new Cluster(type, name));
}
-void
-Cluster::remove(Wt::Dbo::Session& session, std::string type)
+std::vector
+Cluster::getAll(Wt::Dbo::Session& session)
{
- Wt::Dbo::Transaction transaction(session);
- session.execute("DELETE FROM cluster WHERE type = ?").bind(type);
+ Wt::Dbo::collection res = session.find();
+
+ return std::vector(res.begin(), res.end());
}
Wt::Dbo::Query
@@ -278,15 +258,6 @@ Cluster::getQuery(Wt::Dbo::Session& session, SearchFilter filter)
return query;
}
-std::vector
-Cluster::getAllTypes(Wt::Dbo::Session& session)
-{
- Wt::Dbo::collection res
- = session.query("SELECT type from cluster").groupBy("type").orderBy("type");
-
- return std::vector(res.begin(), res.end());
-}
-
std::vector
Cluster::getByFilter(Wt::Dbo::Session& session, SearchFilter filter, int offset, int size)
{
@@ -295,6 +266,56 @@ Cluster::getByFilter(Wt::Dbo::Session& session, SearchFilter filter, int offset,
return std::vector(res.begin(), res.end());
}
+ClusterType::ClusterType(std::string name)
+ : _name(name)
+{
+}
+
+ClusterType::pointer
+ClusterType::getByName(Wt::Dbo::Session& session, std::string name)
+{
+ return session.find().where("name = ?").bind(name);
+}
+
+std::vector
+ClusterType::getAll(Wt::Dbo::Session& session)
+{
+ Wt::Dbo::collection res = session.find();
+
+ return std::vector(res.begin(), res.end());
+}
+
+ClusterType::pointer
+ClusterType::create(Wt::Dbo::Session& session, std::string name)
+{
+ return session.add(new ClusterType(name));
+}
+
+Cluster::pointer
+ClusterType::getCluster(std::string name) const
+{
+ assert(self());
+ assert(self()->id() != Wt::Dbo::dbo_traits::invalidId() );
+ assert(session());
+
+ return session()->find()
+ .where("name = ?").bind(name)
+ .where("cluster_type_id = ").bind(self()->id());
+}
+
+std::vector
+ClusterType::getClusters() const
+{
+ assert(self());
+ assert(self()->id() != Wt::Dbo::dbo_traits::invalidId() );
+ assert(session());
+
+ Wt::Dbo::collection res = session()->find()
+ .where("cluster_type_id = ").bind(self()->id())
+ .orderBy("name");
+
+ return std::vector(res.begin(), res.end());
+}
} // namespace Database
diff --git a/src/database/Track.hpp b/src/database/Track.hpp
index 7c0f1bc2..878ef796 100644
--- a/src/database/Track.hpp
+++ b/src/database/Track.hpp
@@ -40,64 +40,89 @@ class Artist;
class Release;
class Track;
class PlaylistEntry;
+class ClusterType;
-class Cluster
+class Cluster : public Wt::Dbo::Dbo
{
public:
-
- enum class Type
- {
- Genre = 1,
- Mood = 2,
- };
-
typedef Wt::Dbo::ptr pointer;
typedef Wt::Dbo::dbo_traits::IdType id_type;
Cluster();
- Cluster(std::string type, std::string name);
+ Cluster(Wt::Dbo::ptr type, std::string name);
// Find utility
- static pointer get(Wt::Dbo::Session& session, std::string type, std::string name);
static std::vector getByFilter(Wt::Dbo::Session& session, SearchFilter filter, int offset = -1, int size = -1);
- static Wt::Dbo::collection getAll(Wt::Dbo::Session& session);
- static std::vector getAllTypes(Wt::Dbo::Session& session);
- static std::vector getByType(Wt::Dbo::Session& session, std::string type);
+ static std::vector getAll(Wt::Dbo::Session& session);
// Create utility
- static pointer create(Wt::Dbo::Session& session, std::string type, std::string name);
-
- // Remove utility
- static void remove(Wt::Dbo::Session& session, std::string type); // nested transaction
+ static pointer create(Wt::Dbo::Session& session, Wt::Dbo::ptr type, std::string name);
// Accessors
const std::string& getName(void) const { return _name; }
- const std::string& getType(void) const { return _type; }
- const Wt::Dbo::collection< Wt::Dbo::ptr