[DB] Some code refactoring
This commit is contained in:
+2
-4
@@ -7,6 +7,7 @@ lms_SOURCES = \
|
||||
$(srcdir)/cover/CoverArtGrabber.cpp \
|
||||
$(srcdir)/database/Artist.cpp \
|
||||
$(srcdir)/database/DatabaseHandler.cpp \
|
||||
$(srcdir)/database/DatabaseUpdater.cpp \
|
||||
$(srcdir)/database/MediaDirectory.cpp \
|
||||
$(srcdir)/database/Playlist.cpp \
|
||||
$(srcdir)/database/Release.cpp \
|
||||
@@ -15,13 +16,9 @@ lms_SOURCES = \
|
||||
$(srcdir)/database/Track.cpp \
|
||||
$(srcdir)/database/User.cpp \
|
||||
$(srcdir)/database/Video.cpp \
|
||||
$(srcdir)/database-updater/DatabaseUpdater.cpp \
|
||||
$(srcdir)/database-updater/Checksum.cpp \
|
||||
$(srcdir)/image/Image.cpp \
|
||||
$(srcdir)/logger/Logger.cpp \
|
||||
$(srcdir)/metadata/AvFormat.cpp \
|
||||
$(srcdir)/service/ServiceManager.cpp \
|
||||
$(srcdir)/service/DatabaseUpdateService.cpp \
|
||||
$(srcdir)/ui/LmsApplication.cpp \
|
||||
$(srcdir)/ui/auth/LmsAuth.cpp \
|
||||
$(srcdir)/ui/audio/AudioPlayer.cpp \
|
||||
@@ -57,6 +54,7 @@ lms_SOURCES = \
|
||||
$(srcdir)/ui/settings/SettingsMediaDirectoryFormView.cpp \
|
||||
$(srcdir)/ui/settings/SettingsUserFormView.cpp \
|
||||
$(srcdir)/ui/settings/SettingsUsers.cpp \
|
||||
$(srcdir)/utils/Checksum.cpp \
|
||||
$(srcdir)/utils/Utils.cpp
|
||||
|
||||
if VIDEO
|
||||
|
||||
@@ -83,6 +83,8 @@ Handler::Handler(Wt::Dbo::SqlConnectionPool& connectionPool)
|
||||
_session.mapClass<Database::Artist>("artist");
|
||||
_session.mapClass<Database::Genre>("genre");
|
||||
_session.mapClass<Database::Track>("track");
|
||||
_session.mapClass<Database::Classification>("classification");
|
||||
_session.mapClass<Database::ClassificationData>("classification_data");
|
||||
_session.mapClass<Database::Playlist>("playlist");
|
||||
_session.mapClass<Database::PlaylistEntry>("playlist_entry");
|
||||
_session.mapClass<Database::Release>("release");
|
||||
|
||||
@@ -17,19 +17,19 @@
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/asio/placeholders.hpp>
|
||||
|
||||
#include "logger/Logger.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
|
||||
#include "database/Types.hpp"
|
||||
|
||||
#include "Checksum.hpp"
|
||||
#include "DatabaseUpdater.hpp"
|
||||
#include "cover/CoverArtGrabber.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/Checksum.hpp"
|
||||
|
||||
#include "Types.hpp"
|
||||
#include "DatabaseUpdater.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -115,23 +115,40 @@ isPathInParentPath(const boost::filesystem::path& path, const boost::filesystem:
|
||||
} // namespace
|
||||
|
||||
|
||||
namespace DatabaseUpdater {
|
||||
namespace Database {
|
||||
|
||||
using namespace Database;
|
||||
Updater& Updater::instance(void)
|
||||
{
|
||||
static Updater updater;
|
||||
return updater;
|
||||
}
|
||||
|
||||
|
||||
Updater::Updater(Wt::Dbo::SqlConnectionPool &connectionPool, MetaData::Parser& parser)
|
||||
Updater::Updater()
|
||||
: _running(false),
|
||||
_scheduleTimer(_ioService),
|
||||
_db(connectionPool),
|
||||
_metadataParser(parser)
|
||||
_scheduleTimer(_ioService)
|
||||
{
|
||||
_ioService.setThreadCount(1);
|
||||
}
|
||||
|
||||
void
|
||||
Updater::setConnectionPool(Wt::Dbo::SqlConnectionPool& connectionPool)
|
||||
{
|
||||
_db = new Database::Handler(connectionPool);
|
||||
}
|
||||
|
||||
void
|
||||
Updater::restart(void)
|
||||
{
|
||||
stop();
|
||||
start();
|
||||
}
|
||||
|
||||
void
|
||||
Updater::start(void)
|
||||
{
|
||||
if (_db == nullptr)
|
||||
throw std::logic_error("uninitialized db!");
|
||||
|
||||
_running = true;
|
||||
|
||||
// post some jobs in the io_service
|
||||
@@ -154,9 +171,9 @@ Updater::stop(void)
|
||||
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()) {
|
||||
LMS_LOG(DBUPDATER, INFO) << "Manual scan requested!";
|
||||
@@ -229,9 +246,9 @@ Updater::process(boost::system::error_code err)
|
||||
|
||||
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() ));
|
||||
}
|
||||
|
||||
@@ -253,9 +270,9 @@ Updater::process(boost::system::error_code err)
|
||||
// Update database stats
|
||||
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)
|
||||
settings.modify()->setLastUpdate(now);
|
||||
@@ -279,10 +296,10 @@ Updater::process(boost::system::error_code err)
|
||||
void
|
||||
Updater::updateFileExtensions()
|
||||
{
|
||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
||||
Wt::Dbo::Transaction transaction(_db->getSession());
|
||||
|
||||
_audioFileExtensions = MediaDirectorySettings::get(_db.getSession())->getAudioFileExtensions();
|
||||
_videoFileExtensions = MediaDirectorySettings::get(_db.getSession())->getVideoFileExtensions();
|
||||
_audioFileExtensions = MediaDirectorySettings::get(_db->getSession())->getAudioFileExtensions();
|
||||
_videoFileExtensions = MediaDirectorySettings::get(_db->getSession())->getVideoFileExtensions();
|
||||
}
|
||||
|
||||
Artist::pointer
|
||||
@@ -293,9 +310,9 @@ Updater::getArtist( const boost::filesystem::path& file, const std::string& name
|
||||
// First try to get by MBID
|
||||
if (!mbid.empty())
|
||||
{
|
||||
artist = Artist::getByMBID( _db.getSession(), mbid );
|
||||
artist = Artist::getByMBID( _db->getSession(), mbid );
|
||||
if (!artist)
|
||||
artist = Artist::create( _db.getSession(), name, mbid);
|
||||
artist = Artist::create( _db->getSession(), name, mbid);
|
||||
|
||||
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)
|
||||
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())
|
||||
{
|
||||
@@ -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
|
||||
if (!artist)
|
||||
artist = Artist::create( _db.getSession(), name);
|
||||
artist = Artist::create( _db->getSession(), name);
|
||||
|
||||
return artist;
|
||||
}
|
||||
|
||||
return Artist::getNone( _db.getSession() );
|
||||
return Artist::getNone( _db->getSession() );
|
||||
}
|
||||
|
||||
Release::pointer
|
||||
@@ -330,9 +347,9 @@ Updater::getRelease( const boost::filesystem::path& file, const std::string& nam
|
||||
// First try to get by MBID
|
||||
if (!mbid.empty())
|
||||
{
|
||||
release = Release::getByMBID( _db.getSession(), mbid );
|
||||
release = Release::getByMBID( _db->getSession(), mbid );
|
||||
if (!release)
|
||||
release = Release::create( _db.getSession(), name, mbid);
|
||||
release = Release::create( _db->getSession(), name, mbid);
|
||||
|
||||
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)
|
||||
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())
|
||||
{
|
||||
@@ -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
|
||||
if (!release)
|
||||
release = Release::create( _db.getSession(), name);
|
||||
release = Release::create( _db->getSession(), name);
|
||||
|
||||
return release;
|
||||
}
|
||||
|
||||
return Release::getNone( _db.getSession() );
|
||||
return Release::getNone( _db->getSession() );
|
||||
}
|
||||
|
||||
std::vector<Genre::pointer>
|
||||
@@ -366,15 +383,15 @@ Updater::getGenres( const std::list<std::string>& 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)
|
||||
genre = Genre::create(_db.getSession(), name);
|
||||
genre = Genre::create(_db->getSession(), name);
|
||||
|
||||
genres.push_back( genre );
|
||||
}
|
||||
|
||||
if (genres.empty())
|
||||
genres.push_back( Genre::getNone( _db.getSession() ));
|
||||
genres.push_back( Genre::getNone( _db->getSession() ));
|
||||
|
||||
return genres;
|
||||
}
|
||||
@@ -386,9 +403,9 @@ Updater::processAudioFile( const boost::filesystem::path& file, Stats& stats)
|
||||
|
||||
// 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)
|
||||
{
|
||||
@@ -412,9 +429,9 @@ Updater::processAudioFile( const boost::filesystem::path& file, Stats& stats)
|
||||
std::vector<unsigned char> 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 found a least one audio stream
|
||||
@@ -510,7 +527,7 @@ Updater::processAudioFile( const boost::filesystem::path& file, Stats& stats)
|
||||
if (!track)
|
||||
{
|
||||
// Create a new song
|
||||
track = Track::create(_db.getSession(), file);
|
||||
track = Track::create(_db->getSession(), file);
|
||||
LMS_LOG(DBUPDATER, INFO) << "Adding '" << file << "'";
|
||||
stats.nbAdded++;
|
||||
}
|
||||
@@ -675,8 +692,8 @@ Updater::checkAudioFiles( Stats& stats )
|
||||
{
|
||||
LMS_LOG(DBUPDATER, INFO) << "Checking audio files...";
|
||||
|
||||
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> trackPaths = Track::getAllPaths(_db->getSession());;
|
||||
std::vector<boost::filesystem::path> rootDirs = getRootDirectoriesByType(_db->getSession(), Database::MediaDirectory::Audio);
|
||||
|
||||
LMS_LOG(DBUPDATER, DEBUG) << "Checking tracks...";
|
||||
for (auto& trackPath : trackPaths)
|
||||
@@ -686,9 +703,9 @@ Updater::checkAudioFiles( Stats& stats )
|
||||
|
||||
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)
|
||||
{
|
||||
track.remove();
|
||||
@@ -699,10 +716,10 @@ Updater::checkAudioFiles( Stats& stats )
|
||||
|
||||
LMS_LOG(DBUPDATER, DEBUG) << "Checking Genres...";
|
||||
{
|
||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
||||
Wt::Dbo::Transaction transaction(_db->getSession());
|
||||
|
||||
// Now process orphan Genre (no track)
|
||||
auto genres = Genre::getAll(_db.getSession());
|
||||
auto genres = Genre::getAll(_db->getSession());
|
||||
for (auto genre : genres)
|
||||
{
|
||||
if (genre->getTracks().size() == 0)
|
||||
@@ -715,9 +732,9 @@ Updater::checkAudioFiles( Stats& stats )
|
||||
|
||||
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)
|
||||
{
|
||||
LMS_LOG(DBUPDATER, DEBUG) << "Removing orphan artist '" << artist->getName() << "'";
|
||||
@@ -727,9 +744,9 @@ Updater::checkAudioFiles( Stats& stats )
|
||||
|
||||
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)
|
||||
{
|
||||
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";
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
Updater::checkVideoFiles( Stats& stats )
|
||||
{
|
||||
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> rootDirs = getRootDirectoriesByType(_db->getSession(), Database::MediaDirectory::Video);
|
||||
std::vector<boost::filesystem::path> videoPaths = Video::getAllPaths(_db->getSession());
|
||||
|
||||
LMS_LOG(DBUPDATER, DEBUG) << "Checking videos...";
|
||||
for (auto& videoPath : videoPaths)
|
||||
@@ -777,9 +794,9 @@ Updater::checkVideoFiles( Stats& stats )
|
||||
|
||||
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)
|
||||
{
|
||||
video.remove();
|
||||
@@ -797,10 +814,10 @@ Updater::processVideoFile( const boost::filesystem::path& file, Stats& stats)
|
||||
// Check last update time
|
||||
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
|
||||
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)
|
||||
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.
|
||||
if (!video)
|
||||
{
|
||||
video = Video::create(_db.getSession(), file);
|
||||
video = Video::create(_db->getSession(), file);
|
||||
LMS_LOG(DBUPDATER, DEBUG) << "Adding '" << file << "'";
|
||||
stats.nbAdded++;
|
||||
}
|
||||
@@ -860,4 +877,4 @@ Updater::processVideoFile( const boost::filesystem::path& file, Stats& stats)
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
} // namespace DatabaseUpdater
|
||||
} // namespace Database
|
||||
@@ -20,28 +20,22 @@
|
||||
#ifndef DB_UPDATER_HPP
|
||||
#define DB_UPDATER_HPP
|
||||
|
||||
#include <boost/asio/deadline_timer.hpp>
|
||||
#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"
|
||||
|
||||
namespace DatabaseUpdater {
|
||||
namespace Database {
|
||||
|
||||
class Updater
|
||||
{
|
||||
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
|
||||
{
|
||||
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;}
|
||||
};
|
||||
|
||||
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
|
||||
{
|
||||
Database::MediaDirectory::Type type;
|
||||
@@ -96,19 +109,21 @@ class Updater
|
||||
|
||||
bool _running;
|
||||
Wt::WIOService _ioService;
|
||||
Wt::Signal<Stats> _sigChanged;
|
||||
std::mutex _mutex;
|
||||
|
||||
boost::asio::deadline_timer _scheduleTimer;
|
||||
|
||||
Database::Handler _db;
|
||||
Database::Handler* _db = nullptr;
|
||||
|
||||
std::vector<boost::filesystem::path> _audioFileExtensions;
|
||||
std::vector<boost::filesystem::path> _videoFileExtensions;
|
||||
|
||||
MetaData::Parser& _metadataParser;
|
||||
MetaData::AvFormat _metadataParser;
|
||||
|
||||
|
||||
}; // class Updater
|
||||
|
||||
} // DatabaseUpdater
|
||||
} // Database
|
||||
|
||||
#endif
|
||||
+10
-1
@@ -37,6 +37,8 @@ class Artist;
|
||||
class Release;
|
||||
class Track;
|
||||
class PlaylistEntry;
|
||||
class Classification;
|
||||
class ClassificationData;
|
||||
|
||||
class Genre
|
||||
{
|
||||
@@ -156,6 +158,8 @@ class Track
|
||||
void setArtist(Wt::Dbo::ptr<Artist> artist) { _artist = artist; }
|
||||
void setRelease(Wt::Dbo::ptr<Release> release) { _release = release; }
|
||||
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 getTotalTrackNumber(void) const { return _totalTrackNumber; }
|
||||
@@ -175,6 +179,8 @@ class Track
|
||||
Wt::Dbo::ptr<Release> getRelease(void) const { return _release; }
|
||||
std::vector< Genre::pointer > getGenres(void) const;
|
||||
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>
|
||||
void persist(Action& a)
|
||||
@@ -198,6 +204,8 @@ class Track
|
||||
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, _playlistEntries, Wt::Dbo::ManyToOne, "track");
|
||||
Wt::Dbo::hasMany(a, _classifications, Wt::Dbo::ManyToOne, "track");
|
||||
Wt::Dbo::hasMany(a, _classificationData, Wt::Dbo::ManyToOne, "track");
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -228,7 +236,8 @@ class Track
|
||||
Wt::Dbo::ptr<Release> _release;
|
||||
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<Classification> > _classifications;
|
||||
Wt::Dbo::collection< Wt::Dbo::ptr<ClassificationData> > _classificationData;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "Artist.hpp"
|
||||
#include "Track.hpp"
|
||||
#include "Playlist.hpp"
|
||||
#include "Classification.hpp"
|
||||
#include "Release.hpp"
|
||||
#include "Video.hpp"
|
||||
#include "MediaDirectory.hpp"
|
||||
|
||||
+15
-19
@@ -19,18 +19,17 @@
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <Wt/WServer>
|
||||
|
||||
#include "config/config.h"
|
||||
#include "av/AvInfo.hpp"
|
||||
#include "av/AvTranscoder.hpp"
|
||||
#include "logger/Logger.hpp"
|
||||
#include "image/Image.hpp"
|
||||
|
||||
#include "database/DatabaseUpdater.hpp"
|
||||
#include "ui/LmsApplication.hpp"
|
||||
|
||||
#include "service/ServiceManager.hpp"
|
||||
#include "service/DatabaseUpdateService.hpp"
|
||||
|
||||
#include <Wt/WServer>
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
@@ -49,8 +48,6 @@ int main(int argc, char* argv[])
|
||||
|
||||
Wt::WServer::instance()->logger().configure("*"); // log everything
|
||||
|
||||
Service::ServiceManager& serviceManager = Service::ServiceManager::instance();
|
||||
|
||||
// lib init
|
||||
Image::init(argv[0]);
|
||||
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
|
||||
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
|
||||
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...";
|
||||
server.start();
|
||||
|
||||
// Start underlying services
|
||||
LMS_LOG(MAIN, INFO) << "Starting services...";
|
||||
serviceManager.start();
|
||||
|
||||
// Wait
|
||||
LMS_LOG(MAIN, INFO) << "Now running...";
|
||||
|
||||
// Waiting for shutdown command
|
||||
Wt::WServer::waitForShutdown(argv[0]);
|
||||
|
||||
LMS_LOG(MAIN, INFO) << "Stopping services...";
|
||||
serviceManager.stop();
|
||||
serviceManager.clear();
|
||||
|
||||
// Stop
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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 "logger/Logger.hpp"
|
||||
#include "service/ServiceManager.hpp"
|
||||
#include "service/DatabaseUpdateService.hpp"
|
||||
#include "database/DatabaseUpdater.hpp"
|
||||
|
||||
#include "LmsApplication.hpp"
|
||||
|
||||
@@ -74,11 +73,29 @@ Settings::Settings(Wt::WContainerWidget* parent)
|
||||
if (userIsAdmin)
|
||||
{
|
||||
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");
|
||||
|
||||
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("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 UserInterface
|
||||
|
||||
@@ -28,11 +28,6 @@ class Settings : public Wt::WContainerWidget
|
||||
Settings(Wt::WContainerWidget* parent = 0);
|
||||
|
||||
private:
|
||||
|
||||
void handleDatabaseDirectoriesChanged();
|
||||
|
||||
void restartDatabaseUpdateService(void);
|
||||
|
||||
};
|
||||
|
||||
} // namespace Settings
|
||||
|
||||
@@ -20,6 +20,6 @@
|
||||
#include <vector>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
|
||||
// TODO move to utils
|
||||
void computeCrc(const boost::filesystem::path& p, std::vector<unsigned char>& checksum);
|
||||
|
||||
Reference in New Issue
Block a user