From 9cb4918f4416f5e890da0e2975c4012b08e95809 Mon Sep 17 00:00:00 2001 From: emeric Date: Mon, 16 Apr 2018 16:56:51 +0200 Subject: [PATCH] Upgrade from Wt3 to Wt4 --- README.md | 32 ++-- TODO | 1 - approot/admin-initwizard.xml | 2 +- configure.ac | 32 +--- src/Makefile.am | 7 +- src/av/AvInfo.cpp | 14 +- src/av/AvInfo.hpp | 4 +- src/av/AvTranscoder.cpp | 4 +- src/cover/CoverArtGrabber.cpp | 8 +- src/database/DatabaseHandler.cpp | 58 +++---- src/database/DatabaseHandler.hpp | 12 +- src/database/DbArtist.cpp | 4 +- src/database/DbArtist.hpp | 6 +- src/database/MediaDirectory.cpp | 2 +- src/database/MediaDirectory.hpp | 5 +- src/database/Playlist.cpp | 4 +- src/database/Playlist.hpp | 2 +- src/database/Release.cpp | 15 +- src/database/Release.hpp | 6 +- src/database/SearchFilter.cpp | 40 ----- src/database/SearchFilter.hpp | 68 -------- src/database/Setting.cpp | 31 +--- src/database/Setting.hpp | 18 +-- src/database/Track.cpp | 48 +----- src/database/Track.hpp | 50 +++--- src/database/User.cpp | 2 +- src/database/User.hpp | 4 +- src/feature/FeatureExtractor.cpp | 216 -------------------------- src/feature/FeatureExtractor.hpp | 43 ----- src/feature/FeatureStore.cpp | 126 --------------- src/feature/FeatureStore.hpp | 47 ------ src/image/Image.cpp | 2 +- src/main/main.cpp | 15 +- src/metadata/AvFormat.cpp | 50 +++--- src/metadata/MetaData.hpp | 6 +- src/metadata/TagLibParser.cpp | 45 +++--- src/scanner/MediaScanner.cpp | 137 ++++++++-------- src/scanner/MediaScanner.hpp | 18 ++- src/ui/Auth.cpp | 47 +++--- src/ui/Auth.hpp | 10 +- src/ui/HomeView.cpp | 9 +- src/ui/HomeView.hpp | 4 +- src/ui/LmsApplication.cpp | 170 +++++++------------- src/ui/LmsApplication.hpp | 37 +++-- src/ui/MediaPlayer.cpp | 10 +- src/ui/MediaPlayer.hpp | 12 +- src/ui/PlayQueueView.cpp | 105 ++++++------- src/ui/PlayQueueView.hpp | 14 +- src/ui/SettingsView.cpp | 129 ++++++++------- src/ui/SettingsView.hpp | 5 +- src/ui/admin/DatabaseSettingsView.cpp | 138 +++++++--------- src/ui/admin/DatabaseSettingsView.hpp | 5 +- src/ui/admin/InitWizardView.cpp | 59 ++++--- src/ui/admin/InitWizardView.hpp | 5 +- src/ui/admin/UserView.cpp | 99 ++++++------ src/ui/admin/UserView.hpp | 4 +- src/ui/admin/UsersView.cpp | 45 +++--- src/ui/admin/UsersView.hpp | 6 +- src/ui/common/InputRange.cpp | 56 ------- src/ui/common/InputRange.hpp | 51 ------ src/ui/common/LineEdit.cpp | 55 ------- src/ui/common/LineEdit.hpp | 44 ------ src/ui/common/Validators.cpp | 21 +-- src/ui/common/Validators.hpp | 8 +- src/ui/explore/ArtistView.cpp | 68 ++++---- src/ui/explore/ArtistView.hpp | 6 +- src/ui/explore/ArtistsView.cpp | 34 ++-- src/ui/explore/ArtistsView.hpp | 11 +- src/ui/explore/Explore.cpp | 68 ++++---- src/ui/explore/Explore.hpp | 18 +-- src/ui/explore/Filters.cpp | 69 +++----- src/ui/explore/Filters.hpp | 13 +- src/ui/explore/ReleaseView.cpp | 71 ++++----- src/ui/explore/ReleaseView.hpp | 4 +- src/ui/explore/ReleasesView.cpp | 59 +++---- src/ui/explore/ReleasesView.hpp | 11 +- src/ui/explore/TracksView.cpp | 63 +++----- src/ui/explore/TracksView.hpp | 10 +- src/ui/resource/ImageResource.cpp | 39 ++--- src/ui/resource/ImageResource.hpp | 4 +- src/ui/resource/TranscodeResource.cpp | 7 +- src/ui/resource/TranscodeResource.hpp | 4 +- src/utils/Logger.hpp | 6 +- src/utils/Path.cpp | 2 +- src/utils/Utils.cpp | 61 +++----- src/utils/Utils.hpp | 37 ++--- test/TestAvMetadata.cpp | 14 +- 87 files changed, 954 insertions(+), 2057 deletions(-) delete mode 100644 src/database/SearchFilter.cpp delete mode 100644 src/database/SearchFilter.hpp delete mode 100644 src/feature/FeatureExtractor.cpp delete mode 100644 src/feature/FeatureExtractor.hpp delete mode 100644 src/feature/FeatureStore.cpp delete mode 100644 src/feature/FeatureStore.hpp delete mode 100644 src/ui/common/InputRange.cpp delete mode 100644 src/ui/common/InputRange.hpp delete mode 100644 src/ui/common/LineEdit.cpp delete mode 100644 src/ui/common/LineEdit.hpp diff --git a/README.md b/README.md index 923266e5..510eb624 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,13 @@ # LMS - Lightweight Media Server LMS is a self-hosted media streaming software, released under the GPLv3 license. -It allows you to access your music and your videos using an http(s) web interface. +It allows you to access your music using an http(s) web interface. ## Features - Audio transcode for maximum interoperability and low bandwith requirements - - User management - - Playlist support - MusicBrainzID support to handle duplicated artist and release names - -Tags are automatically created to facilitate music searching, using: - - Multi genre information from metadata - - High-level information from AcousticBrainz + - Filter by genre and/or group + - User management LMS is written entirely in C++. Therefore, it is suitable to run on embedded devices, where space and memory are limited. @@ -19,29 +15,29 @@ LMS is written entirely in C++. Therefore, it is suitable to run on embedded dev ### Debian ```sh -$ apt-get install g++ autoconf automake libboost-dev libboost-locale-dev libboost-iostreams-dev libavcodec-dev libavutil-dev libavformat-dev libav-tools libwtdbosqlite-dev libwthttp-dev libwtdbo-dev libwt-dev libmagick++-dev libpstreams-dev libcurlpp-dev libconfig++-dev libpstreams-dev ffmpeg libtag1-dev +apt-get install g++ autoconf automake libboost-filesystem-dev libboost-system-dev libavcodec-dev libavutil-dev libavformat-dev libav-tools libwtdbosqlite-dev libwthttp-dev libwtdbo-dev libwt-dev libmagick++-dev libpstreams-dev libconfig++-dev libpstreams-dev ffmpeg libtag1-dev ``` ## Build ```sh -$ git clone https://github.com/epoupon/lms.git lms -$ cd lms -$ autoreconf -vfi -$ mkdir build -$ cd build -$ ../configure --prefix=/usr --sysconfdir=/etc +git clone https://github.com/epoupon/lms.git lms +cd lms +autoreconf -vfi +mkdir build +cd build +../configure --prefix=/usr --sysconfdir=/etc ``` configure will complain if a mandatory library is missing. ```sh -$ make -j 4 +make ``` ## Install ```sh -$ make install +make install ``` This command requires root privileges @@ -49,13 +45,13 @@ This command requires root privileges LMS uses a configuration file, installed in '/etc/lms.conf' It is recommended to edit this file and change the relevant settings (working directory, listen port, etc.) -Other settings are set using the web interface. +All other settings are set using the web interface. It is highly recommended to run LMS as a non root user. Therefore make sure the user has write permissions on the working directory. ## Running ```sh -$ lms [config_file] +lms [config_file] ``` Logs are output in the working directory, in the file 'lms.log' diff --git a/TODO b/TODO index bcdc9f75..d498857e 100644 --- a/TODO +++ b/TODO @@ -37,7 +37,6 @@ - Display only the most popular cluster of each cluster type? [Settings] - - Add a audio settings: format + bitrate to be used - Add a user management view - Add multi root directories support - Add a first connection wizard diff --git a/approot/admin-initwizard.xml b/approot/admin-initwizard.xml index 175cb54d..5eb94e27 100644 --- a/approot/admin-initwizard.xml +++ b/approot/admin-initwizard.xml @@ -5,7 +5,7 @@
diff --git a/configure.ac b/configure.ac index 41173572..9b81e6c6 100644 --- a/configure.ac +++ b/configure.ac @@ -16,7 +16,7 @@ fi AC_SUBST(MAGICKXX_CFLAGS) AC_SUBST(MAGICKXX_LIBS) -AC_CHECK_HEADERS([Wt/WApplication pstreams/pstream.h], +AC_CHECK_HEADERS([Wt/WApplication.h pstreams/pstream.h], [], [AC_MSG_ERROR([Header not found or unusable !])]) @@ -66,36 +66,6 @@ AC_CHECK_LIB( [boost_filesystem], , [AC_MSG_ERROR([libboost_filesystem not found!])]) -AC_CHECK_LIB( [boost_locale], - [main], - , - [AC_MSG_ERROR([libboost_locale not found!])]) - -AC_CHECK_LIB( [boost_date_time], - [main], - , - [AC_MSG_ERROR([libboost_date_time not found!])]) - -AC_CHECK_LIB( [boost_iostreams], - [main], - , - [AC_MSG_ERROR([libboost_iostreams not found!])]) - -AC_CHECK_LIB( [boost_thread], - [main], - , - [AC_MSG_ERROR([libboost_thread not found!])]) - -AC_CHECK_LIB( [curlpp], - [main], - , - [AC_MSG_ERROR([libcurlpp not found!])]) - -AC_CHECK_LIB( [curl], - [curl_easy_cleanup], - , - [AC_MSG_ERROR([libcurl not found!])]) - AC_CHECK_LIB( [tag], [main], , diff --git a/src/Makefile.am b/src/Makefile.am index d6e43294..88626589 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -10,13 +10,10 @@ lms_SOURCES = \ $(srcdir)/database/MediaDirectory.cpp \ $(srcdir)/database/Playlist.cpp \ $(srcdir)/database/Release.cpp \ - $(srcdir)/database/SearchFilter.cpp \ $(srcdir)/database/Setting.cpp \ $(srcdir)/database/SqlQuery.cpp \ $(srcdir)/database/Track.cpp \ $(srcdir)/database/User.cpp \ - $(srcdir)/feature/FeatureExtractor.cpp \ - $(srcdir)/feature/FeatureStore.cpp \ $(srcdir)/image/Image.cpp \ $(srcdir)/metadata/AvFormat.cpp \ $(srcdir)/metadata/TagLibParser.cpp \ @@ -31,8 +28,6 @@ lms_SOURCES = \ $(srcdir)/ui/admin/InitWizardView.cpp \ $(srcdir)/ui/admin/UserView.cpp \ $(srcdir)/ui/admin/UsersView.cpp \ - $(srcdir)/ui/common/InputRange.cpp \ - $(srcdir)/ui/common/LineEdit.cpp \ $(srcdir)/ui/common/Validators.cpp \ $(srcdir)/ui/explore/ArtistView.cpp \ $(srcdir)/ui/explore/ArtistsView.cpp \ @@ -48,6 +43,6 @@ lms_SOURCES = \ $(srcdir)/utils/Path.cpp \ $(srcdir)/utils/Utils.cpp -lms_CXXFLAGS=-std=c++11 -Wall -I$(srcdir)/third-party -I$(srcdir)/ui $(MAGICKXX_CFLAGS) -D_REENTRANT -DBOOST_SPIRIT_THREADSAFE +lms_CXXFLAGS=-std=c++14 -Wall -I$(srcdir)/third-party -I$(srcdir)/ui $(MAGICKXX_CFLAGS) -D_REENTRANT lms_LDADD=$(MAGICKXX_LIBS) diff --git a/src/av/AvInfo.cpp b/src/av/AvInfo.cpp index 8ba4551c..d433fd43 100644 --- a/src/av/AvInfo.cpp +++ b/src/av/AvInfo.cpp @@ -57,14 +57,14 @@ MediaFile::MediaFile(const boost::filesystem::path& p) int error = avformat_open_input(&_context, _p.string().c_str(), nullptr, nullptr); if (error < 0) { - LMS_LOG(AV, ERROR) << "Cannot open " << _p << ": " << averror_to_string(error); + LMS_LOG(AV, ERROR) << "Cannot open " << _p.string() << ": " << averror_to_string(error); throw MediaFileException(error); } error = avformat_find_stream_info(_context, nullptr); if (error < 0) { - LMS_LOG(AV, ERROR) << "Cannot find stream information on " << _p << ": " << averror_to_string(error); + LMS_LOG(AV, ERROR) << "Cannot find stream information on " << _p.string() << ": " << averror_to_string(error); avformat_close_input(&_context); throw MediaFileException(error); } @@ -75,13 +75,13 @@ MediaFile::~MediaFile() avformat_close_input(&_context); } -boost::posix_time::time_duration +std::chrono::milliseconds MediaFile::getDuration() const { - if (static_cast(_context->duration) != AV_NOPTS_VALUE ) - return boost::posix_time::seconds(_context->duration / AV_TIME_BASE); - else - return boost::posix_time::seconds(0); // TODO, do something better? + if (_context->duration == AV_NOPTS_VALUE) + return std::chrono::milliseconds(0); // TODO estimate + + return std::chrono::milliseconds(_context->duration / AV_TIME_BASE * 1000); } void diff --git a/src/av/AvInfo.hpp b/src/av/AvInfo.hpp index 45e44f45..f3a4ee53 100644 --- a/src/av/AvInfo.hpp +++ b/src/av/AvInfo.hpp @@ -33,10 +33,10 @@ extern "C" #include #include #include +#include #include #include -#include //no i/o just types #include "utils/Exception.hpp" @@ -75,7 +75,7 @@ class MediaFile const boost::filesystem::path& getPath() const {return _p;}; - boost::posix_time::time_duration getDuration() const; + std::chrono::milliseconds getDuration() const; std::map getMetaData(void); std::vector getStreamInfo() const; diff --git a/src/av/AvTranscoder.cpp b/src/av/AvTranscoder.cpp index 44c7c33f..4d02191c 100644 --- a/src/av/AvTranscoder.cpp +++ b/src/av/AvTranscoder.cpp @@ -101,7 +101,7 @@ Transcoder::init() } if (!avConvPath.empty()) - LMS_LOG(TRANSCODE, INFO) << "Using transcoder " << avConvPath; + LMS_LOG(TRANSCODE, INFO) << "Using transcoder " << avConvPath.string(); else throw std::runtime_error("Cannot find any transcoder binary!"); } @@ -123,7 +123,7 @@ Transcoder::start() else if (!boost::filesystem::is_regular( _filePath) ) return false; - LMS_LOG_TRANSCODE(INFO) << "Transcoding file '" << _filePath << "'"; + LMS_LOG_TRANSCODE(INFO) << "Transcoding file '" << _filePath.string() << "'"; std::vector args; diff --git a/src/cover/CoverArtGrabber.cpp b/src/cover/CoverArtGrabber.cpp index 49546400..f720e7c2 100644 --- a/src/cover/CoverArtGrabber.cpp +++ b/src/cover/CoverArtGrabber.cpp @@ -65,7 +65,7 @@ getFromAvMediaFile(const Av::MediaFile& input, std::size_t nbMaxCovers) if (image.load(picture.data)) res.push_back( image ); else - LMS_LOG(COVER, ERROR) << "Cannot load embedded cover file in '" << input.getPath() << "'"; + LMS_LOG(COVER, ERROR) << "Cannot load embedded cover file in '" << input.getPath().string() << "'"; } return res; @@ -87,7 +87,7 @@ Grabber::getFromDirectory(const boost::filesystem::path& p, std::size_t nbMaxCov if (image.load(coverPath)) res.push_back(image); else - LMS_LOG(COVER, ERROR) << "Cannot load image in file '" << coverPath << "'"; + LMS_LOG(COVER, ERROR) << "Cannot load image in file '" << coverPath.string() << "'"; } return res; @@ -116,7 +116,7 @@ Grabber::getCoverPaths(const boost::filesystem::path& directoryPath, std::size_t if (boost::filesystem::file_size(path) > _maxFileSize) { - LMS_LOG(COVER, INFO) << "Cover file '" << path << " is too big (" << boost::filesystem::file_size(path) << "), limit is " << _maxFileSize; + LMS_LOG(COVER, INFO) << "Cover file '" << path.string() << " is too big (" << boost::filesystem::file_size(path) << "), limit is " << _maxFileSize; continue; } @@ -138,7 +138,7 @@ Grabber::getFromTrack(const boost::filesystem::path& p, std::size_t nbMaxCovers) } catch (Av::MediaFileException& e) { - LMS_LOG(COVER, ERROR) << "Cannot get covers from track " << p << ": " << e.what(); + LMS_LOG(COVER, ERROR) << "Cannot get covers from track " << p.string() << ": " << e.what(); } return std::vector(); diff --git a/src/database/DatabaseHandler.cpp b/src/database/DatabaseHandler.cpp index 2186d2c7..d4267fed 100644 --- a/src/database/DatabaseHandler.cpp +++ b/src/database/DatabaseHandler.cpp @@ -19,17 +19,17 @@ #include -#include -#include +#include +#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include "Setting.hpp" @@ -51,24 +51,24 @@ Handler::configureAuth(void) { authService.setEmailVerificationEnabled(false); authService.setAuthTokensEnabled(true, "lmsauth"); - authService.setIdentityPolicy(Wt::Auth::LoginNameIdentity); + authService.setIdentityPolicy(Wt::Auth::IdentityPolicy::LoginName); authService.setRandomTokenLength(32); authService.setTokenHashFunction(new Wt::Auth::BCryptHashFunction(8)); - Wt::Auth::PasswordVerifier *verifier = new Wt::Auth::PasswordVerifier(); - verifier->addHashFunction(new Wt::Auth::BCryptHashFunction(8)); - passwordService.setVerifier(verifier); + auto verifier = std::make_unique(); + verifier->addHashFunction(std::make_unique(8)); + passwordService.setVerifier(std::move(verifier)); passwordService.setAttemptThrottlingEnabled(true); - Wt::Auth::PasswordStrengthValidator* strengthValidator = new Wt::Auth::PasswordStrengthValidator(); + auto strengthValidator = std::make_unique(); // Reduce some constraints... - strengthValidator->setMinimumLength( Wt::Auth::PasswordStrengthValidator::PassPhrase, 4); - strengthValidator->setMinimumLength( Wt::Auth::PasswordStrengthValidator::OneCharClass, 4); - strengthValidator->setMinimumLength( Wt::Auth::PasswordStrengthValidator::TwoCharClass, 4); - strengthValidator->setMinimumLength( Wt::Auth::PasswordStrengthValidator::ThreeCharClass, 4 ); - strengthValidator->setMinimumLength( Wt::Auth::PasswordStrengthValidator::FourCharClass, 4 ); + strengthValidator->setMinimumLength( Wt::Auth::PasswordStrengthType::PassPhrase, 4); + strengthValidator->setMinimumLength( Wt::Auth::PasswordStrengthType::OneCharClass, 4); + strengthValidator->setMinimumLength( Wt::Auth::PasswordStrengthType::TwoCharClass, 4); + strengthValidator->setMinimumLength( Wt::Auth::PasswordStrengthType::ThreeCharClass, 4 ); + strengthValidator->setMinimumLength( Wt::Auth::PasswordStrengthType::FourCharClass, 4 ); - passwordService.setStrengthValidator(strengthValidator); + passwordService.setStrengthValidator(std::move(strengthValidator)); } const Wt::Auth::AuthService& @@ -182,24 +182,26 @@ Handler::createUser(const Wt::Auth::User& authUser) return User::pointer(); } - User::pointer user = _session.add(new User()); + User::pointer user = _session.add(std::make_unique()); Wt::Dbo::ptr authInfo = _users->find(authUser); authInfo.modify()->setUser(user); return user; } -Wt::Dbo::SqlConnectionPool* +std::unique_ptr Handler::createConnectionPool(boost::filesystem::path p) { - LMS_LOG(DB, INFO) << "Creating connection pool on file " << p; - - Wt::Dbo::backend::Sqlite3 *connection = new Wt::Dbo::backend::Sqlite3(p.string()); + LMS_LOG(DB, INFO) << "Creating connection pool on file " << p.string(); + auto connection = std::make_unique(p.string()); connection->executeSql("pragma journal_mode=WAL"); - connection->setProperty("show-queries", "true"); - return new Wt::Dbo::FixedSqlConnectionPool(connection, 1); + + auto pool = std::make_unique(std::move(connection), 1); + pool->setTimeout(std::chrono::seconds(1)); + + return pool; } diff --git a/src/database/DatabaseHandler.hpp b/src/database/DatabaseHandler.hpp index f99aa870..1a1a8006 100644 --- a/src/database/DatabaseHandler.hpp +++ b/src/database/DatabaseHandler.hpp @@ -23,12 +23,12 @@ #include #include -#include -#include +#include +#include -#include -#include -#include +#include +#include +#include #include "Types.hpp" @@ -60,7 +60,7 @@ class Handler static const Wt::Auth::AuthService& getAuthService(); static const Wt::Auth::PasswordService& getPasswordService(); - static Wt::Dbo::SqlConnectionPool* createConnectionPool(boost::filesystem::path db); + static std::unique_ptr createConnectionPool(boost::filesystem::path db); private: diff --git a/src/database/DbArtist.cpp b/src/database/DbArtist.cpp index ec08bc52..ac332472 100644 --- a/src/database/DbArtist.cpp +++ b/src/database/DbArtist.cpp @@ -54,7 +54,7 @@ Artist::getById(Wt::Dbo::Session& session, Artist::id_type id) Artist::pointer Artist::create(Wt::Dbo::Session& session, const std::string& name, const std::string& MBID) { - return session.add(new Artist(name, MBID)); + return session.add(std::make_unique(name, MBID)); } std::vector @@ -75,7 +75,7 @@ Artist::getAllOrphans(Wt::Dbo::Session& session) static Wt::Dbo::Query getQuery(Wt::Dbo::Session& session, - const std::set& clusterIds, + const std::set& clusterIds, const std::vector& keywords) { WhereClause where; diff --git a/src/database/DbArtist.hpp b/src/database/DbArtist.hpp index 6ee5b283..89c9a92b 100644 --- a/src/database/DbArtist.hpp +++ b/src/database/DbArtist.hpp @@ -23,10 +23,8 @@ #include #include -#include -#include - -#include "SearchFilter.hpp" +#include +#include namespace Database { diff --git a/src/database/MediaDirectory.cpp b/src/database/MediaDirectory.cpp index 88b30e88..d9801689 100644 --- a/src/database/MediaDirectory.cpp +++ b/src/database/MediaDirectory.cpp @@ -31,7 +31,7 @@ MediaDirectory::MediaDirectory(boost::filesystem::path p) MediaDirectory::pointer MediaDirectory::create(Wt::Dbo::Session& session, boost::filesystem::path p) { - return session.add( new MediaDirectory(p) ); + return session.add( std::make_unique(p) ); } void diff --git a/src/database/MediaDirectory.hpp b/src/database/MediaDirectory.hpp index 3bc2e497..434e78a3 100644 --- a/src/database/MediaDirectory.hpp +++ b/src/database/MediaDirectory.hpp @@ -24,8 +24,9 @@ #include -#include -#include +#include +#include + namespace Database { class MediaDirectory diff --git a/src/database/Playlist.cpp b/src/database/Playlist.cpp index f29e4927..8676ffda 100644 --- a/src/database/Playlist.cpp +++ b/src/database/Playlist.cpp @@ -38,7 +38,7 @@ Playlist::Playlist(std::string name, bool isPublic, Wt::Dbo::ptr user) Playlist::pointer Playlist::create(Wt::Dbo::Session& session, std::string name, bool isPublic, Wt::Dbo::ptr user) { - return session.add( new Playlist(name, isPublic, user) ); + return session.add( std::make_unique(name, isPublic, user) ); } PlaylistEntry::PlaylistEntry() @@ -75,7 +75,7 @@ PlaylistEntry::PlaylistEntry(Wt::Dbo::ptr track, Wt::Dbo::ptr p PlaylistEntry::pointer PlaylistEntry::create(Wt::Dbo::Session& session, Wt::Dbo::ptr track, Wt::Dbo::ptr playlist) { - return session.add( new PlaylistEntry( track, playlist) ); + return session.add( std::make_unique( track, playlist) ); } diff --git a/src/database/Playlist.hpp b/src/database/Playlist.hpp index 4e2b1f04..beddbfa7 100644 --- a/src/database/Playlist.hpp +++ b/src/database/Playlist.hpp @@ -20,7 +20,7 @@ #ifndef DATABASE_PLAYLIST_HPP #define DATABASE_PLAYLIST_HPP -#include +#include #include diff --git a/src/database/Release.cpp b/src/database/Release.cpp index 73c65bdf..ad372248 100644 --- a/src/database/Release.cpp +++ b/src/database/Release.cpp @@ -18,7 +18,6 @@ */ #include "Types.hpp" -#include "SearchFilter.hpp" #include "SqlQuery.hpp" namespace Database @@ -53,7 +52,7 @@ Release::getById(Wt::Dbo::Session& session, Release::id_type id) Release::pointer Release::create(Wt::Dbo::Session& session, const std::string& name, const std::string& MBID) { - return session.add(new Release(name, MBID)); + return session.add(std::make_unique(name, MBID)); } std::vector @@ -74,7 +73,7 @@ Release::getAllOrphans(Wt::Dbo::Session& session) static Wt::Dbo::Query getQuery(Wt::Dbo::Session& session, - const std::set& clusterIds, + const std::set& clusterIds, const std::vector keywords) { WhereClause where; @@ -140,22 +139,22 @@ Release::getReleaseYear(bool original) const { assert(session()); - Wt::Dbo::collection times = session()->query( + Wt::Dbo::collection dates = session()->query( std::string("SELECT ") + (original ? "t.original_date" : "t.date") + " FROM track t INNER JOIN release r ON r.id = t.release_id") .where("r.id = ?") .groupBy("t.date") .bind(this->id()); /* various dates, no date */ - if (times.empty() || times.size() > 1) + if (dates.empty() || dates.size() > 1) return boost::none; - boost::gregorian::date date = times.front().date(); + auto date = dates.front(); - if (date.is_special()) + if (!date.isValid()) return boost::none; - return boost::make_optional(date.year()); + return date.year(); } std::vector> diff --git a/src/database/Release.hpp b/src/database/Release.hpp index 7e46795e..1e143e29 100644 --- a/src/database/Release.hpp +++ b/src/database/Release.hpp @@ -21,9 +21,7 @@ #include -#include - -#include "SearchFilter.hpp" +#include namespace Database { @@ -68,7 +66,7 @@ class Release : public Wt::Dbo::Dbo // Accessors std::string getName() const { return _name; } std::string getMBID() const { return _MBID; } - boost::posix_time::time_duration getDuration(void) const; + std::chrono::seconds getDuration(void) const; // Get the artists of this release std::vector > getArtists() const; diff --git a/src/database/SearchFilter.cpp b/src/database/SearchFilter.cpp deleted file mode 100644 index 5fb23e94..00000000 --- a/src/database/SearchFilter.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2015 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 . - */ - -#include "utils/Logger.hpp" - -#include "SearchFilter.hpp" - -namespace Database -{ - -void -SearchFilter::operator+=(const SearchFilter& filter) -{ -} - -SqlQuery -SearchFilter::generatePartialQuery() -{ - SqlQuery sqlQuery; - return sqlQuery; -} - -} // namespace Database - diff --git a/src/database/SearchFilter.hpp b/src/database/SearchFilter.hpp deleted file mode 100644 index 01bbcb06..00000000 --- a/src/database/SearchFilter.hpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2015 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 . - */ - -#ifndef _DB_SEARCH_FILTER_HPP_ -#define _DB_SEARCH_FILTER_HPP_ - -#include -#include -#include - -#include - -#include "SqlQuery.hpp" - -namespace Database -{ - -typedef Wt::Dbo::dbo_default_traits::IdType id_type; - -class SearchFilter -{ - public: - - typedef int id_type; - - SearchFilter() {} - - static SearchFilter Artist(std::string name) {return SearchFilter();} - static SearchFilter Artist(id_type id) {return SearchFilter();} - - static SearchFilter Release(std::string name) {return SearchFilter();} - static SearchFilter Release(id_type id) {return SearchFilter();} - - static SearchFilter Track(std::string name) {return SearchFilter();} - - static SearchFilter Cluster(id_type id) {return SearchFilter();} - - // Combine search filters by add operation - // Caution: multiple filters on different artist/release/track - // values may lead to empty results - void operator+=(const SearchFilter& filter); - - SqlQuery generatePartialQuery(); - - private: - -}; - - -} // namespace Database - -#endif // _DB_SEARCH_FILTER_HPP_ diff --git a/src/database/Setting.cpp b/src/database/Setting.cpp index c5dc5200..e987d111 100644 --- a/src/database/Setting.cpp +++ b/src/database/Setting.cpp @@ -52,8 +52,8 @@ Setting::getBool(Wt::Dbo::Session& session, std::string setting, bool defaultVal return (res->_value == "true"); } -boost::posix_time::time_duration -Setting::getDuration(Wt::Dbo::Session& session, std::string setting, boost::posix_time::time_duration defaultValue) +Wt::WTime +Setting::getTime(Wt::Dbo::Session& session, std::string setting, Wt::WTime defaultValue) { Wt::Dbo::Transaction transaction(session); @@ -61,19 +61,7 @@ Setting::getDuration(Wt::Dbo::Session& session, std::string setting, boost::posi if (!res) return defaultValue; - return boost::posix_time::duration_from_string(res->_value); -} - -boost::posix_time::ptime -Setting::getTime(Wt::Dbo::Session& session, std::string setting, boost::posix_time::ptime defaultValue) -{ - Wt::Dbo::Transaction transaction(session); - - pointer res = getByName(session, setting); - if (!res) - return defaultValue; - - return boost::posix_time::time_from_string(res->_value); + return Wt::WTime::fromString(res->_value); } int @@ -93,7 +81,7 @@ Setting::getInt(Wt::Dbo::Session& session, std::string setting, int defaultValue Setting::pointer Setting::create(Wt::Dbo::Session& session, std::string name) { - return session.add(new Setting(name)); + return session.add(std::make_unique(name)); } Setting::pointer @@ -127,17 +115,10 @@ Setting::setBool(Wt::Dbo::Session& session, std::string setting, bool value) } void -Setting::setDuration(Wt::Dbo::Session& session, std::string setting, boost::posix_time::time_duration value) +Setting::setTime(Wt::Dbo::Session& session, std::string setting, Wt::WTime value) { Wt::Dbo::Transaction transaction(session); - getOrCreateByName(session, setting).modify()->_value = boost::posix_time::to_simple_string(value); -} - -void -Setting::setTime(Wt::Dbo::Session& session, std::string setting, boost::posix_time::ptime value) -{ - Wt::Dbo::Transaction transaction(session); - getOrCreateByName(session, setting).modify()->_value = boost::posix_time::to_simple_string(value); + getOrCreateByName(session, setting).modify()->_value = value.toString().toUTF8(); } void diff --git a/src/database/Setting.hpp b/src/database/Setting.hpp index 394fc7bc..808a0902 100644 --- a/src/database/Setting.hpp +++ b/src/database/Setting.hpp @@ -19,9 +19,8 @@ #pragma once -#include - -#include +#include +#include namespace Database { @@ -29,7 +28,10 @@ namespace Database { class Setting { public: + using pointer = Wt::Dbo::ptr; + Setting() {} + Setting(std::string name) : _name(name) {} // check if a setting exists or not static bool exists(Wt::Dbo::Session& session, std::string setting); @@ -38,16 +40,14 @@ class Setting // Nested transactions static std::string getString(Wt::Dbo::Session& session, std::string setting, std::string defaultValue = ""); static bool getBool(Wt::Dbo::Session& session, std::string setting, bool defaultValue = false); - static boost::posix_time::time_duration getDuration(Wt::Dbo::Session& session, std::string setting, boost::posix_time::time_duration defaultDuration = boost::posix_time::seconds(0) ); - static boost::posix_time::ptime getTime(Wt::Dbo::Session& session, std::string setting, boost::posix_time::ptime defaultTime = boost::posix_time::ptime()); + static Wt::WTime getTime(Wt::Dbo::Session& session, std::string setting, Wt::WTime defaultValue = Wt::WTime()); static int getInt(Wt::Dbo::Session& session, std::string setting, int defaultValue = 0); // Setters // Nested transactions static void setString(Wt::Dbo::Session& session, std::string setting, std::string value); static void setBool(Wt::Dbo::Session& session, std::string setting, bool value); - static void setDuration(Wt::Dbo::Session& session, std::string setting, boost::posix_time::time_duration value); - static void setTime(Wt::Dbo::Session& session, std::string setting, boost::posix_time::ptime time); + static void setTime(Wt::Dbo::Session& session, std::string setting, Wt::WTime value); static void setInt(Wt::Dbo::Session& session, std::string setting, int value); template @@ -58,10 +58,6 @@ class Setting } private: - Setting(std::string name) : _name(name) {} - - typedef Wt::Dbo::ptr pointer; - static pointer getByName(Wt::Dbo::Session& session, std::string name); static pointer create(Wt::Dbo::Session& session, std::string name); static pointer getOrCreateByName(Wt::Dbo::Session& session, std::string name); diff --git a/src/database/Track.cpp b/src/database/Track.cpp index a222e77a..6054a367 100644 --- a/src/database/Track.cpp +++ b/src/database/Track.cpp @@ -17,10 +17,6 @@ * along with LMS. If not, see . */ -#include - -#include - #include "utils/Logger.hpp" #include "SqlQuery.hpp" @@ -75,7 +71,7 @@ Track::getByMBID(Wt::Dbo::Session& session, const std::string& mbid) Track::pointer Track::create(Wt::Dbo::Session& session, const boost::filesystem::path& p) { - return session.add(new Track(p) ); + return session.add(std::make_unique(p)); } std::vector @@ -111,7 +107,7 @@ Track::getClusters(void) const static Wt::Dbo::Query< Track::pointer > getQuery(Wt::Dbo::Session& session, - const std::set& clusterIds, + const std::set& clusterIds, const std::vector keywords) { WhereClause where; @@ -149,20 +145,6 @@ getQuery(Wt::Dbo::Session& session, return query; } -Track::StatsQueryResult -Track::getStats(Wt::Dbo::Session& session, SearchFilter filter) -{ - SqlQuery sqlQuery = filter.generatePartialQuery(); - - Wt::Dbo::Query query = session.query( "SELECT COUNT(\"id\"), SUM(\"dur\") FROM (SELECT t.id as \"id\", t.duration as \"dur\" FROM track t INNER JOIN artist a ON t.artist_id = a.id INNER JOIN cluster c ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id INNER JOIN release r ON r.id = t.release_id " + sqlQuery.where().get() + " GROUP BY t.id)"); - - for (const std::string& bindArg : sqlQuery.where().getBindArgs()) - query.bind(bindArg); - - return query; -} - - std::vector Track::getByFilter(Wt::Dbo::Session& session, const std::set& clusterIds, @@ -233,7 +215,7 @@ Cluster::Cluster(Wt::Dbo::ptr type, std::string name) Cluster::pointer Cluster::create(Wt::Dbo::Session& session, Wt::Dbo::ptr type, std::string name) { - return session.add(new Cluster(type, name)); + return session.add(std::make_unique(type, name)); } std::vector @@ -244,28 +226,6 @@ Cluster::getAll(Wt::Dbo::Session& session) return std::vector(res.begin(), res.end()); } -Wt::Dbo::Query -Cluster::getQuery(Wt::Dbo::Session& session, SearchFilter filter) -{ - SqlQuery sqlQuery = filter.generatePartialQuery(); - - Wt::Dbo::Query query - = session.query( "SELECT g FROM cluster c INNER JOIN track_cluster t_c ON t_c.cluster_id = c.id INNER JOIN artist a ON t.artist_id = a.id INNER JOIN release r ON r.id = t.release_id INNER JOIN track t ON t.id = t_c.track_id " + sqlQuery.where().get()).groupBy("c.name").orderBy("c.name"); - - for (const std::string& bindArg : sqlQuery.where().getBindArgs()) - query.bind(bindArg); - - return query; -} - -std::vector -Cluster::getByFilter(Wt::Dbo::Session& session, SearchFilter filter, int offset, int size) -{ - Wt::Dbo::collection res = getQuery(session, filter).limit(size).offset(offset); - - return std::vector(res.begin(), res.end()); -} - ClusterType::ClusterType(std::string name) : _name(name) { @@ -297,7 +257,7 @@ ClusterType::getAll(Wt::Dbo::Session& session) ClusterType::pointer ClusterType::create(Wt::Dbo::Session& session, std::string name) { - return session.add(new ClusterType(name)); + return session.add(std::make_unique(name)); } Cluster::pointer diff --git a/src/database/Track.hpp b/src/database/Track.hpp index 3bec8ee9..1f2ef635 100644 --- a/src/database/Track.hpp +++ b/src/database/Track.hpp @@ -21,17 +21,15 @@ #include #include +#include #include -#include #include -#include -#include +#include +#include -#include - -#include "SearchFilter.hpp" +#include namespace Database { @@ -52,7 +50,6 @@ class Cluster : public Wt::Dbo::Dbo Cluster(Wt::Dbo::ptr type, std::string name); // Find utility - static std::vector getByFilter(Wt::Dbo::Session& session, SearchFilter filter, int offset = -1, int size = -1); static std::vector getAll(Wt::Dbo::Session& session); // Create utility @@ -75,7 +72,6 @@ class Cluster : public Wt::Dbo::Dbo } private: - static Wt::Dbo::Query getQuery(Wt::Dbo::Session& session, SearchFilter filter); static const std::size_t _maxNameLength = 128; @@ -159,14 +155,6 @@ class Track static std::vector getMBIDDuplicates(Wt::Dbo::Session& session); static std::vector getChecksumDuplicates(Wt::Dbo::Session& session); - // Utility fonctions - // Stats for a given search filter - typedef boost::tuple< - int, // Total tracks - boost::posix_time::time_duration // Total duration - > StatsQueryResult; - static StatsQueryResult getStats(Wt::Dbo::Session& session, SearchFilter filter); - // Create utility static pointer create(Wt::Dbo::Session& session, const boost::filesystem::path& p); @@ -179,12 +167,12 @@ class Track void setDiscNumber(int num) { _discNumber = num; } void setTotalDiscNumber(int num) { _totalDiscNumber = num; } void setName(const std::string& name) { _name = std::string(name, 0, _maxNameLength); } - void setDuration(boost::posix_time::time_duration duration) { _duration = duration; } - void setLastWriteTime(boost::posix_time::ptime time) { _fileLastWrite = time; } - void setAddedTime(boost::posix_time::ptime time) { _fileAdded = time; } + void setDuration(std::chrono::milliseconds duration) { _duration = duration; } + void setLastWriteTime(Wt::WDateTime time) { _fileLastWrite = time; } + void setAddedTime(Wt::WDateTime time) { _fileAdded = time; } void setChecksum(const std::vector& checksum) { _fileChecksum = checksum; } - void setDate(const boost::posix_time::ptime& date) { _date = date; } - void setOriginalDate(const boost::posix_time::ptime& date) { _originalDate = date; } + void setDate(Wt::WDate date) { _date = date; } + void setOriginalDate(Wt::WDate date) { _originalDate = date; } void setGenres(const std::string& genreList) { _genreList = genreList; } void setCoverType(CoverType coverType) { _coverType = coverType; } void setMBID(const std::string& MBID) { _MBID = MBID; } @@ -197,11 +185,11 @@ class Track boost::optional getTotalDiscNumber(void) const; std::string getName(void) const { return _name; } boost::filesystem::path getPath(void) const { return _filePath; } - boost::posix_time::time_duration getDuration(void) const { return _duration; } - boost::posix_time::ptime getDate(void) const { return _date; } - boost::posix_time::ptime getOriginalDate(void) const { return _originalDate; } - boost::posix_time::ptime getLastWriteTime(void) const { return _fileLastWrite; } - boost::posix_time::ptime getAddedTime(void) const { return _fileAdded; } + std::chrono::milliseconds getDuration(void) const { return _duration; } + Wt::WDate getDate(void) const { return _date; } + Wt::WDate getOriginalDate(void) const { return _originalDate; } + Wt::WDateTime getLastWriteTime(void) const { return _fileLastWrite; } + Wt::WDateTime getAddedTime(void) const { return _fileAdded; } const std::vector& getChecksum(void) const { return _fileChecksum; } CoverType getCoverType(void) const { return _coverType; } const std::string& getMBID(void) const { return _MBID; } @@ -244,14 +232,14 @@ class Track std::string _name; std::string _artistName; std::string _releaseName; - boost::posix_time::time_duration _duration; - boost::posix_time::ptime _date; - boost::posix_time::ptime _originalDate; // original date time + std::chrono::duration _duration; + Wt::WDate _date; + Wt::WDate _originalDate; // original date time std::string _genreList; std::string _filePath; std::vector _fileChecksum; - boost::posix_time::ptime _fileLastWrite; - boost::posix_time::ptime _fileAdded; + Wt::WDateTime _fileLastWrite; + Wt::WDateTime _fileAdded; CoverType _coverType; std::string _MBID; // Musicbrainz Identifier diff --git a/src/database/User.cpp b/src/database/User.cpp index 61584657..9cc52dfd 100644 --- a/src/database/User.cpp +++ b/src/database/User.cpp @@ -51,7 +51,7 @@ User::getAll(Wt::Dbo::Session& session) User::pointer User::create(Wt::Dbo::Session& session) { - return session.add(new User()); + return session.add(std::make_unique()); } User::pointer diff --git a/src/database/User.hpp b/src/database/User.hpp index d9c1923e..28127150 100644 --- a/src/database/User.hpp +++ b/src/database/User.hpp @@ -22,8 +22,8 @@ #include -#include -#include +#include +#include namespace Database { diff --git a/src/feature/FeatureExtractor.cpp b/src/feature/FeatureExtractor.cpp deleted file mode 100644 index 48a0a888..00000000 --- a/src/feature/FeatureExtractor.cpp +++ /dev/null @@ -1,216 +0,0 @@ - -/* - * Copyright (C) 2016 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 . - */ - -#include -#include - -#include - -#include - -#include "utils/Logger.hpp" -#include "utils/Path.hpp" - -#include "FeatureExtractor.hpp" - -namespace Feature { - -static boost::filesystem::path extractorPath = boost::filesystem::path(); - -bool -Extractor::init(void) -{ - static const std::string execName = "streaming_extractor_music"; - extractorPath = searchExecPath(execName); - - if (extractorPath.empty()) - { - LMS_LOG(FEATURE, ERROR) << "Failed to find path to " << execName; - return false; - } - - return true; -} - -Extractor::Extractor() -{ } - - - -static bool fetchJSONData(boost::property_tree::ptree& pt, std::string url) -{ - try - { - curlpp::Cleanup myCleanup; - - std::ostringstream os; - os << curlpp::options::Url(url); - - std::istringstream iss(os.str()); - boost::property_tree::ptree res; - boost::property_tree::json_parser::read_json(iss, res); - - pt = res; - } - catch( curlpp::RuntimeError &e ) - { - LMS_LOG(FEATURE, ERROR) << "curlpp error: " << e.what(); - return false; - } - catch( curlpp::LogicError &e ) - { - LMS_LOG(FEATURE, ERROR) << "curlpp error: " << e.what(); - return false; - } - catch ( boost::property_tree::ptree_error& e) - { - LMS_LOG(FEATURE, ERROR) << "JSON paring failed: " << e.what(); - return false; - } - - return true; -} - - -bool -Extractor::getLowLevel(boost::property_tree::ptree& pt, std::string mbid) -{ - LMS_LOG(FEATURE, DEBUG) << "Trying to fetch low level metadata for track '" << mbid << "' on AcousticBrainz"; - - boost::property_tree::ptree res; - if (!fetchJSONData(res, "https://acousticbrainz.org/" + mbid + "/low-level")) - return false; - - auto message = res.get_child_optional("message"); - if (message) - { - LMS_LOG(FEATURE, ERROR) << "Track '" << mbid << "': cannot get data on AcousticBrainz: " << message->data(); - return false; - } - - auto lowlevel = res.get_child_optional("lowlevel"); - if (!lowlevel) - { - LMS_LOG(FEATURE, ERROR) << "Track '" << mbid << "': low level data not found!"; - return false; - } - - // Keep metadata to ease debugging -// res.erase("metadata"); - - pt = res; - - return true; -} - -bool -Extractor::getHighLevel(boost::property_tree::ptree& pt, std::string mbid) -{ - LMS_LOG(FEATURE, DEBUG) << "Trying to fetch high level metadata for track '" << mbid << "' on AcousticBrainz"; - - // TODO check MBID - if (mbid.empty()) - return false; - - boost::property_tree::ptree res; - if (!fetchJSONData(res, "https://acousticbrainz.org/" + mbid + "/high-level")) - return false; - - auto message = res.get_child_optional("message"); - if (message) - { - LMS_LOG(FEATURE, ERROR) << "Track '" << mbid << "': cannot get data on AcousticBrainz: " << message->data(); - return false; - } - - auto lowlevel = res.get_child_optional("highlevel"); - if (!lowlevel) - { - LMS_LOG(FEATURE, ERROR) << "Track '" << mbid << "': high level data not found!"; - return false; - } - - res.erase("metadata"); - - pt = res; - - return true; -} - - -bool -Extractor::getLowLevel(boost::property_tree::ptree& pt, boost::filesystem::path path) -{ - LMS_LOG(FEATURE, DEBUG) << "Extracting low level data from '" << path << "'"; - - if (extractorPath.empty()) - return false; - - std::vector args; - - args.push_back(extractorPath.string()); - args.push_back(path.string()); - args.push_back("-"); // output to stdout - - std::string jsonData; - { - redi::ipstream in; - in.open(extractorPath.string(), args); - if (!in.is_open()) - { - LMS_LOG(FEATURE, ERROR) << "Exec failed!"; - return false; - } - - bool firstLineHit = false; - - std::string line; - while(std::getline(in, line)) - { - if (!firstLineHit) - { - if (line != "{") - continue; - - firstLineHit = true; - } - jsonData += line; - jsonData += '\n'; - } - } - - try - { - std::istringstream iss(jsonData); - boost::property_tree::json_parser::read_json(iss, pt); - - pt.erase("metadata"); - } - catch ( boost::property_tree::ptree_error& e) - { - LMS_LOG(FEATURE, ERROR) << "JSON parsing failed: " << e.what(); - return false; - } - - return true; -} - -} // namespace Feature - diff --git a/src/feature/FeatureExtractor.hpp b/src/feature/FeatureExtractor.hpp deleted file mode 100644 index ed7169c2..00000000 --- a/src/feature/FeatureExtractor.hpp +++ /dev/null @@ -1,43 +0,0 @@ - -/* - * Copyright (C) 2016 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 . - */ - -#include -#include - -#pragma once - -namespace Feature { - -class Extractor -{ - public: - static bool init(void); - - static bool getLowLevel(boost::property_tree::ptree& pt, boost::filesystem::path path); - static bool getLowLevel(boost::property_tree::ptree& pt, std::string mbid); - - static bool getHighLevel(boost::property_tree::ptree& pt, std::string mbid); - - private: - Extractor(); -}; - -} // namespace Feature - diff --git a/src/feature/FeatureStore.cpp b/src/feature/FeatureStore.cpp deleted file mode 100644 index 2f52eff8..00000000 --- a/src/feature/FeatureStore.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2016 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 . - */ - -#include - -#include "utils/Config.hpp" -#include "utils/Logger.hpp" -#include "utils/Path.hpp" - -#include "FeatureStore.hpp" - -namespace Feature { - -Store::Store() -{ -} - -Store& -Store::instance(void) -{ - static Store instance; - return instance; -} - -static boost::filesystem::path -getPath(std::string mbid, std::string type) -{ - return Config::instance().getPath("working-dir") / "features" / (mbid + "_" + type); -} - -bool -Store::exists(Wt::Dbo::Session& session, Database::Track::id_type trackId, std::string type) -{ - Wt::Dbo::Transaction transaction(session); - - auto track = Database::Track::getById(session, trackId); - std::string mbid = track->getMBID(); - - transaction.commit(); - - if (mbid.empty()) - return false; - - boost::filesystem::path path = getPath(mbid, type); - return boost::filesystem::exists(path); -} - -bool -Store::get(Wt::Dbo::Session& session, Database::Track::id_type trackId, std::string type, boost::property_tree::ptree& feature) -{ - Wt::Dbo::Transaction transaction(session); - - auto track = Database::Track::getById(session, trackId); - std::string mbid = track->getMBID(); - - transaction.commit(); - - if (mbid.empty()) - return false; - - boost::filesystem::path path = getPath(mbid, type); - if (!boost::filesystem::exists(path)) - return false; - - try - { - std::ifstream iss(path.string().c_str(), std::ios::in); - boost::property_tree::json_parser::read_json(iss, feature); - } - catch (boost::property_tree::ptree_error& e) - { - LMS_LOG(FEATURE, ERROR) << "JSON parsing failed: " << e.what(); - return false; - } - - return true; -} - - -bool -Store::set(Wt::Dbo::Session& session, Database::Track::id_type trackId, std::string type, const boost::property_tree::ptree& feature) -{ - Wt::Dbo::Transaction transaction(session); - - auto track = Database::Track::getById(session, trackId); - std::string mbid = track->getMBID(); - - transaction.commit(); - - if (mbid.empty()) - return false; - - boost::filesystem::path path = getPath(mbid, type); - - try - { - std::ofstream oss(path.string().c_str(), std::ios::out); - boost::property_tree::json_parser::write_json(oss, feature); - } - catch (boost::property_tree::ptree_error& e) - { - LMS_LOG(FEATURE, ERROR) << "JSON writing failed: " << e.what(); - return false; - } - - return true; -} - -} // namespace CoverArt - diff --git a/src/feature/FeatureStore.hpp b/src/feature/FeatureStore.hpp deleted file mode 100644 index a02e1400..00000000 --- a/src/feature/FeatureStore.hpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2016 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 . - */ - -#pragma once - -#include -#include - -#include "database/Types.hpp" - -namespace Feature { - -class Store -{ - public: - Store(const Store&) = delete; - Store& operator=(const Store&) = delete; - - static Store& instance(); - - bool exists(Wt::Dbo::Session& session, Database::Track::id_type trackId, std::string type); - bool get(Wt::Dbo::Session& session, Database::Track::id_type trackId, std::string type, boost::property_tree::ptree& feature); - - bool set(Wt::Dbo::Session& session, Database::Track::id_type trackId, std::string type, const boost::property_tree::ptree& feature); - - private: - Store(); -}; - -} // namespace CoverArt - diff --git a/src/image/Image.cpp b/src/image/Image.cpp index 4ba865f2..03fea576 100644 --- a/src/image/Image.cpp +++ b/src/image/Image.cpp @@ -79,7 +79,7 @@ Image::load(boost::filesystem::path p) } catch (Magick::Exception& e) { - LMS_LOG(COVER, ERROR) << "Caught Magick exception while loading image from file '" << p << "': " << e.what(); + LMS_LOG(COVER, ERROR) << "Caught Magick exception while loading image from file '" << p.string() << "': " << e.what(); return false; } } diff --git a/src/main/main.cpp b/src/main/main.cpp index 0abbc96c..4f6aa932 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -20,14 +20,14 @@ #include #include -#include +#include +#include #include "utils/Config.hpp" #include "utils/Logger.hpp" #include "av/AvInfo.hpp" #include "av/AvTranscoder.hpp" #include "image/Image.hpp" -#include "feature/FeatureExtractor.hpp" #include "scanner/MediaScanner.hpp" @@ -117,17 +117,16 @@ int main(int argc, char* argv[]) Av::AvInit(); Av::Transcoder::init(); Database::Handler::configureAuth(); - Feature::Extractor::init(); // Initializing a connection pool to the database that will be shared along services - std::unique_ptr - connectionPool( Database::Handler::createConnectionPool(Config::instance().getPath("working-dir") / "lms.db")); + auto connectionPool = Database::Handler::createConnectionPool(Config::instance().getPath("working-dir") / "lms.db"); Scanner::MediaScanner scanner(*connectionPool); // bind entry point - server.addEntryPoint(Wt::Application, boost::bind(UserInterface::LmsApplication::create, - _1, boost::ref(*connectionPool), boost::ref(scanner))); + server.addEntryPoint(Wt::EntryPointType::Application, + std::bind(UserInterface::LmsApplication::create, + std::placeholders::_1, std::ref(*connectionPool), std::ref(scanner))); // Start LMS_LOG(MAIN, INFO) << "Starting Media scanner..."; @@ -138,7 +137,7 @@ int main(int argc, char* argv[]) // Wait LMS_LOG(MAIN, INFO) << "Now running..."; - Wt::WServer::waitForShutdown(argv[0]); + Wt::WServer::waitForShutdown(); // Stop LMS_LOG(MAIN, INFO) << "Stopping server..."; diff --git a/src/metadata/AvFormat.cpp b/src/metadata/AvFormat.cpp index e2a9c080..50f89e7e 100644 --- a/src/metadata/AvFormat.cpp +++ b/src/metadata/AvFormat.cpp @@ -77,11 +77,11 @@ AvFormat::parse(const boost::filesystem::path& p) std::cout << "TAG = " << tag << ", VAL = " << value << std::endl; #endif if (tag == "ARTIST") - items.insert( std::make_pair(MetaData::Type::Artist, stringTrim( stringToUTF8(value)) )); + items.insert( std::make_pair(MetaData::Type::Artist, stringTrim( value) )); else if (tag == "ALBUM") - items.insert( std::make_pair(MetaData::Type::Album, stringTrim( stringToUTF8(value)) )); + items.insert( std::make_pair(MetaData::Type::Album, stringTrim( value) )); else if (tag == "TITLE") - items.insert( std::make_pair(MetaData::Type::Title, stringTrim( stringToUTF8(value)) )); + items.insert( std::make_pair(MetaData::Type::Title, stringTrim( value) )); else if (tag == "TRACK") { // Expecting 'Number/Total' @@ -89,15 +89,15 @@ AvFormat::parse(const boost::filesystem::path& p) if (strings.size() > 0) { - std::size_t number; - if (readAs(strings[0], number)) - items.insert( std::make_pair(MetaData::Type::TrackNumber, number )); + auto number = readAs(strings[0]); + if (number) + items.insert( std::make_pair(MetaData::Type::TrackNumber, *number )); if (strings.size() > 1) { - std::size_t totalNumber; - if (readAs(strings[1], totalNumber)) - items.insert( std::make_pair(MetaData::Type::TotalTrack, totalNumber )); + auto totalNumber = readAs(strings[1]); + if (totalNumber) + items.insert( std::make_pair(MetaData::Type::TotalTrack, *totalNumber )); } } } @@ -108,15 +108,15 @@ AvFormat::parse(const boost::filesystem::path& p) if (strings.size() > 0) { - std::size_t number; - if (readAs(strings[0], number)) - items.insert( std::make_pair(MetaData::Type::DiscNumber, number )); + auto number = readAs(strings[0]); + if (number) + items.insert( std::make_pair(MetaData::Type::DiscNumber, *number )); if (strings.size() > 1) { - std::size_t totalNumber; - if (readAs(strings[1], totalNumber)) - items.insert( std::make_pair(MetaData::Type::TotalDisc, totalNumber )); + auto totalNumber = readAs(strings[1]); + if (totalNumber) + items.insert( std::make_pair(MetaData::Type::TotalDisc, *totalNumber )); } } } @@ -124,36 +124,36 @@ AvFormat::parse(const boost::filesystem::path& p) || tag == "YEAR" || tag == "WM/Year") { - boost::posix_time::ptime p; - if (readAsPosixTime(value, p)) - items.insert( std::make_pair(MetaData::Type::Date, p)); + auto date = readAs(value); + if (date) + items.insert( std::make_pair(MetaData::Type::Date, *date)); } else if (tag == "TDOR" // Original release time (ID3v2 2.4) || tag == "TORY") // Original release year { - boost::posix_time::ptime p; - if (readAsPosixTime(value, p)) - items.insert( std::make_pair(MetaData::Type::OriginalDate, p)); + auto date = readAs(value); + if (date) + items.insert( std::make_pair(MetaData::Type::OriginalDate, *date)); } else if (tag == "MUSICBRAINZ ARTIST ID" || tag == "MUSICBRAINZ_ARTISTID") { - items.insert( std::make_pair(MetaData::Type::MusicBrainzArtistID, stringTrim( stringToUTF8(value)) )); + items.insert( std::make_pair(MetaData::Type::MusicBrainzArtistID, stringTrim(value)) ); } else if (tag == "MUSICBRAINZ ALBUM ID" || tag == "MUSICBRAINZ_ALBUMID") { - items.insert( std::make_pair(MetaData::Type::MusicBrainzAlbumID, stringTrim( stringToUTF8(value)) )); + items.insert( std::make_pair(MetaData::Type::MusicBrainzAlbumID, stringTrim(value)) ); } else if (tag == "MUSICBRAINZ RELEASE TRACK ID" || tag == "MUSICBRAINZ_RELEASETRACKID" || tag == "MUSICBRAINZ_TRACKID") { - items.insert( std::make_pair(MetaData::Type::MusicBrainzTrackID, stringTrim( stringToUTF8(value)) )); + items.insert( std::make_pair(MetaData::Type::MusicBrainzTrackID, stringTrim(value)) ); } else if (tag == "ACOUSTID ID") { - items.insert( std::make_pair(MetaData::Type::AcoustID, stringTrim( stringToUTF8(value)) )); + items.insert( std::make_pair(MetaData::Type::AcoustID, stringTrim(value)) ); } else if (_clusterMap.find(tag) != _clusterMap.end()) { diff --git a/src/metadata/MetaData.hpp b/src/metadata/MetaData.hpp index c14caed9..a9ebc0c6 100644 --- a/src/metadata/MetaData.hpp +++ b/src/metadata/MetaData.hpp @@ -37,13 +37,13 @@ namespace MetaData Title, // string Album, // string Clusters, // Clusters, ex: { "genre", {"death metal", "brutal death"} }, { "albumgrouping", {"metal"} } - Duration, // boost::posix_time::time_duration + Duration, // std::chrono::milliseconds TrackNumber, // size_t DiscNumber, // size_t TotalTrack, // size_t TotalDisc, // size_t - Date, // boost::posix_time::ptime - OriginalDate, // boost::posix_time::ptime + Date, // Wt::WDate + OriginalDate, // Wt::WDate HasCover, // bool AudioStreams, // vector MusicBrainzArtistID, // string diff --git a/src/metadata/TagLibParser.cpp b/src/metadata/TagLibParser.cpp index 27cb2e54..a5a48be1 100644 --- a/src/metadata/TagLibParser.cpp +++ b/src/metadata/TagLibParser.cpp @@ -55,8 +55,7 @@ TagLibParser::parse(const boost::filesystem::path& p) { TagLib::AudioProperties *properties = f.audioProperties(); - boost::posix_time::time_duration duration = boost::posix_time::seconds(properties->length()); - + std::chrono::milliseconds duration(properties->length() * 1000); items.insert( std::make_pair(MetaData::Type::Duration, duration) ); MetaData::AudioStream audioStream = { .bitRate = static_cast(properties->bitrate() * 1000) }; @@ -124,15 +123,15 @@ TagLibParser::parse(const boost::filesystem::path& p) if (!strings.empty()) { - std::size_t number; - if (readAs(strings[0], number)) - items.insert( std::make_pair(MetaData::Type::TrackNumber, number )); + auto number = readAs(strings[0]); + if (number) + items.insert( std::make_pair(MetaData::Type::TrackNumber, *number )); if (strings.size() > 1) { - std::size_t totalNumber; - if (readAs(strings[1], totalNumber)) - items.insert( std::make_pair(MetaData::Type::TotalTrack, totalNumber )); + auto totalNumber = readAs(strings[1]); + if (totalNumber) + items.insert( std::make_pair(MetaData::Type::TotalTrack, *totalNumber )); } } } @@ -143,32 +142,32 @@ TagLibParser::parse(const boost::filesystem::path& p) if (!strings.empty()) { - std::size_t number; - if (readAs(strings[0], number)) - items.insert( std::make_pair(MetaData::Type::DiscNumber, number )); + auto number = readAs(strings[0]); + if (number) + items.insert( std::make_pair(MetaData::Type::DiscNumber, *number)); if (strings.size() > 1) { - std::size_t totalNumber; - if (readAs(strings[1], totalNumber)) - items.insert( std::make_pair(MetaData::Type::TotalDisc, totalNumber )); + auto totalNumber = readAs(strings[1]); + if (totalNumber) + items.insert( std::make_pair(MetaData::Type::TotalDisc, *totalNumber )); } } } else if (tag == "DATE") { - boost::posix_time::ptime p; - if (readAsPosixTime(values.front().to8Bit(), p)) - items.insert( std::make_pair(MetaData::Type::Date, p)); + auto timePoint = readAs(values.front().to8Bit()); + if (timePoint) + items.insert( std::make_pair(MetaData::Type::Date, *timePoint)); } else if (tag == "ORIGINALDATE") { - boost::posix_time::ptime p; - if (readAsPosixTime(values.front().to8Bit(), p)) + auto timePoint = readAs(values.front().to8Bit()); + if (timePoint) { // Take priority on original year items.erase( MetaData::Type::OriginalDate ); - items.insert( std::make_pair(MetaData::Type::OriginalDate, p)); + items.insert( std::make_pair(MetaData::Type::OriginalDate, *timePoint)); } } else if (tag == "ORIGINALYEAR") @@ -176,9 +175,9 @@ TagLibParser::parse(const boost::filesystem::path& p) // lower priority than original date if (items.find(MetaData::Type::OriginalDate) == items.end()) { - boost::posix_time::ptime p; - if (readAsPosixTime(values.front().to8Bit(), p)) - items.insert( std::make_pair(MetaData::Type::OriginalDate, p)); + auto timePoint = readAs(values.front().to8Bit()); + if (timePoint) + items.insert( std::make_pair(MetaData::Type::OriginalDate, *timePoint)); } } else if (tag == "METADATA_BLOCK_PICTURE") diff --git a/src/scanner/MediaScanner.cpp b/src/scanner/MediaScanner.cpp index b3252c6a..41e0985c 100644 --- a/src/scanner/MediaScanner.cpp +++ b/src/scanner/MediaScanner.cpp @@ -20,9 +20,10 @@ #include #include -#include #include +#include + #include "cover/CoverArtGrabber.hpp" #include "database/Setting.hpp" @@ -36,40 +37,28 @@ namespace { -boost::gregorian::date -getNextDay(const boost::gregorian::date& current) +Wt::WDate +getNextMonday(Wt::WDate current) { - boost::gregorian::day_iterator it(current); - return *(++it); + do + { + current.addDays(1); + } while (current.dayOfWeek() != 1); + + return current; } -boost::gregorian::date -getNextMonday(const boost::gregorian::date& current) +Wt::WDate +getNextFirstOfMonth(Wt::WDate current) { - boost::gregorian::day_iterator it(current); + do + { + current.addDays(1); + } while (current.day() != 1); - ++it; - // While it's not monday - while( it->day_of_week() != 1 ) - ++it; - - return *(it); + return current; } -boost::gregorian::date -getNextFirstOfMonth(const boost::gregorian::date& current) -{ - boost::gregorian::day_iterator it(current); - - ++it; - // While it's not the 1st of the month - while( it->day() != 1 ) - ++it; - - return (*it); -} - - bool isFileSupported(const boost::filesystem::path& file, const std::vector extensions) { @@ -119,14 +108,14 @@ setUpdatePeriod(Wt::Dbo::Session& session, UpdatePeriod updatePeriod) Setting::setInt(session, "update_period", static_cast(updatePeriod)); } -boost::posix_time::time_duration getUpdateStartTime(Wt::Dbo::Session& session) +Wt::WTime getUpdateStartTime(Wt::Dbo::Session& session) { - return Setting::getDuration(session, "update_start_time"); + return Setting::getTime(session, "update_start_time"); } -void setUpdateStartTime(Wt::Dbo::Session& session, boost::posix_time::time_duration startTime) +void setUpdateStartTime(Wt::Dbo::Session& session, Wt::WTime startTime) { - Setting::setDuration(session, "update_start_time", startTime); + Setting::setTime(session, "update_start_time", startTime); } MediaScanner::MediaScanner(Wt::Dbo::SqlConnectionPool& connectionPool) @@ -176,7 +165,7 @@ MediaScanner::scheduleImmediateScan() _ioService.post([=]() { LMS_LOG(DBUPDATER, INFO) << "Schedule immediate scan"; - scheduleScan( boost::posix_time::seconds(0) ); + scheduleScan(std::chrono::seconds(0)); }); } @@ -193,29 +182,31 @@ MediaScanner::reschedule() void MediaScanner::scheduleScan() { - boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); - boost::posix_time::time_duration startTime = getUpdateStartTime(_db.getSession()); + using namespace std::chrono_literals; - boost::gregorian::date nextScanDate; + Wt::WTime startTime = getUpdateStartTime(_db.getSession()); + Wt::WDateTime now = Wt::WLocalDateTime::currentServerDateTime().toUTC(); + + Wt::WDate nextScanDate; switch ( getUpdatePeriod(_db.getSession()) ) { case UpdatePeriod::Daily: - if (now.time_of_day() < startTime) + if (now.time() < startTime) nextScanDate = now.date(); else - nextScanDate = getNextDay(now.date()); + nextScanDate = now.date().addDays(1); break; case UpdatePeriod::Weekly: - if (now.time_of_day() < startTime && now.date().day_of_week() == 1) + if (now.time() < startTime && now.date().dayOfWeek() == 1) nextScanDate = now.date(); else nextScanDate = getNextMonday(now.date()); break; case UpdatePeriod::Monthly: - if (now.time_of_day() < startTime && now.date().day() == 1) + if (now.time() < startTime && now.date().day() == 1) nextScanDate = now.date(); else nextScanDate = getNextFirstOfMonth(now.date()); @@ -226,24 +217,25 @@ MediaScanner::scheduleScan() break; } - if (!nextScanDate.is_special()) - scheduleScan( boost::posix_time::ptime (nextScanDate, startTime) ); + if (nextScanDate.isValid()) + scheduleScan( Wt::WDateTime(nextScanDate, startTime).toTimePoint() ); } void -MediaScanner::scheduleScan( boost::posix_time::time_duration duration) +MediaScanner::scheduleScan(std::chrono::seconds duration) { - LMS_LOG(DBUPDATER, INFO) << "Scheduling next scan in " << duration; - _scheduleTimer.expires_from_now(duration); - _scheduleTimer.async_wait( boost::bind( &MediaScanner::scan, this, boost::asio::placeholders::error) ); + LMS_LOG(DBUPDATER, INFO) << "Scheduling next scan in " << duration.count() << " seconds"; + _scheduleTimer.expires_from_now(std::chrono::seconds(5)); //duration); + _scheduleTimer.async_wait( std::bind( &MediaScanner::scan, this, std::placeholders::_1) ); } void -MediaScanner::scheduleScan( boost::posix_time::ptime time) +MediaScanner::scheduleScan(std::chrono::system_clock::time_point timePoint) { - LMS_LOG(DBUPDATER, INFO) << "Scheduling next scan at " << time; - _scheduleTimer.expires_at(time); - _scheduleTimer.async_wait( boost::bind( &MediaScanner::scan, this, boost::asio::placeholders::error) ); + std::time_t t = std::chrono::system_clock::to_time_t(timePoint); + LMS_LOG(DBUPDATER, INFO) << "Scheduling next scan at " << std::string(std::ctime(&t)); + _scheduleTimer.expires_at(timePoint); + _scheduleTimer.async_wait(std::bind(&MediaScanner::scan, this, std::placeholders::_1)); } void @@ -263,9 +255,9 @@ MediaScanner::scan(boost::system::error_code err) if (!_running) break; - LMS_LOG(DBUPDATER, INFO) << "scaning root directory '" << rootDirectory << "'..."; + LMS_LOG(DBUPDATER, INFO) << "scaning root directory '" << rootDirectory.string() << "'..."; scanRootDirectory(rootDirectory, stats); - LMS_LOG(DBUPDATER, INFO) << "scaning root directory '" << rootDirectory << "' DONE"; + LMS_LOG(DBUPDATER, INFO) << "scaning root directory '" << rootDirectory.string() << "' DONE"; } if (_running) @@ -273,16 +265,9 @@ MediaScanner::scan(boost::system::error_code err) LMS_LOG(DBUPDATER, INFO) << "Scan " << (_running ? "complete" : "aborted") << ". Changes = " << stats.nbChanges() << " (added = " << stats.additions << ", removed = " << stats.deletions << ", updated = " << stats.updates << "), Not changed = " << stats.skips << ", Scanned = " << stats.scans << " (errors = " << stats.scanErrors << ", not imported = " << stats.incompleteScans << "), duplicates = " << stats.nbDuplicates() << " (hash = " << stats.duplicateHashes << ", mbid = " << stats.duplicateMBID << ")"; - // Update database stats - boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); - if (stats.nbChanges() > 0) - Setting::setTime(_db.getSession(), "last_update", now); - // Save the last scan only if it has been completed if (_running) { - Setting::setTime(_db.getSession(), "last_scan", now); - scheduleScan(); scanComplete().emit(stats); @@ -408,7 +393,7 @@ MediaScanner::getClusters( const MetaData::Clusters& clustersNames) void MediaScanner::scanAudioFile( const boost::filesystem::path& file, Stats& stats) { - boost::posix_time::ptime lastWriteTime (boost::posix_time::from_time_t( boost::filesystem::last_write_time( file ) ) ); + auto lastWriteTime = Wt::WDateTime::fromTime_t(boost::filesystem::last_write_time(file)); // Skip file if last write is the same { @@ -445,7 +430,7 @@ MediaScanner::scanAudioFile( const boost::filesystem::path& file, Stats& stats) if ((*items).find(MetaData::Type::AudioStreams) == (*items).end() || boost::any_cast> ((*items)[MetaData::Type::AudioStreams]).empty()) { - LMS_LOG(DBUPDATER, INFO) << "Skipped '" << file << "' (no audio stream found)"; + LMS_LOG(DBUPDATER, INFO) << "Skipped '" << file.string() << "' (no audio stream found)"; // If Track exists here, delete it! if (track) @@ -457,9 +442,9 @@ MediaScanner::scanAudioFile( const boost::filesystem::path& file, Stats& stats) return; } if ((*items).find(MetaData::Type::Duration) == (*items).end() - || boost::any_cast((*items)[MetaData::Type::Duration]).total_seconds() <= 0) + || boost::any_cast((*items)[MetaData::Type::Duration]).count() <= 0) { - LMS_LOG(DBUPDATER, INFO) << "Skipped '" << file << "' (no duration or duration <= 0)"; + LMS_LOG(DBUPDATER, INFO) << "Skipped '" << file.string() << "' (no duration or duration <= 0)"; // If Track exists here, delete it! if (track) @@ -534,12 +519,12 @@ MediaScanner::scanAudioFile( const boost::filesystem::path& file, Stats& stats) { // Create a new song track = Track::create(_db.getSession(), file); - LMS_LOG(DBUPDATER, INFO) << "Adding '" << file << "'"; + LMS_LOG(DBUPDATER, INFO) << "Adding '" << file.string() << "'"; stats.additions++; } else { - LMS_LOG(DBUPDATER, INFO) << "Updating '" << file << "'"; + LMS_LOG(DBUPDATER, INFO) << "Updating '" << file.string() << "'"; // Remove the songs from its clusters for (auto cluster : track->getClusters()) @@ -555,8 +540,8 @@ MediaScanner::scanAudioFile( const boost::filesystem::path& file, Stats& stats) track.modify()->setRelease(release); track.modify()->setLastWriteTime(lastWriteTime); track.modify()->setName(title); - track.modify()->setDuration( boost::any_cast((*items)[MetaData::Type::Duration]) ); - track.modify()->setAddedTime( boost::posix_time::second_clock::local_time() ); + track.modify()->setDuration( boost::any_cast((*items)[MetaData::Type::Duration]) ); + track.modify()->setAddedTime( Wt::WLocalDateTime::currentServerDateTime().toUTC() ); { std::string trackClusterList; @@ -586,15 +571,15 @@ MediaScanner::scanAudioFile( const boost::filesystem::path& file, Stats& stats) track.modify()->setTotalDiscNumber( boost::any_cast((*items)[MetaData::Type::TotalDisc]) ); if ((*items).find(MetaData::Type::Date) != (*items).end()) - track.modify()->setDate( boost::any_cast((*items)[MetaData::Type::Date]) ); + track.modify()->setDate( boost::any_cast((*items)[MetaData::Type::Date]) ); if ((*items).find(MetaData::Type::OriginalDate) != (*items).end()) { - track.modify()->setOriginalDate( boost::any_cast((*items)[MetaData::Type::OriginalDate]) ); + track.modify()->setOriginalDate( boost::any_cast((*items)[MetaData::Type::OriginalDate]) ); // If a file has an OriginalDate but no date, set the date to ease filtering if ((*items).find(MetaData::Type::Date) == (*items).end()) - track.modify()->setDate( boost::any_cast((*items)[MetaData::Type::OriginalDate]) ); + track.modify()->setDate( boost::any_cast((*items)[MetaData::Type::OriginalDate]) ); } if ((*items).find(MetaData::Type::MusicBrainzRecordingID) != (*items).end()) @@ -652,7 +637,7 @@ checkFile(const boost::filesystem::path& p, const std::vector tracks = Database::Track::getMBIDDuplicates(_db.getSession()); for (Track::pointer track : tracks) { - LMS_LOG(DBUPDATER, INFO) << "Found duplicated MBID [" << track->getMBID() << "], file: " << track->getPath() << " - " << track->getName(); + LMS_LOG(DBUPDATER, INFO) << "Found duplicated MBID [" << track->getMBID() << "], file: " << track->getPath().string() << " - " << track->getName(); stats.duplicateMBID++; } 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->getName(); + LMS_LOG(DBUPDATER, INFO) << "Found duplicated checksum [" << bufferToString(track->getChecksum()) << "], file: " << track->getPath().string() << " - " << track->getName(); stats.duplicateHashes++; } diff --git a/src/scanner/MediaScanner.hpp b/src/scanner/MediaScanner.hpp index cb011c1b..79c200d5 100644 --- a/src/scanner/MediaScanner.hpp +++ b/src/scanner/MediaScanner.hpp @@ -19,10 +19,12 @@ #pragma once -#include +#include -#include -#include +#include +#include + +#include #include "metadata/TagLibParser.hpp" @@ -40,8 +42,8 @@ enum class UpdatePeriod { UpdatePeriod getUpdatePeriod(Wt::Dbo::Session& session); void setUpdatePeriod(Wt::Dbo::Session& session, UpdatePeriod updatePeriod); -boost::posix_time::time_duration getUpdateStartTime(Wt::Dbo::Session& session); -void setUpdateStartTime(Wt::Dbo::Session& session, boost::posix_time::time_duration); +Wt::WTime getUpdateStartTime(Wt::Dbo::Session& session); +void setUpdateStartTime(Wt::Dbo::Session& session, Wt::WTime time); class MediaScanner { @@ -92,8 +94,8 @@ class MediaScanner // Job handling void scheduleScan(); - void scheduleScan(boost::posix_time::time_duration duration); - void scheduleScan(boost::posix_time::ptime time); + void scheduleScan(std::chrono::seconds duration); + void scheduleScan(std::chrono::system_clock::time_point time); // Update database (scheduled callback) void scan(boost::system::error_code ec); @@ -119,7 +121,7 @@ class MediaScanner Wt::Signal _sigAddedTrack; Wt::Signal _sigRemovedTrack; - boost::asio::deadline_timer _scheduleTimer; + boost::asio::system_timer _scheduleTimer; Database::Handler _db; diff --git a/src/ui/Auth.cpp b/src/ui/Auth.cpp index 5713d065..d4fbc093 100644 --- a/src/ui/Auth.cpp +++ b/src/ui/Auth.cpp @@ -17,10 +17,10 @@ * along with LMS. If not, see . */ -#include -#include -#include -#include +#include +#include +#include +#include #include "utils/Logger.hpp" @@ -31,10 +31,10 @@ namespace UserInterface { -Auth::Auth(Wt::WContainerWidget *parent) -: Wt::WTemplateFormView(parent) +Auth::Auth() +: Wt::WTemplateFormView() { - _model = new Wt::Auth::AuthModel(DbHandler().getAuthService(), DbHandler().getUserDatabase()); + _model = std::make_shared(LmsApp->getDb().getAuthService(), LmsApp->getDb().getUserDatabase()); _model->addPasswordAuth(&Database::Handler::getPasswordService()); @@ -43,50 +43,47 @@ Auth::Auth(Wt::WContainerWidget *parent) addFunction("id", &WTemplate::Functions::id); // LoginName - auto loginName = new Wt::WLineEdit(); - setFormWidget(Wt::Auth::AuthModel::LoginNameField, loginName); + setFormWidget(Wt::Auth::AuthModel::LoginNameField, std::make_unique()); // Password - auto password = new Wt::WLineEdit(); - setFormWidget(Wt::Auth::AuthModel::PasswordField, password); - password->setEchoMode(Wt::WLineEdit::Password); + auto password = std::make_unique(); + password->setEchoMode(Wt::EchoMode::Password); + password->enterPressed().connect(this, &Auth::processAuth); + setFormWidget(Wt::Auth::AuthModel::PasswordField, std::move(password)); // Remember Me - auto rememberMe = new Wt::WCheckBox(); - setFormWidget(Wt::Auth::AuthModel::RememberMeField, rememberMe); + setFormWidget(Wt::Auth::AuthModel::RememberMeField, std::make_unique()); - auto loginBtn = new Wt::WPushButton(Wt::WString::tr("Lms.login")); - bindWidget("login-btn", loginBtn); + Wt::WPushButton* loginBtn = bindNew("login-btn", Wt::WString::tr("Lms.login")); loginBtn->clicked().connect(this, &Auth::processAuth); - password->enterPressed().connect(this, &Auth::processAuth); - DbHandler().getLogin().changed().connect(std::bind([=] + LmsApp->getDb().getLogin().changed().connect(std::bind([=] { - if (DbHandler().getLogin().loggedIn()) + if (LmsApp->getDb().getLogin().loggedIn()) this->setHidden(true); })); Wt::Auth::User user = _model->processAuthToken(); - _model->loginUser(DbHandler().getLogin(), user, Wt::Auth::WeakLogin); + _model->loginUser(LmsApp->getDb().getLogin(), user, Wt::Auth::LoginState::Weak); - updateView(_model); + updateView(_model.get()); } void Auth::processAuth() { - updateModel(_model); + updateModel(_model.get()); if (_model->validate()) - _model->login(DbHandler().getLogin()); + _model->login(LmsApp->getDb().getLogin()); else - updateView(_model); + updateView(_model.get()); } void Auth::logout() { - _model->logout(DbHandler().getLogin()); + _model->logout(LmsApp->getDb().getLogin()); } } // namespace UserInterface diff --git a/src/ui/Auth.hpp b/src/ui/Auth.hpp index 65eec670..07df5557 100644 --- a/src/ui/Auth.hpp +++ b/src/ui/Auth.hpp @@ -19,24 +19,22 @@ #pragma once -#include -#include -#include -#include +#include +#include namespace UserInterface { class Auth : public Wt::WTemplateFormView { public: - Auth(Wt::WContainerWidget *parent = 0); + Auth(); void logout(); private: void processAuth(); - Wt::Auth::AuthModel* _model; + std::shared_ptr _model; }; diff --git a/src/ui/HomeView.cpp b/src/ui/HomeView.cpp index 9d857b4c..f5309e70 100644 --- a/src/ui/HomeView.cpp +++ b/src/ui/HomeView.cpp @@ -17,7 +17,7 @@ * along with LMS. If not, see . */ -#include +#include #include "utils/Logger.hpp" @@ -28,12 +28,13 @@ namespace UserInterface { -Home::Home(Wt::WContainerWidget *parent) -: Wt::WContainerWidget(parent) +Home::Home() +: Wt::WContainerWidget() { - auto t = new Wt::WTemplate(Wt::WString::tr("Lms.Home.template"), this); + auto t = std::make_unique(Wt::WString::tr("Lms.Home.template")); t->addFunction("tr", &Wt::WTemplate::Functions::tr); + this->addWidget(std::move(t)); } } // namespace UserInterface diff --git a/src/ui/HomeView.hpp b/src/ui/HomeView.hpp index 33f65d5e..8406bc58 100644 --- a/src/ui/HomeView.hpp +++ b/src/ui/HomeView.hpp @@ -19,14 +19,14 @@ #pragma once -#include +#include namespace UserInterface { class Home : public Wt::WContainerWidget { public: - Home(Wt::WContainerWidget *parent = 0); + Home(); private: diff --git a/src/ui/LmsApplication.cpp b/src/ui/LmsApplication.cpp index 7b0dacbb..6a0b76c4 100644 --- a/src/ui/LmsApplication.cpp +++ b/src/ui/LmsApplication.cpp @@ -17,15 +17,16 @@ * along with LMS. If not, see . */ -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "config/config.h" #include "utils/Logger.hpp" @@ -49,14 +50,14 @@ namespace UserInterface { -Wt::WApplication* +std::unique_ptr LmsApplication::create(const Wt::WEnvironment& env, Wt::Dbo::SqlConnectionPool& connectionPool, Scanner::MediaScanner& scanner) { /* * You could read information from the environment to decide whether * the user has permission to start a new application */ - return new LmsApplication(env, connectionPool, scanner); + return std::make_unique(env, connectionPool, scanner); } LmsApplication* @@ -78,10 +79,10 @@ LmsApplication::LmsApplication(const Wt::WEnvironment& env, Wt::Dbo::SqlConnecti _imageResource(nullptr), _transcodeResource(nullptr) { - Wt::WBootstrapTheme *bootstrapTheme = new Wt::WBootstrapTheme(this); - bootstrapTheme->setVersion(Wt::WBootstrapTheme::Version3); + auto bootstrapTheme = std::make_unique(); + bootstrapTheme->setVersion(Wt::BootstrapVersion::v3); bootstrapTheme->setResponsive(true); - setTheme(bootstrapTheme); + setTheme(std::move(bootstrapTheme)); useStyleSheet("css/lms.css"); useStyleSheet("resources/font-awesome/css/font-awesome.min.css"); @@ -90,7 +91,7 @@ LmsApplication::LmsApplication(const Wt::WEnvironment& env, Wt::Dbo::SqlConnecti messageResourceBundle().use(appRoot() + "admin-database"); messageResourceBundle().use(appRoot() + "admin-user"); messageResourceBundle().use(appRoot() + "admin-users"); - messageResourceBundle().use(appRoot() + "admin-wizard"); + messageResourceBundle().use(appRoot() + "admin-initwizard"); messageResourceBundle().use(appRoot() + "artist"); messageResourceBundle().use(appRoot() + "artists"); messageResourceBundle().use(appRoot() + "home"); @@ -113,20 +114,22 @@ LmsApplication::LmsApplication(const Wt::WEnvironment& env, Wt::Dbo::SqlConnecti // If here is no account in the database, launch the first connection wizard bool firstConnection; { - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); - firstConnection = (Database::User::getAll(DboSession()).size() == 0); + firstConnection = (Database::User::getAll(LmsApp->getDboSession()).size() == 0); } LMS_LOG(UI, DEBUG) << "Creating root widget. First connection = " << std::boolalpha << firstConnection; if (firstConnection) { - root()->addWidget(new InitWizardView()); + root()->addWidget(std::make_unique()); } else { - DbHandler().getLogin().changed().connect(std::bind([=] + _auth = root()->addNew(); + + LmsApp->getDb().getLogin().changed().connect(std::bind([=] { try { @@ -138,68 +141,31 @@ LmsApplication::LmsApplication(const Wt::WEnvironment& env, Wt::Dbo::SqlConnecti throw std::runtime_error("Internal error"); } })); - - _auth = new Auth(); - root()->addWidget(_auth); } } -Database::Handler& DbHandler() -{ - return LmsApplication::instance()->getDbHandler(); -} -Wt::Dbo::Session& DboSession() -{ - return DbHandler().getSession(); -} - -const Wt::Auth::User& CurrentAuthUser() -{ - return DbHandler().getLogin().user(); -} - -Database::User::pointer CurrentUser() -{ - return DbHandler().getCurrentUser(); -} - -ImageResource* SessionImageResource() -{ - return LmsApplication::instance()->getImageResource(); -} - -TranscodeResource* SessionTranscodeResource() -{ - return LmsApplication::instance()->getTranscodeResource(); -} - -Scanner::MediaScanner& MediaScanner() -{ - return LmsApplication::instance()->getMediaScanner(); -} - -Wt::WAnchor* +std::unique_ptr LmsApplication::createArtistAnchor(Database::Artist::pointer artist, bool addText) { - auto res = new Wt::WAnchor(Wt::WLink(Wt::WLink::InternalPath, "/artist/" + std::to_string(artist.id()))); + auto res = std::make_unique(Wt::WLink(Wt::LinkType::InternalPath, "/artist/" + std::to_string(artist.id()))); if (addText) { - res->setTextFormat(Wt::PlainText); + res->setTextFormat(Wt::TextFormat::Plain); res->setText(Wt::WString::fromUTF8(artist->getName())); } return res; } -Wt::WAnchor* +std::unique_ptr LmsApplication::createReleaseAnchor(Database::Release::pointer release, bool addText) { - auto res = new Wt::WAnchor(Wt::WLink(Wt::WLink::InternalPath, "/release/" + std::to_string(release.id()))); + auto res = std::make_unique(Wt::WLink(Wt::LinkType::InternalPath, "/release/" + std::to_string(release.id()))); if (addText) { - res->setTextFormat(Wt::PlainText); + res->setTextFormat(Wt::TextFormat::Plain); res->setText(Wt::WString::fromUTF8(release->getName())); } @@ -274,7 +240,7 @@ handlePathChange(Wt::WStackedWidget* stack, bool isAdmin) void LmsApplication::handleAuthEvent(void) { - if (!DbHandler().getLogin().loggedIn()) + if (!LmsApp->getDb().getLogin().loggedIn()) { LMS_LOG(UI, INFO) << "User logged out, session = " << Wt::WApplication::instance()->sessionId(); @@ -282,73 +248,69 @@ LmsApplication::handleAuthEvent(void) return; } - LMS_LOG(UI, INFO) << "User '" << CurrentAuthUser().identity(Wt::Auth::Identity::LoginName) << "' logged in from '" << Wt::WApplication::instance()->environment().clientAddress() << "', user agent = " << Wt::WApplication::instance()->environment().agent() << ", session = " << Wt::WApplication::instance()->sessionId(); + LMS_LOG(UI, INFO) << "User '" << LmsApp->getCurrentAuthUser().identity(Wt::Auth::Identity::LoginName) << "' logged in from '" << Wt::WApplication::instance()->environment().clientAddress() << "', user agent = " << Wt::WApplication::instance()->environment().userAgent() << ", session = " << Wt::WApplication::instance()->sessionId(); { - Wt::Dbo::Transaction transaction (DboSession()); - _isAdmin = CurrentUser()->isAdmin(); + Wt::Dbo::Transaction transaction (LmsApp->getDboSession()); + _isAdmin = LmsApp->getCurrentUser()->isAdmin(); } - _imageResource = new ImageResource(_db, root()); - _transcodeResource = new TranscodeResource(_db, root()); + _imageResource = std::make_shared(_db); + _transcodeResource = std::make_shared(_db); setConfirmCloseMessage(Wt::WString::tr("Lms.quit-confirm")); - auto main = new Wt::WTemplate(Wt::WString::tr("Lms.template"), root()); + Wt::WTemplate* main = root()->addWidget(std::make_unique(Wt::WString::tr("Lms.template"))); // Navbar - auto navbar = new Wt::WNavigationBar(); - navbar->setTitle("LMS", Wt::WLink(Wt::WLink::InternalPath, "/home")); + Wt::WNavigationBar* navbar = main->bindNew("navbar-top"); + navbar->setTitle("LMS", Wt::WLink(Wt::LinkType::InternalPath, "/home")); navbar->setResponsive(true); - main->bindWidget("navbar-top", navbar); - - auto menu = new Wt::WMenu(); + Wt::WMenu* menu = navbar->addMenu(std::make_unique()); { auto menuItem = menu->insertItem(0, Wt::WString::tr("Lms.Explore.artists")); - menuItem->setLink(Wt::WLink(Wt::WLink::InternalPath, "/artists")); + menuItem->setLink(Wt::WLink(Wt::LinkType::InternalPath, "/artists")); menuItem->setSelectable(false); } { auto menuItem = menu->insertItem(1, Wt::WString::tr("Lms.Explore.releases")); - menuItem->setLink(Wt::WLink(Wt::WLink::InternalPath, "/releases")); + menuItem->setLink(Wt::WLink(Wt::LinkType::InternalPath, "/releases")); menuItem->setSelectable(false); } { auto menuItem = menu->insertItem(2, Wt::WString::tr("Lms.Explore.tracks")); - menuItem->setLink(Wt::WLink(Wt::WLink::InternalPath, "/tracks")); + menuItem->setLink(Wt::WLink(Wt::LinkType::InternalPath, "/tracks")); menuItem->setSelectable(false); } { auto menuItem = menu->insertItem(3, Wt::WString::tr("Lms.PlayQueue.playqueue")); - menuItem->setLink(Wt::WLink(Wt::WLink::InternalPath, "/playqueue")); + menuItem->setLink(Wt::WLink(Wt::LinkType::InternalPath, "/playqueue")); menuItem->setSelectable(false); } - navbar->addMenu(menu); - auto rightMenu = new Wt::WMenu(); + Wt::WMenu* rightMenu = navbar->addMenu(std::make_unique(), Wt::AlignmentFlag::Right); std::size_t itemCounter = 0; - if (_isAdmin) { auto menuItem = rightMenu->insertItem(itemCounter++, Wt::WString::tr("Lms.administration")); menuItem->setSelectable(false); - Wt::WPopupMenu *admin = new Wt::WPopupMenu(); + auto admin = std::make_unique(); auto dbSettings = admin->insertItem(0, Wt::WString::tr("Lms.Admin.Database.database")); - dbSettings->setLink(Wt::WLink(Wt::WLink::InternalPath, "/admin/database")); + dbSettings->setLink(Wt::WLink(Wt::LinkType::InternalPath, "/admin/database")); dbSettings->setSelectable(false); auto usersSettings = admin->insertItem(1, Wt::WString::tr("Lms.Admin.Users.users")); - usersSettings->setLink(Wt::WLink(Wt::WLink::InternalPath, "/admin/users")); + usersSettings->setLink(Wt::WLink(Wt::LinkType::InternalPath, "/admin/users")); usersSettings->setSelectable(false); - menuItem->setMenu(admin); + menuItem->setMenu(std::move(admin)); } { auto menuItem = rightMenu->insertItem(itemCounter++, Wt::WString::tr("Lms.Settings.settings")); - menuItem->setLink(Wt::WLink(Wt::WLink::InternalPath, "/settings")); + menuItem->setLink(Wt::WLink(Wt::LinkType::InternalPath, "/settings")); menuItem->setSelectable(false); } { @@ -360,34 +322,22 @@ LmsApplication::handleAuthEvent(void) _auth->logout(); })); } - navbar->addMenu(rightMenu, Wt::AlignRight); // Contents - Wt::WStackedWidget* mainStack = new Wt::WStackedWidget(); - main->bindWidget("contents", mainStack); + // Order is important in mainStack, see IdxRoot! + Wt::WStackedWidget* mainStack = main->bindNew("contents"); - mainStack->addWidget(new Home()); - - auto explore = new Explore(); - mainStack->addWidget(explore); - - auto playqueue = new PlayQueue(); - mainStack->addWidget(playqueue); - - auto settings = new SettingsView(); - mainStack->addWidget(settings); + mainStack->addNew(); + Explore* explore = mainStack->addNew(); + PlayQueue* playqueue = mainStack->addNew(); + mainStack->addNew(); // Admin stuff if (_isAdmin) { - auto databaseSettings = new DatabaseSettingsView(); - mainStack->addWidget(databaseSettings); - - auto users = new UsersView(); - mainStack->addWidget(users); - - auto user = new UserView(); - mainStack->addWidget(user); + mainStack->addNew(); + mainStack->addNew(); + mainStack->addNew(); } explore->tracksAdd.connect(std::bind([=] (std::vector tracks) @@ -400,9 +350,9 @@ LmsApplication::handleAuthEvent(void) playqueue->playTracks(tracks); }, std::placeholders::_1)); + // MediaPlayer - auto player = new MediaPlayer(); - main->bindWidget("player", player); + MediaPlayer* player = main->bindNew("player"); // Events from MediaPlayer player->playNext.connect(std::bind([=] @@ -468,7 +418,7 @@ void LmsApplication::notifyMsg(const Wt::WString& message) { LMS_LOG(UI, INFO) << "Notifying message '" << message.toUTF8() << "'"; - root()->addWidget(new Wt::WText(message)); + root()->addNew(message); } } // namespace UserInterface diff --git a/src/ui/LmsApplication.hpp b/src/ui/LmsApplication.hpp index 062872cc..b8ceda11 100644 --- a/src/ui/LmsApplication.hpp +++ b/src/ui/LmsApplication.hpp @@ -20,8 +20,8 @@ #ifndef LMS_APPLICATION_HPP #define LMS_APPLICATION_HPP -#include -#include +#include +#include #include "database/DatabaseHandler.hpp" #include "scanner/MediaScanner.hpp" @@ -36,13 +36,20 @@ class ImageResource; class LmsApplication : public Wt::WApplication { public: - static Wt::WApplication *create(const Wt::WEnvironment& env, Wt::Dbo::SqlConnectionPool& connectionPool, Scanner::MediaScanner& scanner); + LmsApplication(const Wt::WEnvironment& env, Wt::Dbo::SqlConnectionPool& connectionPool, Scanner::MediaScanner& scanner); + + static std::unique_ptr create(const Wt::WEnvironment& env, + Wt::Dbo::SqlConnectionPool& connectionPool, Scanner::MediaScanner& scanner); static LmsApplication* instance(); // Session application data - ImageResource* getImageResource() { return _imageResource; } - TranscodeResource* getTranscodeResource() { return _transcodeResource; } - Database::Handler& getDbHandler() { return _db;} + std::shared_ptr getImageResource() { return _imageResource; } + std::shared_ptr getTranscodeResource() { return _transcodeResource; } + Database::Handler& getDb() { return _db;} + Wt::Dbo::Session& getDboSession() { return _db.getSession();} + + const Wt::Auth::User& getCurrentAuthUser() { return _db.getLogin().user(); } + Database::User::pointer getCurrentUser() { return _db.getCurrentUser(); } Scanner::MediaScanner& getMediaScanner() { return _scanner; } @@ -51,33 +58,25 @@ class LmsApplication : public Wt::WApplication void goHomeAndQuit(); void notifyMsg(const Wt::WString& message); - static Wt::WAnchor* createArtistAnchor(Database::Artist::pointer artist, bool addText = true); - static Wt::WAnchor* createReleaseAnchor(Database::Release::pointer release, bool addText = true); + static std::unique_ptr createArtistAnchor(Database::Artist::pointer artist, bool addText = true); + static std::unique_ptr createReleaseAnchor(Database::Release::pointer release, bool addText = true); private: - LmsApplication(const Wt::WEnvironment& env, Wt::Dbo::SqlConnectionPool& connectionPool, Scanner::MediaScanner& scanner); - void handleAuthEvent(void); void notify(const Wt::WEvent& event) override; Database::Handler _db; Auth* _auth; Scanner::MediaScanner& _scanner; - ImageResource* _imageResource; - TranscodeResource* _transcodeResource; + std::shared_ptr _imageResource; + std::shared_ptr _transcodeResource; bool _isAdmin = false; }; -// Helpers to get session data +// Helper to get session data #define LmsApp LmsApplication::instance() -Database::Handler& DbHandler(); -Wt::Dbo::Session& DboSession(); - -const Wt::Auth::User& CurrentAuthUser(); -Database::User::pointer CurrentUser(); - } // namespace UserInterface #endif diff --git a/src/ui/MediaPlayer.cpp b/src/ui/MediaPlayer.cpp index 7c9921e8..b4fd2816 100644 --- a/src/ui/MediaPlayer.cpp +++ b/src/ui/MediaPlayer.cpp @@ -30,8 +30,8 @@ namespace UserInterface { -MediaPlayer::MediaPlayer(Wt::WContainerWidget* parent) -: Wt::WTemplate(Wt::WString::tr("template-mediaplayer"), parent), +MediaPlayer::MediaPlayer() +: Wt::WTemplate(Wt::WString::tr("template-mediaplayer")), playbackEnded(this, "playbackEnded"), playPrevious(this, "playPrevious"), playNext(this, "playNext") @@ -49,8 +49,8 @@ MediaPlayer::playTrack(Database::Track::id_type trackId) { LMS_LOG(UI, DEBUG) << "Playing track ID = " << trackId; - Wt::Dbo::Transaction transaction(DboSession()); - auto track = Database::Track::getById(DboSession(), trackId); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); + auto track = Database::Track::getById(LmsApp->getDboSession(), trackId); try { @@ -66,7 +66,7 @@ MediaPlayer::playTrack(Database::Track::id_type trackId) << " release: " << (track->getRelease() ? "\"" + escape(track->getRelease()->getName()) + "\"" : "undefined" ) << "," << " artist: " << (track->getArtist() ? "\"" + escape(track->getArtist()->getName()) + "\"" : "undefined" ) << "," << " resource: \"" << resource << "\"," - << " duration: " << track->getDuration().total_seconds() << "," + << " duration: " << std::chrono::duration_cast(track->getDuration()).count() << "," << " imgResource: \"" << imgResource << "\"," << "};"; oss << "LMS.mediaplayer.loadTrack(params, true)"; // true to autoplay diff --git a/src/ui/MediaPlayer.hpp b/src/ui/MediaPlayer.hpp index 80d7d74d..55da4f42 100644 --- a/src/ui/MediaPlayer.hpp +++ b/src/ui/MediaPlayer.hpp @@ -19,8 +19,8 @@ #pragma once -#include -#include +#include +#include #include "database/Types.hpp" @@ -29,15 +29,15 @@ namespace UserInterface { class MediaPlayer : public Wt::WTemplate { public: - MediaPlayer(Wt::WContainerWidget* parent = 0); + MediaPlayer(); void stop(); void playTrack(Database::Track::id_type); // Signals - Wt::JSignal playbackEnded; - Wt::JSignal playPrevious; - Wt::JSignal playNext; + Wt::JSignal<> playbackEnded; + Wt::JSignal<> playPrevious; + Wt::JSignal<> playNext; private: diff --git a/src/ui/PlayQueueView.cpp b/src/ui/PlayQueueView.cpp index ae329179..5334f5e5 100644 --- a/src/ui/PlayQueueView.cpp +++ b/src/ui/PlayQueueView.cpp @@ -17,9 +17,9 @@ * along with LMS. If not, see . */ -#include -#include -#include +#include +#include +#include #include "utils/Logger.hpp" @@ -30,26 +30,39 @@ namespace UserInterface { static const std::string currentPlayQueueName = "__current__playqueue__"; -PlayQueue::PlayQueue(Wt::WContainerWidget* parent) -: Wt::WContainerWidget(parent) +PlayQueue::PlayQueue() +: Wt::WTemplate(Wt::WString::tr("Lms.PlayQueue.template")) { - auto container = new Wt::WTemplate(Wt::WString::tr("Lms.PlayQueue.template"), this); - container->addFunction("tr", &Wt::WTemplate::Functions::tr); + addFunction("tr", &Wt::WTemplate::Functions::tr); - auto saveBtn = new Wt::WText(Wt::WString::tr("Lms.PlayQueue.save-to-playlist"), Wt::XHTMLText); - container->bindWidget("save-btn", saveBtn); + bindNew("save-btn", Wt::WString::tr("Lms.PlayQueue.save-to-playlist"), Wt::TextFormat::XHTML); + bindNew("load-btn", Wt::WString::tr("Lms.PlayQueue.load-from-playlist"), Wt::TextFormat::XHTML); + Wt::WText* clearBtn = bindNew("clear-btn", Wt::WString::tr("Lms.PlayQueue.clear"), Wt::TextFormat::XHTML); - auto loadBtn = new Wt::WText(Wt::WString::tr("Lms.PlayQueue.load-from-playlist"), Wt::XHTMLText); - container->bindWidget("load-btn", loadBtn); + _entriesContainer = bindNew("entries"); + + _showMore = bindNew("show-more", Wt::WString::tr("Lms.Explore.show-more")); + _showMore->addFunction("tr", &Wt::WTemplate::Functions::tr); + _showMore->setHidden(true); + + _nbTracks = bindNew("nb-tracks"); + + { + Wt::Dbo::Transaction transaction (LmsApp->getDboSession()); + + auto playlist = Database::Playlist::get(LmsApp->getDboSession(), currentPlayQueueName, LmsApp->getCurrentUser()); + if (!playlist) + playlist = Database::Playlist::create(LmsApp->getDboSession(), currentPlayQueueName, false, LmsApp->getCurrentUser()); + + _trackPos = LmsApp->getCurrentUser()->getCurPlayingTrackPos(); + } - auto clearBtn = new Wt::WText(Wt::WString::tr("Lms.PlayQueue.clear"), Wt::XHTMLText); - container->bindWidget("clear-btn", clearBtn); clearBtn->clicked().connect(std::bind([=] { { - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); - auto playlist = Database::Playlist::get(DboSession(), currentPlayQueueName, CurrentUser()); + auto playlist = Database::Playlist::get(LmsApp->getDboSession(), currentPlayQueueName, LmsApp->getCurrentUser()); playlist.modify()->clear(); _showMore->setHidden(true); } @@ -58,27 +71,6 @@ PlayQueue::PlayQueue(Wt::WContainerWidget* parent) updateInfo(); })); - _entriesContainer = new Wt::WContainerWidget(); - container->bindWidget("entries", _entriesContainer); - - _showMore = new Wt::WTemplate(Wt::WString::tr("Lms.Explore.show-more")); - _showMore->addFunction("tr", &Wt::WTemplate::Functions::tr); - _showMore->setHidden(true); - container->bindWidget("show-more", _showMore); - - _nbTracks = new Wt::WText(); - container->bindWidget("nb-tracks", _nbTracks); - - { - Wt::Dbo::Transaction transaction (DboSession()); - - auto playlist = Database::Playlist::get(DboSession(), currentPlayQueueName, CurrentUser()); - if (!playlist) - playlist = Database::Playlist::create(DboSession(), currentPlayQueueName, false, CurrentUser()); - - _trackPos = CurrentUser()->getCurPlayingTrackPos(); - } - _showMore->clicked().connect(std::bind([=] { addSome(); @@ -103,9 +95,9 @@ PlayQueue::play(std::size_t pos) Database::Track::id_type trackId; { - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); - auto playlist = Database::Playlist::get(DboSession(), currentPlayQueueName, CurrentUser()); + auto playlist = Database::Playlist::get(LmsApp->getDboSession(), currentPlayQueueName, LmsApp->getCurrentUser()); // If out of range, stop playing if (pos >= playlist->getCount()) @@ -149,9 +141,9 @@ PlayQueue::playNext() void PlayQueue::updateInfo() { - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); - auto playlist = Database::Playlist::get(DboSession(), currentPlayQueueName, CurrentUser()); + auto playlist = Database::Playlist::get(LmsApp->getDboSession(), currentPlayQueueName, LmsApp->getCurrentUser()); _nbTracks->setText(Wt::WString::tr("Lms.PlayQueue.nb-tracks").arg(playlist->getCount())); } @@ -179,10 +171,10 @@ PlayQueue::addTracks(const std::vector& tracks) LMS_LOG(UI, DEBUG) << "Adding tracks to the current queue"; - auto playlist = Database::Playlist::get(DboSession(), currentPlayQueueName, CurrentUser()); + auto playlist = Database::Playlist::get(LmsApp->getDboSession(), currentPlayQueueName, LmsApp->getCurrentUser()); for (auto track : tracks) - Database::PlaylistEntry::create(DboSession(), track, playlist); + Database::PlaylistEntry::create(LmsApp->getDboSession(), track, playlist); updateInfo(); addSome(); @@ -193,9 +185,9 @@ PlayQueue::playTracks(const std::vector& tracks) { LMS_LOG(UI, DEBUG) << "Emptying current queue to play new tracks"; - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); - auto playqueue = Database::Playlist::get(DboSession(), currentPlayQueueName, CurrentUser()); + auto playqueue = Database::Playlist::get(LmsApp->getDboSession(), currentPlayQueueName, LmsApp->getCurrentUser()); playqueue.modify()->clear(); _entriesContainer->clear(); @@ -209,9 +201,9 @@ PlayQueue::playTracks(const std::vector& tracks) void PlayQueue::addSome() { - Wt::Dbo::Transaction transaction (DboSession()); + Wt::Dbo::Transaction transaction (LmsApp->getDboSession()); - auto playlist = Database::Playlist::get(DboSession(), currentPlayQueueName, CurrentUser()); + auto playlist = Database::Playlist::get(LmsApp->getDboSession(), currentPlayQueueName, LmsApp->getCurrentUser()); bool moreResults; auto playlistEntries = playlist->getEntries(_entriesContainer->count(), 50, moreResults); @@ -220,27 +212,24 @@ PlayQueue::addSome() auto playlistEntryId = playlistEntry.id(); auto track = playlistEntry->getTrack(); - Wt::WTemplate* entry = new Wt::WTemplate(Wt::WString::tr("Lms.PlayQueue.template.entry"), _entriesContainer); + Wt::WTemplate* entry = _entriesContainer->addNew(Wt::WString::tr("Lms.PlayQueue.template.entry")); - entry->bindString("name", Wt::WString::fromUTF8(track->getName()), Wt::PlainText); + entry->bindString("name", Wt::WString::fromUTF8(track->getName()), Wt::TextFormat::Plain); auto artist = track->getArtist(); if (artist) { entry->setCondition("if-has-artist", true); - Wt::WAnchor *artistAnchor = LmsApplication::createArtistAnchor(track->getArtist()); - entry->bindWidget("artist-name", artistAnchor); + entry->bindWidget("artist-name", LmsApplication::createArtistAnchor(track->getArtist())); } auto release = track->getRelease(); if (release) { entry->setCondition("if-has-release", true); - Wt::WAnchor *releaseAnchor = LmsApplication::createReleaseAnchor(track->getRelease()); - entry->bindWidget("release-name", releaseAnchor); + entry->bindWidget("release-name", LmsApplication::createReleaseAnchor(track->getRelease())); } - auto playBtn = new Wt::WText(Wt::WString::tr("Lms.PlayQueue.play"), Wt::XHTMLText); - entry->bindWidget("play-btn", playBtn); + Wt::WText* playBtn = entry->bindNew("play-btn", Wt::WString::tr("Lms.PlayQueue.play"), Wt::TextFormat::XHTML); playBtn->clicked().connect(std::bind([=] { auto pos = _entriesContainer->indexOf(entry); @@ -248,15 +237,14 @@ PlayQueue::addSome() play(pos); })); - auto delBtn = new Wt::WText(Wt::WString::tr("Lms.PlayQueue.delete"), Wt::XHTMLText); - entry->bindWidget("del-btn", delBtn); + Wt::WText* delBtn = entry->bindNew("del-btn", Wt::WString::tr("Lms.PlayQueue.delete"), Wt::TextFormat::XHTML); delBtn->clicked().connect(std::bind([=] { // Remove the entry n both the widget tree and the playqueue { - Wt::Dbo::Transaction transaction (DboSession()); + Wt::Dbo::Transaction transaction (LmsApp->getDboSession()); - auto entryToRemove = Database::PlaylistEntry::getById(DboSession(), playlistEntryId); + auto entryToRemove = Database::PlaylistEntry::getById(LmsApp->getDboSession(), playlistEntryId); entryToRemove.remove(); } @@ -271,6 +259,7 @@ PlayQueue::addSome() updateInfo(); })); + } _showMore->setHidden(!moreResults); diff --git a/src/ui/PlayQueueView.hpp b/src/ui/PlayQueueView.hpp index 18a0de34..0d65d2a0 100644 --- a/src/ui/PlayQueueView.hpp +++ b/src/ui/PlayQueueView.hpp @@ -19,10 +19,10 @@ #pragma once -#include -#include -#include -#include +#include +#include +#include +#include #include @@ -30,10 +30,10 @@ namespace UserInterface { -class PlayQueue : public Wt::WContainerWidget +class PlayQueue : public Wt::WTemplate { public: - PlayQueue(Wt::WContainerWidget* parent = 0); + PlayQueue(); void addTracks(const std::vector& tracks); void playTracks(const std::vector& tracks); @@ -48,7 +48,7 @@ class PlayQueue : public Wt::WContainerWidget Wt::Signal playTrack; // Signal emitted when play has to be stopped - Wt::Signal playbackStop; + Wt::Signal<> playbackStop; private: void addSome(); diff --git a/src/ui/SettingsView.cpp b/src/ui/SettingsView.cpp index 0daa1295..aa3b962e 100644 --- a/src/ui/SettingsView.cpp +++ b/src/ui/SettingsView.cpp @@ -17,13 +17,13 @@ * along with LMS. If not, see . */ -#include -#include -#include -#include +#include +#include +#include +#include -#include -#include +#include +#include #include "common/Validators.hpp" @@ -45,8 +45,8 @@ class SettingsModel : public Wt::WFormModel static const Field PasswordField; static const Field PasswordConfirmField; - SettingsModel(Wt::WObject *parent = 0) - : Wt::WFormModel(parent) + SettingsModel() + : Wt::WFormModel() { initializeModels(); @@ -61,18 +61,18 @@ class SettingsModel : public Wt::WFormModel loadData(); } - Wt::WAbstractItemModel *bitrateModel() { return _bitrateModel; } - Wt::WAbstractItemModel *encodingModel() { return _encodingModel; } + std::shared_ptr bitrateModel() { return _bitrateModel; } + std::shared_ptr encodingModel() { return _encodingModel; } void loadData() { - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); - auto bitrate = getBitrateRow(CurrentUser()->getAudioBitrate()); + auto bitrate = getBitrateRow(LmsApp->getCurrentUser()->getAudioBitrate()); if (bitrate) setValue(BitrateField, bitrateString(*bitrate)); - auto encodingRow = getEncodingRow(CurrentUser()->getAudioEncoding()); + auto encodingRow = getEncodingRow(LmsApp->getCurrentUser()->getAudioEncoding()); if (encodingRow) setValue(EncodingField, encodingString(*encodingRow)); @@ -80,18 +80,18 @@ class SettingsModel : public Wt::WFormModel void saveData() { - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); auto bitrateRow = getBitrateRow(Wt::asString(value(BitrateField))); assert(bitrateRow); - CurrentUser().modify()->setAudioBitrate(bitrate(*bitrateRow)); + LmsApp->getCurrentUser().modify()->setAudioBitrate(bitrate(*bitrateRow)); auto encodingRow = getEncodingRow(Wt::asString(value(EncodingField))); - CurrentUser().modify()->setAudioEncoding(encoding(*encodingRow)); + LmsApp->getCurrentUser().modify()->setAudioEncoding(encoding(*encodingRow)); if (!valueText(PasswordField).empty()) { - Database::Handler::getPasswordService().updatePassword(CurrentAuthUser(), valueText(PasswordField)); + Database::Handler::getPasswordService().updatePassword(LmsApp->getCurrentAuthUser(), valueText(PasswordField)); } } @@ -105,7 +105,7 @@ class SettingsModel : public Wt::WFormModel { // Evaluate the strength of the password auto res = Database::Handler::getPasswordService().strengthValidator()->evaluateStrength(valueText(PasswordField), - CurrentAuthUser().identity(Wt::Auth::Identity::LoginName), ""); + LmsApp->getCurrentAuthUser().identity(Wt::Auth::Identity::LoginName), ""); if (!res.isValid()) error = res.message(); @@ -115,7 +115,7 @@ class SettingsModel : public Wt::WFormModel } else if (field == PasswordConfirmField) { - if (validation(PasswordField).state() == Wt::WValidator::Valid) + if (validation(PasswordField).state() == Wt::ValidationState::Valid) { if (valueText(PasswordField) != valueText(PasswordConfirmField)) error = Wt::WString::tr("Lms.passwords-dont-match"); @@ -126,9 +126,9 @@ class SettingsModel : public Wt::WFormModel return Wt::WFormModel::validateField(field); } - setValidation(field, Wt::WValidator::Result( error.empty() ? Wt::WValidator::Valid : Wt::WValidator::Invalid, error)); + setValidation(field, Wt::WValidator::Result( error.empty() ? Wt::ValidationState::Valid : Wt::ValidationState::Invalid, error)); - return (validation(field).state() == Wt::WValidator::Valid); + return (validation(field).state() == Wt::ValidationState::Valid); } boost::optional getBitrateRow(Wt::WString value) @@ -155,14 +155,14 @@ class SettingsModel : public Wt::WFormModel std::size_t bitrate(int row) { - return boost::any_cast - (_bitrateModel->data(_bitrateModel->index(row, 0), Wt::UserRole)); + return Wt::cpp17::any_cast + (_bitrateModel->data(_bitrateModel->index(row, 0), Wt::ItemDataRole::User)); } Wt::WString bitrateString(int row) { - return boost::any_cast - (_bitrateModel->data(_bitrateModel->index(row, 0), Wt::DisplayRole)); + return Wt::cpp17::any_cast + (_bitrateModel->data(_bitrateModel->index(row, 0), Wt::ItemDataRole::Display)); } boost::optional getEncodingRow(Wt::WString value) @@ -189,14 +189,14 @@ class SettingsModel : public Wt::WFormModel Database::AudioEncoding encoding(int row) { - return boost::any_cast - (_encodingModel->data(_encodingModel->index(row, 0), Wt::UserRole)); + return Wt::cpp17::any_cast + (_encodingModel->data(_encodingModel->index(row, 0), Wt::ItemDataRole::User)); } Wt::WString encodingString(int row) { - return boost::any_cast - (_encodingModel->data(_encodingModel->index(row, 0), Wt::DisplayRole)); + return Wt::cpp17::any_cast + (_encodingModel->data(_encodingModel->index(row, 0), Wt::ItemDataRole::Display)); } @@ -204,42 +204,42 @@ class SettingsModel : public Wt::WFormModel void initializeModels() { - - _bitrateModel = new Wt::WStringListModel(this); + _bitrateModel = std::make_shared(); std::size_t maxAudioBitrate; { - Wt::Dbo::Transaction transaction(DboSession()); - maxAudioBitrate = CurrentUser()->getMaxAudioBitrate(); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); + maxAudioBitrate = LmsApp->getCurrentUser()->getMaxAudioBitrate(); } std::size_t id = 0; - for (auto bitrate : Database::User::audioBitrates) + for (std::size_t bitrate : Database::User::audioBitrates) { if (bitrate > maxAudioBitrate) break; _bitrateModel->addString( Wt::WString::fromUTF8(std::to_string(bitrate / 1000)) ); - _bitrateModel->setData( id++, 0, bitrate, Wt::UserRole); + _bitrateModel->setData( id, 0, bitrate, Wt::ItemDataRole::User); + id++; } - _encodingModel = new Wt::WStringListModel(this); + _encodingModel = std::make_shared(); _encodingModel->addString(Wt::WString::tr("Lms.Settings.auto")); - _encodingModel->setData(0, 0, Database::AudioEncoding::AUTO, Wt::UserRole); + _encodingModel->setData(0, 0, Database::AudioEncoding::AUTO, Wt::ItemDataRole::User); _encodingModel->addString(Wt::WString::tr("Lms.Settings.mp3")); - _encodingModel->setData(1, 0, Database::AudioEncoding::MP3, Wt::UserRole); + _encodingModel->setData(1, 0, Database::AudioEncoding::MP3, Wt::ItemDataRole::User); _encodingModel->addString(Wt::WString::tr("Lms.Settings.oga")); - _encodingModel->setData(2, 0, Database::AudioEncoding::OGA, Wt::UserRole); + _encodingModel->setData(2, 0, Database::AudioEncoding::OGA, Wt::ItemDataRole::User); _encodingModel->addString(Wt::WString::tr("Lms.Settings.webma")); - _encodingModel->setData(3, 0, Database::AudioEncoding::WEBMA, Wt::UserRole); + _encodingModel->setData(3, 0, Database::AudioEncoding::WEBMA, Wt::ItemDataRole::User); } - Wt::WStringListModel* _bitrateModel; - Wt::WStringListModel* _encodingModel; + std::shared_ptr _bitrateModel; + std::shared_ptr _encodingModel; }; @@ -248,45 +248,38 @@ const Wt::WFormModel::Field SettingsModel::EncodingField = "encoding"; const Wt::WFormModel::Field SettingsModel::PasswordField = "password"; const Wt::WFormModel::Field SettingsModel::PasswordConfirmField = "password-confirm"; -SettingsView::SettingsView(Wt::WContainerWidget *parent) -: Wt::WTemplateFormView(parent) +SettingsView::SettingsView() +: Wt::WTemplateFormView(Wt::WString::tr("Lms.Settings.template")) { - auto model = new SettingsModel(this); - - setTemplateText(tr("Lms.Settings.template")); - addFunction("tr", &WTemplate::Functions::tr); - addFunction("id", &WTemplate::Functions::id); + auto model = std::make_shared(); // Password - Wt::WLineEdit *password = new Wt::WLineEdit(); - setFormWidget(SettingsModel::PasswordField, password); - password->setEchoMode(Wt::WLineEdit::Password); + auto password = std::make_unique(); + password->setEchoMode(Wt::EchoMode::Password); + setFormWidget(SettingsModel::PasswordField, std::move(password)); // Password confirm - Wt::WLineEdit *passwordConfirm = new Wt::WLineEdit(); - setFormWidget(SettingsModel::PasswordConfirmField, passwordConfirm); - passwordConfirm->setEchoMode(Wt::WLineEdit::Password); + auto passwordConfirm = std::make_unique(); + passwordConfirm->setEchoMode(Wt::EchoMode::Password); + setFormWidget(SettingsModel::PasswordConfirmField, std::move(passwordConfirm)); // Bitrate - Wt::WComboBox *bitrate = new Wt::WComboBox(); - setFormWidget(SettingsModel::BitrateField, bitrate); + auto bitrate = std::make_unique(); bitrate->setModel(model->bitrateModel()); + setFormWidget(SettingsModel::BitrateField, std::move(bitrate)); // Encoding - Wt::WComboBox *encoding = new Wt::WComboBox(); - setFormWidget(SettingsModel::EncodingField, encoding); + auto encoding = std::make_unique(); encoding->setModel(model->encodingModel()); + setFormWidget(SettingsModel::EncodingField, std::move(encoding)); // Buttons - Wt::WPushButton *saveBtn = new Wt::WPushButton(Wt::WString::tr("Lms.apply")); - bindWidget("apply-btn", saveBtn); - - Wt::WPushButton *discardBtn = new Wt::WPushButton(Wt::WString::tr("Lms.discard")); - bindWidget("discard-btn", discardBtn); + Wt::WPushButton *saveBtn = bindWidget("apply-btn", std::make_unique(Wt::WString::tr("Lms.apply"))); + Wt::WPushButton *discardBtn = bindWidget("discard-btn", std::make_unique(Wt::WString::tr("Lms.discard"))); saveBtn->clicked().connect(std::bind([=] () { - updateModel(model); + updateModel(model.get()); if (model->validate()) { @@ -295,17 +288,17 @@ SettingsView::SettingsView(Wt::WContainerWidget *parent) } // Udate the view: Delete any validation message in the view, etc. - updateView(model); + updateView(model.get()); })); discardBtn->clicked().connect(std::bind([=] () { model->loadData(); model->validate(); - updateView(model); + updateView(model.get()); })); - updateView(model); + updateView(model.get()); } } // namespace UserInterface diff --git a/src/ui/SettingsView.hpp b/src/ui/SettingsView.hpp index 95708107..ac51a133 100644 --- a/src/ui/SettingsView.hpp +++ b/src/ui/SettingsView.hpp @@ -19,15 +19,14 @@ #pragma once -#include -#include +#include namespace UserInterface { class SettingsView : public Wt::WTemplateFormView { public: - SettingsView(Wt::WContainerWidget *parent = 0); + SettingsView(); }; } // namespace UserInterface diff --git a/src/ui/admin/DatabaseSettingsView.cpp b/src/ui/admin/DatabaseSettingsView.cpp index 9373dd59..8b1c6764 100644 --- a/src/ui/admin/DatabaseSettingsView.cpp +++ b/src/ui/admin/DatabaseSettingsView.cpp @@ -17,13 +17,13 @@ * along with LMS. If not, see . */ -#include -#include -#include -#include +#include +#include +#include +#include -#include -#include +#include +#include #include "common/Validators.hpp" #include "database/MediaDirectory.hpp" @@ -46,8 +46,8 @@ class DatabaseSettingsModel : public Wt::WFormModel static const Field UpdatePeriodField; static const Field UpdateStartTimeField; - DatabaseSettingsModel(Wt::WObject *parent = 0) - : Wt::WFormModel(parent) + DatabaseSettingsModel() + : Wt::WFormModel() { initializeModels(); @@ -55,7 +55,7 @@ class DatabaseSettingsModel : public Wt::WFormModel addField(UpdatePeriodField); addField(UpdateStartTimeField); - DirectoryValidator* dirValidator = new DirectoryValidator(); + auto dirValidator = std::make_shared(); dirValidator->setMandatory(true); setValidator(MediaDirectoryField, dirValidator); @@ -66,42 +66,42 @@ class DatabaseSettingsModel : public Wt::WFormModel loadData(); } - Wt::WAbstractItemModel *updatePeriodModel() { return _updatePeriodModel; } - Wt::WAbstractItemModel *updateStartTimeModel() { return _updateStartTimeModel; } + std::shared_ptr updatePeriodModel() { return _updatePeriodModel; } + std::shared_ptr updateStartTimeModel() { return _updateStartTimeModel; } void loadData() { using namespace Database; - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); - std::vector mediaDirectories = MediaDirectory::getAll(DboSession()); + std::vector mediaDirectories = MediaDirectory::getAll(LmsApp->getDboSession()); if (!mediaDirectories.empty()) setValue(MediaDirectoryField, mediaDirectories.front()->getPath().string()); - auto periodRow = getUpdatePeriodModelRow( Scanner::getUpdatePeriod(DboSession()) ); + auto periodRow = getUpdatePeriodModelRow( Scanner::getUpdatePeriod(LmsApp->getDboSession()) ); if (periodRow) setValue(UpdatePeriodField, updatePeriodString(*periodRow)); - auto startTimeRow = getUpdateStartTimeModelRow( Scanner::getUpdateStartTime(DboSession()) ); + auto startTimeRow = getUpdateStartTimeModelRow( Scanner::getUpdateStartTime(LmsApp->getDboSession()) ); if (startTimeRow) setValue(UpdateStartTimeField, updateStartTimeString(*startTimeRow) ); } void saveData() { - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); - MediaDirectory::eraseAll(DboSession()); - MediaDirectory::create(DboSession(), boost::any_cast(value(MediaDirectoryField)).toUTF8()); + MediaDirectory::eraseAll(LmsApp->getDboSession()); + MediaDirectory::create(LmsApp->getDboSession(), Wt::cpp17::any_cast(value(MediaDirectoryField)).toUTF8()); - auto updatePeriodRow = getUpdatePeriodModelRow( boost::any_cast(value(UpdatePeriodField))); + auto updatePeriodRow = getUpdatePeriodModelRow( Wt::cpp17::any_cast(value(UpdatePeriodField))); assert(updatePeriodRow); - Scanner::setUpdatePeriod(DboSession(), updatePeriod(*updatePeriodRow)); + Scanner::setUpdatePeriod(LmsApp->getDboSession(), updatePeriod(*updatePeriodRow)); - auto startTimeRow = getUpdateStartTimeModelRow( boost::any_cast(value(UpdateStartTimeField))); + auto startTimeRow = getUpdateStartTimeModelRow( Wt::cpp17::any_cast(value(UpdateStartTimeField))); assert(startTimeRow); - Scanner::setUpdateStartTime(DboSession(), updateStartTime(*startTimeRow)); + Scanner::setUpdateStartTime(LmsApp->getDboSession(), updateStartTime(*startTimeRow)); } boost::optional getUpdatePeriodModelRow(Wt::WString value) @@ -128,14 +128,14 @@ class DatabaseSettingsModel : public Wt::WFormModel Scanner::UpdatePeriod updatePeriod(int row) { - return boost::any_cast - (_updatePeriodModel->data(_updatePeriodModel->index(row, 0), Wt::UserRole)); + return Wt::cpp17::any_cast + (_updatePeriodModel->data(_updatePeriodModel->index(row, 0), Wt::ItemDataRole::User)); } Wt::WString updatePeriodString(int row) { - return boost::any_cast - (_updatePeriodModel->data(_updatePeriodModel->index(row, 0), Wt::DisplayRole)); + return Wt::cpp17::any_cast + (_updatePeriodModel->data(_updatePeriodModel->index(row, 0), Wt::ItemDataRole::Display)); } @@ -150,7 +150,7 @@ class DatabaseSettingsModel : public Wt::WFormModel return boost::none; } - boost::optional getUpdateStartTimeModelRow(boost::posix_time::time_duration startTime) + boost::optional getUpdateStartTimeModelRow(Wt::WTime startTime) { for (int i = 0; i < _updateStartTimeModel->rowCount(); ++i) { @@ -161,16 +161,16 @@ class DatabaseSettingsModel : public Wt::WFormModel return boost::none; } - boost::posix_time::time_duration updateStartTime(int row) + Wt::WTime updateStartTime(int row) { - return boost::any_cast - (_updateStartTimeModel->data(_updateStartTimeModel->index(row, 0), Wt::UserRole)); + return Wt::cpp17::any_cast + (_updateStartTimeModel->data(_updateStartTimeModel->index(row, 0), Wt::ItemDataRole::User)); } Wt::WString updateStartTimeString(int row) { - return boost::any_cast - (_updateStartTimeModel->data(_updateStartTimeModel->index(row, 0), Wt::DisplayRole)); + return Wt::cpp17::any_cast + (_updateStartTimeModel->data(_updateStartTimeModel->index(row, 0), Wt::ItemDataRole::Display)); } @@ -179,43 +179,35 @@ class DatabaseSettingsModel : public Wt::WFormModel void initializeModels() { - _updatePeriodModel = new Wt::WStringListModel(this); + _updatePeriodModel = std::make_shared(); _updatePeriodModel->addString(Wt::WString::tr("Lms.Admin.Database.never")); - _updatePeriodModel->setData(0, 0, Scanner::UpdatePeriod::Never, Wt::UserRole); + _updatePeriodModel->setData(0, 0, Scanner::UpdatePeriod::Never, Wt::ItemDataRole::User); _updatePeriodModel->addString(Wt::WString::tr("Lms.Admin.Database.daily")); - _updatePeriodModel->setData(1, 0, Scanner::UpdatePeriod::Daily, Wt::UserRole); + _updatePeriodModel->setData(1, 0, Scanner::UpdatePeriod::Daily, Wt::ItemDataRole::User); _updatePeriodModel->addString(Wt::WString::tr("Lms.Admin.Database.weekly")); - _updatePeriodModel->setData(2, 0, Scanner::UpdatePeriod::Weekly, Wt::UserRole); + _updatePeriodModel->setData(2, 0, Scanner::UpdatePeriod::Weekly, Wt::ItemDataRole::User); _updatePeriodModel->addString(Wt::WString::tr("Lms.Admin.Database.monthly")); - _updatePeriodModel->setData(3, 0, Scanner::UpdatePeriod::Monthly, Wt::UserRole); + _updatePeriodModel->setData(3, 0, Scanner::UpdatePeriod::Monthly, Wt::ItemDataRole::User); - _updateStartTimeModel = new Wt::WStringListModel(this); + _updateStartTimeModel = std::make_shared(); for (std::size_t i = 0; i < 24; ++i) { - boost::posix_time::time_duration dur = boost::posix_time::hours(i); + Wt::WTime time(i, 0); - boost::posix_time::time_facet* facet = new boost::posix_time::time_facet("%H:%M"); - facet->time_duration_format("%H:%M"); - - std::ostringstream oss; - oss.imbue(std::locale(oss.getloc(), facet)); - - oss << dur; - - _updateStartTimeModel->addString( oss.str() ); - _updateStartTimeModel->setData(i, 0, dur, Wt::UserRole); + _updateStartTimeModel->addString( time.toString() ); + _updateStartTimeModel->setData(i, 0, time, Wt::ItemDataRole::User); } } - Wt::WStringListModel* _updatePeriodModel; - Wt::WStringListModel* _updateStartTimeModel; + std::shared_ptr _updatePeriodModel; + std::shared_ptr _updateStartTimeModel; }; @@ -224,43 +216,33 @@ const Wt::WFormModel::Field DatabaseSettingsModel::UpdatePeriodField = "update- const Wt::WFormModel::Field DatabaseSettingsModel::UpdateStartTimeField = "update-start-time"; -DatabaseSettingsView::DatabaseSettingsView(Wt::WContainerWidget *parent) -: Wt::WTemplateFormView(parent) +DatabaseSettingsView::DatabaseSettingsView() +: Wt::WTemplateFormView(Wt::WString::tr("Lms.Admin.Database.template")) { - auto model = new DatabaseSettingsModel(this); - - setTemplateText(tr("Lms.Admin.Database.template")); - addFunction("tr", &WTemplate::Functions::tr); - addFunction("id", &WTemplate::Functions::id); + auto model = std::make_shared(); // Media Directory - Wt::WLineEdit *mediaDirectoryEdit = new Wt::WLineEdit(); - setFormWidget(DatabaseSettingsModel::MediaDirectoryField, mediaDirectoryEdit); + setFormWidget(DatabaseSettingsModel::MediaDirectoryField, std::make_unique()); // Update Period - Wt::WComboBox *updatePeriodCB = new Wt::WComboBox(); - setFormWidget(DatabaseSettingsModel::UpdatePeriodField, updatePeriodCB); - updatePeriodCB->setModel(model->updatePeriodModel()); + auto updatePeriod = std::make_unique(); + updatePeriod->setModel(model->updatePeriodModel()); + setFormWidget(DatabaseSettingsModel::UpdatePeriodField, std::move(updatePeriod)); // Update Start Time - Wt::WComboBox *updateStartTimeCB = new Wt::WComboBox(); - setFormWidget(DatabaseSettingsModel::UpdateStartTimeField, updateStartTimeCB); - updateStartTimeCB->setModel(model->updateStartTimeModel()); + auto updateStartTime = std::make_unique(); + updateStartTime->setModel(model->updateStartTimeModel()); + setFormWidget(DatabaseSettingsModel::UpdateStartTimeField, std::move(updateStartTime)); // Buttons - Wt::WPushButton *saveBtn = new Wt::WPushButton(Wt::WString::tr("Lms.apply")); - bindWidget("apply-btn", saveBtn); - - Wt::WPushButton *discardBtn = new Wt::WPushButton(Wt::WString::tr("Lms.discard")); - bindWidget("discard-btn", discardBtn); - - Wt::WPushButton *immScanBtn = new Wt::WPushButton(Wt::WString::tr("Lms.Admin.Database.immediate-scan")); - bindWidget("immediate-scan-btn", immScanBtn); + Wt::WPushButton *saveBtn = bindWidget("apply-btn", std::make_unique(Wt::WString::tr("Lms.apply"))); + Wt::WPushButton *discardBtn = bindWidget("discard-btn", std::make_unique(Wt::WString::tr("Lms.discard"))); + Wt::WPushButton *immScanBtn = bindWidget("immediate-scan-btn", std::make_unique(Wt::WString::tr("Lms.Admin.Database.immediate-scan"))); saveBtn->clicked().connect(std::bind([=] () { - updateModel(model); + updateModel(model.get()); if (model->validate()) { @@ -271,14 +253,14 @@ DatabaseSettingsView::DatabaseSettingsView(Wt::WContainerWidget *parent) } // Udate the view: Delete any validation message in the view, etc. - updateView(model); + updateView(model.get()); })); discardBtn->clicked().connect(std::bind([=] () { model->loadData(); model->validate(); - updateView(model); + updateView(model.get()); })); immScanBtn->clicked().connect(std::bind([=] () @@ -287,7 +269,7 @@ DatabaseSettingsView::DatabaseSettingsView(Wt::WContainerWidget *parent) LmsApp->notifyMsg(Wt::WString::tr("Lms.Admin.Database.scan-launched")); })); - updateView(model); + updateView(model.get()); } } // namespace UserInterface diff --git a/src/ui/admin/DatabaseSettingsView.hpp b/src/ui/admin/DatabaseSettingsView.hpp index 2ae471db..99653c9f 100644 --- a/src/ui/admin/DatabaseSettingsView.hpp +++ b/src/ui/admin/DatabaseSettingsView.hpp @@ -19,15 +19,14 @@ #pragma once -#include -#include +#include namespace UserInterface { class DatabaseSettingsView : public Wt::WTemplateFormView { public: - DatabaseSettingsView(Wt::WContainerWidget *parent = 0); + DatabaseSettingsView(); }; diff --git a/src/ui/admin/InitWizardView.cpp b/src/ui/admin/InitWizardView.cpp index 79608064..f1b2d6d9 100644 --- a/src/ui/admin/InitWizardView.cpp +++ b/src/ui/admin/InitWizardView.cpp @@ -17,10 +17,10 @@ * along with LMS. If not, see . */ -#include -#include -#include -#include +#include +#include +#include +#include #include "utils/Logger.hpp" @@ -40,8 +40,7 @@ class InitWizardModel : public Wt::WFormModel static const Field PasswordField; static const Field PasswordConfirmField; - InitWizardModel(Wt::WObject *parent = 0) - : Wt::WFormModel(parent) + InitWizardModel() : Wt::WFormModel() { addField(AdminLoginField); addField(PasswordField); @@ -54,16 +53,16 @@ class InitWizardModel : public Wt::WFormModel void saveData() { - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); // Check if a user already exist // If it's the case, just do nothing - if (!Database::User::getAll(DboSession()).empty()) + if (!Database::User::getAll(LmsApp->getDboSession()).empty()) throw std::runtime_error("Admin user already created"); // Create user - Wt::Auth::User authUser = DbHandler().getUserDatabase().registerNew(); - Database::User::pointer user = DbHandler().getUser(authUser); + Wt::Auth::User authUser = LmsApp->getDb().getUserDatabase().registerNew(); + Database::User::pointer user = LmsApp->getDb().createUser(authUser); // Account authUser.setIdentity(Wt::Auth::Identity::LoginName, valueText(AdminLoginField)); @@ -94,7 +93,7 @@ class InitWizardModel : public Wt::WFormModel } else if (field == PasswordConfirmField) { - if (validation(PasswordField).state() == Wt::WValidator::Valid) + if (validation(PasswordField).state() == Wt::ValidationState::Valid) { if (valueText(PasswordField) != valueText(PasswordConfirmField)) error = Wt::WString::tr("Lms.passwords-dont-match"); @@ -105,9 +104,9 @@ class InitWizardModel : public Wt::WFormModel return Wt::WFormModel::validateField(field); } - setValidation(field, Wt::WValidator::Result( error.empty() ? Wt::WValidator::Valid : Wt::WValidator::Invalid, error)); + setValidation(field, Wt::WValidator::Result( error.empty() ? Wt::ValidationState::Valid : Wt::ValidationState::Invalid, error)); - return (validation(field).state() == Wt::WValidator::Valid); + return (validation(field).state() == Wt::ValidationState::Valid); } }; @@ -116,34 +115,28 @@ const Wt::WFormModel::Field InitWizardModel::AdminLoginField = "admin-login"; const Wt::WFormModel::Field InitWizardModel::PasswordField = "password"; const Wt::WFormModel::Field InitWizardModel::PasswordConfirmField = "password-confirm"; -InitWizardView::InitWizardView(Wt::WContainerWidget *parent) -: Wt::WTemplateFormView(parent) +InitWizardView::InitWizardView() +: Wt::WTemplateFormView(Wt::WString::tr("Lms.Admin.InitWizard.template")) { - auto model = new InitWizardModel(this); - - setTemplateText(Wt::WString::tr("Lms.Admin.InitWizard.template")); - addFunction("tr", &WTemplate::Functions::tr); - addFunction("id", &WTemplate::Functions::id); + auto model = std::make_shared(); // AdminLogin - Wt::WLineEdit* accountEdit = new Wt::WLineEdit(); - setFormWidget(InitWizardModel::AdminLoginField, accountEdit); + setFormWidget(InitWizardModel::AdminLoginField, std::make_unique()); // Password - Wt::WLineEdit* passwordEdit = new Wt::WLineEdit(); - setFormWidget(InitWizardModel::PasswordField, passwordEdit ); - passwordEdit->setEchoMode(Wt::WLineEdit::Password); + auto passwordEdit = std::make_unique(); + passwordEdit->setEchoMode(Wt::EchoMode::Password); + setFormWidget(InitWizardModel::PasswordField, std::move(passwordEdit) ); // Password confirmation - Wt::WLineEdit* passwordConfirmEdit = new Wt::WLineEdit(); - setFormWidget(InitWizardModel::PasswordConfirmField, passwordConfirmEdit); - passwordConfirmEdit->setEchoMode(Wt::WLineEdit::Password); + auto passwordConfirmEdit = std::make_unique(); + passwordConfirmEdit->setEchoMode(Wt::EchoMode::Password); + setFormWidget(InitWizardModel::PasswordConfirmField, std::move(passwordConfirmEdit)); - auto saveButton = new Wt::WPushButton(Wt::WString::tr("Lms.create")); - bindWidget("create-btn", saveButton); + Wt::WPushButton* saveButton = bindNew("create-btn", Wt::WString::tr("Lms.create")); saveButton->clicked().connect(std::bind([=] { - updateModel(model); + updateModel(model.get()); if (model->validate()) { @@ -152,10 +145,10 @@ InitWizardView::InitWizardView(Wt::WContainerWidget *parent) saveButton->setEnabled(false); } - updateView(model); + updateView(model.get()); })); - updateView(model); + updateView(model.get()); } } // namespace UserInterface diff --git a/src/ui/admin/InitWizardView.hpp b/src/ui/admin/InitWizardView.hpp index d294fe58..260dd9bf 100644 --- a/src/ui/admin/InitWizardView.hpp +++ b/src/ui/admin/InitWizardView.hpp @@ -19,15 +19,14 @@ #pragma once -#include -#include +#include namespace UserInterface { class InitWizardView : public Wt::WTemplateFormView { public: - InitWizardView(Wt::WContainerWidget *parent = 0); + InitWizardView(); }; diff --git a/src/ui/admin/UserView.cpp b/src/ui/admin/UserView.cpp index e2d54c58..3975299d 100644 --- a/src/ui/admin/UserView.cpp +++ b/src/ui/admin/UserView.cpp @@ -17,15 +17,15 @@ * along with LMS. If not, see . */ -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include -#include -#include +#include +#include #include "common/Validators.hpp" #include "utils/Utils.hpp" @@ -44,8 +44,8 @@ class UserModel : public Wt::WFormModel static const Field PasswordField; static const Field BitrateLimitField; - UserModel(boost::optional userId, Wt::WObject *parent = 0) - : Wt::WFormModel(parent), + UserModel(boost::optional userId) + : Wt::WFormModel(), _userId(userId) { if (!_userId) @@ -72,12 +72,12 @@ class UserModel : public Wt::WFormModel if (!_userId) return; - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); - Wt::Auth::User authUser = DbHandler().getUserDatabase().findWithId( std::to_string(*_userId) ); - Database::User::pointer user = DbHandler().getUser(authUser); + Wt::Auth::User authUser = LmsApp->getDb().getUserDatabase().findWithId( std::to_string(*_userId) ); + Database::User::pointer user = LmsApp->getDb().getUser(authUser); - if (user == CurrentUser()) + if (user == LmsApp->getCurrentUser()) throw std::runtime_error("Cannot edit ourselves"); auto bitrate = getBitrateLimitRow(user->getMaxAudioBitrate()); @@ -87,13 +87,13 @@ class UserModel : public Wt::WFormModel void saveData() { - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); if (_userId) { // Update user - Wt::Auth::User authUser = DbHandler().getUserDatabase().findWithId( std::to_string(*_userId) ); - Database::User::pointer user = DbHandler().getUser( authUser ); + Wt::Auth::User authUser = LmsApp->getDb().getUserDatabase().findWithId( std::to_string(*_userId) ); + Database::User::pointer user = LmsApp->getDb().getUser( authUser ); // Account if (!valueText(PasswordField).empty()) @@ -106,8 +106,8 @@ class UserModel : public Wt::WFormModel else { // Create user - Wt::Auth::User authUser = DbHandler().getUserDatabase().registerNew(); - Database::User::pointer user = DbHandler().createUser(authUser); + Wt::Auth::User authUser = LmsApp->getDb().getUserDatabase().registerNew(); + Database::User::pointer user = LmsApp->getDb().createUser(authUser); // Account authUser.setIdentity(Wt::Auth::Identity::LoginName, valueText(LoginField)); @@ -142,35 +142,35 @@ class UserModel : public Wt::WFormModel std::size_t bitrateLimit(int row) { - return boost::any_cast - (_bitrateModel->data(_bitrateModel->index(row, 0), Wt::UserRole)); + return Wt::cpp17::any_cast + (_bitrateModel->data(_bitrateModel->index(row, 0), Wt::ItemDataRole::User)); } Wt::WString bitrateLimitString(int row) { - return boost::any_cast - (_bitrateModel->data(_bitrateModel->index(row, 0), Wt::DisplayRole)); + return Wt::cpp17::any_cast + (_bitrateModel->data(_bitrateModel->index(row, 0), Wt::ItemDataRole::Display)); } - Wt::WAbstractItemModel *bitrateModel() { return _bitrateModel; } + std::shared_ptr bitrateModel() { return _bitrateModel; } private: void initializeModels() { - _bitrateModel = new Wt::WStringListModel(this); + _bitrateModel = std::make_shared(); std::size_t id = 0; for (auto bitrate : Database::User::audioBitrates) { _bitrateModel->addString( Wt::WString::fromUTF8(std::to_string(bitrate / 1000)) ); - _bitrateModel->setData( id++, 0, bitrate, Wt::UserRole); + _bitrateModel->setData( id++, 0, bitrate, Wt::ItemDataRole::User); } } - Wt::WStringListModel* _bitrateModel; + std::shared_ptr _bitrateModel; boost::optional _userId; }; @@ -178,8 +178,7 @@ const Wt::WFormModel::Field UserModel::LoginField = "login"; const Wt::WFormModel::Field UserModel::PasswordField = "password"; const Wt::WFormModel::Field UserModel::BitrateLimitField = "audio-bitrate-limit"; -UserView::UserView(Wt::WContainerWidget* parent) -: Wt::WContainerWidget(parent) +UserView::UserView() { wApp->internalPathChanged().connect(std::bind([=] { @@ -195,47 +194,44 @@ UserView::refreshView() if (!wApp->internalPathMatches("/admin/user")) return; - auto userId = readLong(wApp->internalPathNextPart("/admin/user/")); + auto userId = readAs(wApp->internalPathNextPart("/admin/user/")); + + LMS_LOG(UI, DEBUG) << "userId = " << (userId ? std::to_string(*userId) : "none"); clear(); - auto t = new Wt::WTemplateFormView(Wt::WString::tr("Lms.Admin.User.template"), this); + Wt::WTemplateFormView* t = addNew(Wt::WString::tr("Lms.Admin.User.template")); - t->addFunction("tr", &Wt::WTemplate::Functions::tr); - t->addFunction("id", &Wt::WTemplate::Functions::id); - - auto model = new UserModel(userId ? boost::make_optional(*userId) : boost::none, this); + auto model = std::make_shared(userId); if (userId) { - auto authUser = DbHandler().getUserDatabase().findWithId( std::to_string(*userId) ); + auto authUser = LmsApp->getDb().getUserDatabase().findWithId( std::to_string(*userId) ); auto name = authUser.identity(Wt::Auth::Identity::LoginName); - t->bindString("title", Wt::WString::tr("Lms.Admin.User.user-edit").arg(name), Wt::PlainText); + t->bindString("title", Wt::WString::tr("Lms.Admin.User.user-edit").arg(name), Wt::TextFormat::Plain); } else { // Login t->setCondition("if-has-login", true); - t->setFormWidget(UserModel::LoginField, new Wt::WLineEdit()); + t->setFormWidget(UserModel::LoginField, std::make_unique()); t->bindString("title", Wt::WString::tr("Lms.Admin.User.user-create")); } - // Password - Wt::WLineEdit* passwordEdit = new Wt::WLineEdit(); - t->setFormWidget(UserModel::PasswordField, passwordEdit ); - passwordEdit->setEchoMode(Wt::WLineEdit::Password); + auto passwordEdit = std::make_unique(); + passwordEdit->setEchoMode(Wt::EchoMode::Password); + t->setFormWidget(UserModel::PasswordField, std::move(passwordEdit)); - // AudioBitrate - Wt::WComboBox *bitrateCB = new Wt::WComboBox(); - t->setFormWidget(UserModel::BitrateLimitField, bitrateCB); - bitrateCB->setModel(model->bitrateModel()); + // Bitrate + auto bitrate = std::make_unique(); + bitrate->setModel(model->bitrateModel()); + t->setFormWidget(UserModel::BitrateLimitField, std::move(bitrate)); - auto saveBtn = new Wt::WPushButton(Wt::WString::tr(userId ? "Lms.save" : "Lms.create")); - t->bindWidget("save-btn", saveBtn); + Wt::WPushButton* saveBtn = t->bindNew("save-btn", Wt::WString::tr(userId ? "Lms.save" : "Lms.create")); saveBtn->clicked().connect(std::bind([=] { - t->updateModel(model); + t->updateModel(model.get()); if (model->validate()) { @@ -245,12 +241,11 @@ UserView::refreshView() } else { - t->updateView(model); + t->updateView(model.get()); } })); - t->updateView(model); - + t->updateView(model.get()); } } // namespace UserInterface diff --git a/src/ui/admin/UserView.hpp b/src/ui/admin/UserView.hpp index b081d745..a4950f13 100644 --- a/src/ui/admin/UserView.hpp +++ b/src/ui/admin/UserView.hpp @@ -19,14 +19,14 @@ #pragma once -#include +#include namespace UserInterface { class UserView : public Wt::WContainerWidget { public: - UserView(Wt::WContainerWidget *parent = 0); + UserView(); private: void refreshView(); diff --git a/src/ui/admin/UsersView.cpp b/src/ui/admin/UsersView.cpp index bdba16b5..97709a1f 100644 --- a/src/ui/admin/UsersView.cpp +++ b/src/ui/admin/UsersView.cpp @@ -17,8 +17,8 @@ * along with LMS. If not, see . */ -#include -#include +#include +#include #include "database/Types.hpp" #include "utils/Logger.hpp" @@ -28,18 +28,14 @@ namespace UserInterface { -UsersView::UsersView(Wt::WContainerWidget *parent) - : Wt::WContainerWidget(parent) +UsersView::UsersView() + : Wt::WTemplate(Wt::WString::tr("Lms.Admin.Users.template")) { - auto t = new Wt::WTemplate(Wt::WString::tr("Lms.Admin.Users.template"), this); - t->addFunction("tr", &Wt::WTemplate::Functions::tr); + addFunction("tr", &Wt::WTemplate::Functions::tr); - _container = new Wt::WContainerWidget(); - t->bindWidget("users", _container); - - auto addBtn = new Wt::WPushButton(Wt::WString::tr("Lms.Admin.Users.add")); - t->bindWidget("add-btn", addBtn); + _container = bindNew("users"); + Wt::WPushButton* addBtn = bindNew("add-btn", Wt::WString::tr("Lms.Admin.Users.add")); addBtn->clicked().connect(std::bind([=] { LmsApp->setInternalPath("/admin/user", true); @@ -61,44 +57,41 @@ UsersView::refreshView() _container->clear(); - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); - auto users = Database::User::getAll(DboSession()); + auto users = Database::User::getAll(LmsApp->getDboSession()); for (auto user : users) { auto userId = std::to_string(user.id()); - auto entry = new Wt::WTemplate(Wt::WString::tr("Lms.Admin.Users.template.entry"), _container); - - Wt::Auth::User authUser = DbHandler().getUserDatabase().findWithId(userId); + Wt::WTemplate* entry = _container->addNew(Wt::WString::tr("Lms.Admin.Users.template.entry")); + Wt::Auth::User authUser = LmsApp->getDb().getUserDatabase().findWithId(userId); if (!authUser.isValid()) { LMS_LOG(UI, ERROR) << "Skipping invalid userId = " << user.id(); continue; } - entry->bindString("name", authUser.identity(Wt::Auth::Identity::LoginName), Wt::PlainText); + entry->bindString("name", authUser.identity(Wt::Auth::Identity::LoginName), Wt::TextFormat::Plain); // Don't edit ourself this way - if (CurrentUser() == user) + if (LmsApp->getCurrentUser() == user) continue; entry->setCondition("if-edit", true); - auto editBtn = new Wt::WPushButton(Wt::WString::tr("Lms.Admin.Users.edit")); - entry->bindWidget("edit-btn", editBtn); + Wt::WPushButton* editBtn = entry->bindNew("edit-btn", Wt::WString::tr("Lms.Admin.Users.edit")); editBtn->clicked().connect(std::bind([=] { LmsApp->setInternalPath("/admin/user/" + std::to_string(user.id()), true); })); - auto delBtn = new Wt::WPushButton(Wt::WString::tr("Lms.Admin.Users.del")); - entry->bindWidget("del-btn", delBtn); + Wt::WPushButton* delBtn = entry->bindNew("del-btn", Wt::WString::tr("Lms.Admin.Users.del")); delBtn->clicked().connect(std::bind([=] { - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); - auto authUser = DbHandler().getUserDatabase().findWithId(userId); - auto user = DbHandler().getUser(authUser); - DbHandler().getUserDatabase().deleteUser( authUser ); + auto authUser = LmsApp->getDb().getUserDatabase().findWithId(userId); + auto user = LmsApp->getDb().getUser(authUser); + LmsApp->getDb().getUserDatabase().deleteUser( authUser ); user.remove(); _container->removeWidget(entry); })); diff --git a/src/ui/admin/UsersView.hpp b/src/ui/admin/UsersView.hpp index 45717f34..aba8fbca 100644 --- a/src/ui/admin/UsersView.hpp +++ b/src/ui/admin/UsersView.hpp @@ -19,14 +19,14 @@ #pragma once -#include +#include namespace UserInterface { -class UsersView : public Wt::WContainerWidget +class UsersView : public Wt::WTemplate { public: - UsersView(Wt::WContainerWidget *parent = 0); + UsersView(); private: void refreshView(); diff --git a/src/ui/common/InputRange.cpp b/src/ui/common/InputRange.cpp deleted file mode 100644 index cb1ce054..00000000 --- a/src/ui/common/InputRange.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2015 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 . - */ - -#include - -#if WT_VERSION < 0X03030500 -#include -#include -#endif - -#include "InputRange.hpp" - -#if WT_VERSION >= 0X03030500 -InputRange::InputRange(Wt::WContainerWidget *parent) -: Wt::WWebWidget(parent) -{ - setHtmlTagName("input"); - setAttributeValue("type", "range"); -} - -std::string -InputRange::jsRef(void) const -{ - return Wt::WWebWidget::jsRef(); -} - -#else -InputRange::InputRange(Wt::WContainerWidget *parent) -: Wt::WContainerWidget(parent) -{ - addWidget(new Wt::WTemplate("")); -} - -std::string -InputRange::jsRef(void) const -{ - return Wt::WWebWidget::jsRef() + ".getElementsByTagName(\"input\")[0]"; -} -#endif - diff --git a/src/ui/common/InputRange.hpp b/src/ui/common/InputRange.hpp deleted file mode 100644 index 9ccb8fa8..00000000 --- a/src/ui/common/InputRange.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2015 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 . - */ - -#pragma once - -#include -#include - -#include -#if WT_VERSION >= 0X03030500 -class InputRange : public Wt::WWebWidget -{ - public: - InputRange(Wt::WContainerWidget *parent = 0); - Wt::DomElementType domElementType() const - { - return Wt::DomElement_INPUT; - } - - std::string jsRef() const; -}; - -#else - -class InputRange : public Wt::WContainerWidget -{ - public: - InputRange(Wt::WContainerWidget *parent = 0); - - std::string jsRef() const; -}; - -#endif - - diff --git a/src/ui/common/LineEdit.cpp b/src/ui/common/LineEdit.cpp deleted file mode 100644 index d5f21fda..00000000 --- a/src/ui/common/LineEdit.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2015 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 . - */ - -#include - -#include "LineEdit.hpp" - -namespace UserInterface { - - -LineEdit::LineEdit(std::size_t ms, Wt::WContainerWidget* parent) -: Wt::WLineEdit(parent) -{ - - Wt::WTimer *timer = new Wt::WTimer(this); - timer->setSingleShot(true); - timer->setInterval(ms); - - this->keyWentUp().connect(std::bind([=] (Wt::WKeyEvent keyEvent) - { - if (timer->isActive()) - timer->stop(); - - if (keyEvent.key() == Wt::Key_Enter) - _sigTimedChanged.emit(this->text()); - else - timer->start(); - }, std::placeholders::_1)); - - timer->timeout().connect(std::bind([=] () - { - _sigTimedChanged.emit(this->text()); - })); -} - - -} // namespace UserInterface - - diff --git a/src/ui/common/LineEdit.hpp b/src/ui/common/LineEdit.hpp deleted file mode 100644 index 9d27c43a..00000000 --- a/src/ui/common/LineEdit.hpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2015 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 . - */ - -#ifndef UI_LINE_EDIT_HPP -#define UI_LINE_EDIT_HPP - -#include -#include -#include - -namespace UserInterface { - -class LineEdit : public Wt::WLineEdit -{ - public: - LineEdit(std::size_t ms, Wt::WContainerWidget* parent = 0); - - Wt::Signal& timedChanged() { return _sigTimedChanged; } - - private: - - Wt::Signal _sigTimedChanged; -}; - -} // namespace UserInterface - -#endif - diff --git a/src/ui/common/Validators.cpp b/src/ui/common/Validators.cpp index 39308989..72b7258e 100644 --- a/src/ui/common/Validators.cpp +++ b/src/ui/common/Validators.cpp @@ -19,28 +19,31 @@ #include +#include + #include "Validators.hpp" namespace UserInterface { -Wt::WValidator* createNameValidator() +std::shared_ptr +createNameValidator() { - Wt::WLengthValidator *v = new Wt::WLengthValidator(); + auto v = std::make_shared(); v->setMandatory(true); v->setMinimumLength(::Database::User::MinNameLength); v->setMaximumLength(::Database::User::MaxNameLength); return v; } -Wt::WValidator* createMandatoryValidator() +std::shared_ptr +createMandatoryValidator() { - auto v = new Wt::WValidator(); + auto v = std::make_shared(); v->setMandatory(true); return v; } -DirectoryValidator::DirectoryValidator(Wt::WObject *parent) -: Wt::WValidator(parent) +DirectoryValidator::DirectoryValidator() : Wt::WValidator() { } @@ -56,11 +59,11 @@ DirectoryValidator::validate(const Wt::WString& input) const // TODO check rights bool res = boost::filesystem::is_directory(p, ec); if (ec) - return Wt::WValidator::Result(Wt::WValidator::Invalid, ec.message()); // TODO translate common errors + return Wt::WValidator::Result(Wt::ValidationState::Invalid, ec.message()); // TODO translate common errors else if (res) - return Wt::WValidator::Result(Wt::WValidator::Valid); + return Wt::WValidator::Result(Wt::ValidationState::Valid); else - return Wt::WValidator::Result(Wt::WValidator::Invalid, Wt::WString::tr("Lms.not-a-directory")); + return Wt::WValidator::Result(Wt::ValidationState::Invalid, Wt::WString::tr("Lms.not-a-directory")); } diff --git a/src/ui/common/Validators.hpp b/src/ui/common/Validators.hpp index 45f5fd99..11f9d502 100644 --- a/src/ui/common/Validators.hpp +++ b/src/ui/common/Validators.hpp @@ -19,19 +19,19 @@ #pragma once -#include +#include #include "database/User.hpp" namespace UserInterface { -Wt::WValidator* createNameValidator(); -Wt::WValidator* createMandatoryValidator(); +std::shared_ptr createNameValidator(); +std::shared_ptr createMandatoryValidator(); class DirectoryValidator : public Wt::WValidator { public: - DirectoryValidator(Wt::WObject *parent = 0); + DirectoryValidator(); Wt::WValidator::Result validate(const Wt::WString& input) const override; diff --git a/src/ui/explore/ArtistView.cpp b/src/ui/explore/ArtistView.cpp index 96caffca..c11a66d0 100644 --- a/src/ui/explore/ArtistView.cpp +++ b/src/ui/explore/ArtistView.cpp @@ -17,11 +17,10 @@ * along with LMS. If not, see . */ -#include -#include -#include -#include -#include +#include +#include +#include +#include #include "database/Types.hpp" @@ -36,9 +35,8 @@ namespace UserInterface { -Artist::Artist(Filters* filters, Wt::WContainerWidget* parent) -: Wt::WContainerWidget(parent), - _filters(filters) +Artist::Artist(Filters* filters) +: _filters(filters) { wApp->internalPathChanged().connect(std::bind([=] { @@ -60,81 +58,73 @@ Artist::refresh() clear(); - Database::Artist::id_type artistId; - if (!readAs(wApp->internalPathNextPart("/artist/"), artistId)) + auto artistId = readAs(wApp->internalPathNextPart("/artist/")); + if (!artistId) return; - Wt::Dbo::Transaction transaction(DboSession()); - auto artist = Database::Artist::getById(DboSession(), artistId); - + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); + auto artist = Database::Artist::getById(LmsApp->getDboSession(), *artistId); if (!artist) { LmsApp->goHome(); return; } - auto t = new Wt::WTemplate(Wt::WString::tr("Lms.Explore.Artist.template"), this); + Wt::WTemplate* t = addNew(Wt::WString::tr("Lms.Explore.Artist.template")); t->addFunction("tr", &Wt::WTemplate::Functions::tr); - auto clusterContainers = new Wt::WContainerWidget(); - t->bindWidget("clusters", clusterContainers); + Wt::WContainerWidget* clusterContainers = t->bindNew("clusters"); { auto clusters = artist->getClusters(3); for (auto cluster : clusters) { - auto entry = new Wt::WTemplate(Wt::WString::tr("Lms.Explore.Artist.template.cluster-entry"), clusterContainers); - - entry->bindString("name", Wt::WString::fromUTF8(cluster->getName()), Wt::PlainText); + Wt::WTemplate* entry = clusterContainers->addNew(Wt::WString::tr("Lms.Explore.Artist.template.cluster-entry")); + entry->bindString("name", Wt::WString::fromUTF8(cluster->getName()), Wt::TextFormat::Plain); } } - t->bindString("name", Wt::WString::fromUTF8(artist->getName()), Wt::PlainText); + t->bindString("name", Wt::WString::fromUTF8(artist->getName()), Wt::TextFormat::Plain); { - auto playBtn = new Wt::WText(Wt::WString::tr("Lms.Explore.Artist.play"), Wt::XHTMLText); - t->bindWidget("play-btn", playBtn); + Wt::WText* playBtn = t->bindNew("play-btn", Wt::WString::tr("Lms.Explore.Artist.play"), Wt::TextFormat::XHTML); playBtn->clicked().connect(std::bind([=] { - artistPlay.emit(artistId); + artistPlay.emit(*artistId); })); } { - auto addBtn = new Wt::WText(Wt::WString::tr("Lms.Explore.Artist.add"), Wt::XHTMLText); - t->bindWidget("add-btn", addBtn); + Wt::WText* addBtn = t->bindNew("add-btn", Wt::WString::tr("Lms.Explore.Artist.add"), Wt::TextFormat::XHTML); addBtn->clicked().connect(std::bind([=] { - artistAdd.emit(artistId); + artistAdd.emit(*artistId); })); } - auto releasesContainer = new Wt::WContainerWidget(); - t->bindWidget("releases", releasesContainer); + Wt::WContainerWidget* releasesContainer = t->bindNew("releases"); auto releases = artist->getReleases(_filters->getClusterIds()); for (auto release : releases) { auto releaseId = release.id(); - Wt::WTemplate* entry = new Wt::WTemplate(Wt::WString::tr("Lms.Explore.Artist.template.entry"), releasesContainer); + Wt::WTemplate* entry = releasesContainer->addNew(Wt::WString::tr("Lms.Explore.Artist.template.entry")); entry->addFunction("tr", Wt::WTemplate::Functions::tr); { - Wt::WAnchor* coverAnchor = LmsApplication::createReleaseAnchor(release, false); - Wt::WImage* cover = new Wt::WImage(coverAnchor); + Wt::WAnchor* anchor = entry->bindWidget("cover", LmsApplication::createReleaseAnchor(release, false)); + + auto cover = std::make_unique(); cover->setImageLink(LmsApp->getImageResource()->getReleaseUrl(release.id(), 128)); // Some images may not be square cover->setWidth(128); - entry->bindWidget("cover", coverAnchor); + anchor->setImage(std::move(cover)); } - { - Wt::WAnchor* releaseAnchor = LmsApplication::createReleaseAnchor(release); - entry->bindWidget("name", releaseAnchor); - } + entry->bindWidget("name", LmsApplication::createReleaseAnchor(release)); if (release->hasVariousArtists()) entry->setCondition("if-has-various-artists", true); @@ -153,15 +143,13 @@ Artist::refresh() } } - auto playBtn = new Wt::WText(Wt::WString::tr("Lms.Explore.Artist.play"), Wt::XHTMLText); - entry->bindWidget("play-btn", playBtn); + Wt::WText* playBtn = entry->bindNew("play-btn", Wt::WString::tr("Lms.Explore.Artist.play"), Wt::TextFormat::XHTML); playBtn->clicked().connect(std::bind([=] { releasePlay.emit(releaseId); })); - auto addBtn = new Wt::WText(Wt::WString::tr("Lms.Explore.Artist.add"), Wt::XHTMLText); - entry->bindWidget("add-btn", addBtn); + Wt::WText* addBtn = entry->bindNew("add-btn", Wt::WString::tr("Lms.Explore.Artist.add"), Wt::TextFormat::XHTML); addBtn->clicked().connect(std::bind([=] { releaseAdd.emit(releaseId); diff --git a/src/ui/explore/ArtistView.hpp b/src/ui/explore/ArtistView.hpp index b6f7d78e..b4bb329f 100644 --- a/src/ui/explore/ArtistView.hpp +++ b/src/ui/explore/ArtistView.hpp @@ -19,8 +19,8 @@ #pragma once -#include -#include +#include +#include namespace UserInterface { @@ -29,7 +29,7 @@ class Filters; class Artist : public Wt::WContainerWidget { public: - Artist(Filters* filters, Wt::WContainerWidget* parent = 0); + Artist(Filters* filters); Wt::Signal artistAdd; Wt::Signal artistPlay; diff --git a/src/ui/explore/ArtistsView.cpp b/src/ui/explore/ArtistsView.cpp index c6044b3d..45ccfce1 100644 --- a/src/ui/explore/ArtistsView.cpp +++ b/src/ui/explore/ArtistsView.cpp @@ -17,9 +17,9 @@ * along with LMS. If not, see . */ -#include -#include -#include +#include +#include +#include #include "database/Types.hpp" @@ -34,24 +34,20 @@ namespace UserInterface { using namespace Database; -Artists::Artists(Filters* filters, Wt::WContainerWidget* parent) -: Wt::WContainerWidget(parent), +Artists::Artists(Filters* filters) +: Wt::WTemplate(Wt::WString::tr("Lms.Explore.Artists.template")), _filters(filters) { - auto container = new Wt::WTemplate(Wt::WString::tr("Lms.Explore.Artists.template"), this); - container->addFunction("tr", &Wt::WTemplate::Functions::tr); + addFunction("tr", &Wt::WTemplate::Functions::tr); - _search = new Wt::WLineEdit(); - container->bindWidget("search", _search); + _search = bindNew("search"); _search->setPlaceholderText(Wt::WString::tr("Lms.Explore.search-placeholder")); _search->textInput().connect(this, &Artists::refresh); - _artistsContainer = new Wt::WContainerWidget(); - container->bindWidget("artists", _artistsContainer); + _artistsContainer = bindNew("artists"); - _showMore = new Wt::WTemplate(Wt::WString::tr("Lms.Explore.template.show-more")); + _showMore = bindNew("show-more", Wt::WString::tr("Lms.Explore.template.show-more")); _showMore->addFunction("tr", &Wt::WTemplate::Functions::tr); - container->bindWidget("show-more", _showMore); _showMore->clicked().connect(std::bind([=] { @@ -77,24 +73,20 @@ Artists::addSome() auto clusterIds = _filters->getClusterIds(); - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); bool moreResults; - auto artists = Artist::getByFilter(DboSession(), + auto artists = Artist::getByFilter(LmsApp->getDboSession(), clusterIds, searchKeywords, _artistsContainer->count(), 20, moreResults); for (auto artist : artists) { - auto entry = new Wt::WTemplate(Wt::WString::tr("Lms.Explore.Artists.template.entry"), _artistsContainer); + Wt::WTemplate* entry = _artistsContainer->addNew(Wt::WString::tr("Lms.Explore.Artists.template.entry")); entry->bindInt("nb-release", artist->getReleases(clusterIds).size()); - - { - Wt::WAnchor *artistAnchor = LmsApplication::createArtistAnchor(artist); - entry->bindWidget("name", artistAnchor); - } + entry->bindWidget("name", LmsApplication::createArtistAnchor(artist)); } _showMore->setHidden(!moreResults); diff --git a/src/ui/explore/ArtistsView.hpp b/src/ui/explore/ArtistsView.hpp index f51c8706..bfb643f6 100644 --- a/src/ui/explore/ArtistsView.hpp +++ b/src/ui/explore/ArtistsView.hpp @@ -19,18 +19,19 @@ #pragma once -#include -#include -#include +#include +#include +#include +#include namespace UserInterface { class Filters; -class Artists : public Wt::WContainerWidget +class Artists : public Wt::WTemplate { public: - Artists(Filters* filters, Wt::WContainerWidget* parent = 0); + Artists(Filters* filters); Wt::Signal artistAdd; Wt::Signal artistPlay; diff --git a/src/ui/explore/Explore.cpp b/src/ui/explore/Explore.cpp index 42be7b49..99da8f63 100644 --- a/src/ui/explore/Explore.cpp +++ b/src/ui/explore/Explore.cpp @@ -17,9 +17,9 @@ * along with LMS. If not, see . */ -#include -#include -#include +#include +#include +#include #include "utils/Logger.hpp" @@ -70,54 +70,44 @@ handlePathChange(Wt::WStackedWidget* stack) } } -Explore::Explore(Wt::WContainerWidget* parent) -: Wt::WContainerWidget(parent) +Explore::Explore() +: Wt::WTemplate(Wt::WString::tr("Lms.Explore.template")) { - auto container = new Wt::WTemplate(Wt::WString::tr("Lms.Explore.template"), this); - - _filters = new Filters(); - container->bindWidget("filters", _filters); + _filters = bindNew("filters"); // Contents - Wt::WStackedWidget* stack = new Wt::WStackedWidget(); - container->bindWidget("contents", stack); - - auto artists = new Artists(_filters); - stack->addWidget(artists); + Wt::WStackedWidget* stack = bindNew("contents"); + auto artists = std::make_unique(_filters); artists->artistAdd.connect(this, &Explore::handleArtistAdd); artists->artistPlay.connect(this, &Explore::handleArtistPlay); + stack->addWidget(std::move(artists)); - auto artist = new Artist(_filters); - stack->addWidget(artist); - + auto artist = std::make_unique(_filters); artist->artistAdd.connect(this, &Explore::handleArtistAdd); artist->artistPlay.connect(this, &Explore::handleArtistPlay); artist->releaseAdd.connect(this, &Explore::handleReleaseAdd); artist->releasePlay.connect(this, &Explore::handleReleasePlay); + stack->addWidget(std::move(artist)); - auto releases = new Releases(_filters); - stack->addWidget(releases); - + auto releases = std::make_unique(_filters); releases->releaseAdd.connect(this, &Explore::handleReleaseAdd); releases->releasePlay.connect(this, &Explore::handleReleasePlay); + stack->addWidget(std::move(releases)); - auto release = new Release(_filters); - stack->addWidget(release); - + auto release = std::make_unique(_filters); release->releaseAdd.connect(this, &Explore::handleReleaseAdd); release->releasePlay.connect(this, &Explore::handleReleasePlay); release->trackAdd.connect(this, &Explore::handleTrackAdd); release->trackPlay.connect(this, &Explore::handleTrackPlay); + stack->addWidget(std::move(release)); - auto tracks = new Tracks(_filters); - stack->addWidget(tracks); - + auto tracks = std::make_unique(_filters); tracks->trackAdd.connect(this, &Explore::handleTrackAdd); tracks->trackPlay.connect(this, &Explore::handleTrackPlay); tracks->tracksAdd.connect(this, &Explore::handleTracksAdd); tracks->tracksPlay.connect(this, &Explore::handleTracksPlay); - + stack->addWidget(std::move(tracks)); wApp->internalPathChanged().connect(std::bind([=] { @@ -175,49 +165,49 @@ static std::vector getTrack(Wt::Dbo::Session& session, void Explore::handleArtistAdd(Database::id_type id) { - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); - tracksAdd.emit(getArtistTracks(DboSession(), id, _filters->getClusterIds())); + tracksAdd.emit(getArtistTracks(LmsApp->getDboSession(), id, _filters->getClusterIds())); } void Explore::handleArtistPlay(Database::id_type id) { - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); - tracksPlay.emit(getArtistTracks(DboSession(), id, _filters->getClusterIds())); + tracksPlay.emit(getArtistTracks(LmsApp->getDboSession(), id, _filters->getClusterIds())); } void Explore::handleReleaseAdd(Database::id_type id) { - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); - tracksAdd.emit(getReleaseTracks(DboSession(), id, _filters->getClusterIds())); + tracksAdd.emit(getReleaseTracks(LmsApp->getDboSession(), id, _filters->getClusterIds())); } void Explore::handleReleasePlay(Database::id_type id) { - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); - tracksPlay.emit(getReleaseTracks(DboSession(), id, _filters->getClusterIds())); + tracksPlay.emit(getReleaseTracks(LmsApp->getDboSession(), id, _filters->getClusterIds())); } void Explore::handleTrackAdd(Database::id_type id) { - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); - tracksAdd.emit(getTrack(DboSession(), id)); + tracksAdd.emit(getTrack(LmsApp->getDboSession(), id)); } void Explore::handleTrackPlay(Database::id_type id) { - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); - tracksPlay.emit(getTrack(DboSession(), id)); + tracksPlay.emit(getTrack(LmsApp->getDboSession(), id)); } void diff --git a/src/ui/explore/Explore.hpp b/src/ui/explore/Explore.hpp index 3c0dd136..75302f6e 100644 --- a/src/ui/explore/Explore.hpp +++ b/src/ui/explore/Explore.hpp @@ -19,7 +19,7 @@ #pragma once -#include +#include #include "database/Types.hpp" @@ -27,22 +27,22 @@ namespace UserInterface { class Filters; -class Explore : public Wt::WContainerWidget +class Explore : public Wt::WTemplate { public: - Explore(Wt::WContainerWidget *parent = 0); + Explore(); Wt::Signal> tracksAdd; Wt::Signal> tracksPlay; private: - void handleArtistAdd(Database::id_type id); - void handleArtistPlay(Database::id_type id); - void handleReleaseAdd(Database::id_type id); - void handleReleasePlay(Database::id_type id); - void handleTrackAdd(Database::id_type id); - void handleTrackPlay(Database::id_type id); + void handleArtistAdd(Database::Artist::id_type id); + void handleArtistPlay(Database::Artist::id_type id); + void handleReleaseAdd(Database::Release::id_type id); + void handleReleasePlay(Database::Release::id_type id); + void handleTrackAdd(Database::Track::id_type id); + void handleTrackPlay(Database::Track::id_type id); void handleTracksAdd(std::vector tracks); void handleTracksPlay(std::vector tracks); diff --git a/src/ui/explore/Filters.cpp b/src/ui/explore/Filters.cpp index 719e5444..59619d08 100644 --- a/src/ui/explore/Filters.cpp +++ b/src/ui/explore/Filters.cpp @@ -17,10 +17,10 @@ * along with LMS. If not, see . */ -#include -#include -#include -#include +#include +#include +#include +#include #include "Filters.hpp" @@ -31,32 +31,25 @@ namespace UserInterface { void Filters::showDialog() { - auto dialog = new Wt::WDialog(Wt::WString::tr("Lms.Explore.add-filter")); + auto dialog = std::make_shared(Wt::WString::tr("Lms.Explore.add-filter")); - auto container = new Wt::WTemplate(Wt::WString::tr("Lms.Explore.template.add-filter")); + Wt::WTemplate* container = dialog->contents()->addNew(Wt::WString::tr("Lms.Explore.template.add-filter")); container->addFunction("tr", &Wt::WTemplate::Functions::tr); - dialog->contents()->addWidget(container); + Wt::WComboBox* typeCombo = container->bindNew("type"); + Wt::WComboBox* valueCombo = container->bindNew("value"); - auto typeCombo = new Wt::WComboBox(); - container->bindWidget("type", typeCombo); + Wt::WPushButton* addBtn = container->bindNew("add-btn", Wt::WString::tr("Lms.add")); + addBtn->clicked().connect(dialog.get(), &Wt::WDialog::accept); - auto valueCombo = new Wt::WComboBox(); - container->bindWidget("value", valueCombo); - - auto addBtn = new Wt::WPushButton(Wt::WString::tr("Lms.add")); - container->bindWidget("add-btn", addBtn); - addBtn->clicked().connect(dialog, &Wt::WDialog::accept); - - auto cancelBtn = new Wt::WPushButton(Wt::WString::tr("Lms.cancel")); - container->bindWidget("cancel-btn", cancelBtn); - cancelBtn->clicked().connect(dialog, &Wt::WDialog::reject); + Wt::WPushButton* cancelBtn = container->bindNew("cancel-btn", Wt::WString::tr("Lms.cancel")); + cancelBtn->clicked().connect(dialog.get(), &Wt::WDialog::reject); // Populate data { - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); - auto types = Database::ClusterType::getAll(DboSession()); + auto types = Database::ClusterType::getAll(LmsApp->getDboSession()); for (auto type : types) typeCombo->addItem(Wt::WString::fromUTF8(type->getName())); @@ -81,9 +74,9 @@ Filters::showDialog() valueCombo->clear(); - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); - auto clusterType = Database::ClusterType::getByName(DboSession(), name); + auto clusterType = Database::ClusterType::getByName(LmsApp->getDboSession(), name); auto values = clusterType->getClusters(); for (auto value : values) @@ -94,24 +87,22 @@ Filters::showDialog() })); dialog->setModal(true); -#if WT_VERSION >= 0x03030700 dialog->setMovable(false); -#endif dialog->setResizable(false); dialog->setClosable(false); dialog->finished().connect(std::bind([=] { - if (dialog->result() != Wt::WDialog::Accepted) + if (dialog->result() != Wt::DialogCode::Accepted) return; auto type = typeCombo->valueText().toUTF8(); auto value = valueCombo->valueText().toUTF8(); - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); - auto clusterType = Database::ClusterType::getByName(DboSession(), type); + auto clusterType = Database::ClusterType::getByName(LmsApp->getDboSession(), type); if (!clusterType) return; @@ -123,8 +114,7 @@ Filters::showDialog() _filterIds.insert(clusterId); _sigUpdated.emit(); - auto filterBtn = new Wt::WPushButton(Wt::WString::fromUTF8(value)); - _filters->addWidget(filterBtn); + Wt::WPushButton* filterBtn = _filters->addNew(Wt::WString::fromUTF8(value), Wt::TextFormat::Plain); filterBtn->clicked().connect(std::bind([=] { @@ -137,23 +127,14 @@ Filters::showDialog() dialog->show(); } -Filters::Filters(Wt::WContainerWidget *parent) -: Wt::WContainerWidget(parent) +Filters::Filters() +: Wt::WTemplate(Wt::WString::tr("Lms.Explore.template.filters")) { - auto container = new Wt::WTemplate(Wt::WString::tr("Lms.Explore.template.filters"), this); - // Filters - Wt::WPushButton *addFilterBtn = new Wt::WPushButton(Wt::WText::tr("Lms.Explore.add-filter")); - container->bindWidget("add-filter", addFilterBtn); - - _filters = new Wt::WContainerWidget(); - container->bindWidget("filters", _filters); - - addFilterBtn->clicked().connect(std::bind([this] - { - showDialog(); - })); + Wt::WPushButton *addFilterBtn = bindNew("add-filter", Wt::WText::tr("Lms.Explore.add-filter")); + addFilterBtn->clicked().connect(this, &Filters::showDialog); + _filters = bindNew("filters"); } diff --git a/src/ui/explore/Filters.hpp b/src/ui/explore/Filters.hpp index d0753915..aa3d30ce 100644 --- a/src/ui/explore/Filters.hpp +++ b/src/ui/explore/Filters.hpp @@ -19,8 +19,9 @@ #pragma once -#include -#include +#include +#include +#include #include "database/Types.hpp" @@ -28,21 +29,21 @@ namespace UserInterface { -class Filters : public Wt::WContainerWidget +class Filters : public Wt::WTemplate { public: - Filters(Wt::WContainerWidget *parent = 0); + Filters(); std::set getClusterIds() const { return _filterIds; } - Wt::Signal& updated() { return _sigUpdated; } + Wt::Signal<>& updated() { return _sigUpdated; } private: void showDialog(); Wt::WContainerWidget *_filters; - Wt::Signal _sigUpdated; + Wt::Signal<> _sigUpdated; std::set _filterIds; }; diff --git a/src/ui/explore/ReleaseView.cpp b/src/ui/explore/ReleaseView.cpp index 602f1d6f..809e8998 100644 --- a/src/ui/explore/ReleaseView.cpp +++ b/src/ui/explore/ReleaseView.cpp @@ -17,11 +17,11 @@ * along with LMS. If not, see . */ -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include "database/Types.hpp" @@ -36,9 +36,8 @@ namespace UserInterface { -Release::Release(Filters* filters, Wt::WContainerWidget* parent) -: Wt::WContainerWidget(parent), - _filters(filters) +Release::Release(Filters* filters) +: _filters(filters) { wApp->internalPathChanged().connect(std::bind([=] { @@ -60,24 +59,23 @@ Release::refresh() clear(); - Database::Release::id_type releaseId; - - if (!readAs(wApp->internalPathNextPart("/release/"), releaseId)) + auto releaseId = readAs(wApp->internalPathNextPart("/release/")); + if (!releaseId) return; - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); - auto release = Database::Release::getById(DboSession(), releaseId); + auto release = Database::Release::getById(LmsApp->getDboSession(), *releaseId); if (!release) { LmsApp->goHome(); return; } - auto t = new Wt::WTemplate(Wt::WString::tr("Lms.Explore.Release.template"), this); + Wt::WTemplate* t = addNew(Wt::WString::tr("Lms.Explore.Release.template")); t->addFunction("tr", &Wt::WTemplate::Functions::tr); - t->bindString("name", Wt::WString::fromUTF8(release->getName()), Wt::PlainText); + t->bindString("name", Wt::WString::fromUTF8(release->getName()), Wt::TextFormat::Plain); boost::optional year = release->getReleaseYear(); if (year) @@ -103,49 +101,40 @@ Release::refresh() else if (artists.size() == 1) { t->setCondition("if-has-artist", true); - Wt::WAnchor *artistAnchor = LmsApplication::createArtistAnchor(artists.front()); - t->bindWidget("artist-name", artistAnchor); + t->bindWidget("artist-name", LmsApplication::createArtistAnchor(artists.front())); } } - Wt::WImage *cover = new Wt::WImage(); - cover->setImageLink(Wt::WLink(LmsApp->getImageResource()->getReleaseUrl(release.id(), 512))); - t->bindWidget("cover", cover); - - auto clusterContainers = new Wt::WContainerWidget(); - t->bindWidget("clusters", clusterContainers); + t->bindNew("cover", Wt::WLink(LmsApp->getImageResource()->getReleaseUrl(release.id(), 512))); + Wt::WContainerWidget* clusterContainers = t->bindNew("clusters"); { auto clusters = release->getClusters(3); for (auto cluster : clusters) { - auto entry = new Wt::WTemplate(Wt::WString::tr("Lms.Explore.Release.template.cluster-entry"), clusterContainers); - - entry->bindString("name", Wt::WString::fromUTF8(cluster->getName()), Wt::PlainText); + Wt::WTemplate* entry = clusterContainers->addNew(Wt::WString::tr("Lms.Explore.Release.template.cluster-entry")); + entry->bindString("name", Wt::WString::fromUTF8(cluster->getName()), Wt::TextFormat::Plain); } } { - auto playBtn = new Wt::WText(Wt::WString::tr("Lms.Explore.Release.play"), Wt::XHTMLText); - t->bindWidget("play-btn", playBtn); + Wt::WText* playBtn = t->bindNew("play-btn", Wt::WString::tr("Lms.Explore.Release.play"), Wt::TextFormat::XHTML); playBtn->clicked().connect(std::bind([=] { - releasePlay.emit(releaseId); + releasePlay.emit(*releaseId); })); } { - auto addBtn = new Wt::WText(Wt::WString::tr("Lms.Explore.Release.add"), Wt::XHTMLText); - t->bindWidget("add-btn", addBtn); + Wt::WText* addBtn = t->bindNew("add-btn", Wt::WString::tr("Lms.Explore.Release.add"), Wt::TextFormat::XHTML); addBtn->clicked().connect(std::bind([=] { - releaseAdd.emit(releaseId); + releaseAdd.emit(*releaseId); })); } - auto tracksContainer = new Wt::WContainerWidget(); - t->bindWidget("tracks", tracksContainer); + Wt::WContainerWidget* tracksContainer = t->bindNew("tracks"); auto clusterIds = _filters->getClusterIds(); auto tracks = release->getTracks(clusterIds); @@ -156,15 +145,13 @@ Release::refresh() { auto trackId = track.id(); - Wt::WTemplate* entry = new Wt::WTemplate(Wt::WString::tr("Lms.Explore.Release.template.entry"), tracksContainer); - - entry->bindString("name", Wt::WString::fromUTF8(track->getName()), Wt::PlainText); + Wt::WTemplate* entry = tracksContainer->addNew(Wt::WString::tr("Lms.Explore.Release.template.entry")); + entry->bindString("name", Wt::WString::fromUTF8(track->getName()), Wt::TextFormat::Plain); if (variousArtists && track->getArtist()) { entry->setCondition("if-has-artist", true); - Wt::WAnchor *artistAnchor = LmsApplication::createArtistAnchor(track->getArtist()); - entry->bindWidget("artist-name", artistAnchor); + entry->bindWidget("artist-name", LmsApplication::createArtistAnchor(track->getArtist())); } auto trackNumber = track->getTrackNumber(); @@ -182,15 +169,13 @@ Release::refresh() entry->bindInt("disc-number", *discNumber); } - auto playBtn = new Wt::WText(Wt::WString::tr("Lms.Explore.Release.play"), Wt::XHTMLText); - entry->bindWidget("play-btn", playBtn); + Wt::WText* playBtn = entry->bindNew("play-btn", Wt::WString::tr("Lms.Explore.Release.play"), Wt::TextFormat::XHTML); playBtn->clicked().connect(std::bind([=] { trackPlay.emit(trackId); })); - auto addBtn = new Wt::WText(Wt::WString::tr("Lms.Explore.Release.add"), Wt::XHTMLText); - entry->bindWidget("add-btn", addBtn); + Wt::WText* addBtn = entry->bindNew("add-btn", Wt::WString::tr("Lms.Explore.Release.add"), Wt::TextFormat::XHTML); addBtn->clicked().connect(std::bind([=] { trackAdd.emit(trackId); diff --git a/src/ui/explore/ReleaseView.hpp b/src/ui/explore/ReleaseView.hpp index a11be0c2..12bde073 100644 --- a/src/ui/explore/ReleaseView.hpp +++ b/src/ui/explore/ReleaseView.hpp @@ -19,7 +19,7 @@ #pragma once -#include +#include namespace UserInterface { @@ -27,7 +27,7 @@ class Filters; class Release : public Wt::WContainerWidget { public: - Release(Filters* filters, Wt::WContainerWidget* parent = 0); + Release(Filters* filters); Wt::Signal releaseAdd; Wt::Signal releasePlay; diff --git a/src/ui/explore/ReleasesView.cpp b/src/ui/explore/ReleasesView.cpp index 5fcf654f..7151f6d3 100644 --- a/src/ui/explore/ReleasesView.cpp +++ b/src/ui/explore/ReleasesView.cpp @@ -17,11 +17,11 @@ * along with LMS. If not, see . */ -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include "database/Types.hpp" @@ -38,25 +38,20 @@ namespace UserInterface { using namespace Database; -Releases::Releases(Filters* filters, Wt::WContainerWidget* parent) -: Wt::WContainerWidget(parent), - _filters(filters) +Releases::Releases(Filters* filters) +: Wt::WTemplate(Wt::WString::tr("Lms.Explore.Releases.template")), +_filters(filters) { - auto container = new Wt::WTemplate(Wt::WString::tr("Lms.Explore.Releases.template"), this); - container->addFunction("tr", &Wt::WTemplate::Functions::tr); + addFunction("tr", &Wt::WTemplate::Functions::tr); - _search = new Wt::WLineEdit(); - container->bindWidget("search", _search); + _search = bindNew("search"); _search->setPlaceholderText(Wt::WString::tr("Lms.Explore.search-placeholder")); _search->textInput().connect(this, &Releases::refresh); - _releasesContainer = new Wt::WContainerWidget(); - container->bindWidget("releases", _releasesContainer); + _releasesContainer = bindNew("releases"); - _showMore = new Wt::WTemplate(Wt::WString::tr("Lms.Explore.show-more")); + _showMore = bindNew("show-more", Wt::WString::tr("Lms.Explore.show-more")); _showMore->addFunction("tr", &Wt::WTemplate::Functions::tr); - container->bindWidget("show-more", _showMore); - _showMore->clicked().connect(std::bind([=] { addSome(); @@ -81,29 +76,24 @@ Releases::addSome() auto clusterIds = _filters->getClusterIds(); - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); bool moreResults; - auto releases = Release::getByFilter(DboSession(), clusterIds, searchKeywords, _releasesContainer->count(), 20, moreResults); + auto releases = Release::getByFilter(LmsApp->getDboSession(), clusterIds, searchKeywords, _releasesContainer->count(), 20, moreResults); for (auto release : releases) { auto releaseId = release.id(); - Wt::WTemplate* entry = new Wt::WTemplate(Wt::WString::tr("Lms.Explore.Releases.template.entry"), _releasesContainer); + Wt::WTemplate* entry = _releasesContainer->addNew(Wt::WString::tr("Lms.Explore.Releases.template.entry")); entry->addFunction("tr", Wt::WTemplate::Functions::tr); - Wt::WAnchor* coverAnchor = LmsApplication::createReleaseAnchor(release, false); - Wt::WImage* cover = new Wt::WImage(coverAnchor); - cover->setImageLink(LmsApp->getImageResource()->getReleaseUrl(releaseId, 128)); - // Some images may not be square - cover->setWidth(128); - entry->bindWidget("cover", coverAnchor); + Wt::WAnchor* anchor = entry->bindWidget("cover", LmsApplication::createReleaseAnchor(release, false)); + auto cover = std::make_unique(); + cover->setImageLink(LmsApp->getImageResource()->getReleaseUrl(release.id(), 128)); + anchor->setImage(std::move(cover)); - { - Wt::WAnchor* releaseAnchor = LmsApplication::createReleaseAnchor(release); - entry->bindWidget("release-name", releaseAnchor); - } + entry->bindWidget("release-name", LmsApplication::createReleaseAnchor(release)); auto artists = release->getArtists(); if (artists.size() > 1) @@ -114,19 +104,16 @@ Releases::addSome() else if (artists.size() == 1) { entry->setCondition("if-has-artist", true); - Wt::WAnchor* artistAnchor = LmsApplication::createArtistAnchor(artists.front()); - entry->bindWidget("artist-name", artistAnchor); + entry->bindWidget("artist-name", LmsApplication::createArtistAnchor(artists.front())); } - auto playBtn = new Wt::WText(Wt::WString::tr("Lms.Explore.Releases.play"), Wt::XHTMLText); - entry->bindWidget("play-btn", playBtn); + Wt::WText* playBtn = entry->bindNew("play-btn", Wt::WString::tr("Lms.Explore.Releases.play"), Wt::TextFormat::XHTML); playBtn->clicked().connect(std::bind([=] { releasePlay.emit(releaseId); })); - auto addBtn = new Wt::WText(Wt::WString::tr("Lms.Explore.Releases.add"), Wt::XHTMLText); - entry->bindWidget("add-btn", addBtn); + Wt::WText* addBtn = entry->bindNew("add-btn", Wt::WString::tr("Lms.Explore.Releases.add"), Wt::TextFormat::XHTML); addBtn->clicked().connect(std::bind([=] { releaseAdd.emit(releaseId); diff --git a/src/ui/explore/ReleasesView.hpp b/src/ui/explore/ReleasesView.hpp index 6626656b..9797da51 100644 --- a/src/ui/explore/ReleasesView.hpp +++ b/src/ui/explore/ReleasesView.hpp @@ -19,18 +19,19 @@ #pragma once -#include -#include -#include +#include +#include +#include +#include namespace UserInterface { class Filters; -class Releases : public Wt::WContainerWidget +class Releases : public Wt::WTemplate { public: - Releases(Filters* filters, Wt::WContainerWidget* parent = 0); + Releases(Filters* filters); Wt::Signal releaseAdd; Wt::Signal releasePlay; diff --git a/src/ui/explore/TracksView.cpp b/src/ui/explore/TracksView.cpp index a646c1bb..19544136 100644 --- a/src/ui/explore/TracksView.cpp +++ b/src/ui/explore/TracksView.cpp @@ -17,10 +17,10 @@ * along with LMS. If not, see . */ -#include -#include -#include -#include +#include +#include +#include +#include #include "database/Types.hpp" @@ -37,41 +37,34 @@ namespace UserInterface { using namespace Database; -Tracks::Tracks(Filters* filters, Wt::WContainerWidget* parent) -: Wt::WContainerWidget(parent), - _filters(filters) +Tracks::Tracks(Filters* filters) +: Wt::WTemplate(Wt::WString::tr("Lms.Explore.Tracks.template")), +_filters(filters) { - auto container = new Wt::WTemplate(Wt::WString::tr("Lms.Explore.Tracks.template"), this); - container->addFunction("tr", &Wt::WTemplate::Functions::tr); + addFunction("tr", &Wt::WTemplate::Functions::tr); - _search = new Wt::WLineEdit(); - container->bindWidget("search", _search); + _search = bindNew("search"); _search->setPlaceholderText(Wt::WString::tr("Lms.Explore.search-placeholder")); _search->textInput().connect(this, &Tracks::refresh); - auto playBtn = new Wt::WText(Wt::WString::tr("Lms.Explore.Tracks.play"), Wt::XHTMLText); - container->bindWidget("play-btn", playBtn); + Wt::WText* playBtn = bindNew("play-btn", Wt::WString::tr("Lms.Explore.Tracks.play"), Wt::TextFormat::XHTML); playBtn->clicked().connect(std::bind([=] { - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); tracksPlay.emit(getTracks()); })); - auto addBtn = new Wt::WText(Wt::WString::tr("Lms.Explore.Tracks.add"), Wt::XHTMLText); - container->bindWidget("add-btn", addBtn); + Wt::WText* addBtn = bindNew("add-btn", Wt::WString::tr("Lms.Explore.Tracks.add"), Wt::TextFormat::XHTML); addBtn->clicked().connect(std::bind([=] { - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); tracksAdd.emit(getTracks()); })); - _tracksContainer = new Wt::WContainerWidget(); - container->bindWidget("tracks", _tracksContainer); + _tracksContainer = bindNew("tracks"); - _showMore = new Wt::WTemplate(Wt::WString::tr("Lms.Explore.template.show-more")); + _showMore = bindNew("show-more", Wt::WString::tr("Lms.Explore.template.show-more")); _showMore->addFunction("tr", &Wt::WTemplate::Functions::tr); - container->bindWidget("show-more", _showMore); - _showMore->clicked().connect(std::bind([=] { addSome(); @@ -88,9 +81,9 @@ Tracks::getTracks(int offset, int size, bool& moreResults) auto searchKeywords = splitString(_search->text().toUTF8(), " "); auto clusterIds = _filters->getClusterIds(); - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); - return Track::getByFilter(DboSession(), clusterIds, searchKeywords, offset, size, moreResults); + return Track::getByFilter(LmsApp->getDboSession(), clusterIds, searchKeywords, offset, size, moreResults); } std::vector @@ -110,7 +103,7 @@ Tracks::refresh() void Tracks::addSome() { - Wt::Dbo::Transaction transaction(DboSession()); + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); bool moreResults; auto tracks = getTracks(_tracksContainer->count(), 20, moreResults); @@ -118,41 +111,35 @@ Tracks::addSome() for (auto track : tracks) { auto trackId = track.id(); - Wt::WTemplate* entry = new Wt::WTemplate(Wt::WString::tr("Lms.Explore.Tracks.template.entry"), _tracksContainer); + Wt::WTemplate* entry = _tracksContainer->addNew(Wt::WString::tr("Lms.Explore.Tracks.template.entry")); - entry->bindString("name", Wt::WString::fromUTF8(track->getName()), Wt::PlainText); + entry->bindString("name", Wt::WString::fromUTF8(track->getName()), Wt::TextFormat::Plain); auto artist = track->getArtist(); if (artist) { entry->setCondition("if-has-artist", true); - Wt::WAnchor *artistAnchor = LmsApplication::createArtistAnchor(track->getArtist()); - entry->bindWidget("artist-name", artistAnchor); + entry->bindWidget("artist-name", LmsApplication::createArtistAnchor(track->getArtist())); } auto release = track->getRelease(); if (release) { entry->setCondition("if-has-release", true); - Wt::WAnchor *releaseAnchor = LmsApplication::createReleaseAnchor(track->getRelease()); - entry->bindWidget("release-name", releaseAnchor); + entry->bindWidget("release-name", LmsApplication::createReleaseAnchor(track->getRelease())); } - Wt::WImage *cover = new Wt::WImage(); - cover->setImageLink(LmsApp->getImageResource()->getTrackUrl(track.id(), 64)); + Wt::WImage* cover = entry->bindNew("cover", LmsApp->getImageResource()->getTrackUrl(track.id(), 64)); // Some images may not be square cover->setWidth(64); - entry->bindWidget("cover", cover); - auto playBtn = new Wt::WText(Wt::WString::tr("Lms.Explore.Tracks.play"), Wt::XHTMLText); - entry->bindWidget("play-btn", playBtn); + Wt::WText* playBtn = entry->bindNew("play-btn", Wt::WString::tr("Lms.Explore.Tracks.play"), Wt::TextFormat::XHTML); playBtn->clicked().connect(std::bind([=] { trackPlay.emit(trackId); })); - auto addBtn = new Wt::WText(Wt::WString::tr("Lms.Explore.Tracks.add"), Wt::XHTMLText); - entry->bindWidget("add-btn", addBtn); + Wt::WText* addBtn = entry->bindNew("add-btn", Wt::WString::tr("Lms.Explore.Tracks.add"), Wt::TextFormat::XHTML); addBtn->clicked().connect(std::bind([=] { trackAdd.emit(trackId); diff --git a/src/ui/explore/TracksView.hpp b/src/ui/explore/TracksView.hpp index 9b7e1c5c..2b46be07 100644 --- a/src/ui/explore/TracksView.hpp +++ b/src/ui/explore/TracksView.hpp @@ -19,17 +19,17 @@ #pragma once -#include -#include -#include +#include +#include +#include namespace UserInterface { class Filters; -class Tracks : public Wt::WContainerWidget +class Tracks : public Wt::WTemplate { public: - Tracks(Filters* filters, Wt::WContainerWidget* parent = 0); + Tracks(Filters* filters); Wt::Signal trackAdd; Wt::Signal trackPlay; diff --git a/src/ui/resource/ImageResource.cpp b/src/ui/resource/ImageResource.cpp index 9b56846a..b64b0529 100644 --- a/src/ui/resource/ImageResource.cpp +++ b/src/ui/resource/ImageResource.cpp @@ -17,8 +17,8 @@ * along with LMS. If not, see . */ -#include -#include +#include +#include #include "utils/Logger.hpp" #include "utils/Utils.hpp" @@ -34,9 +34,8 @@ namespace UserInterface { static const std::string unknownCoverPath = "/images/unknown-cover.jpg"; static const std::string unknownArtistImagePath = "/images/unknown-artist.jpg"; -ImageResource::ImageResource(Database::Handler& db, Wt::WObject *parent) -: Wt::WResource(parent), -_db(db) +ImageResource::ImageResource(Database::Handler& db) +: _db(db) { } @@ -154,14 +153,14 @@ ImageResource::handleRequest(const Wt::Http::Request& request, Wt::Http::Respons if (!sizeStr) return; - std::size_t size; - if (!readAs(*sizeStr, size) || size > maxSize) + auto size = readAs(*sizeStr); + if (!size || *size > maxSize) return; if (trackIdStr) { - Database::Track::id_type trackId; - if (!readAs(*trackIdStr, trackId)) + auto trackId = readAs(*trackIdStr); + if (!trackId) return; boost::filesystem::path path; @@ -172,7 +171,7 @@ ImageResource::handleRequest(const Wt::Http::Request& request, Wt::Http::Respons Wt::Dbo::Transaction transaction(_db.getSession()); - Database::Track::pointer track = Database::Track::getById(_db.getSession(), trackId); + Database::Track::pointer track = Database::Track::getById(_db.getSession(), *trackId); if (track) { coverType = track->getCoverType(); @@ -195,17 +194,16 @@ ImageResource::handleRequest(const Wt::Http::Request& request, Wt::Http::Respons break; } - putCover(response, covers, size); + putCover(response, covers, *size); return; } - putImage(response, getDefaultCover(size)); - return; + putImage(response, getDefaultCover(*size)); } else if (releaseIdStr) { - Database::Release::id_type releaseId; - if (!readAs(*releaseIdStr, releaseId)) + auto releaseId = readAs(*releaseIdStr); + if (!releaseId) return; std::vector covers; @@ -213,21 +211,18 @@ ImageResource::handleRequest(const Wt::Http::Request& request, Wt::Http::Respons // transactions are not thread safe { Wt::WApplication::UpdateLock lock(LmsApplication::instance()); - covers = CoverArt::Grabber::instance().getFromRelease(_db.getSession(), releaseId); + covers = CoverArt::Grabber::instance().getFromRelease(_db.getSession(), *releaseId); } - putCover(response, covers, size); - return; + putCover(response, covers, *size); } else if (artistIdStr) { - putImage(response, getDefaultArtistImage(size)); - return; + putImage(response, getDefaultArtistImage(*size)); } else { - putImage(response, getDefaultCover(size)); - return; + putImage(response, getDefaultCover(*size)); } } diff --git a/src/ui/resource/ImageResource.hpp b/src/ui/resource/ImageResource.hpp index 187d4dd2..3629b468 100644 --- a/src/ui/resource/ImageResource.hpp +++ b/src/ui/resource/ImageResource.hpp @@ -22,7 +22,7 @@ #include -#include +#include #include "database/DatabaseHandler.hpp" #include "image/Image.hpp" @@ -35,7 +35,7 @@ class ImageResource : public Wt::WResource public: static const std::size_t maxSize = 512; - ImageResource(Database::Handler& db, Wt::WObject *parent = 0); + ImageResource(Database::Handler& db); ~ImageResource(); std::string getReleaseUrl(Database::Release::id_type releaseId, size_t size) const; diff --git a/src/ui/resource/TranscodeResource.cpp b/src/ui/resource/TranscodeResource.cpp index 6d9203f9..f1b0755d 100644 --- a/src/ui/resource/TranscodeResource.cpp +++ b/src/ui/resource/TranscodeResource.cpp @@ -17,7 +17,7 @@ * along with LMS. If not, see . */ -#include +#include #include "utils/Logger.hpp" @@ -27,9 +27,8 @@ namespace UserInterface { -TranscodeResource::TranscodeResource(Database::Handler& db, Wt::WObject *parent) -: Wt::WResource(parent), -_db(db) +TranscodeResource::TranscodeResource(Database::Handler& db) +: _db(db) { LMS_LOG(UI, DEBUG) << "CONSTRUCTING RESOURCE"; } diff --git a/src/ui/resource/TranscodeResource.hpp b/src/ui/resource/TranscodeResource.hpp index 51f8ecc8..02847e53 100644 --- a/src/ui/resource/TranscodeResource.hpp +++ b/src/ui/resource/TranscodeResource.hpp @@ -21,7 +21,7 @@ #include -#include +#include #include "av/AvTranscoder.hpp" @@ -32,7 +32,7 @@ namespace UserInterface { class TranscodeResource : public Wt::WResource { public: - TranscodeResource(Database::Handler& db, Wt::WObject *parent); + TranscodeResource(Database::Handler& db); ~TranscodeResource(); std::string getUrl(Database::Track::id_type trackId, Av::Encoding encoding, boost::posix_time::time_duration offset) const; diff --git a/src/utils/Logger.hpp b/src/utils/Logger.hpp index b44a7d64..dc2dd11f 100644 --- a/src/utils/Logger.hpp +++ b/src/utils/Logger.hpp @@ -19,12 +19,10 @@ #pragma once -#include -#include -#include - #include +#include +#include enum class Severity { diff --git a/src/utils/Path.cpp b/src/utils/Path.cpp index dfc49ba4..8f6a6ede 100644 --- a/src/utils/Path.cpp +++ b/src/utils/Path.cpp @@ -73,7 +73,7 @@ void computeCrc(const boost::filesystem::path& p, std::vector& cr } else { - LMS_LOG(DBUPDATER, ERROR) << "Failed to open file '" << p << "'"; + LMS_LOG(DBUPDATER, ERROR) << "Failed to open file '" << p.string() << "'"; throw std::runtime_error("Failed to open file '" + p.string() + "'" ); } diff --git a/src/utils/Utils.cpp b/src/utils/Utils.cpp index 67117b20..f65287b5 100644 --- a/src/utils/Utils.cpp +++ b/src/utils/Utils.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -26,42 +27,28 @@ #include "Utils.hpp" - -boost::optional -readLong(const std::string& str) +template<> +boost::optional readAs(const std::string& str) { - try - { - return std::stol(str); - } - catch (std::exception& e) - { - return boost::none; - } -} - -bool readAsPosixTime(const std::string& str, boost::posix_time::ptime& time) -{ - const std::locale formats[] = { - std::locale(std::locale::classic(), new boost::posix_time::time_input_facet("%Y-%m-%d")), - std::locale(std::locale::classic(), new boost::posix_time::time_input_facet("%Y-%b-%d")), - std::locale(std::locale::classic(), new boost::posix_time::time_input_facet("%Y-%B-%d")), - std::locale(std::locale::classic(), new boost::posix_time::time_input_facet("%Y/%m/%d")), - std::locale(std::locale::classic(), new boost::posix_time::time_input_facet("%d.%m.%Y")), - std::locale(std::locale::classic(), new boost::posix_time::time_input_facet("%Y-%m")), - std::locale(std::locale::classic(), new boost::posix_time::time_input_facet("%Y/%m")), - std::locale(std::locale::classic(), new boost::posix_time::time_input_facet("%Y.%m")), - std::locale(std::locale::classic(), new boost::posix_time::time_input_facet("%Y")), + const std::vector formats = { + "yyyy-MM-dd", + "yyyy/MM/dd", + "yyyy-MM", + "yyyy/MM", + "yyyy" }; - for(size_t i=0; i < sizeof(formats)/sizeof(formats[0]); ++i) + + for (auto format : formats) { - std::istringstream iss(str); - iss.imbue(formats[i]); - if (iss >> time) - return true; + auto date = Wt::WDate::fromString(str, format); + + if (!date.isValid()) + continue; + + return date; } - return false; + return boost::none; } bool readList(const std::string& str, const std::string& separators, std::list& results) @@ -72,7 +59,7 @@ bool readList(const std::string& str, const std::string& separators, std::list(str, "UTF-8"); -} - std::string bufferToString(const std::vector& data) { diff --git a/src/utils/Utils.hpp b/src/utils/Utils.hpp index 905297c4..61674756 100644 --- a/src/utils/Utils.hpp +++ b/src/utils/Utils.hpp @@ -19,26 +19,21 @@ #pragma once -#include -#include +#include #include +#include +#include +#include -#include #include -#include - -boost::optional -readLong(const std::string& str); - -bool -readAsPosixTime(const std::string& str, boost::posix_time::ptime& time); +#include bool readList(const std::string& str, const std::string& separators, std::list& results); -std::string -durationToString(boost::posix_time::time_duration duration, std::string format); +//std::string +//durationToString(boost::posix_time::time_duration duration, std::string format); std::vector splitString(std::string string, std::string separators); @@ -49,17 +44,23 @@ stringTrim(const std::string& str, const std::string& whitespaces = " \t"); std::string stringTrimEnd(const std::string& str, const std::string& whitespaces = " \t"); -std::string -stringToUTF8(const std::string& str); - std::string bufferToString(const std::vector& data); template -static inline bool readAs(const std::string& str, T& data) +boost::optional readAs(const std::string& str) { + T res; + std::istringstream iss ( str ); - iss >> data; - return !iss.fail(); + iss >> res; + if (iss.fail()) + return boost::none; + + return res; } +template<> +boost::optional readAs(const std::string& str); + + diff --git a/test/TestAvMetadata.cpp b/test/TestAvMetadata.cpp index c91d0ea3..8109a82e 100644 --- a/test/TestAvMetadata.cpp +++ b/test/TestAvMetadata.cpp @@ -1,11 +1,11 @@ #include - -#include -#include +#include #include #include +#include + #include "av/AvInfo.hpp" #include "metadata/AvFormat.hpp" #include "metadata/TagLibParser.hpp" @@ -67,7 +67,7 @@ int main(int argc, char *argv[]) break; case MetaData::Type::Duration: - std::cout << "Duration: " << boost::posix_time::to_simple_string(boost::any_cast(item.second)) << std::endl; + std::cout << "Duration: " << boost::any_cast(item.second).count() / 1000 << "s" << std::endl; break; case MetaData::Type::TrackNumber: @@ -87,11 +87,11 @@ int main(int argc, char *argv[]) break; case MetaData::Type::Date: - std::cout << "Date: " << boost::posix_time::to_simple_string(boost::any_cast(item.second)) << std::endl; + std::cout << "Date: " << boost::any_cast(item.second).toString() << std::endl; break; case MetaData::Type::OriginalDate: - std::cout << "Original date: " << boost::posix_time::to_simple_string(boost::any_cast(item.second)) << std::endl; + std::cout << "Original date: " << boost::any_cast(item.second).toString() << std::endl; break; case MetaData::Type::HasCover: @@ -100,7 +100,7 @@ int main(int argc, char *argv[]) case MetaData::Type::AudioStreams: for (auto& audioStream : boost::any_cast >(item.second)) - std::cout << "Audio stream '" << audioStream.desc << "' - " << audioStream.bitRate << " bps" << std::endl; + std::cout << "Audio stream: " << audioStream.bitRate << " bps" << std::endl; break; case MetaData::Type::MusicBrainzArtistID: