Splitting services, begin the switch to a more integrated Wt daemon

This commit is contained in:
epoupon
2015-09-07 12:43:21 +02:00
parent de62abdf0f
commit 614b05105a
13 changed files with 72 additions and 312 deletions
-1
View File
@@ -28,7 +28,6 @@ lms_SOURCES = \
$(srcdir)/metadata/Utils.cpp \
$(srcdir)/service/ServiceManager.cpp \
$(srcdir)/service/DatabaseUpdateService.cpp \
$(srcdir)/service/UserInterfaceService.cpp \
$(srcdir)/transcode/AvConvTranscoder.cpp \
$(srcdir)/transcode/Format.cpp \
$(srcdir)/transcode/Parameters.cpp \
+3
View File
@@ -79,6 +79,7 @@ Handler::Handler(Wt::Dbo::SqlConnectionPool& connectionPool)
{
_session.setConnectionPool(connectionPool);
_session.mapClass<Database::Artist>("artist");
_session.mapClass<Database::Genre>("genre");
_session.mapClass<Database::Track>("track");
@@ -95,6 +96,8 @@ Handler::Handler(Wt::Dbo::SqlConnectionPool& connectionPool)
_session.mapClass<Database::AuthInfo::AuthTokenType>("auth_token");
try {
Wt::Dbo::Transaction transaction(_session);
_session.createTables();
_session.execute("CREATE INDEX artist_name_idx ON artist(name)");
_session.execute("CREATE INDEX genre_name_idx ON genre(name)");
+13 -13
View File
@@ -81,6 +81,19 @@ Logger::init()
boost::log::register_simple_formatter_factory< Severity, char >("Severity");
if (ConfigReader::instance().getBool("main.logger.console.enable", false))
{
boost::log::add_console_log(std::cout,
boost::log::keywords::format = (
boost::log::expressions::stream
<< boost::log::expressions::format_date_time< boost::posix_time::ptime >("TimeStamp", "[%Y-%m-%d %H:%M:%S]")
<< " [" << boost::log::expressions::attr< Module >("Module") << "]"
<< " [" << boost::log::expressions::attr< Severity >("Severity") << "]"
<< " " << boost::log::expressions::smessage
)
);
}
if (ConfigReader::instance().getBool("main.logger.file.enable", false))
{
boost::log::add_file_log
@@ -99,19 +112,6 @@ Logger::init()
);
}
if (ConfigReader::instance().getBool("main.logger.console.enable", false))
{
boost::log::add_console_log(std::cout,
boost::log::keywords::format = (
boost::log::expressions::stream
<< boost::log::expressions::format_date_time< boost::posix_time::ptime >("TimeStamp", "[%Y-%m-%d %H:%M:%S]")
<< " [" << boost::log::expressions::attr< Module >("Module") << "]"
<< " [" << boost::log::expressions::attr< Severity >("Severity") << "]"
<< " " << boost::log::expressions::smessage
)
);
}
boost::log::core::get()->set_filter
(
boost::log::expressions::attr<Severity>("Severity") <= ConfigReader::instance().getULong("main.logger.level", SEV_DEBUG)
+30 -24
View File
@@ -26,16 +26,18 @@
#include "logger/Logger.hpp"
#include "cover/CoverArtGrabber.hpp"
#include "ui/LmsApplication.hpp"
#include "service/ServiceManager.hpp"
#include "service/DatabaseUpdateService.hpp"
#include "service/UserInterfaceService.hpp"
#if defined HAVE_LMSAPI
#include "service/LmsAPIServerService.hpp"
#endif
#include <Wt/WServer>
int main(int argc, char* argv[])
{
int res = EXIT_FAILURE;
assert(argc > 0);
@@ -43,25 +45,10 @@ int main(int argc, char* argv[])
try
{
// TODO generate a nice command line help with args
// Open configuration file
boost::filesystem::path configFile("/etc/lms.conf"); // TODO
if (argc > 1)
configFile = boost::filesystem::path(argv[1]);
boost::filesystem::path configFilePath("/etc/lms.conf"); // TODO use $confdir from autotools
if ( !boost::filesystem::exists(configFile))
{
std::cerr << "Config file '" << configFile << "' does not exist!" << std::endl;
return EXIT_FAILURE;
}
else if (!boost::filesystem::is_regular(configFile))
{
std::cerr << "Config file '" << configFile << "' is not regular!" << std::endl;
return EXIT_FAILURE;
}
ConfigReader::instance().setFile(configFile);
ConfigReader::instance().setFile(configFilePath);
Logger::instance().init();
CoverArt::Grabber::instance().init();
@@ -76,17 +63,36 @@ int main(int argc, char* argv[])
// Initializing a connection pool to the database that will be shared along services
std::unique_ptr<Wt::Dbo::SqlConnectionPool> connectionPool( Database::Handler::createConnectionPool( ConfigReader::instance().getString("main.database.path") ));
LMS_LOG(MOD_MAIN, SEV_INFO) << "Starting services...";
serviceManager.startService( std::make_shared<Service::DatabaseUpdateService>(*connectionPool));
serviceManager.startService( std::make_shared<Service::UserInterfaceService>(boost::filesystem::path(argv[0]), *connectionPool));
serviceManager.add( std::make_shared<Service::DatabaseUpdateService>(*connectionPool));
#if defined HAVE_LMSAPI
serviceManager.startService( std::make_shared<Service::LmsAPIService>(*connectionPool));
serviceManager.add( std::make_shared<Service::LmsAPIService>(*connectionPool));
#endif
Wt::WServer server(argv[0]);
server.setServerConfiguration (argc, argv);
// bind entry point
server.addEntryPoint(Wt::Application, boost::bind(UserInterface::LmsApplication::create, _1, boost::ref(*connectionPool)));
LMS_LOG(MOD_MAIN, SEV_NOTICE) << "Now running...";
serviceManager.run();
// Start underlying services
LMS_LOG(MOD_MAIN, SEV_INFO) << "Starting services...";
serviceManager.start();
// Starting the main server
LMS_LOG(MOD_MAIN, SEV_INFO) << "Starting server...";
server.start();
// Waiting for shutdown command
Wt::WServer::waitForShutdown(argv[0]);
LMS_LOG(MOD_MAIN, SEV_INFO) << "Stopping server...";
server.stop();
LMS_LOG(MOD_MAIN, SEV_INFO) << "Stopping services...";
serviceManager.stop();
res = EXIT_SUCCESS;
}
+15 -79
View File
@@ -19,9 +19,6 @@
#include "logger/Logger.hpp"
#include <boost/foreach.hpp>
#include <boost/bind.hpp>
#include "ServiceManager.hpp"
namespace Service {
@@ -34,112 +31,51 @@ ServiceManager::instance()
}
ServiceManager::ServiceManager()
: _signalSet(_ioService)
{
_signalSet.add(SIGINT);
_signalSet.add(SIGTERM);
#if defined(SIGQUIT)
_signalSet.add(SIGQUIT);
#endif // defined(SIGQUIT)
_signalSet.add(SIGHUP);
// Excplicitely ignore SIGCHLD to avoid zombies
// when avconv child processes are being killed
if (::signal(SIGCHLD, SIG_IGN) == SIG_ERR)
throw std::runtime_error("ServiceManager::ServiceManager, signal failed!");
}
ServiceManager::~ServiceManager()
{
LMS_LOG(MOD_SERVICE, SEV_NOTICE) << "Stopping services...";
stopServices();
stop();
}
void
ServiceManager::run()
{
asyncWaitSignals();
LMS_LOG(MOD_SERVICE, SEV_DEBUG) << "ServiceManager: waiting for events...";
try {
// Wait for events
_ioService.run();
}
catch( std::exception& e )
{
LMS_LOG(MOD_SERVICE, SEV_ERROR) << "ServiceManager: exception in ioService::run: " << e.what();
}
// Stopping services
stopServices();
LMS_LOG(MOD_SERVICE, SEV_DEBUG) << "ServiceManager: run complete !";
}
void
ServiceManager::asyncWaitSignals(void)
{
_signalSet.async_wait(boost::bind(&ServiceManager::handleSignal,
this,
boost::asio::placeholders::error,
boost::asio::placeholders::signal_number));
}
void
ServiceManager::startService(Service::pointer service)
ServiceManager::add(Service::pointer service)
{
_services.insert(service);
service->start();
}
void
ServiceManager::stopService(Service::pointer service)
ServiceManager::del(Service::pointer service)
{
_services.erase(service);
service->stop();
_services.erase(service);
}
void
ServiceManager::stopServices(void)
ServiceManager::start(void)
{
BOOST_FOREACH(Service::pointer service, _services)
for (Service::pointer service : _services)
service->start();
}
void
ServiceManager::stop(void)
{
for (Service::pointer service : _services)
service->stop();
}
void
ServiceManager::restartServices(void)
ServiceManager::restart(void)
{
LMS_LOG(MOD_SERVICE, SEV_NOTICE) << "Restarting services...";
BOOST_FOREACH(Service::pointer service, _services)
for (Service::pointer service : _services)
service->restart();
}
void
ServiceManager::handleSignal(boost::system::error_code /*ec*/, int signo)
{
LMS_LOG(MOD_SERVICE, SEV_INFO) << "Received signal " << signo;
switch (signo)
{
case SIGINT:
case SIGTERM:
case SIGQUIT:
stopServices();
// Do not listen for signals, this will make the ioservice.run return
break;
case SIGHUP:
restartServices();
asyncWaitSignals();
break;
default:
LMS_LOG(MOD_SERVICE, SEV_NOTICE) << "Unhandled signal " << signo;
}
}
} // namespace Service
+10 -24
View File
@@ -20,7 +20,6 @@
#ifndef SERVICE_CONTROLER_HPP
#define SERVICE_CONTROLER_HPP
#include <boost/asio.hpp>
#include <set>
#include "Service.hpp"
@@ -35,15 +34,14 @@ class ServiceManager
static ServiceManager& instance();
~ServiceManager();
void stopService(Service::pointer service);
void startService(Service::pointer service);
void add(Service::pointer service);
void del(Service::pointer service);
void stopAllServices();
void start();
void stop();
void restart();
// Return in case of failure/stop by user
void run();
template <class T> typename T::pointer getService();
template <class T> typename T::pointer get();
boost::mutex& mutex() { return _mutex;}
@@ -53,32 +51,20 @@ class ServiceManager
ServiceManager(ServiceManager const&); // Don't Implement
void operator=(ServiceManager const&); // Don't implement
void restartServices(void);
void stopServices(void);
void asyncWaitSignals(void);
void handleSignal(boost::system::error_code error, int signo);
boost::mutex _mutex;
boost::asio::io_service _ioService;
// Listen for interesting signals
boost::asio::signal_set _signalSet;
std::set<Service::pointer> _services;
};
template <class T> typename T::pointer
ServiceManager::getService()
ServiceManager::get()
{
std::set<Service::pointer>::iterator it;
for (std::set<Service::pointer>::iterator it = _services.begin(); it != _services.end(); ++it)
for (Service::pointer service : _services)
{
if (typeid(*(*it)) == typeid(T)) {
return std::dynamic_pointer_cast<T>(*it);
if (typeid(*(service)) == typeid(T)) {
return std::dynamic_pointer_cast<T>(service);
}
}
return std::shared_ptr<T>();
-85
View File
@@ -1,85 +0,0 @@
/*
* Copyright (C) 2013 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include <Wt/Dbo/SqlConnectionPool>
#include "logger/Logger.hpp"
#include "UserInterfaceService.hpp"
#include "ui/LmsApplication.hpp"
#include "config/ConfigReader.hpp"
namespace Service {
UserInterfaceService::UserInterfaceService( boost::filesystem::path runAppPath, Wt::Dbo::SqlConnectionPool& connectionPool)
: _server(runAppPath.string())
{
std::vector<std::string> args;
args.push_back(runAppPath.string());
args.push_back("--docroot=" + ConfigReader::instance().getString("ui.resources.docroot"));
args.push_back("--approot=" + ConfigReader::instance().getString("ui.resources.approot"));
args.push_back("--https-port=" + std::to_string( ConfigReader::instance().getULong("ui.listen-endpoint.port")));
args.push_back("--https-address=" + ConfigReader::instance().getString("ui.listen-endpoint.addr"));
args.push_back("--ssl-certificate=" + ConfigReader::instance().getString("ui.ssl-crypto.cert"));
args.push_back("--ssl-private-key=" + ConfigReader::instance().getString("ui.ssl-crypto.key"));
args.push_back("--ssl-tmp-dh=" + ConfigReader::instance().getString("ui.ssl-crypto.dh"));
// Construct argc/argv
int argc = args.size();
const char* argv[args.size()];
for (int i = 0; i < argc; ++i)
argv[i] = args[i].c_str();
for(int i = 0; i < argc; ++i)
{
LMS_LOG(MOD_SERVICE, SEV_DEBUG) << "i = " << i << ", arg = '" << argv[i] << "'";
}
_server.setServerConfiguration (argc, const_cast<char**>(argv));
// bind entry point
_server.addEntryPoint(Wt::Application, boost::bind(UserInterface::LmsApplication::create, _1, boost::ref(connectionPool)));
}
void
UserInterfaceService::start(void)
{
_server.start();
LMS_LOG(MOD_SERVICE, SEV_DEBUG) << "UserInterfaceService::start -> Service started...";
}
void
UserInterfaceService::stop(void)
{
LMS_LOG(MOD_SERVICE, SEV_DEBUG) << "UserInterfaceService::stop -> stopping...";
_server.stop();
LMS_LOG(MOD_SERVICE, SEV_DEBUG) << "UserInterfaceService::stop -> stopped!";
}
void
UserInterfaceService::restart(void)
{
}
} // namespace Service
-50
View File
@@ -1,50 +0,0 @@
/*
* Copyright (C) 2013 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WEB_SERVER_SERVICE_HPP
#define WEB_SERVER_SERVICE_HPP
#include <boost/filesystem.hpp>
#include <Wt/WServer>
#include "Service.hpp"
namespace Service {
class UserInterfaceService : public Service
{
public:
UserInterfaceService(boost::filesystem::path runAppPath, Wt::Dbo::SqlConnectionPool& connectionPool);
void start(void);
void stop(void);
void restart(void);
private:
Wt::WServer _server;
};
} //namespace Service
#endif
-423
View File
@@ -1,423 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<messages xmlns:if="Wt.WTemplate.conditions">
<!--FORMS message blocks-->
<message id="firstConnectionForm-template">
<legend>${title}</legend>
<div class="form-horizontal">
<div class="form-group">
<label class="control-label col-sm-2" for="${id:name}">
Name
</label>
<div class="col-sm-5">
${name}
</div>
<div class="help-block col-sm-5">
${name-info}
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="${id:email}">
e-Mail
</label>
<div class="col-sm-5">
${email}
</div>
<div class="help-block col-sm-5">
${email-info}
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="${id:password}">
Password
</label>
<div class="col-sm-5">
${password}
</div>
${password-info}
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="${id:password-confirm}">
Confirm password
</label>
<div class="col-sm-5">
${password-confirm}
</div>
<div class="help-block col-sm-5">
${password-confirm-info}
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
${save-button}
</div>
</div>
${apply-info}
</div>
</message>
<message id="userForm-template">
<legend>${title}</legend>
<div class="form-horizontal">
<div class="form-group">
<label class="control-label col-sm-2" for="${id:name}">
Name
</label>
<div class="col-sm-5">
${name}
</div>
<div class="help-block col-sm-5">
${name-info}
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="${id:email}">
e-Mail
</label>
<div class="col-sm-5">
${email}
</div>
<div class="help-block col-sm-5">
${email-info}
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="${id:password}">
Password
</label>
<div class="col-sm-5">
${password}
</div>
<div class="help-block col-sm-5">
${password-info}
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="${id:password-confirm}">
Confirm password
</label>
<div class="col-sm-5">
${password-confirm}
</div>
<div class="help-block col-sm-5">
${password-confirm-info}
</div>
</div>
</div>
<legend>${access}</legend>
<div class="form-horizontal">
<div class="form-group">
<label class="control-label col-sm-2" for="${id:admin}">
Admin
</label>
<div class="col-sm-5">
${admin}
</div>
<div class="help-block col-sm-5">
${admin-info}
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="${id:audio-bitrate-limit}">
Audio Bitrate Limit
</label>
<div class="col-sm-5">
<div class="input-group">
${audio-bitrate-limit}
<span class="input-group-addon">kbps</span>
</div>
</div>
<div class="help-block col-sm-5">
${audio-bitrate-limit-info}
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="${id:video-bitrate-limit}">
Video Bitrate Limit
</label>
<div class="col-sm-5">
<div class="input-group">
${video-bitrate-limit}
<span class="input-group-addon">kbps</span>
</div>
</div>
<div class="help-block col-sm-5">
${video-bitrate-limit-info}
</div>
</div>
</div>
<div class="form-horizontal">
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
${save-button} ${cancel-button}
</div>
</div>
</div>
</message>
<message id="userAccountForm-template">
<legend>${title}</legend>
<div class="form-horizontal">
<div class="form-group">
<label class="control-label col-sm-2" for="${id:name}">
Name
</label>
<div class="col-sm-5">
${name}
</div>
<div class="help-block col-sm-5">
${name-info}
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="${id:email}">
e-Mail
</label>
<div class="col-sm-5">
${email}
</div>
<div class="help-block col-sm-5">
${email-info}
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="${id:password}">
Password
</label>
<div class="col-sm-5">
${password}
</div>
<div class="help-block col-sm-5">
${password-info}
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="${id:password-confirm}">
Confirm password
</label>
<div class="col-sm-5">
${password-confirm}
</div>
<div class="help-block col-sm-5">
${password-confirm-info}
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
${save-button} ${cancel-button}
</div>
</div>
${apply-info}
</div>
</message>
<message id="audioForm-template">
<legend>${title}</legend>
<div class="form-horizontal">
<div class="form-group">
<label class="control-label col-sm-2" for="${id:bitrate}">
Audio bitrate
</label>
<div class="col-sm-5">
<div class="input-group">
${bitrate}
<span class="input-group-addon">kbps</span>
</div>
</div>
<div class="help-block col-sm-5">
${bitrate-info}
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="${id:encoding}">
Audio Encoding
</label>
<div class="col-sm-5">
${encoding}
</div>
<div class="help-block col-sm-5">
${encoding-info}
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
${save-button} ${cancel-button}
</div>
</div>
${apply-info}
</div>
</message>
<message id="mediaDirectoryForm-template">
<legend>${title}</legend>
<div class="form-horizontal">
<div class="form-group">
<label class="control-label col-sm-2" for="${id:path}">
Path
</label>
<div class="col-sm-5">
${path}
</div>
<div class="help-block col-sm-5">
${path-info}
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="${id:type}">
Type
</label>
<div class="col-sm-5">
${type}
</div>
<div class="help-block col-sm-5">
${type-info}
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
${save-button} ${cancel-button}
</div>
</div>
${apply-info}
</div>
</message>
<message id="databaseForm-template">
<legend>${title}</legend>
<div class="form-horizontal">
<div class="form-group">
<label class="control-label col-sm-2" for="${id:update-period}">
Update period
</label>
<div class="col-sm-5">
${update-period}
</div>
<div class="help-block col-sm-5">
${update-period-info}
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="${id:update-start-time}">
Update start time
</label>
<div class="col-sm-5">
${update-start-time}
</div>
<div class="help-block col-sm-5">
${update-start-time-info}
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
${apply-button} ${discard-button} ${immediate-scan-button}
</div>
</div>
${apply-info}
</div>
</message>
<message id="mediaplayer-controls">
<div class="btn-group" role="group" aria-label="...">
${prev}
${play}
${pause}
${next}
</div>
</message>
<message id="mobile-search">
<div class="row">
<div class="col-xs-12">${search}</div>
</div>
</message>
<message id="mobile-search-title">
<div class="row">
<div class="col-xs-12">
<div class="mobile-search-title">${text}</div>
</div>
</div>
</message>
<message id="mobile-search-more">
<div class="row">
<div class="col-xs-12">
<div class="mobile-search-more vertical-align">${text}</div>
</div>
</div>
</message>
<message id="mobile-artist-res">
<div class="row">
<div class="col-xs-12">
<div class="mobile-search-entry">${name}</div>
</div>
</div>
</message>
<message id="mobile-release-res">
<div class="row">
<div class="col-xs-12">
<div class="mobile-search-entry">
<div class="row">
<div class ="vertical-align">
<div class="col-xs-2" style="margin-top:3px">${cover}</div>
<div class="col-xs-10">${name}</div>
</div>
</div>
</div>
</div>
</div>
</message>
<message id="mobile-track-res">
<div class="row">
<div class="col-xs-12">
<div class="mobile-search-entry">
<div class="row">
<div class="vertical-align">
<div class="col-xs-2" style="margin-top:3px">${cover}</div>
<div class="col-xs-7">${name}</div>
<div class="col-xs-3">${btn}</div>
</div>
</div>
</div>
</div>
</div>
</message>
<message id="mobile-audio-footer">
<nav class="navbar navbar-default navbar-fixed-bottom" role="navigation">
${player}
</nav>
</message>
<message id="mobile-audio-player">
<div class="container">
<div class="row">
<div class="col-xs-12">
<div class="row">
<div class="mobile-audio-footer">
<div class="vertical-align mobile-audio-footer">
<div class="col-xs-2">${cover}</div>
<div class="col-xs-7">
<div class="row">
<div class="col-xs-12">${track}</div>
</div>
<div class="row">
<div class="col-xs-12">${artist}</div>
</div>
</div>
<div class="col-xs-3">${play}${pause}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</message>
</messages>
-119
View File
@@ -1,119 +0,0 @@
.main-nav {
margin-bottom: 0px;
}
.Wt-hrh2 {
background-color: white;
}
.Wt-vrh2 {
background-color: white;
}
div.contents {
padding: 0px 12px 6px;
}
.playqueue {
background-color: #EEE;
border-radius: 10px;
}
.playqueue-playing {
font-weight: bold;
}
.playqueue-track {
font-size: 120%;
margin-top: 12px;
line-height: normal;
}
.playqueue-artist {
line-height: normal;
font-style: italic;
}
.playqueue-cover {
width: 64px;
height: 64px;
}
.mediaplayer {
background-color: #CCC;
border-radius: 10px;
min-width: 360px;
}
.mediaplayer-btn-controls {
font-weight: bold;
}
.mediaplayer-current-cover {
width: 72px;
height: 72px;
border-radius: 8px;
box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.5);
}
.mediaplayer-current-track {
font-weight: bold;
font-size: 120%;
}
.mediaplayer-current-artist {
font-style: italic;
}
.mobile-search-title {
font-weight: bold;
height: 32px;
line-height: 32px;
background-color: grey;
color: white;
text-align: center;
}
.mobile-search-entry {
min-height: 64px;
border-bottom: 1px solid lightgray;
overflow: hidden;
text-overflow: ellipsis;
}
.mobile-search-entry:active {
background-color: lightgrey;
}
.mobile-search-more {
height: 64px;
border-bottom: 1px solid lightgray;
}
.mobile-search-more:active {
background-color: lightgrey;
}
.mobile-track {
font-weight: bold;
}
.mobile-artist {
font-style: italic;
}
.vertical-align {
display: flex;
align-items: center;
}
.mobile-audio-footer {
background-color: #f5f5f5;
height: 60px;
}
.mobile-audio-player-cover {
width: 48px;
height: 48px;
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

+1 -1
View File
@@ -107,7 +107,7 @@ Settings::restartDatabaseUpdateService()
// Restarting the update service
boost::lock_guard<boost::mutex> serviceLock (Service::ServiceManager::instance().mutex());
Service::DatabaseUpdateService::pointer service = Service::ServiceManager::instance().getService<Service::DatabaseUpdateService>();
Service::DatabaseUpdateService::pointer service = Service::ServiceManager::instance().get<Service::DatabaseUpdateService>();
if (service)
service->restart();
}