Prepare the customization of the cluster types

This commit is contained in:
emeric
2018-05-06 16:09:29 +02:00
parent aa19caffbd
commit a4969c134b
4 changed files with 125 additions and 41 deletions
+109 -37
View File
@@ -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<std::string> 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<std::string> 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<UpdatePeriod>(Setting::getInt(session, "update_period", static_cast<int>(UpdatePeriod::Never)));
return static_cast<UpdatePeriod>(Setting::getInt(session, updatePeriodSetting, static_cast<int>(UpdatePeriod::Never)));
}
void
setUpdatePeriod(Wt::Dbo::Session& session, UpdatePeriod updatePeriod)
{
Setting::setInt(session, "update_period", static_cast<int>(updatePeriod));
Setting::setInt(session, updatePeriodSetting, static_cast<int>(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 = 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 = 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)
{
+4 -3
View File
@@ -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<Database::Cluster::pointer> 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<std::string> _clusterTypes;
std::vector<boost::filesystem::path> _fileExtensions;
std::vector<boost::filesystem::path> _rootDirectories;
+9 -1
View File
@@ -20,10 +20,12 @@
#include <string>
#include <sstream>
#include <iomanip>
#include <iostream>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string.hpp>
#include <iostream>
#include "Utils.hpp"
bool readList(const std::string& str, const std::string& separators, std::list<std::string>& results)
@@ -62,6 +64,12 @@ splitString(std::string string, std::string separators)
return res;
}
std::string
joinStrings(std::vector<std::string> strings, std::string delimiter)
{
return boost::algorithm::join(strings, delimiter);
}
std::string
stringTrim(const std::string& str, const std::string& whitespace)
{
+3
View File
@@ -35,6 +35,9 @@ readList(const std::string& str, const std::string& separators, std::list<std::s
std::vector<std::string>
splitString(std::string string, std::string separators);
std::string
joinStrings(std::vector<std::string> strings, std::string delimiter);
std::string
stringTrim(const std::string& str, const std::string& whitespaces = " \t");