From 8a0ef211ac3eb0e031a801346514f27704724e3e Mon Sep 17 00:00:00 2001 From: epoupon Date: Tue, 13 Oct 2015 13:21:45 +0200 Subject: [PATCH] [UI] Added settings to select the audio/video files to be scanned using the file extensions --- approot/templates.xml | 24 +++++ src/database-updater/DatabaseUpdater.cpp | 33 +++---- src/database-updater/DatabaseUpdater.hpp | 8 +- src/database/MediaDirectory.cpp | 57 +++++++++++- src/database/MediaDirectory.hpp | 8 ++ src/ui/settings/Settings.cpp | 2 +- src/ui/settings/SettingsDatabaseFormView.cpp | 96 ++++++++++++++++---- 7 files changed, 187 insertions(+), 41 deletions(-) diff --git a/approot/templates.xml b/approot/templates.xml index b55f513b..1e9d1148 100644 --- a/approot/templates.xml +++ b/approot/templates.xml @@ -311,6 +311,30 @@ +
+ +
+ ${audio-file-extensions} +
+
+ ${audio-file-extensions-info} +
+
+ +
+ +
+ ${video-file-extensions} +
+
+ ${video-file-extensions-info} +
+
+
${apply-button} ${discard-button} ${immediate-scan-button} diff --git a/src/database-updater/DatabaseUpdater.cpp b/src/database-updater/DatabaseUpdater.cpp index c747713d..eba1e54b 100644 --- a/src/database-updater/DatabaseUpdater.cpp +++ b/src/database-updater/DatabaseUpdater.cpp @@ -128,20 +128,6 @@ _metadataParser(parser) _ioService.setThreadCount(1); } -void -Updater::setAudioExtensions(const std::vector& extensions) -{ - for (const std::string& extension : extensions) - _audioExtensions.push_back("." + extension); -} - -void -Updater::setVideoExtensions(const std::vector& extensions) -{ - for (const std::string& extension : extensions) - _videoExtensions.push_back("." + extension); -} - void Updater::start(void) { @@ -233,6 +219,8 @@ Updater::process(boost::system::error_code err) { if (!err) { + updateFileExtensions(); + Stats stats; checkAudioFiles(stats); @@ -284,6 +272,15 @@ Updater::process(boost::system::error_code err) } } +void +Updater::updateFileExtensions() +{ + Wt::Dbo::Transaction transaction(_db.getSession()); + + _audioFileExtensions = MediaDirectorySettings::get(_db.getSession())->getAudioFileExtensions(); + _videoFileExtensions = MediaDirectorySettings::get(_db.getSession())->getVideoFileExtensions(); +} + Artist::pointer Updater::getArtist( const boost::filesystem::path& file, const std::string& name, const std::string& mbid) { @@ -574,13 +571,13 @@ Updater::processRootDirectory(RootDirectory rootDirectory, Stats& stats) switch( rootDirectory.type ) { case Database::MediaDirectory::Audio: - if (isFileSupported(*itPath, _audioExtensions)) + if (isFileSupported(*itPath, _audioFileExtensions)) processAudioFile( *itPath, stats ); break; case Database::MediaDirectory::Video: - if (isFileSupported(*itPath, _videoExtensions)) + if (isFileSupported(*itPath, _videoFileExtensions)) processVideoFile( *itPath, stats); break; } @@ -655,7 +652,7 @@ Updater::checkAudioFiles( Stats& stats ) if (!_running) return; - if (!checkFile(trackPath, rootDirs, _audioExtensions)) + if (!checkFile(trackPath, rootDirs, _audioFileExtensions)) { Wt::Dbo::Transaction transaction(_db.getSession()); @@ -723,7 +720,7 @@ Updater::checkVideoFiles( Stats& stats ) if (!_running) return; - if (!checkFile(videoPath, rootDirs, _videoExtensions)) + if (!checkFile(videoPath, rootDirs, _videoFileExtensions)) { Wt::Dbo::Transaction transaction(_db.getSession()); diff --git a/src/database-updater/DatabaseUpdater.hpp b/src/database-updater/DatabaseUpdater.hpp index f614426b..ed90ebdf 100644 --- a/src/database-updater/DatabaseUpdater.hpp +++ b/src/database-updater/DatabaseUpdater.hpp @@ -80,6 +80,7 @@ class Updater Database::Artist::pointer getArtist( const boost::filesystem::path& file, const std::string& name, const std::string& MBID); Database::Release::pointer getRelease( const boost::filesystem::path& file, const std::string& name, const std::string& MBID); std::vector getGenres( const std::list& names); + void updateFileExtensions(); // Audio void checkAudioFiles( Stats& stats ); @@ -96,11 +97,8 @@ class Updater Database::Handler _db; - std::vector _audioExtensions - = {".mp3", ".ogg", ".oga", ".aac", ".m4a", ".flac", ".wav", ".wma", ".aif", ".aiff", ".ape", ".mpc", ".shn"}; // TODO parametrize - - std::vector _videoExtensions - = {".flv", ".avi", ".mpg", ".mpeg", ".mp4", ".m4v", ".mkv", ".mov", ".wmv", ".ogv", ".divx", ".m2ts"}; // TODO parametrize + std::vector _audioFileExtensions; + std::vector _videoFileExtensions; MetaData::Parser& _metadataParser; diff --git a/src/database/MediaDirectory.cpp b/src/database/MediaDirectory.cpp index ca4209a1..75f25724 100644 --- a/src/database/MediaDirectory.cpp +++ b/src/database/MediaDirectory.cpp @@ -21,11 +21,40 @@ #include "Types.hpp" +static std::string pathsToString(const std::vector& paths) +{ + std::ostringstream oss; + + bool first = true; + for (auto& path : paths) + { + if (!first) + oss << " "; + + oss << path.string(); + first = false; + } + + return oss.str(); +} + +static std::vector stringToPaths(const std::string value) +{ + std::vector res; + std::istringstream iss(value); + + std::copy(std::istream_iterator(iss), std::istream_iterator(), std::back_inserter(res)); + + return std::vector(res.begin(), res.end()); +} + namespace Database { MediaDirectorySettings::MediaDirectorySettings() : _manualScanRequested(false), -_updatePeriod(Never) +_updatePeriod(Never), +_audioFileExtensions(".mp3 .ogg .oga .aac .m4a .flac .wav .wma .aif .aiff .ape .mpc .shn"), +_videoFileExtensions(".flv .avi .mpg .mpeg .mp4 .m4v .mkv .mov .wmv .ogv .divx .m2ts") { } @@ -48,6 +77,31 @@ MediaDirectorySettings::get(Wt::Dbo::Session& session) return res; } +std::vector +MediaDirectorySettings::getAudioFileExtensions(void) const +{ + return stringToPaths(_audioFileExtensions); +} + +std::vector +MediaDirectorySettings::getVideoFileExtensions(void) const +{ + return stringToPaths(_videoFileExtensions); +} + +void +MediaDirectorySettings::setAudioFileExtensions(std::vector extensions) +{ + _audioFileExtensions = pathsToString(extensions); +} + +void +MediaDirectorySettings::setVideoFileExtensions(std::vector extensions) +{ + _videoFileExtensions = pathsToString(extensions); +} + + MediaDirectory::pointer MediaDirectory::create(Wt::Dbo::Session& session, boost::filesystem::path p, Type type) { @@ -84,4 +138,5 @@ MediaDirectory::get(Wt::Dbo::Session& session, boost::filesystem::path p, Type t return session.find().where("path = ?").where("type = ?").bind( p.string()).bind(type); } + } // namespace Database diff --git a/src/database/MediaDirectory.hpp b/src/database/MediaDirectory.hpp index 6eae74bb..f4085be5 100644 --- a/src/database/MediaDirectory.hpp +++ b/src/database/MediaDirectory.hpp @@ -55,6 +55,8 @@ class MediaDirectorySettings void setUpdateStartTime(boost::posix_time::time_duration dur) { _updateStartTime = dur;} void setLastUpdate(boost::posix_time::ptime time) { _lastUpdate = time; } void setLastScan(boost::posix_time::ptime time) { _lastScan = time; } + void setAudioFileExtensions(std::vector extensions); + void setVideoFileExtensions(std::vector extensions); // Read accessors bool getManualScanRequested(void) const { return _manualScanRequested; } @@ -62,6 +64,8 @@ class MediaDirectorySettings boost::posix_time::time_duration getUpdateStartTime(void) const { return _updateStartTime; } boost::posix_time::ptime getLastUpdated(void) const { return _lastUpdate; } boost::posix_time::ptime getLastScan(void) const { return _lastScan; } + std::vector getAudioFileExtensions(void) const; + std::vector getVideoFileExtensions(void) const; template void persist(Action& a) @@ -69,6 +73,8 @@ class MediaDirectorySettings Wt::Dbo::field(a, _manualScanRequested, "manual_scan_requested"); Wt::Dbo::field(a, _updatePeriod, "update_period"); Wt::Dbo::field(a, _updateStartTime, "update_start_time"); + Wt::Dbo::field(a, _audioFileExtensions, "audio_file_extensions"); + Wt::Dbo::field(a, _videoFileExtensions, "video_file_extensions"); Wt::Dbo::field(a, _lastUpdate, "last_update"); Wt::Dbo::field(a, _lastScan, "last_scan"); Wt::Dbo::hasMany(a, _mediaDirectories, Wt::Dbo::ManyToOne, "media_directory_settings"); @@ -79,6 +85,8 @@ class MediaDirectorySettings bool _manualScanRequested; // Immadiate scan has been requested by user UpdatePeriod _updatePeriod; // How long between updates boost::posix_time::time_duration _updateStartTime; // Time of day to begin the update + std::string _audioFileExtensions; // Extension of the audio files to be scanned + std::string _videoFileExtensions; // Extension of the video files to be scanned boost::posix_time::ptime _lastUpdate; // last time the database has changed boost::posix_time::ptime _lastScan; // last time the database has been scanned Wt::Dbo::collection< Wt::Dbo::ptr > _mediaDirectories; // list of media directories diff --git a/src/ui/settings/Settings.cpp b/src/ui/settings/Settings.cpp index bdde115b..c2e8d727 100644 --- a/src/ui/settings/Settings.cpp +++ b/src/ui/settings/Settings.cpp @@ -77,7 +77,7 @@ Settings::Settings(Wt::WContainerWidget* parent) DatabaseFormView* databaseFormView = new DatabaseFormView(); databaseFormView->changed().connect(this, &Settings::restartDatabaseUpdateService); - menu->addItem("Database Update", databaseFormView); + menu->addItem("Database", databaseFormView); menu->addItem("Users", new Users()); } diff --git a/src/ui/settings/SettingsDatabaseFormView.cpp b/src/ui/settings/SettingsDatabaseFormView.cpp index a2fafeb8..d0c8cb16 100644 --- a/src/ui/settings/SettingsDatabaseFormView.cpp +++ b/src/ui/settings/SettingsDatabaseFormView.cpp @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include @@ -37,12 +39,16 @@ namespace UserInterface { namespace Settings { +using namespace Database; + class DatabaseFormModel : public Wt::WFormModel { public: // Associate each field with a unique string literal. static const Field UpdatePeriodField; static const Field UpdateStartTimeField; + static const Field AudioFileExtensionsField; + static const Field VideoFileExtensionsField; DatabaseFormModel(Wt::WObject *parent = 0) : Wt::WFormModel(parent) @@ -51,9 +57,13 @@ class DatabaseFormModel : public Wt::WFormModel addField(UpdatePeriodField); addField(UpdateStartTimeField); + addField(AudioFileExtensionsField); + addField(VideoFileExtensionsField); - setValidator(UpdatePeriodField, createUpdatePeriodValidator()); - setValidator(UpdateStartTimeField, createStartTimeValidator()); + setValidator(UpdatePeriodField, createUpdatePeriodValidator()); + setValidator(UpdateStartTimeField, createStartTimeValidator()); + setValidator(AudioFileExtensionsField, createFileExtensionValidator()); + setValidator(VideoFileExtensionsField, createFileExtensionValidator()); // populate the model with initial data loadData(); @@ -67,7 +77,7 @@ class DatabaseFormModel : public Wt::WFormModel Wt::Dbo::Transaction transaction(DboSession()); // Get refresh settings - ::Database::MediaDirectorySettings::pointer settings = ::Database::MediaDirectorySettings::get(DboSession()); + MediaDirectorySettings::pointer settings = MediaDirectorySettings::get(DboSession()); int periodRow = getUpdatePeriodModelRow( settings->getUpdatePeriod() ); if (periodRow != -1) @@ -77,13 +87,30 @@ class DatabaseFormModel : public Wt::WFormModel if (startTimeRow != -1) setValue(UpdateStartTimeField, updateStartTime( startTimeRow ) ); + std::vector audioFileExtensions = settings->getAudioFileExtensions(); + { + std::ostringstream oss; + for (auto& fileExtension : audioFileExtensions) + oss << fileExtension.string() << " "; + + setValue(AudioFileExtensionsField, oss.str()); + } + + std::vector videoFileExtensions = settings->getVideoFileExtensions(); + { + std::ostringstream oss; + for (auto& fileExtension : videoFileExtensions) + oss << fileExtension.string() << " "; + + setValue(VideoFileExtensionsField, oss.str()); + } } void saveData() { Wt::Dbo::Transaction transaction(DboSession()); - ::Database::MediaDirectorySettings::pointer settings = ::Database::MediaDirectorySettings::get(DboSession()); + MediaDirectorySettings::pointer settings = MediaDirectorySettings::get(DboSession()); int periodRow = getUpdatePeriodModelRow( boost::any_cast(value(UpdatePeriodField))); assert(periodRow != -1); @@ -93,14 +120,32 @@ class DatabaseFormModel : public Wt::WFormModel assert(startTimeRow != -1); settings.modify()->setUpdateStartTime( updateStartTimeDuration( startTimeRow ) ); + { + std::vector res; + std::istringstream iss(boost::any_cast(value(AudioFileExtensionsField)).toUTF8()); + + std::copy(std::istream_iterator(iss), std::istream_iterator(), std::back_inserter(res)); + + settings.modify()->setAudioFileExtensions( std::vector(res.begin(), res.end()) ); + } + + { + std::vector res; + std::istringstream iss(boost::any_cast(value(VideoFileExtensionsField)).toUTF8()); + + std::copy(std::istream_iterator(iss), std::istream_iterator(), std::back_inserter(res)); + + settings.modify()->setVideoFileExtensions( std::vector(res.begin(), res.end()) ); + } } bool setImmediateScan(Wt::WString& error) { - try { + try + { Wt::Dbo::Transaction transaction( DboSession()); - ::Database::MediaDirectorySettings::pointer settings = ::Database::MediaDirectorySettings::get(DboSession() ); + MediaDirectorySettings::pointer settings = MediaDirectorySettings::get(DboSession() ); settings.modify()->setManualScanRequested( true ); } @@ -123,7 +168,7 @@ class DatabaseFormModel : public Wt::WFormModel return -1; } - int getUpdatePeriodModelRow(Database::MediaDirectorySettings::UpdatePeriod duration) + int getUpdatePeriodModelRow(MediaDirectorySettings::UpdatePeriod duration) { for (int i = 0; i < _updatePeriodModel->rowCount(); ++i) { @@ -134,8 +179,8 @@ class DatabaseFormModel : public Wt::WFormModel return -1; } - Database::MediaDirectorySettings::UpdatePeriod updatePeriodDuration(int row) { - return boost::any_cast + MediaDirectorySettings::UpdatePeriod updatePeriodDuration(int row) { + return boost::any_cast (_updatePeriodModel->data(_updatePeriodModel->index(row, 0), Wt::UserRole)); } @@ -185,16 +230,16 @@ class DatabaseFormModel : public Wt::WFormModel _updatePeriodModel = new Wt::WStringListModel(this); _updatePeriodModel->addString("Never"); - _updatePeriodModel->setData(0, 0, Database::MediaDirectorySettings::Never, Wt::UserRole); + _updatePeriodModel->setData(0, 0, MediaDirectorySettings::Never, Wt::UserRole); _updatePeriodModel->addString("Daily"); - _updatePeriodModel->setData(1, 0, Database::MediaDirectorySettings::Daily, Wt::UserRole); + _updatePeriodModel->setData(1, 0, MediaDirectorySettings::Daily, Wt::UserRole); _updatePeriodModel->addString("Weekly"); - _updatePeriodModel->setData(2, 0, Database::MediaDirectorySettings::Weekly, Wt::UserRole); + _updatePeriodModel->setData(2, 0, MediaDirectorySettings::Weekly, Wt::UserRole); _updatePeriodModel->addString("Monthly"); - _updatePeriodModel->setData(3, 0, Database::MediaDirectorySettings::Monthly, Wt::UserRole); + _updatePeriodModel->setData(3, 0, MediaDirectorySettings::Monthly, Wt::UserRole); _updateStartTimeModel = new Wt::WStringListModel(this); @@ -216,18 +261,25 @@ class DatabaseFormModel : public Wt::WFormModel } - Wt::WValidator *createUpdatePeriodValidator() { + Wt::WValidator *createUpdatePeriodValidator() + { Wt::WValidator* v = new Wt::WValidator(); v->setMandatory(true); return v; } - Wt::WValidator *createStartTimeValidator() { + Wt::WValidator *createStartTimeValidator() + { Wt::WValidator* v = new Wt::WValidator(); v->setMandatory(true); return v; } + Wt::WValidator *createFileExtensionValidator() + { + Wt::WRegExpValidator *v = new Wt::WRegExpValidator("(?:\\.\\w+(?:\\s*))+"); + return v; + } Wt::WStringListModel* _updatePeriodModel; Wt::WStringListModel* _updateStartTimeModel; @@ -236,6 +288,8 @@ class DatabaseFormModel : public Wt::WFormModel const Wt::WFormModel::Field DatabaseFormModel::UpdatePeriodField = "update-period"; const Wt::WFormModel::Field DatabaseFormModel::UpdateStartTimeField = "update-start-time"; +const Wt::WFormModel::Field DatabaseFormModel::AudioFileExtensionsField = "audio-file-extensions"; +const Wt::WFormModel::Field DatabaseFormModel::VideoFileExtensionsField = "video-file-extensions"; DatabaseFormView::DatabaseFormView(Wt::WContainerWidget *parent) @@ -264,8 +318,18 @@ DatabaseFormView::DatabaseFormView(Wt::WContainerWidget *parent) updateStartTimeCB->setModel(_model->updateStartTimeModel()); updateStartTimeCB->changed().connect(_applyInfo, &Wt::WWidget::hide); + // Audio file extensions + Wt::WLineEdit *audioFileExtensionsEdit = new Wt::WLineEdit(); + setFormWidget(DatabaseFormModel::AudioFileExtensionsField, audioFileExtensionsEdit); + audioFileExtensionsEdit->changed().connect(_applyInfo, &Wt::WWidget::hide); + + // Video file extensions + Wt::WLineEdit *videoFileExtensionsEdit = new Wt::WLineEdit(); + setFormWidget(DatabaseFormModel::VideoFileExtensionsField, videoFileExtensionsEdit); + videoFileExtensionsEdit->changed().connect(_applyInfo, &Wt::WWidget::hide); + // Title & Buttons - bindString("title", "Database update settings"); + bindString("title", "Database settings"); Wt::WPushButton *saveButton = new Wt::WPushButton("Apply"); bindWidget("apply-button", saveButton);