diff --git a/TODO b/TODO
index 343ebbcc..51a0ca71 100644
--- a/TODO
+++ b/TODO
@@ -1,19 +1,12 @@
-[ServiceManager]
-- Rework the whole start/stop/try/cach/thread/interrupts things
-- Use our own WIOService
-
-[Services]
-- consider adding support for external web servers (new FCGI service?)
-
-[Users]
-- Handle login lifetime?
-- Limit multi login from UI and remote interfaces (limit per interface is acceptable)
+[Book]
+- Make the feature
[Cover]
- Scaling: find something more "reliable" than GIL and its custom extensions (adobe work, io_new)?
- Handle several file formats (not only jpg)
- Handle preferred cover file names
+- Implement a cache and a grabber from some web service (mandatory for artists)
[Database]
- Optim, use SQL query to get the "genre" orphans
@@ -24,8 +17,22 @@
[Metadata]
- OGG metadata -> properly handle metadata nested in the audio stream
+[Playlist]
+- Make public playlists so that users can see what other people are listening to
+
+[Users]
+- Handle login lifetime?
+- Limit multi login from UI and remote interfaces (limit per interface is acceptable)
+
+[ServiceManager]
+- Rework the whole start/stop/try/cach/thread/interrupts things
+- Use our own WIOService
+
+[Services]
+- consider adding support for external web servers (new FCGI service?)
+
[Transcode]
-- some early end of playback spotted on flac files. Spotted on old firefox versions?
+- some early end of playback spotted on files. Maybe this is because the stderr of the forked process is not properly closed?
[UI]
- handle internationalization
@@ -44,9 +51,10 @@
[Audio]
- Style eveything nicely...
- - MediaPlayer: move the slider using js (http://redmine.webtoolkit.eu/boards/2/topics/7924?r=8478)
- - TrackView : handle durations > 1 hour
- - TrackView : Reselect the current selected item when displaying the updated search results
+ - MediaPlayer: move the slider using js (http://redmine.webtoolkit.eu/boards/2/topics/7924?r=8478, http://redmine.emweb.be/boards/2/topics/10994)
+ - TrackView: handle durations > 1 hour
+ - TrackView: Reselect the current selected item when displaying the updated search results
+ - TrackView: display the total duration of the track query
- Add covers in the release filter?
- Add a download button to get the current playlist in a streamed zip file
- Add a upload button to upload media files in a dedicated directory
@@ -65,7 +73,7 @@
- Implement partial text search options in the GetXXX messages
[REST API]
-- Make another dedicated REST API. Maybe use the SubSonic API?
+- Make another dedicated REST API. Maybe use the SubSonic API or Ampache API?
[Logs]
- Capture transcoder log output to get more information on errors
diff --git a/conf/lms.conf.sample b/conf/lms.conf.sample
index 9174d9d7..01ffec79 100644
--- a/conf/lms.conf.sample
+++ b/conf/lms.conf.sample
@@ -2,9 +2,14 @@
main = {
logger = {
- file = "/var/lms/lms.log" # comment to disable file logging
- console = true;
- level = 7;
+ level = 7; # level common for all loggers
+ file = {
+ enable = true;
+ path = "/var/lms/lms.log"; # comment to disable file logging
+ }
+ console = {
+ enable = true;
+ }
}
database = {
@@ -16,15 +21,13 @@ main = {
cover = {
file_extensions = "jpg jpeg";
- file_max_size = 500000;
+ file_max_size = 5000000;
file_preferred_names = "cover front";
}
}
ui = {
- enable = true;
-
resources = {
docroot = "/var/lms/docroot"
approot = "/var/lms/approot"
@@ -44,8 +47,6 @@ ui = {
}
remote = {
- enable = true;
-
nb-threads = 1;
listen-endpoint = {
diff --git a/include/.empty b/include/.empty
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/lms-api/proto/auth.proto b/lms-api/proto/auth.proto
similarity index 98%
rename from src/lms-api/proto/auth.proto
rename to lms-api/proto/auth.proto
index b054ef06..1ad02a48 100644
--- a/src/lms-api/proto/auth.proto
+++ b/lms-api/proto/auth.proto
@@ -17,8 +17,6 @@
* along with LMS. If not, see .
*/
-import "common.proto";
-
package LmsAPI;
message AuthRequest
diff --git a/src/lms-api/proto/collection.proto b/lms-api/proto/collection.proto
similarity index 99%
rename from src/lms-api/proto/collection.proto
rename to lms-api/proto/collection.proto
index 8037ab02..8666a98b 100644
--- a/src/lms-api/proto/collection.proto
+++ b/lms-api/proto/collection.proto
@@ -17,8 +17,6 @@
* along with LMS. If not, see .
*/
-import "common.proto";
-
package LmsAPI;
message AudioCollectionRequest
diff --git a/src/lms-api/proto/media.proto b/lms-api/proto/media.proto
similarity index 99%
rename from src/lms-api/proto/media.proto
rename to lms-api/proto/media.proto
index 5dae7257..20af5d02 100644
--- a/src/lms-api/proto/media.proto
+++ b/lms-api/proto/media.proto
@@ -17,8 +17,6 @@
* along with LMS. If not, see .
*/
-import "common.proto";
-
package LmsAPI;
message MediaRequest
diff --git a/src/lms-api/proto/messages.proto b/lms-api/proto/messages.proto
similarity index 98%
rename from src/lms-api/proto/messages.proto
rename to lms-api/proto/messages.proto
index 7ba930c3..a6eb280b 100644
--- a/src/lms-api/proto/messages.proto
+++ b/lms-api/proto/messages.proto
@@ -17,8 +17,6 @@
* along with LMS. If not, see .
*/
-import "common.proto";
-
import "auth.proto";
import "collection.proto";
import "media.proto";
diff --git a/src/Makefile.am b/src/Makefile.am
index e537e5c2..e60d4e1c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -81,8 +81,6 @@ nodist_lms_SOURCES = \
$(builddir)/auth.pb.h \
$(builddir)/collection.pb.cc \
$(builddir)/collection.pb.h \
- $(builddir)/common.pb.cc \
- $(builddir)/common.pb.h \
$(builddir)/media.pb.cc \
$(builddir)/media.pb.h \
$(builddir)/messages.pb.cc \
@@ -93,8 +91,6 @@ BUILT_SOURCES = \
$(builddir)/auth.pb.h \
$(builddir)/collection.pb.cc \
$(builddir)/collection.pb.h \
- $(builddir)/common.pb.cc \
- $(builddir)/common.pb.h \
$(builddir)/media.pb.cc \
$(builddir)/media.pb.h \
$(builddir)/messages.pb.cc \
@@ -105,15 +101,13 @@ MOSTLYCLEANFILES = \
$(builddir)/auth.pb.h \
$(builddir)/collection.pb.cc \
$(builddir)/collection.pb.h \
- $(builddir)/common.pb.cc \
- $(builddir)/common.pb.h \
$(builddir)/media.pb.cc \
$(builddir)/media.pb.h \
$(builddir)/messages.pb.cc \
$(builddir)/messages.pb.h
-%.pb.cc %.pb.h: $(srcdir)/lms-api/proto/%.proto
- $(PROTOC) --proto_path=$(srcdir)/lms-api/proto/ --cpp_out=$(builddir)/ $^
+%.pb.cc %.pb.h: $(top_srcdir)/lms-api/proto/%.proto
+ $(PROTOC) --proto_path=$(top_srcdir)/lms-api/proto/ --cpp_out=$(builddir)/ $^
endif
diff --git a/src/config/ConfigReader.cpp b/src/config/ConfigReader.cpp
index 5e351bc8..90c093de 100644
--- a/src/config/ConfigReader.cpp
+++ b/src/config/ConfigReader.cpp
@@ -23,89 +23,52 @@
namespace {
- void splitStrings(const std::string& source, std::vector& res)
- {
- std::istringstream oss(source);
-
- std::string str;
- while(oss >> str)
- res.push_back(str);
- }
-
}
-ConfigReader::ConfigReader(boost::filesystem::path p)
+ConfigReader::ConfigReader()
+: _config (nullptr)
{
- _config.readFile(p.string().c_str());
+}
+
+ConfigReader&
+ConfigReader::instance()
+{
+ static ConfigReader instance;
+ return instance;
}
void
-ConfigReader::getLoggerConfig(Logger::Config& config)
+ConfigReader::setFile(boost::filesystem::path p)
{
- config.enableFileLogging = _config.lookupValue("main.logger.file", config.logPath);
- config.enableConsoleLogging = _config.lookup("main.logger.console");
- config.minSeverity = static_cast((int)_config.lookup("main.logger.level"));
+ if (_config != nullptr)
+ delete _config;
+
+ _config = new libconfig::Config();
+
+ _config->readFile(p.string().c_str());
}
-void
-ConfigReader::getCoverGrabberConfig(CoverArt::Grabber::Config& config)
+std::string
+ConfigReader::getString(std::string setting)
{
- std::string extensions = _config.lookup("main.cover.file_extensions");
- config.maxFileSize = static_cast(_config.lookup("main.cover.file_max_size"));
- std::string filenames = _config.lookup("main.cover.file_preferred_names");
-
- splitStrings(extensions, config.fileExtensions);
- splitStrings(filenames, config.preferredFileNames);
+ return _config->lookup(setting);
}
-void
-ConfigReader::getUserInterfaceConfig(Service::UserInterfaceService::Config& config)
+unsigned long
+ConfigReader::getULong(std::string setting)
{
-
- config.enable = _config.lookup("ui.enable");
- if (!config.enable)
- return;
-
- config.docRootPath = _config.lookup("ui.resources.docroot");
- config.appRootPath = _config.lookup("ui.resources.approot");
- config.httpsPort = static_cast(_config.lookup("ui.listen-endpoint.port"));
- config.httpsAddress = boost::asio::ip::address::from_string((const char*)_config.lookup("ui.listen-endpoint.addr"));
- config.sslCertificatePath = _config.lookup("ui.ssl-crypto.cert");
- config.sslPrivateKeyPath = _config.lookup("ui.ssl-crypto.key");
- config.sslTempDhPath = _config.lookup("ui.ssl-crypto.dh");
-
- config.dbPath = _config.lookup("main.database.path");
+ return static_cast(_config->lookup(setting));
}
-#if defined HAVE_LMSAPI
-void
-ConfigReader::getLmsAPIConfig(Service::LmsAPIService::Config& config)
+long
+ConfigReader::getLong(std::string setting)
{
- config.enable = _config.lookup("remote.enable");
- if (!config.enable)
- return;
-
- config.port = static_cast(_config.lookup("remote.listen-endpoint.port"));
- config.address = boost::asio::ip::address::from_string((const char*)_config.lookup("remote.listen-endpoint.addr"));
- config.sslCertificatePath = _config.lookup("remote.ssl-crypto.cert");
- config.sslPrivateKeyPath = _config.lookup("remote.ssl-crypto.key");
- config.sslTempDhPath = _config.lookup("remote.ssl-crypto.dh");
-
- config.dbPath = _config.lookup("main.database.path");
-}
-#endif
-
-void
-ConfigReader::getDatabaseUpdateConfig(Service::DatabaseUpdateService::Config& config)
-{
- config.enable = true;
-
- config.dbPath = _config.lookup("main.database.path");
-
- std::string audioExtensions = _config.lookup("main.database.audio_extensions");
- std::string videoExtensions = _config.lookup("main.database.video_extensions");
-
- splitStrings(audioExtensions, config.audioExtensions);
- splitStrings(videoExtensions, config.videoExtensions);
+ return _config->lookup(setting);
+}
+
+bool
+ConfigReader::getBool(std::string setting)
+{
+ return _config->lookup(setting);
}
diff --git a/src/config/ConfigReader.hpp b/src/config/ConfigReader.hpp
index 6abc5039..6f68156c 100644
--- a/src/config/ConfigReader.hpp
+++ b/src/config/ConfigReader.hpp
@@ -23,40 +23,27 @@
#include
#include
-#include "config/config.h"
-
-#include "cover/CoverArtGrabber.hpp"
-#include "logger/Logger.hpp"
-
-#include "service/UserInterfaceService.hpp"
-#include "service/DatabaseUpdateService.hpp"
-#if defined HAVE_LMSAPI
-#include "service/LmsAPIServerService.hpp"
-#endif
-
class ConfigReader
{
public:
- ConfigReader(boost::filesystem::path p);
+ ConfigReader(const ConfigReader&) = delete;
+ ConfigReader& operator=(const ConfigReader&) = delete;
- // Logger configuration
- void getLoggerConfig(Logger::Config& config);
+ static ConfigReader& instance();
- // Covers
- void getCoverGrabberConfig(CoverArt::Grabber::Config& config);
+ void setFile(boost::filesystem::path p);
- // Service configurations
- void getUserInterfaceConfig(Service::UserInterfaceService::Config& config);
- void getDatabaseUpdateConfig(Service::DatabaseUpdateService::Config& config);
-
-#if defined HAVE_LMSAPI
- void getLmsAPIConfig(Service::LmsAPIService::Config& config);
-#endif
+ std::string getString(std::string setting);
+ unsigned long getULong(std::string setting);
+ long getLong(std::string setting);
+ bool getBool(std::string setting);
private:
- libconfig::Config _config;
+ ConfigReader();
+
+ libconfig::Config *_config;
};
#endif
diff --git a/src/cover/CoverArtGrabber.cpp b/src/cover/CoverArtGrabber.cpp
index 9194330a..695ddc3e 100644
--- a/src/cover/CoverArtGrabber.cpp
+++ b/src/cover/CoverArtGrabber.cpp
@@ -17,10 +17,8 @@
* along with LMS. If not, see .
*/
-
-#include
-
#include "logger/Logger.hpp"
+#include "config/ConfigReader.hpp"
#include "av/InputFormatContext.hpp"
#include "CoverArtGrabber.hpp"
@@ -28,6 +26,18 @@
namespace {
+std::vector splitStrings(const std::string& source)
+{
+ std::vector res;
+ std::istringstream oss(source);
+
+ std::string str;
+ while(oss >> str)
+ res.push_back(str);
+
+ return res;
+}
+
bool
isFileSupported(const boost::filesystem::path& file, const std::vector extensions)
{
@@ -58,12 +68,12 @@ Grabber::instance()
}
void
-Grabber::init(const Config& config)
+Grabber::init()
{
- for (auto extension : config.fileExtensions)
+ for (const std::string& extension : splitStrings( ConfigReader::instance().getString("main.cover.file_extensions")))
_fileExtensions.push_back("." + extension);
- _maxFileSize = config.maxFileSize;
+ _maxFileSize = ConfigReader::instance().getULong("main.cover.file_max_size");
}
std::vector
@@ -75,7 +85,7 @@ Grabber::getFromInputFormatContext(const Av::InputFormatContext& input, std::siz
{
std::vector pictures = input.getPictures(nbMaxCovers);
- BOOST_FOREACH(const Av::Picture& picture, pictures)
+ for (Av::Picture& picture : pictures)
res.push_back( CoverArt(picture.mimeType, picture.data) );
}
diff --git a/src/cover/CoverArtGrabber.hpp b/src/cover/CoverArtGrabber.hpp
index b07bbb56..f2dbb33e 100644
--- a/src/cover/CoverArtGrabber.hpp
+++ b/src/cover/CoverArtGrabber.hpp
@@ -38,14 +38,7 @@ class Grabber
static Grabber& instance();
- struct Config
- {
- std::vector fileExtensions;
- std::size_t maxFileSize;
- std::vector preferredFileNames;
- };
-
- void init(const Config& config);
+ void init();
std::vector getCoverPaths(const boost::filesystem::path& directoryPath, std::size_t nbMaxCovers = 1) const;
std::vector getFromDirectory(const boost::filesystem::path& path, std::size_t nbMaxCovers = 1) const;
diff --git a/src/database-updater/DatabaseUpdater.cpp b/src/database-updater/DatabaseUpdater.cpp
index dd4d0683..2239d96c 100644
--- a/src/database-updater/DatabaseUpdater.cpp
+++ b/src/database-updater/DatabaseUpdater.cpp
@@ -493,6 +493,7 @@ Updater::processAudioFile( const boost::filesystem::path& file, Stats& stats)
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() );
{
std::string trackGenreList;
@@ -630,19 +631,15 @@ void
Updater::checkAudioFiles( Stats& stats )
{
- LMS_LOG(MOD_DBUPDATER, SEV_DEBUG) << "Checking audio files...";
+ LMS_LOG(MOD_DBUPDATER, SEV_INFO) << "Checking audio files...";
Wt::Dbo::Transaction transaction(_db.getSession());
std::vector rootDirs = getRootDirectoriesByType(_db.getSession(), Database::MediaDirectory::Audio);
LMS_LOG(MOD_DBUPDATER, SEV_DEBUG) << "Checking tracks...";
- typedef Wt::Dbo::collection< Wt::Dbo::ptr