[DB] Some code refactoring
This commit is contained in:
@@ -2,6 +2,9 @@
|
|||||||
[Book]
|
[Book]
|
||||||
- Make the feature?
|
- Make the feature?
|
||||||
|
|
||||||
|
[Build]
|
||||||
|
- Makefile per directory. Use the include flags only where needed?
|
||||||
|
|
||||||
[Cover]
|
[Cover]
|
||||||
- Handle preferred cover file names ("front.xxx", "cover.xxx", ...)
|
- Handle preferred cover file names ("front.xxx", "cover.xxx", ...)
|
||||||
- Implement a cache and a grabber from some web service (mandatory for artists?)
|
- Implement a cache and a grabber from some web service (mandatory for artists?)
|
||||||
|
|||||||
+2
-4
@@ -7,6 +7,7 @@ lms_SOURCES = \
|
|||||||
$(srcdir)/cover/CoverArtGrabber.cpp \
|
$(srcdir)/cover/CoverArtGrabber.cpp \
|
||||||
$(srcdir)/database/Artist.cpp \
|
$(srcdir)/database/Artist.cpp \
|
||||||
$(srcdir)/database/DatabaseHandler.cpp \
|
$(srcdir)/database/DatabaseHandler.cpp \
|
||||||
|
$(srcdir)/database/DatabaseUpdater.cpp \
|
||||||
$(srcdir)/database/MediaDirectory.cpp \
|
$(srcdir)/database/MediaDirectory.cpp \
|
||||||
$(srcdir)/database/Playlist.cpp \
|
$(srcdir)/database/Playlist.cpp \
|
||||||
$(srcdir)/database/Release.cpp \
|
$(srcdir)/database/Release.cpp \
|
||||||
@@ -15,13 +16,9 @@ lms_SOURCES = \
|
|||||||
$(srcdir)/database/Track.cpp \
|
$(srcdir)/database/Track.cpp \
|
||||||
$(srcdir)/database/User.cpp \
|
$(srcdir)/database/User.cpp \
|
||||||
$(srcdir)/database/Video.cpp \
|
$(srcdir)/database/Video.cpp \
|
||||||
$(srcdir)/database-updater/DatabaseUpdater.cpp \
|
|
||||||
$(srcdir)/database-updater/Checksum.cpp \
|
|
||||||
$(srcdir)/image/Image.cpp \
|
$(srcdir)/image/Image.cpp \
|
||||||
$(srcdir)/logger/Logger.cpp \
|
$(srcdir)/logger/Logger.cpp \
|
||||||
$(srcdir)/metadata/AvFormat.cpp \
|
$(srcdir)/metadata/AvFormat.cpp \
|
||||||
$(srcdir)/service/ServiceManager.cpp \
|
|
||||||
$(srcdir)/service/DatabaseUpdateService.cpp \
|
|
||||||
$(srcdir)/ui/LmsApplication.cpp \
|
$(srcdir)/ui/LmsApplication.cpp \
|
||||||
$(srcdir)/ui/auth/LmsAuth.cpp \
|
$(srcdir)/ui/auth/LmsAuth.cpp \
|
||||||
$(srcdir)/ui/audio/AudioPlayer.cpp \
|
$(srcdir)/ui/audio/AudioPlayer.cpp \
|
||||||
@@ -57,6 +54,7 @@ lms_SOURCES = \
|
|||||||
$(srcdir)/ui/settings/SettingsMediaDirectoryFormView.cpp \
|
$(srcdir)/ui/settings/SettingsMediaDirectoryFormView.cpp \
|
||||||
$(srcdir)/ui/settings/SettingsUserFormView.cpp \
|
$(srcdir)/ui/settings/SettingsUserFormView.cpp \
|
||||||
$(srcdir)/ui/settings/SettingsUsers.cpp \
|
$(srcdir)/ui/settings/SettingsUsers.cpp \
|
||||||
|
$(srcdir)/utils/Checksum.cpp \
|
||||||
$(srcdir)/utils/Utils.cpp
|
$(srcdir)/utils/Utils.cpp
|
||||||
|
|
||||||
if VIDEO
|
if VIDEO
|
||||||
|
|||||||
@@ -83,6 +83,8 @@ Handler::Handler(Wt::Dbo::SqlConnectionPool& connectionPool)
|
|||||||
_session.mapClass<Database::Artist>("artist");
|
_session.mapClass<Database::Artist>("artist");
|
||||||
_session.mapClass<Database::Genre>("genre");
|
_session.mapClass<Database::Genre>("genre");
|
||||||
_session.mapClass<Database::Track>("track");
|
_session.mapClass<Database::Track>("track");
|
||||||
|
_session.mapClass<Database::Classification>("classification");
|
||||||
|
_session.mapClass<Database::ClassificationData>("classification_data");
|
||||||
_session.mapClass<Database::Playlist>("playlist");
|
_session.mapClass<Database::Playlist>("playlist");
|
||||||
_session.mapClass<Database::PlaylistEntry>("playlist_entry");
|
_session.mapClass<Database::PlaylistEntry>("playlist_entry");
|
||||||
_session.mapClass<Database::Release>("release");
|
_session.mapClass<Database::Release>("release");
|
||||||
|
|||||||
@@ -17,19 +17,19 @@
|
|||||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include <boost/thread.hpp>
|
#include <boost/thread.hpp>
|
||||||
#include <boost/asio/placeholders.hpp>
|
#include <boost/asio/placeholders.hpp>
|
||||||
|
|
||||||
#include "logger/Logger.hpp"
|
#include "logger/Logger.hpp"
|
||||||
#include "utils/Utils.hpp"
|
|
||||||
|
|
||||||
#include "database/Types.hpp"
|
|
||||||
|
|
||||||
#include "Checksum.hpp"
|
|
||||||
#include "DatabaseUpdater.hpp"
|
|
||||||
#include "cover/CoverArtGrabber.hpp"
|
#include "cover/CoverArtGrabber.hpp"
|
||||||
|
#include "utils/Utils.hpp"
|
||||||
|
#include "utils/Checksum.hpp"
|
||||||
|
|
||||||
|
#include "Types.hpp"
|
||||||
|
#include "DatabaseUpdater.hpp"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@@ -115,23 +115,40 @@ isPathInParentPath(const boost::filesystem::path& path, const boost::filesystem:
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
namespace DatabaseUpdater {
|
namespace Database {
|
||||||
|
|
||||||
using namespace Database;
|
Updater& Updater::instance(void)
|
||||||
|
{
|
||||||
|
static Updater updater;
|
||||||
|
return updater;
|
||||||
|
}
|
||||||
|
|
||||||
|
Updater::Updater()
|
||||||
Updater::Updater(Wt::Dbo::SqlConnectionPool &connectionPool, MetaData::Parser& parser)
|
|
||||||
: _running(false),
|
: _running(false),
|
||||||
_scheduleTimer(_ioService),
|
_scheduleTimer(_ioService)
|
||||||
_db(connectionPool),
|
|
||||||
_metadataParser(parser)
|
|
||||||
{
|
{
|
||||||
_ioService.setThreadCount(1);
|
_ioService.setThreadCount(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Updater::setConnectionPool(Wt::Dbo::SqlConnectionPool& connectionPool)
|
||||||
|
{
|
||||||
|
_db = new Database::Handler(connectionPool);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Updater::restart(void)
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Updater::start(void)
|
Updater::start(void)
|
||||||
{
|
{
|
||||||
|
if (_db == nullptr)
|
||||||
|
throw std::logic_error("uninitialized db!");
|
||||||
|
|
||||||
_running = true;
|
_running = true;
|
||||||
|
|
||||||
// post some jobs in the io_service
|
// post some jobs in the io_service
|
||||||
@@ -154,9 +171,9 @@ Updater::stop(void)
|
|||||||
void
|
void
|
||||||
Updater::processNextJob(void)
|
Updater::processNextJob(void)
|
||||||
{
|
{
|
||||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
Wt::Dbo::Transaction transaction(_db->getSession());
|
||||||
|
|
||||||
MediaDirectorySettings::pointer settings = MediaDirectorySettings::get(_db.getSession());
|
MediaDirectorySettings::pointer settings = MediaDirectorySettings::get(_db->getSession());
|
||||||
|
|
||||||
if (settings->getManualScanRequested()) {
|
if (settings->getManualScanRequested()) {
|
||||||
LMS_LOG(DBUPDATER, INFO) << "Manual scan requested!";
|
LMS_LOG(DBUPDATER, INFO) << "Manual scan requested!";
|
||||||
@@ -229,9 +246,9 @@ Updater::process(boost::system::error_code err)
|
|||||||
|
|
||||||
std::vector<RootDirectory> rootDirectories;
|
std::vector<RootDirectory> rootDirectories;
|
||||||
{
|
{
|
||||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
Wt::Dbo::Transaction transaction(_db->getSession());
|
||||||
|
|
||||||
for (MediaDirectory::pointer directory : MediaDirectory::getAll(_db.getSession()))
|
for (MediaDirectory::pointer directory : MediaDirectory::getAll(_db->getSession()))
|
||||||
rootDirectories.push_back( RootDirectory( directory->getType(), directory->getPath() ));
|
rootDirectories.push_back( RootDirectory( directory->getType(), directory->getPath() ));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,9 +270,9 @@ Updater::process(boost::system::error_code err)
|
|||||||
// Update database stats
|
// Update database stats
|
||||||
boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
|
boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
|
||||||
{
|
{
|
||||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
Wt::Dbo::Transaction transaction(_db->getSession());
|
||||||
|
|
||||||
Database::MediaDirectorySettings::pointer settings = Database::MediaDirectorySettings::get(_db.getSession());
|
Database::MediaDirectorySettings::pointer settings = Database::MediaDirectorySettings::get(_db->getSession());
|
||||||
|
|
||||||
if (stats.nbChanges() > 0)
|
if (stats.nbChanges() > 0)
|
||||||
settings.modify()->setLastUpdate(now);
|
settings.modify()->setLastUpdate(now);
|
||||||
@@ -279,10 +296,10 @@ Updater::process(boost::system::error_code err)
|
|||||||
void
|
void
|
||||||
Updater::updateFileExtensions()
|
Updater::updateFileExtensions()
|
||||||
{
|
{
|
||||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
Wt::Dbo::Transaction transaction(_db->getSession());
|
||||||
|
|
||||||
_audioFileExtensions = MediaDirectorySettings::get(_db.getSession())->getAudioFileExtensions();
|
_audioFileExtensions = MediaDirectorySettings::get(_db->getSession())->getAudioFileExtensions();
|
||||||
_videoFileExtensions = MediaDirectorySettings::get(_db.getSession())->getVideoFileExtensions();
|
_videoFileExtensions = MediaDirectorySettings::get(_db->getSession())->getVideoFileExtensions();
|
||||||
}
|
}
|
||||||
|
|
||||||
Artist::pointer
|
Artist::pointer
|
||||||
@@ -293,9 +310,9 @@ Updater::getArtist( const boost::filesystem::path& file, const std::string& name
|
|||||||
// First try to get by MBID
|
// First try to get by MBID
|
||||||
if (!mbid.empty())
|
if (!mbid.empty())
|
||||||
{
|
{
|
||||||
artist = Artist::getByMBID( _db.getSession(), mbid );
|
artist = Artist::getByMBID( _db->getSession(), mbid );
|
||||||
if (!artist)
|
if (!artist)
|
||||||
artist = Artist::create( _db.getSession(), name, mbid);
|
artist = Artist::create( _db->getSession(), name, mbid);
|
||||||
|
|
||||||
return artist;
|
return artist;
|
||||||
}
|
}
|
||||||
@@ -303,7 +320,7 @@ Updater::getArtist( const boost::filesystem::path& file, const std::string& name
|
|||||||
// Fall back on artist name (collisions may occur)
|
// Fall back on artist name (collisions may occur)
|
||||||
if (!name.empty())
|
if (!name.empty())
|
||||||
{
|
{
|
||||||
for (Artist::pointer sameNamedArtist : Artist::getByName( _db.getSession(), name ))
|
for (Artist::pointer sameNamedArtist : Artist::getByName( _db->getSession(), name ))
|
||||||
{
|
{
|
||||||
if (sameNamedArtist->getMBID().empty())
|
if (sameNamedArtist->getMBID().empty())
|
||||||
{
|
{
|
||||||
@@ -314,12 +331,12 @@ Updater::getArtist( const boost::filesystem::path& file, const std::string& name
|
|||||||
|
|
||||||
// No Artist found with the same name and without MBID -> creating
|
// No Artist found with the same name and without MBID -> creating
|
||||||
if (!artist)
|
if (!artist)
|
||||||
artist = Artist::create( _db.getSession(), name);
|
artist = Artist::create( _db->getSession(), name);
|
||||||
|
|
||||||
return artist;
|
return artist;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Artist::getNone( _db.getSession() );
|
return Artist::getNone( _db->getSession() );
|
||||||
}
|
}
|
||||||
|
|
||||||
Release::pointer
|
Release::pointer
|
||||||
@@ -330,9 +347,9 @@ Updater::getRelease( const boost::filesystem::path& file, const std::string& nam
|
|||||||
// First try to get by MBID
|
// First try to get by MBID
|
||||||
if (!mbid.empty())
|
if (!mbid.empty())
|
||||||
{
|
{
|
||||||
release = Release::getByMBID( _db.getSession(), mbid );
|
release = Release::getByMBID( _db->getSession(), mbid );
|
||||||
if (!release)
|
if (!release)
|
||||||
release = Release::create( _db.getSession(), name, mbid);
|
release = Release::create( _db->getSession(), name, mbid);
|
||||||
|
|
||||||
return release;
|
return release;
|
||||||
}
|
}
|
||||||
@@ -340,7 +357,7 @@ Updater::getRelease( const boost::filesystem::path& file, const std::string& nam
|
|||||||
// Fall back on release name (collisions may occur)
|
// Fall back on release name (collisions may occur)
|
||||||
if (!name.empty())
|
if (!name.empty())
|
||||||
{
|
{
|
||||||
for (Release::pointer sameNamedRelease : Release::getByName( _db.getSession(), name ))
|
for (Release::pointer sameNamedRelease : Release::getByName( _db->getSession(), name ))
|
||||||
{
|
{
|
||||||
if (sameNamedRelease->getMBID().empty())
|
if (sameNamedRelease->getMBID().empty())
|
||||||
{
|
{
|
||||||
@@ -351,12 +368,12 @@ Updater::getRelease( const boost::filesystem::path& file, const std::string& nam
|
|||||||
|
|
||||||
// No release found with the same name and without MBID -> creating
|
// No release found with the same name and without MBID -> creating
|
||||||
if (!release)
|
if (!release)
|
||||||
release = Release::create( _db.getSession(), name);
|
release = Release::create( _db->getSession(), name);
|
||||||
|
|
||||||
return release;
|
return release;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Release::getNone( _db.getSession() );
|
return Release::getNone( _db->getSession() );
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Genre::pointer>
|
std::vector<Genre::pointer>
|
||||||
@@ -366,15 +383,15 @@ Updater::getGenres( const std::list<std::string>& names)
|
|||||||
|
|
||||||
for (const std::string& name : names)
|
for (const std::string& name : names)
|
||||||
{
|
{
|
||||||
Genre::pointer genre ( Genre::getByName(_db.getSession(), name) );
|
Genre::pointer genre ( Genre::getByName(_db->getSession(), name) );
|
||||||
if (!genre)
|
if (!genre)
|
||||||
genre = Genre::create(_db.getSession(), name);
|
genre = Genre::create(_db->getSession(), name);
|
||||||
|
|
||||||
genres.push_back( genre );
|
genres.push_back( genre );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (genres.empty())
|
if (genres.empty())
|
||||||
genres.push_back( Genre::getNone( _db.getSession() ));
|
genres.push_back( Genre::getNone( _db->getSession() ));
|
||||||
|
|
||||||
return genres;
|
return genres;
|
||||||
}
|
}
|
||||||
@@ -386,9 +403,9 @@ Updater::processAudioFile( const boost::filesystem::path& file, Stats& stats)
|
|||||||
|
|
||||||
// Skip file if last write is the same
|
// Skip file if last write is the same
|
||||||
{
|
{
|
||||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
Wt::Dbo::Transaction transaction(_db->getSession());
|
||||||
|
|
||||||
Wt::Dbo::ptr<Track> track = Track::getByPath(_db.getSession(), file);
|
Wt::Dbo::ptr<Track> track = Track::getByPath(_db->getSession(), file);
|
||||||
|
|
||||||
if (track && track->getLastWriteTime() == lastWriteTime)
|
if (track && track->getLastWriteTime() == lastWriteTime)
|
||||||
{
|
{
|
||||||
@@ -412,9 +429,9 @@ Updater::processAudioFile( const boost::filesystem::path& file, Stats& stats)
|
|||||||
std::vector<unsigned char> checksum ;
|
std::vector<unsigned char> checksum ;
|
||||||
computeCrc(file, checksum);
|
computeCrc(file, checksum);
|
||||||
|
|
||||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
Wt::Dbo::Transaction transaction(_db->getSession());
|
||||||
|
|
||||||
Wt::Dbo::ptr<Track> track = Track::getByPath(_db.getSession(), file);
|
Wt::Dbo::ptr<Track> track = Track::getByPath(_db->getSession(), file);
|
||||||
|
|
||||||
// We estimate this is a audio file if:
|
// We estimate this is a audio file if:
|
||||||
// - we found a least one audio stream
|
// - we found a least one audio stream
|
||||||
@@ -510,7 +527,7 @@ Updater::processAudioFile( const boost::filesystem::path& file, Stats& stats)
|
|||||||
if (!track)
|
if (!track)
|
||||||
{
|
{
|
||||||
// Create a new song
|
// Create a new song
|
||||||
track = Track::create(_db.getSession(), file);
|
track = Track::create(_db->getSession(), file);
|
||||||
LMS_LOG(DBUPDATER, INFO) << "Adding '" << file << "'";
|
LMS_LOG(DBUPDATER, INFO) << "Adding '" << file << "'";
|
||||||
stats.nbAdded++;
|
stats.nbAdded++;
|
||||||
}
|
}
|
||||||
@@ -675,8 +692,8 @@ Updater::checkAudioFiles( Stats& stats )
|
|||||||
{
|
{
|
||||||
LMS_LOG(DBUPDATER, INFO) << "Checking audio files...";
|
LMS_LOG(DBUPDATER, INFO) << "Checking audio files...";
|
||||||
|
|
||||||
std::vector<boost::filesystem::path> trackPaths = Track::getAllPaths(_db.getSession());;
|
std::vector<boost::filesystem::path> trackPaths = Track::getAllPaths(_db->getSession());;
|
||||||
std::vector<boost::filesystem::path> rootDirs = getRootDirectoriesByType(_db.getSession(), Database::MediaDirectory::Audio);
|
std::vector<boost::filesystem::path> rootDirs = getRootDirectoriesByType(_db->getSession(), Database::MediaDirectory::Audio);
|
||||||
|
|
||||||
LMS_LOG(DBUPDATER, DEBUG) << "Checking tracks...";
|
LMS_LOG(DBUPDATER, DEBUG) << "Checking tracks...";
|
||||||
for (auto& trackPath : trackPaths)
|
for (auto& trackPath : trackPaths)
|
||||||
@@ -686,9 +703,9 @@ Updater::checkAudioFiles( Stats& stats )
|
|||||||
|
|
||||||
if (!checkFile(trackPath, rootDirs, _audioFileExtensions))
|
if (!checkFile(trackPath, rootDirs, _audioFileExtensions))
|
||||||
{
|
{
|
||||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
Wt::Dbo::Transaction transaction(_db->getSession());
|
||||||
|
|
||||||
Track::pointer track = Track::getByPath(_db.getSession(), trackPath);
|
Track::pointer track = Track::getByPath(_db->getSession(), trackPath);
|
||||||
if (track)
|
if (track)
|
||||||
{
|
{
|
||||||
track.remove();
|
track.remove();
|
||||||
@@ -699,10 +716,10 @@ Updater::checkAudioFiles( Stats& stats )
|
|||||||
|
|
||||||
LMS_LOG(DBUPDATER, DEBUG) << "Checking Genres...";
|
LMS_LOG(DBUPDATER, DEBUG) << "Checking Genres...";
|
||||||
{
|
{
|
||||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
Wt::Dbo::Transaction transaction(_db->getSession());
|
||||||
|
|
||||||
// Now process orphan Genre (no track)
|
// Now process orphan Genre (no track)
|
||||||
auto genres = Genre::getAll(_db.getSession());
|
auto genres = Genre::getAll(_db->getSession());
|
||||||
for (auto genre : genres)
|
for (auto genre : genres)
|
||||||
{
|
{
|
||||||
if (genre->getTracks().size() == 0)
|
if (genre->getTracks().size() == 0)
|
||||||
@@ -715,9 +732,9 @@ Updater::checkAudioFiles( Stats& stats )
|
|||||||
|
|
||||||
LMS_LOG(DBUPDATER, DEBUG) << "Checking artists...";
|
LMS_LOG(DBUPDATER, DEBUG) << "Checking artists...";
|
||||||
{
|
{
|
||||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
Wt::Dbo::Transaction transaction(_db->getSession());
|
||||||
|
|
||||||
auto artists = Artist::getAllOrphans(_db.getSession());
|
auto artists = Artist::getAllOrphans(_db->getSession());
|
||||||
for (auto artist : artists)
|
for (auto artist : artists)
|
||||||
{
|
{
|
||||||
LMS_LOG(DBUPDATER, DEBUG) << "Removing orphan artist '" << artist->getName() << "'";
|
LMS_LOG(DBUPDATER, DEBUG) << "Removing orphan artist '" << artist->getName() << "'";
|
||||||
@@ -727,9 +744,9 @@ Updater::checkAudioFiles( Stats& stats )
|
|||||||
|
|
||||||
LMS_LOG(DBUPDATER, DEBUG) << "Checking releases...";
|
LMS_LOG(DBUPDATER, DEBUG) << "Checking releases...";
|
||||||
{
|
{
|
||||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
Wt::Dbo::Transaction transaction(_db->getSession());
|
||||||
|
|
||||||
auto releases = Release::getAllOrphans(_db.getSession());
|
auto releases = Release::getAllOrphans(_db->getSession());
|
||||||
for (auto release : releases)
|
for (auto release : releases)
|
||||||
{
|
{
|
||||||
LMS_LOG(DBUPDATER, DEBUG) << "Removing orphan release '" << release->getName() << "'";
|
LMS_LOG(DBUPDATER, DEBUG) << "Removing orphan release '" << release->getName() << "'";
|
||||||
@@ -745,15 +762,15 @@ Updater::checkDuplicatedAudioFiles(Stats& stats)
|
|||||||
{
|
{
|
||||||
LMS_LOG(DBUPDATER, INFO) << "Checking duplicated audio files";
|
LMS_LOG(DBUPDATER, INFO) << "Checking duplicated audio files";
|
||||||
|
|
||||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
Wt::Dbo::Transaction transaction(_db->getSession());
|
||||||
|
|
||||||
std::vector<Track::pointer> tracks = Database::Track::getMBIDDuplicates(_db.getSession());
|
std::vector<Track::pointer> tracks = Database::Track::getMBIDDuplicates(_db->getSession());
|
||||||
for (Track::pointer track : tracks)
|
for (Track::pointer track : tracks)
|
||||||
{
|
{
|
||||||
LMS_LOG(DBUPDATER, INFO) << "Found duplicated MBID [" << track->getMBID() << "], file: " << track->getPath() << " - " << track->getArtist()->getName() << " - " << track->getName();
|
LMS_LOG(DBUPDATER, INFO) << "Found duplicated MBID [" << track->getMBID() << "], file: " << track->getPath() << " - " << track->getArtist()->getName() << " - " << track->getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
tracks = Database::Track::getChecksumDuplicates(_db.getSession());
|
tracks = Database::Track::getChecksumDuplicates(_db->getSession());
|
||||||
for (Track::pointer track : tracks)
|
for (Track::pointer track : tracks)
|
||||||
{
|
{
|
||||||
LMS_LOG(DBUPDATER, INFO) << "Found duplicated checksum [" << bufferToString(track->getChecksum()) << "], file: " << track->getPath() << " - " << track->getArtist()->getName() << " - " << track->getName();
|
LMS_LOG(DBUPDATER, INFO) << "Found duplicated checksum [" << bufferToString(track->getChecksum()) << "], file: " << track->getPath() << " - " << track->getArtist()->getName() << " - " << track->getName();
|
||||||
@@ -766,8 +783,8 @@ Updater::checkDuplicatedAudioFiles(Stats& stats)
|
|||||||
void
|
void
|
||||||
Updater::checkVideoFiles( Stats& stats )
|
Updater::checkVideoFiles( Stats& stats )
|
||||||
{
|
{
|
||||||
std::vector<boost::filesystem::path> rootDirs = getRootDirectoriesByType(_db.getSession(), Database::MediaDirectory::Video);
|
std::vector<boost::filesystem::path> rootDirs = getRootDirectoriesByType(_db->getSession(), Database::MediaDirectory::Video);
|
||||||
std::vector<boost::filesystem::path> videoPaths = Video::getAllPaths(_db.getSession());
|
std::vector<boost::filesystem::path> videoPaths = Video::getAllPaths(_db->getSession());
|
||||||
|
|
||||||
LMS_LOG(DBUPDATER, DEBUG) << "Checking videos...";
|
LMS_LOG(DBUPDATER, DEBUG) << "Checking videos...";
|
||||||
for (auto& videoPath : videoPaths)
|
for (auto& videoPath : videoPaths)
|
||||||
@@ -777,9 +794,9 @@ Updater::checkVideoFiles( Stats& stats )
|
|||||||
|
|
||||||
if (!checkFile(videoPath, rootDirs, _videoFileExtensions))
|
if (!checkFile(videoPath, rootDirs, _videoFileExtensions))
|
||||||
{
|
{
|
||||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
Wt::Dbo::Transaction transaction(_db->getSession());
|
||||||
|
|
||||||
Video::pointer video = Video::getByPath(_db.getSession(), videoPath);
|
Video::pointer video = Video::getByPath(_db->getSession(), videoPath);
|
||||||
if (video)
|
if (video)
|
||||||
{
|
{
|
||||||
video.remove();
|
video.remove();
|
||||||
@@ -797,10 +814,10 @@ Updater::processVideoFile( const boost::filesystem::path& file, Stats& stats)
|
|||||||
// Check last update time
|
// Check last update time
|
||||||
boost::posix_time::ptime lastWriteTime (boost::posix_time::from_time_t( boost::filesystem::last_write_time( file ) ) );
|
boost::posix_time::ptime lastWriteTime (boost::posix_time::from_time_t( boost::filesystem::last_write_time( file ) ) );
|
||||||
|
|
||||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
Wt::Dbo::Transaction transaction(_db->getSession());
|
||||||
|
|
||||||
// Skip file if last write is the same
|
// Skip file if last write is the same
|
||||||
Wt::Dbo::ptr<Video> video = Video::getByPath(_db.getSession(), file);
|
Wt::Dbo::ptr<Video> video = Video::getByPath(_db->getSession(), file);
|
||||||
if (video && video->getLastWriteTime() == lastWriteTime)
|
if (video && video->getLastWriteTime() == lastWriteTime)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -841,7 +858,7 @@ Updater::processVideoFile( const boost::filesystem::path& file, Stats& stats)
|
|||||||
// Today we are very aggressive, but we could also guess names from path, etc.
|
// Today we are very aggressive, but we could also guess names from path, etc.
|
||||||
if (!video)
|
if (!video)
|
||||||
{
|
{
|
||||||
video = Video::create(_db.getSession(), file);
|
video = Video::create(_db->getSession(), file);
|
||||||
LMS_LOG(DBUPDATER, DEBUG) << "Adding '" << file << "'";
|
LMS_LOG(DBUPDATER, DEBUG) << "Adding '" << file << "'";
|
||||||
stats.nbAdded++;
|
stats.nbAdded++;
|
||||||
}
|
}
|
||||||
@@ -860,4 +877,4 @@ Updater::processVideoFile( const boost::filesystem::path& file, Stats& stats)
|
|||||||
transaction.commit();
|
transaction.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace DatabaseUpdater
|
} // namespace Database
|
||||||
@@ -20,28 +20,22 @@
|
|||||||
#ifndef DB_UPDATER_HPP
|
#ifndef DB_UPDATER_HPP
|
||||||
#define DB_UPDATER_HPP
|
#define DB_UPDATER_HPP
|
||||||
|
|
||||||
#include <boost/asio/deadline_timer.hpp>
|
|
||||||
#include <Wt/WIOService>
|
#include <Wt/WIOService>
|
||||||
|
#include <Wt/WSignal>
|
||||||
|
|
||||||
#include "metadata/MetaData.hpp"
|
#include <mutex>
|
||||||
|
|
||||||
|
#include <boost/asio/deadline_timer.hpp>
|
||||||
|
|
||||||
|
#include "metadata/AvFormat.hpp"
|
||||||
|
|
||||||
#include "database/DatabaseHandler.hpp"
|
#include "database/DatabaseHandler.hpp"
|
||||||
|
|
||||||
namespace DatabaseUpdater {
|
namespace Database {
|
||||||
|
|
||||||
class Updater
|
class Updater
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Updater(Wt::Dbo::SqlConnectionPool& connectionPool, MetaData::Parser& parser);
|
|
||||||
|
|
||||||
void setAudioExtensions(const std::vector<std::string>& extensions);
|
|
||||||
void setVideoExtensions(const std::vector<std::string>& extensions);
|
|
||||||
|
|
||||||
void start();
|
|
||||||
void stop();
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
struct Stats
|
struct Stats
|
||||||
{
|
{
|
||||||
std::size_t nbSkipped = 0; // no change since last scan
|
std::size_t nbSkipped = 0; // no change since last scan
|
||||||
@@ -55,6 +49,25 @@ class Updater
|
|||||||
std::size_t nbChanges() const { return nbAdded + nbRemoved + nbModified;}
|
std::size_t nbChanges() const { return nbAdded + nbRemoved + nbModified;}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static Updater& instance();
|
||||||
|
|
||||||
|
void setConnectionPool(Wt::Dbo::SqlConnectionPool& connectionPool);
|
||||||
|
|
||||||
|
void setAudioExtensions(const std::vector<std::string>& extensions);
|
||||||
|
void setVideoExtensions(const std::vector<std::string>& extensions);
|
||||||
|
|
||||||
|
void start();
|
||||||
|
void stop();
|
||||||
|
void restart();
|
||||||
|
|
||||||
|
Wt::Signal<Stats>& changed() { return _sigChanged; }
|
||||||
|
|
||||||
|
std::mutex& getMutex(void) { return _mutex; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Updater();
|
||||||
|
|
||||||
struct RootDirectory
|
struct RootDirectory
|
||||||
{
|
{
|
||||||
Database::MediaDirectory::Type type;
|
Database::MediaDirectory::Type type;
|
||||||
@@ -96,19 +109,21 @@ class Updater
|
|||||||
|
|
||||||
bool _running;
|
bool _running;
|
||||||
Wt::WIOService _ioService;
|
Wt::WIOService _ioService;
|
||||||
|
Wt::Signal<Stats> _sigChanged;
|
||||||
|
std::mutex _mutex;
|
||||||
|
|
||||||
boost::asio::deadline_timer _scheduleTimer;
|
boost::asio::deadline_timer _scheduleTimer;
|
||||||
|
|
||||||
Database::Handler _db;
|
Database::Handler* _db = nullptr;
|
||||||
|
|
||||||
std::vector<boost::filesystem::path> _audioFileExtensions;
|
std::vector<boost::filesystem::path> _audioFileExtensions;
|
||||||
std::vector<boost::filesystem::path> _videoFileExtensions;
|
std::vector<boost::filesystem::path> _videoFileExtensions;
|
||||||
|
|
||||||
MetaData::Parser& _metadataParser;
|
MetaData::AvFormat _metadataParser;
|
||||||
|
|
||||||
|
|
||||||
}; // class Updater
|
}; // class Updater
|
||||||
|
|
||||||
} // DatabaseUpdater
|
} // Database
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+10
-1
@@ -37,6 +37,8 @@ class Artist;
|
|||||||
class Release;
|
class Release;
|
||||||
class Track;
|
class Track;
|
||||||
class PlaylistEntry;
|
class PlaylistEntry;
|
||||||
|
class Classification;
|
||||||
|
class ClassificationData;
|
||||||
|
|
||||||
class Genre
|
class Genre
|
||||||
{
|
{
|
||||||
@@ -156,6 +158,8 @@ class Track
|
|||||||
void setArtist(Wt::Dbo::ptr<Artist> artist) { _artist = artist; }
|
void setArtist(Wt::Dbo::ptr<Artist> artist) { _artist = artist; }
|
||||||
void setRelease(Wt::Dbo::ptr<Release> release) { _release = release; }
|
void setRelease(Wt::Dbo::ptr<Release> release) { _release = release; }
|
||||||
void setGenres(std::vector<Genre::pointer> genres);
|
void setGenres(std::vector<Genre::pointer> genres);
|
||||||
|
void addClassifification(Wt::Dbo::ptr<Classification> classification);
|
||||||
|
void addClassifificationData(Wt::Dbo::ptr<ClassificationData> classificationData);
|
||||||
|
|
||||||
int getTrackNumber(void) const { return _trackNumber; }
|
int getTrackNumber(void) const { return _trackNumber; }
|
||||||
int getTotalTrackNumber(void) const { return _totalTrackNumber; }
|
int getTotalTrackNumber(void) const { return _totalTrackNumber; }
|
||||||
@@ -175,6 +179,8 @@ class Track
|
|||||||
Wt::Dbo::ptr<Release> getRelease(void) const { return _release; }
|
Wt::Dbo::ptr<Release> getRelease(void) const { return _release; }
|
||||||
std::vector< Genre::pointer > getGenres(void) const;
|
std::vector< Genre::pointer > getGenres(void) const;
|
||||||
bool hasGenre(Genre::pointer genre) const { return _genres.count(genre); }
|
bool hasGenre(Genre::pointer genre) const { return _genres.count(genre); }
|
||||||
|
std::vector< Wt::Dbo::ptr<Classification> > getClassifications(void) const;
|
||||||
|
std::vector< Wt::Dbo::ptr<ClassificationData> > getClassificationData(void) const;
|
||||||
|
|
||||||
template<class Action>
|
template<class Action>
|
||||||
void persist(Action& a)
|
void persist(Action& a)
|
||||||
@@ -198,6 +204,8 @@ class Track
|
|||||||
Wt::Dbo::belongsTo(a, _artist, "artist", Wt::Dbo::OnDeleteCascade);
|
Wt::Dbo::belongsTo(a, _artist, "artist", Wt::Dbo::OnDeleteCascade);
|
||||||
Wt::Dbo::hasMany(a, _genres, Wt::Dbo::ManyToMany, "track_genre", "", Wt::Dbo::OnDeleteCascade);
|
Wt::Dbo::hasMany(a, _genres, Wt::Dbo::ManyToMany, "track_genre", "", Wt::Dbo::OnDeleteCascade);
|
||||||
Wt::Dbo::hasMany(a, _playlistEntries, Wt::Dbo::ManyToOne, "track");
|
Wt::Dbo::hasMany(a, _playlistEntries, Wt::Dbo::ManyToOne, "track");
|
||||||
|
Wt::Dbo::hasMany(a, _classifications, Wt::Dbo::ManyToOne, "track");
|
||||||
|
Wt::Dbo::hasMany(a, _classificationData, Wt::Dbo::ManyToOne, "track");
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -228,7 +236,8 @@ class Track
|
|||||||
Wt::Dbo::ptr<Release> _release;
|
Wt::Dbo::ptr<Release> _release;
|
||||||
Wt::Dbo::collection< Genre::pointer > _genres; // Genres that are related to this track
|
Wt::Dbo::collection< Genre::pointer > _genres; // Genres that are related to this track
|
||||||
Wt::Dbo::collection< Wt::Dbo::ptr<PlaylistEntry> > _playlistEntries;
|
Wt::Dbo::collection< Wt::Dbo::ptr<PlaylistEntry> > _playlistEntries;
|
||||||
|
Wt::Dbo::collection< Wt::Dbo::ptr<Classification> > _classifications;
|
||||||
|
Wt::Dbo::collection< Wt::Dbo::ptr<ClassificationData> > _classificationData;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include "Artist.hpp"
|
#include "Artist.hpp"
|
||||||
#include "Track.hpp"
|
#include "Track.hpp"
|
||||||
#include "Playlist.hpp"
|
#include "Playlist.hpp"
|
||||||
|
#include "Classification.hpp"
|
||||||
#include "Release.hpp"
|
#include "Release.hpp"
|
||||||
#include "Video.hpp"
|
#include "Video.hpp"
|
||||||
#include "MediaDirectory.hpp"
|
#include "MediaDirectory.hpp"
|
||||||
|
|||||||
+15
-19
@@ -19,18 +19,17 @@
|
|||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
#include <Wt/WServer>
|
||||||
|
|
||||||
#include "config/config.h"
|
#include "config/config.h"
|
||||||
#include "av/AvInfo.hpp"
|
#include "av/AvInfo.hpp"
|
||||||
#include "av/AvTranscoder.hpp"
|
#include "av/AvTranscoder.hpp"
|
||||||
#include "logger/Logger.hpp"
|
#include "logger/Logger.hpp"
|
||||||
#include "image/Image.hpp"
|
#include "image/Image.hpp"
|
||||||
|
|
||||||
|
#include "database/DatabaseUpdater.hpp"
|
||||||
#include "ui/LmsApplication.hpp"
|
#include "ui/LmsApplication.hpp"
|
||||||
|
|
||||||
#include "service/ServiceManager.hpp"
|
|
||||||
#include "service/DatabaseUpdateService.hpp"
|
|
||||||
|
|
||||||
#include <Wt/WServer>
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
@@ -49,8 +48,6 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
Wt::WServer::instance()->logger().configure("*"); // log everything
|
Wt::WServer::instance()->logger().configure("*"); // log everything
|
||||||
|
|
||||||
Service::ServiceManager& serviceManager = Service::ServiceManager::instance();
|
|
||||||
|
|
||||||
// lib init
|
// lib init
|
||||||
Image::init(argv[0]);
|
Image::init(argv[0]);
|
||||||
Av::AvInit();
|
Av::AvInit();
|
||||||
@@ -60,30 +57,29 @@ int main(int argc, char* argv[])
|
|||||||
// Initializing a connection pool to the database that will be shared along services
|
// Initializing a connection pool to the database that will be shared along services
|
||||||
std::unique_ptr<Wt::Dbo::SqlConnectionPool> connectionPool( Database::Handler::createConnectionPool("/var/lms/lms.db")); // TODO use $datadir from autotools
|
std::unique_ptr<Wt::Dbo::SqlConnectionPool> connectionPool( Database::Handler::createConnectionPool("/var/lms/lms.db")); // TODO use $datadir from autotools
|
||||||
|
|
||||||
serviceManager.add( std::make_shared<Service::DatabaseUpdateService>(*connectionPool));
|
Database::Updater::instance().setConnectionPool(*connectionPool);
|
||||||
|
|
||||||
// bind entry point
|
// bind entry point
|
||||||
server.addEntryPoint(Wt::Application, boost::bind(UserInterface::LmsApplication::create, _1, boost::ref(*connectionPool)));
|
server.addEntryPoint(Wt::Application, boost::bind(UserInterface::LmsApplication::create, _1, boost::ref(*connectionPool)));
|
||||||
|
|
||||||
// Starting the main server
|
// Start
|
||||||
|
LMS_LOG(MAIN, INFO) << "Starting database updater...";
|
||||||
|
Database::Updater::instance().start();
|
||||||
|
|
||||||
LMS_LOG(MAIN, INFO) << "Starting server...";
|
LMS_LOG(MAIN, INFO) << "Starting server...";
|
||||||
server.start();
|
server.start();
|
||||||
|
|
||||||
// Start underlying services
|
// Wait
|
||||||
LMS_LOG(MAIN, INFO) << "Starting services...";
|
|
||||||
serviceManager.start();
|
|
||||||
|
|
||||||
LMS_LOG(MAIN, INFO) << "Now running...";
|
LMS_LOG(MAIN, INFO) << "Now running...";
|
||||||
|
|
||||||
// Waiting for shutdown command
|
|
||||||
Wt::WServer::waitForShutdown(argv[0]);
|
Wt::WServer::waitForShutdown(argv[0]);
|
||||||
|
|
||||||
LMS_LOG(MAIN, INFO) << "Stopping services...";
|
// Stop
|
||||||
serviceManager.stop();
|
|
||||||
serviceManager.clear();
|
|
||||||
|
|
||||||
LMS_LOG(MAIN, INFO) << "Stopping server...";
|
LMS_LOG(MAIN, INFO) << "Stopping server...";
|
||||||
server.stop();
|
Database::Updater::instance().stop();
|
||||||
|
|
||||||
|
LMS_LOG(MAIN, INFO) << "Stopping database updater...";
|
||||||
|
Database::Updater::instance().stop();
|
||||||
|
|
||||||
|
|
||||||
res = EXIT_SUCCESS;
|
res = EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2013 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 <boost/thread.hpp>
|
|
||||||
|
|
||||||
#include "DatabaseUpdateService.hpp"
|
|
||||||
|
|
||||||
namespace Service {
|
|
||||||
|
|
||||||
DatabaseUpdateService::DatabaseUpdateService(Wt::Dbo::SqlConnectionPool &connectionPool)
|
|
||||||
: _metadataParser(),
|
|
||||||
_databaseUpdater( connectionPool, _metadataParser)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
DatabaseUpdateService::start(void)
|
|
||||||
{
|
|
||||||
_databaseUpdater.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
DatabaseUpdateService::stop(void)
|
|
||||||
{
|
|
||||||
_databaseUpdater.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
DatabaseUpdateService::restart(void)
|
|
||||||
{
|
|
||||||
stop();
|
|
||||||
start();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Service
|
|
||||||
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2013 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef DB_UPDATE_SERVICE_HPP
|
|
||||||
#define DB_UPDATE_SERVICE_HPP
|
|
||||||
|
|
||||||
#include <boost/thread.hpp>
|
|
||||||
#include <boost/asio/io_service.hpp>
|
|
||||||
|
|
||||||
#include "metadata/AvFormat.hpp"
|
|
||||||
#include "database-updater/DatabaseUpdater.hpp"
|
|
||||||
|
|
||||||
#include "Service.hpp"
|
|
||||||
|
|
||||||
namespace Service {
|
|
||||||
|
|
||||||
class DatabaseUpdateService : public Service
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
typedef std::shared_ptr<DatabaseUpdateService> pointer;
|
|
||||||
|
|
||||||
DatabaseUpdateService(Wt::Dbo::SqlConnectionPool &connectionPool);
|
|
||||||
|
|
||||||
// Service interface
|
|
||||||
void start(void);
|
|
||||||
void stop(void);
|
|
||||||
void restart(void);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
MetaData::AvFormat _metadataParser;
|
|
||||||
DatabaseUpdater::Updater _databaseUpdater; // Todo use handler
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Service
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2013 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef SERVICE_HPP
|
|
||||||
#define SERVICE_HPP
|
|
||||||
|
|
||||||
#include <boost/thread.hpp>
|
|
||||||
#include <memory>
|
|
||||||
#include <set>
|
|
||||||
|
|
||||||
namespace Service {
|
|
||||||
|
|
||||||
// Interface class wrapper for running services
|
|
||||||
class Service
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
typedef std::shared_ptr<Service> pointer;
|
|
||||||
|
|
||||||
Service(const Service&) = delete;
|
|
||||||
Service& operator=(const Service&) = delete;
|
|
||||||
|
|
||||||
Service() {}
|
|
||||||
virtual ~Service() {}
|
|
||||||
|
|
||||||
virtual void start(void) = 0;
|
|
||||||
virtual void stop(void) = 0;
|
|
||||||
virtual void restart(void) = 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Service
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2013 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 "ServiceManager.hpp"
|
|
||||||
|
|
||||||
namespace Service {
|
|
||||||
|
|
||||||
ServiceManager&
|
|
||||||
ServiceManager::instance()
|
|
||||||
{
|
|
||||||
static ServiceManager instance;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
ServiceManager::ServiceManager()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ServiceManager::~ServiceManager()
|
|
||||||
{
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ServiceManager::add(Service::pointer service)
|
|
||||||
{
|
|
||||||
_services.insert(service);
|
|
||||||
service->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ServiceManager::del(Service::pointer service)
|
|
||||||
{
|
|
||||||
service->stop();
|
|
||||||
_services.erase(service);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ServiceManager::clear(void)
|
|
||||||
{
|
|
||||||
stop();
|
|
||||||
_services.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ServiceManager::start(void)
|
|
||||||
{
|
|
||||||
for (Service::pointer service : _services)
|
|
||||||
service->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ServiceManager::stop(void)
|
|
||||||
{
|
|
||||||
for (Service::pointer service : _services)
|
|
||||||
service->stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
ServiceManager::restart(void)
|
|
||||||
{
|
|
||||||
for (Service::pointer service : _services)
|
|
||||||
service->restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Service
|
|
||||||
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2013 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef SERVICE_CONTROLER_HPP
|
|
||||||
#define SERVICE_CONTROLER_HPP
|
|
||||||
|
|
||||||
#include <set>
|
|
||||||
|
|
||||||
#include "Service.hpp"
|
|
||||||
|
|
||||||
namespace Service {
|
|
||||||
|
|
||||||
// Start/Stop/Reload Services
|
|
||||||
class ServiceManager
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
static ServiceManager& instance();
|
|
||||||
~ServiceManager();
|
|
||||||
|
|
||||||
void add(Service::pointer service);
|
|
||||||
void del(Service::pointer service);
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
void start();
|
|
||||||
void stop();
|
|
||||||
void restart();
|
|
||||||
|
|
||||||
template <class T> typename T::pointer get();
|
|
||||||
|
|
||||||
boost::mutex& mutex() { return _mutex;}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
ServiceManager();
|
|
||||||
ServiceManager(ServiceManager const&); // Don't Implement
|
|
||||||
void operator=(ServiceManager const&); // Don't implement
|
|
||||||
|
|
||||||
boost::mutex _mutex;
|
|
||||||
|
|
||||||
std::set<Service::pointer> _services;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
template <class T> typename T::pointer
|
|
||||||
ServiceManager::get()
|
|
||||||
{
|
|
||||||
std::set<Service::pointer>::iterator it;
|
|
||||||
for (Service::pointer service : _services)
|
|
||||||
{
|
|
||||||
if (typeid(*(service)) == typeid(T)) {
|
|
||||||
return std::dynamic_pointer_cast<T>(service);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return std::shared_ptr<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Service
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -30,8 +30,7 @@
|
|||||||
#include "SettingsUsers.hpp"
|
#include "SettingsUsers.hpp"
|
||||||
|
|
||||||
#include "logger/Logger.hpp"
|
#include "logger/Logger.hpp"
|
||||||
#include "service/ServiceManager.hpp"
|
#include "database/DatabaseUpdater.hpp"
|
||||||
#include "service/DatabaseUpdateService.hpp"
|
|
||||||
|
|
||||||
#include "LmsApplication.hpp"
|
#include "LmsApplication.hpp"
|
||||||
|
|
||||||
@@ -74,11 +73,29 @@ Settings::Settings(Wt::WContainerWidget* parent)
|
|||||||
if (userIsAdmin)
|
if (userIsAdmin)
|
||||||
{
|
{
|
||||||
MediaDirectories* mediaDirectories = new MediaDirectories();
|
MediaDirectories* mediaDirectories = new MediaDirectories();
|
||||||
mediaDirectories->changed().connect(this, &Settings::handleDatabaseDirectoriesChanged);
|
mediaDirectories->changed().connect(std::bind([=]
|
||||||
|
{
|
||||||
|
LMS_LOG(UI, INFO) << "Media directories have changed: requesting imediate scan";
|
||||||
|
|
||||||
|
// On directory add or delete, request an immediate scan
|
||||||
|
//
|
||||||
|
{
|
||||||
|
Wt::Dbo::Transaction transaction(DboSession());
|
||||||
|
Database::MediaDirectorySettings::get(DboSession()).modify()->setManualScanRequested(true);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(Database::Updater::instance().getMutex());
|
||||||
|
Database::Updater::instance().restart();
|
||||||
|
}
|
||||||
|
}));
|
||||||
menu->addItem("Media Folders", mediaDirectories)->setPathComponent("mediadirectories");
|
menu->addItem("Media Folders", mediaDirectories)->setPathComponent("mediadirectories");
|
||||||
|
|
||||||
DatabaseFormView* databaseFormView = new DatabaseFormView();
|
DatabaseFormView* databaseFormView = new DatabaseFormView();
|
||||||
databaseFormView->changed().connect(this, &Settings::restartDatabaseUpdateService);
|
databaseFormView->changed().connect(std::bind([=]
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(Database::Updater::instance().getMutex());
|
||||||
|
Database::Updater::instance().restart();
|
||||||
|
}));
|
||||||
menu->addItem("Database", databaseFormView)->setPathComponent("database");
|
menu->addItem("Database", databaseFormView)->setPathComponent("database");
|
||||||
|
|
||||||
menu->addItem("Users", new Users())->setPathComponent("users");
|
menu->addItem("Users", new Users())->setPathComponent("users");
|
||||||
@@ -90,29 +107,5 @@ Settings::Settings(Wt::WContainerWidget* parent)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
Settings::handleDatabaseDirectoriesChanged()
|
|
||||||
{
|
|
||||||
LMS_LOG(UI, INFO) << "Media directories have changed: requesting imediate scan";
|
|
||||||
// On directory add or delete, request an immediate scan
|
|
||||||
{
|
|
||||||
Wt::Dbo::Transaction transaction(DboSession());
|
|
||||||
Database::MediaDirectorySettings::get(DboSession()).modify()->setManualScanRequested(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
restartDatabaseUpdateService();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Settings::restartDatabaseUpdateService()
|
|
||||||
{
|
|
||||||
// Restarting the update service
|
|
||||||
boost::lock_guard<boost::mutex> serviceLock (Service::ServiceManager::instance().mutex());
|
|
||||||
|
|
||||||
Service::DatabaseUpdateService::pointer service = Service::ServiceManager::instance().get<Service::DatabaseUpdateService>();
|
|
||||||
if (service)
|
|
||||||
service->restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Settings
|
} // namespace Settings
|
||||||
} // namespace UserInterface
|
} // namespace UserInterface
|
||||||
|
|||||||
@@ -28,11 +28,6 @@ class Settings : public Wt::WContainerWidget
|
|||||||
Settings(Wt::WContainerWidget* parent = 0);
|
Settings(Wt::WContainerWidget* parent = 0);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void handleDatabaseDirectoriesChanged();
|
|
||||||
|
|
||||||
void restartDatabaseUpdateService(void);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Settings
|
} // namespace Settings
|
||||||
|
|||||||
@@ -20,6 +20,6 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
// TODO move to utils
|
||||||
void computeCrc(const boost::filesystem::path& p, std::vector<unsigned char>& checksum);
|
void computeCrc(const boost::filesystem::path& p, std::vector<unsigned char>& checksum);
|
||||||
|
|
||||||
Reference in New Issue
Block a user