From a4969c134bc54f24375e62a9e30e959ad4f2d033 Mon Sep 17 00:00:00 2001 From: emeric Date: Sun, 6 May 2018 16:09:29 +0200 Subject: [PATCH] Prepare the customization of the cluster types --- src/scanner/MediaScanner.cpp | 146 ++++++++++++++++++++++++++--------- src/scanner/MediaScanner.hpp | 7 +- src/utils/Utils.cpp | 10 ++- src/utils/Utils.hpp | 3 + 4 files changed, 125 insertions(+), 41 deletions(-) diff --git a/src/scanner/MediaScanner.cpp b/src/scanner/MediaScanner.cpp index 9e3a7d56..1d3819f9 100644 --- a/src/scanner/MediaScanner.cpp +++ b/src/scanner/MediaScanner.cpp @@ -37,6 +37,35 @@ namespace { +const std::string updatePeriodSetting = "update_period"; +const std::string updateStartTimeSetting = "update_start_time"; +const std::string clustersSetting = "clusters"; +const std::string fileExtensionsSetting = "file_extensions"; + +const std::vector defaultFileExtensions = +{ + ".mp3", + ".ogg", + ".oga", + ".aac", + ".m4a", + ".flac", + ".wav", + ".wma", + ".aif", + ".aiff", + ".ape", + ".mpc", + ".shn", +}; + +// Caution current implementation prevents spaces with the names +const std::vector defaultClusters = +{ + "Genre", + "Group", +}; + Wt::WDate getNextMonday(Wt::WDate current) { @@ -99,23 +128,23 @@ using namespace Database; UpdatePeriod getUpdatePeriod(Wt::Dbo::Session& session) { - return static_cast(Setting::getInt(session, "update_period", static_cast(UpdatePeriod::Never))); + return static_cast(Setting::getInt(session, updatePeriodSetting, static_cast(UpdatePeriod::Never))); } void setUpdatePeriod(Wt::Dbo::Session& session, UpdatePeriod updatePeriod) { - Setting::setInt(session, "update_period", static_cast(updatePeriod)); + Setting::setInt(session, updatePeriodSetting, static_cast(updatePeriod)); } Wt::WTime getUpdateStartTime(Wt::Dbo::Session& session) { - return Setting::getTime(session, "update_start_time"); + return Setting::getTime(session, updateStartTimeSetting); } void setUpdateStartTime(Wt::Dbo::Session& session, Wt::WTime startTime) { - Setting::setTime(session, "update_start_time", startTime); + Setting::setTime(session, updateStartTimeSetting, startTime); } MediaScanner::MediaScanner(Wt::Dbo::SqlConnectionPool& connectionPool) @@ -127,8 +156,11 @@ _db(connectionPool) Wt::Dbo::Transaction transaction(_db.getSession()); - if (!Setting::exists(_db.getSession(), "file_extensions")) - Setting::setString(_db.getSession(), "file_extensions", ".mp3 .ogg .oga .aac .m4a .flac .wav .wma .aif .aiff .ape .mpc .shn" ); + if (!Setting::exists(_db.getSession(), fileExtensionsSetting)) + Setting::setString(_db.getSession(), fileExtensionsSetting, joinStrings(defaultFileExtensions, " ")); + + if (!Setting::exists(_db.getSession(), clustersSetting)) + Setting::setString(_db.getSession(), clustersSetting, joinStrings(defaultClusters, " ")); } void @@ -244,11 +276,17 @@ MediaScanner::scan(boost::system::error_code err) if (err) return; + LMS_LOG(UI, INFO) << "New scan started!"; + refreshScanSettings(); + bool forceScan = false; Stats stats; checkAudioFiles(stats); + forceScan = checkClusters(); + + LMS_LOG(UI, INFO) << "Checks complete, force scan = " << forceScan; for (auto rootDirectory : _rootDirectories) { @@ -256,7 +294,7 @@ MediaScanner::scan(boost::system::error_code err) break; LMS_LOG(DBUPDATER, INFO) << "scaning root directory '" << rootDirectory.string() << "'..."; - scanRootDirectory(rootDirectory, stats); + scanRootDirectory(rootDirectory, forceScan, stats); LMS_LOG(DBUPDATER, INFO) << "scaning root directory '" << rootDirectory.string() << "' DONE"; } @@ -280,12 +318,16 @@ MediaScanner::refreshScanSettings() Wt::Dbo::Transaction transaction(_db.getSession()); _fileExtensions.clear(); - for (auto extension : splitString(Setting::getString(_db.getSession(), "file_extensions"), " ")) + for (auto extension : splitString(Setting::getString(_db.getSession(), fileExtensionsSetting), " ")) _fileExtensions.push_back( extension ); _rootDirectories.clear(); for (auto rootDir : Database::MediaDirectory::getAll(_db.getSession())) _rootDirectories.push_back(rootDir->getPath()); + + _clusterTypes.clear(); + for (auto cluster : splitString(Setting::getString(_db.getSession(), clustersSetting), " ")) + _clusterTypes.push_back(cluster); } Artist::pointer @@ -369,17 +411,13 @@ MediaScanner::getClusters( const MetaData::Clusters& clustersNames) for (auto clusterNames : clustersNames) { - ClusterType::pointer clusterType = ClusterType::getByName(_db.getSession(), clusterNames.first); + auto clusterType = ClusterType::getByName(_db.getSession(), clusterNames.first); if (!clusterType) - { - clusterType = ClusterType::create(_db.getSession(), clusterNames.first); - _db.getSession().flush(); // Make sure the newly createdType has an id - } + continue; for (auto clusterName : clusterNames.second) { - Cluster::pointer cluster = clusterType->getCluster(clusterName); - + auto cluster = clusterType->getCluster(clusterName); if (!cluster) cluster = Cluster::create(_db.getSession(), clusterType, clusterName); @@ -391,20 +429,23 @@ MediaScanner::getClusters( const MetaData::Clusters& clustersNames) } void -MediaScanner::scanAudioFile( const boost::filesystem::path& file, Stats& stats) +MediaScanner::scanAudioFile(const boost::filesystem::path& file, bool forceScan, Stats& stats) { auto lastWriteTime = Wt::WDateTime::fromTime_t(boost::filesystem::last_write_time(file)); - // Skip file if last write is the same + if (!forceScan) { - Wt::Dbo::Transaction transaction(_db.getSession()); - - Wt::Dbo::ptr track = Track::getByPath(_db.getSession(), file); - - if (track && track->getLastWriteTime() == lastWriteTime) + // Skip file if last write is the same { - stats.skips++; - return; + Wt::Dbo::Transaction transaction(_db.getSession()); + + Wt::Dbo::ptr track = Track::getByPath(_db.getSession(), file); + + if (track && track->getLastWriteTime() == lastWriteTime) + { + stats.skips++; + return; + } } } @@ -601,7 +642,7 @@ MediaScanner::scanAudioFile( const boost::filesystem::path& file, Stats& stats) } void -MediaScanner::scanRootDirectory(boost::filesystem::path rootDirectory, Stats& stats) +MediaScanner::scanRootDirectory(boost::filesystem::path rootDirectory, bool forceScan, Stats& stats) { boost::system::error_code ec; @@ -619,7 +660,7 @@ MediaScanner::scanRootDirectory(boost::filesystem::path rootDirectory, Stats& st if (boost::filesystem::is_regular(path)) { if (isFileSupported(path, _fileExtensions)) - scanAudioFile(path, stats ); + scanAudioFile(path, forceScan, stats ); } } } @@ -702,7 +743,7 @@ MediaScanner::checkAudioFiles( Stats& stats ) } } - LMS_LOG(DBUPDATER, DEBUG) << "Checking Clusters..."; + LMS_LOG(DBUPDATER, DEBUG) << "Checking orphan clusters..."; { Wt::Dbo::Transaction transaction(_db.getSession()); @@ -717,17 +758,9 @@ MediaScanner::checkAudioFiles( Stats& stats ) cluster.remove(); } } - - // Now process orphan cluster types - auto clusterTypes = ClusterType::getAllOrphans(_db.getSession()); - for (auto clusterType : clusterTypes) - { - LMS_LOG(DBUPDATER, DEBUG) << "Removing orphan cluster type '" << clusterType->getName() << "'"; - clusterType.remove(); - } } - LMS_LOG(DBUPDATER, DEBUG) << "Checking artists..."; + LMS_LOG(DBUPDATER, DEBUG) << "Checking orphan artists..."; { Wt::Dbo::Transaction transaction(_db.getSession()); @@ -739,7 +772,7 @@ MediaScanner::checkAudioFiles( Stats& stats ) } } - LMS_LOG(DBUPDATER, DEBUG) << "Checking releases..."; + LMS_LOG(DBUPDATER, DEBUG) << "Checking orphan releases..."; { Wt::Dbo::Transaction transaction(_db.getSession()); @@ -754,6 +787,45 @@ MediaScanner::checkAudioFiles( Stats& stats ) LMS_LOG(DBUPDATER, INFO) << "Check audio files done!"; } +bool +MediaScanner::checkClusters() +{ + bool hasChanges = false; + + LMS_LOG(DBUPDATER, INFO) << "Checking clusters"; + + Wt::Dbo::Transaction transaction(_db.getSession()); + auto clusterTypes = ClusterType::getAll(_db.getSession()); + + // Remove no longer desired clusters + for (auto clusterType : clusterTypes) + { + if (std::none_of(_clusterTypes.begin(), _clusterTypes.end(), + [&clusterType](std::string clusterTypeName) { return clusterTypeName == clusterType->getName(); })) + { + LMS_LOG(DBUPDATER, INFO) << "Removing cluster type " << clusterType->getName(); + clusterType.remove(); + hasChanges = true; + } + } + + // Add any missing clusters + for (auto clusterTypeName : _clusterTypes) + { + if (std::none_of(clusterTypes.begin(), clusterTypes.end(), + [&clusterTypeName](ClusterType::pointer clusterType) { return (clusterType->getName() == clusterTypeName); })) + { + LMS_LOG(DBUPDATER, INFO) << "Creating cluster type " << clusterTypeName; + ClusterType::create(_db.getSession(), clusterTypeName); + hasChanges = true; + } + } + + LMS_LOG(DBUPDATER, INFO) << "Checking clusters done!"; + + return hasChanges; +} + void MediaScanner::checkDuplicatedAudioFiles(Stats& stats) { diff --git a/src/scanner/MediaScanner.hpp b/src/scanner/MediaScanner.hpp index 79c200d5..9d8cfa3d 100644 --- a/src/scanner/MediaScanner.hpp +++ b/src/scanner/MediaScanner.hpp @@ -100,7 +100,7 @@ class MediaScanner // Update database (scheduled callback) void scan(boost::system::error_code ec); - void scanRootDirectory( boost::filesystem::path rootDirectory, Stats& stats); + void scanRootDirectory( boost::filesystem::path rootDirectory, bool forceScan, Stats& stats); // Helpers Database::Artist::pointer getArtist( const boost::filesystem::path& file, const std::string& name, const std::string& MBID); @@ -108,10 +108,10 @@ class MediaScanner std::vector getClusters( const MetaData::Clusters& names); void refreshScanSettings(); - // Audio void checkAudioFiles( Stats& stats ); + bool checkClusters(); void checkDuplicatedAudioFiles( Stats& stats ); - void scanAudioFile( const boost::filesystem::path& file, Stats& stats); + void scanAudioFile( const boost::filesystem::path& file, bool forceScan, Stats& stats); bool _running; Wt::WIOService _ioService; @@ -126,6 +126,7 @@ class MediaScanner Database::Handler _db; // Scan settings + std::vector _clusterTypes; std::vector _fileExtensions; std::vector _rootDirectories; diff --git a/src/utils/Utils.cpp b/src/utils/Utils.cpp index a027b6f8..d1013209 100644 --- a/src/utils/Utils.cpp +++ b/src/utils/Utils.cpp @@ -20,10 +20,12 @@ #include #include #include +#include #include +#include #include -#include + #include "Utils.hpp" bool readList(const std::string& str, const std::string& separators, std::list& results) @@ -62,6 +64,12 @@ splitString(std::string string, std::string separators) return res; } +std::string +joinStrings(std::vector strings, std::string delimiter) +{ + return boost::algorithm::join(strings, delimiter); +} + std::string stringTrim(const std::string& str, const std::string& whitespace) { diff --git a/src/utils/Utils.hpp b/src/utils/Utils.hpp index d5ab7d63..cba5fe91 100644 --- a/src/utils/Utils.hpp +++ b/src/utils/Utils.hpp @@ -35,6 +35,9 @@ readList(const std::string& str, const std::string& separators, std::list splitString(std::string string, std::string separators); +std::string +joinStrings(std::vector strings, std::string delimiter); + std::string stringTrim(const std::string& str, const std::string& whitespaces = " \t");