diff --git a/Makefile.am b/Makefile.am index 28e6ebfb..4c5d337c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -34,6 +34,7 @@ lms_approot_DATA = \ approot/login.xml \ approot/mediaplayer.xml \ approot/messages.xml \ + approot/messages_fr.xml \ approot/playhistory.xml \ approot/playqueue.xml \ approot/release.xml \ diff --git a/approot/admin-user.xml b/approot/admin-user.xml index b74f00b4..754f7ab5 100644 --- a/approot/admin-user.xml +++ b/approot/admin-user.xml @@ -6,6 +6,16 @@

${title}

+ ${} +
+ +
+ ${last-login-attempt} +
+
+ ${
} ${}
diff --git a/approot/messages.xml b/approot/messages.xml index cc421dab..3d056f79 100644 --- a/approot/messages.xml +++ b/approot/messages.xml @@ -49,6 +49,7 @@ Demo account Demo account already exists! Demo password must be the login name! +Last login attempt User already exists! New user New user created! @@ -84,7 +85,7 @@ Recently added -Top releases +Top albums Recently added @@ -118,4 +119,9 @@ WEBMA New settings saved! + + + + + diff --git a/approot/messages_fr.xml b/approot/messages_fr.xml new file mode 100644 index 00000000..0a2690f8 --- /dev/null +++ b/approot/messages_fr.xml @@ -0,0 +1,132 @@ + + + + +Ajouter +Appliquer +Annuler +Administration +Annuler +Créer +Login +Logout +N'est pas un répertoire +Mot de passe +Confirmation du mot de passe +Les mots de passe ne correspondent pas +Êtes-vous sûr ? +Une autre session a été ouverte. Reouvrir celle-ci ? +Sauvegarder + + +Tous les jours +Base de données +Scanner maintenant ! +Tous les mois +Jamais +Dossier racine des fichiers de musique +Scan terminé : {1} fichiers, {2} ajouts, {3} mises à jour, {4} suppressions, {5} duplicatas, {6} erreurs +Scan lancé ! +Options +Nouveaux paramètres sauvegardés ! +Tags +Périodicité des mises à jour +Heure de départ de la mise à jour +Toutes les semaines + + +Ajouter +Admin +Supprimer +Supprimer l'utilisateur +Supprimer l'utilisateur ? +Demo +Editer +Utilisateurs + + +Limite du bitrate +Compte de démonstration +Le compte de démonstration existe déjà ! +Le password doit être égal au login ! +Dernière tentative de login +L'utilisateur existe déjà ! +Nouvel utilisateur +Nouvel utilisateur créé ! +Utilisateur {1} +L'utilisateur a été mis à jour ! + + +Le compte d'administration a été créé. Rafraichissez la page pour continuer ! +Creation du compte administrateur + + +Se souvenir de moi +Bienvenue ! + + +Ajouter filtre +Artistes +Filtres +Albums +Rechercher... +Montrer plus +Pistes +Type +Valeur +Artistes divers + + +Ajouts récents +Artistes populaires + + +Copyright + + +Ajouts récents +Albums populaires + + +Ajouts récents +Pistes populaires + + + +Effacer +{1} pistes +{1} pistes ajoutées +{1} pistes ajouées +Liste de lecture +Mode radio +Repéter +Mélanger + + +Historique de lecture + + + +Compte +Audio +Auto +Bitrate +Impossible de sauvegarder en utilisant un compte de démo ! +Encodage +MP3 +OGA +Paramètres +WEBMA +Paramètres sauvegardés ! + + +Oui +Non + + + +Invalide + +Mot de passe invalide + + diff --git a/approot/release.xml b/approot/release.xml index ea9191ec..0824a57b 100644 --- a/approot/release.xml +++ b/approot/release.xml @@ -2,6 +2,10 @@ + + + +
diff --git a/docroot/css/lms.css b/docroot/css/lms.css index 7bf20079..0485a49b 100644 --- a/docroot/css/lms.css +++ b/docroot/css/lms.css @@ -158,7 +158,7 @@ a:hover { } .Lms-explore-release-entry-controls { - text-align: center; + text-align: right; } .Lms-explore-release-entry-playing { @@ -202,7 +202,7 @@ a:hover { } .Lms-explore-tracks-entry-controls { - text-align: center; + text-align: right; } .Lms-explore-tracksinfo-entry { @@ -235,7 +235,7 @@ a:hover { } .Lms-playqueue-entry-controls { - text-align: center; + text-align: right; } .Lms-playqueue-btn { diff --git a/src/database/DatabaseHandler.cpp b/src/database/DatabaseHandler.cpp index 1473d7d1..4645d464 100644 --- a/src/database/DatabaseHandler.cpp +++ b/src/database/DatabaseHandler.cpp @@ -54,6 +54,7 @@ Handler::configureAuth(void) { authService.setEmailVerificationEnabled(false); authService.setAuthTokensEnabled(true, "lmsauth"); + authService.setAuthTokenValidity(24 * 60 * 365); // A year authService.setIdentityPolicy(Wt::Auth::IdentityPolicy::LoginName); authService.setRandomTokenLength(32); diff --git a/src/database/Track.hpp b/src/database/Track.hpp index e16b54d3..18c96618 100644 --- a/src/database/Track.hpp +++ b/src/database/Track.hpp @@ -95,6 +95,7 @@ class Track : public Wt::Dbo::Dbo void setCopyrightURL(const std::string& copyrightURL) { _copyrightURL = std::string(copyrightURL, 0, _maxCopyrightURLLength); } void setArtist(Wt::Dbo::ptr artist) { _artist = artist; } void setRelease(Wt::Dbo::ptr release) { _release = release; } + void eraseClusters() { _clusters.clear(); } std::size_t getScanVersion() const { return _scanVersion; } boost::optional getTrackNumber() const; diff --git a/src/database/User.cpp b/src/database/User.cpp index d108e103..1fc4b460 100644 --- a/src/database/User.cpp +++ b/src/database/User.cpp @@ -35,11 +35,7 @@ User::audioBitrates = }; User::User() -: _maxAudioBitrate(audioBitrates.back()), -_type(Type::REGULAR), -_audioBitrate(defaultAudioBitrate), -_audioEncoding(AudioEncoding::AUTO), -_curPlayingTrackPos(0) +: _maxAudioBitrate(audioBitrates.back()) { } diff --git a/src/database/User.hpp b/src/database/User.hpp index cd3aa01a..83188d96 100644 --- a/src/database/User.hpp +++ b/src/database/User.hpp @@ -76,6 +76,8 @@ class User : public Wt::Dbo::Dbo void setAudioEncoding(AudioEncoding encoding) { _audioEncoding = encoding; } void setMaxAudioBitrate(std::size_t bitrate); void setCurPlayingTrackPos(std::size_t pos) { _curPlayingTrackPos = pos; } + void setRadio(bool val) { _radio = val; } + void setRepeatAll(bool val) { _repeatAll = val; } // read bool isAdmin() const { return _type == Type::ADMIN; } @@ -84,6 +86,8 @@ class User : public Wt::Dbo::Dbo AudioEncoding getAudioEncoding() const { return _audioEncoding; } std::size_t getMaxAudioBitrate() const; std::size_t getCurPlayingTrackPos() const { return _curPlayingTrackPos; } + bool isRepeatAllSet() const { return _repeatAll; } + bool isRadioSet() const { return _radio; } Wt::Dbo::ptr getQueuedTrackList() const; Wt::Dbo::ptr getPlayedTrackList() const; @@ -97,6 +101,8 @@ class User : public Wt::Dbo::Dbo Wt::Dbo::field(a, _audioEncoding, "audio_encoding"); // User's dynamic data Wt::Dbo::field(a, _curPlayingTrackPos, "cur_playing_track_pos"); + Wt::Dbo::field(a, _repeatAll, "repeat_all"); + Wt::Dbo::field(a, _radio, "radio"); Wt::Dbo::hasMany(a, _tracklists, Wt::Dbo::ManyToOne, "user"); } @@ -106,14 +112,16 @@ class User : public Wt::Dbo::Dbo // Admin defined settings int _maxAudioBitrate; - Type _type; + Type _type = Type::REGULAR; // User defined settings - int _audioBitrate; - AudioEncoding _audioEncoding; + int _audioBitrate = defaultAudioBitrate; + AudioEncoding _audioEncoding = AudioEncoding::AUTO; // User's dynamic data - int _curPlayingTrackPos; // Current track position in queue + int _curPlayingTrackPos = 0; // Current track position in queue + bool _repeatAll = false; + bool _radio = false; Wt::Dbo::collection< Wt::Dbo::ptr > _tracklists; diff --git a/src/scanner/MediaScanner.cpp b/src/scanner/MediaScanner.cpp index 28d54b7f..a6b0ec59 100644 --- a/src/scanner/MediaScanner.cpp +++ b/src/scanner/MediaScanner.cpp @@ -504,8 +504,7 @@ MediaScanner::scanAudioFile(const boost::filesystem::path& file, bool forceScan, LMS_LOG(DBUPDATER, INFO) << "Updating '" << file.string() << "'"; // Remove the songs from its clusters - for (auto cluster : track->getClusters()) - cluster.remove(); + track.modify()->eraseClusters(); stats.updates++; } diff --git a/src/ui/LmsApplication.cpp b/src/ui/LmsApplication.cpp index 9d49104d..2116765e 100644 --- a/src/ui/LmsApplication.cpp +++ b/src/ui/LmsApplication.cpp @@ -85,6 +85,8 @@ LmsApplication::LmsApplication(const Wt::WEnvironment& env, Wt::Dbo::SqlConnecti bootstrapTheme->setResponsive(true); setTheme(std::move(bootstrapTheme)); + addMetaHeader(Wt::MetaHeaderType::Meta, "viewport", "width=device-width, user-scalable=no"); + useStyleSheet("css/lms.css"); useStyleSheet("resources/font-awesome/css/font-awesome.min.css"); diff --git a/src/ui/PlayQueueView.cpp b/src/ui/PlayQueueView.cpp index 3715e8b7..0ee9fd88 100644 --- a/src/ui/PlayQueueView.cpp +++ b/src/ui/PlayQueueView.cpp @@ -30,7 +30,6 @@ #include "LmsApplication.hpp" - namespace UserInterface { PlayQueue::PlayQueue() @@ -38,6 +37,12 @@ PlayQueue::PlayQueue() { addFunction("tr", &Wt::WTemplate::Functions::tr); + { + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); + _repeatAll = LmsApp->getUser()->isRepeatAllSet(); + _radioMode = LmsApp->getUser()->isRadioSet(); + } + Wt::WText* clearBtn = bindNew("clear-btn", Wt::WString::tr("Lms.PlayQueue.template.clear-btn"), Wt::TextFormat::XHTML); clearBtn->setToolTip(Wt::WString::tr("Lms.PlayQueue.clear")); clearBtn->clicked().connect([=] @@ -68,21 +73,33 @@ PlayQueue::PlayQueue() addSome(); }); - Wt::WText* repeatBtn = bindNew("repeat-btn", Wt::WString::tr("Lms.PlayQueue.template.repeat-btn"), Wt::TextFormat::XHTML); - repeatBtn->setToolTip(Wt::WString::tr("Lms.PlayQueue.repeat")); - repeatBtn->clicked().connect([=] + _repeatBtn = bindNew("repeat-btn", Wt::WString::tr("Lms.PlayQueue.template.repeat-btn"), Wt::TextFormat::XHTML); + _repeatBtn->setToolTip(Wt::WString::tr("Lms.PlayQueue.repeat")); + _repeatBtn->clicked().connect([=] { _repeatAll = !_repeatAll; - repeatBtn->toggleStyleClass("Lms-playqueue-btn-selected", _repeatAll); - }); + updateRepeatBtn(); - Wt::WText* radioBtn = bindNew("radio-btn", Wt::WString::tr("Lms.PlayQueue.template.radio-btn")); - radioBtn->setToolTip(Wt::WString::tr("Lms.PlayQueue.radio-mode")); - radioBtn->clicked().connect([=] + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); + + if (!LmsApp->getUser()->isDemo()) + LmsApp->getUser().modify()->setRepeatAll(_repeatAll); + }); + updateRepeatBtn(); + + _radioBtn = bindNew("radio-btn", Wt::WString::tr("Lms.PlayQueue.template.radio-btn")); + _radioBtn->setToolTip(Wt::WString::tr("Lms.PlayQueue.radio-mode")); + _radioBtn->clicked().connect([=] { _radioMode = !_radioMode; - radioBtn->toggleStyleClass("Lms-playqueue-btn-selected", _radioMode); + updateRadioBtn(); + + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); + + if (!LmsApp->getUser()->isDemo()) + LmsApp->getUser().modify()->setRadio(_radioMode); }); + updateRadioBtn(); _nbTracks = bindNew("nb-tracks"); @@ -103,15 +120,31 @@ PlayQueue::PlayQueue() updateInfo(); addSome(); - if (!LmsApp->getUser()->isDemo()) { - LmsApp->post([=] + Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); + + if (!LmsApp->getUser()->isDemo()) { - load(LmsApp->getUser()->getCurPlayingTrackPos(), false); - }); + LmsApp->post([=] + { + load(LmsApp->getUser()->getCurPlayingTrackPos(), false); + }); + } } } +void +PlayQueue::updateRepeatBtn() +{ + _repeatBtn->toggleStyleClass("Lms-playqueue-btn-selected", _repeatAll); +} + +void +PlayQueue::updateRadioBtn() +{ + _radioBtn->toggleStyleClass("Lms-playqueue-btn-selected",_radioMode); +} + Database::TrackList::pointer PlayQueue::getTrackList() { diff --git a/src/ui/PlayQueueView.hpp b/src/ui/PlayQueueView.hpp index 03d27f55..be0f7b19 100644 --- a/src/ui/PlayQueueView.hpp +++ b/src/ui/PlayQueueView.hpp @@ -63,6 +63,8 @@ class PlayQueue : public Wt::WTemplate void addRadioTrack(); void updateInfo(); void updateCurrentTrack(bool selected); + void updateRepeatBtn(); + void updateRadioBtn(); void load(std::size_t pos, bool play); void stop(); @@ -70,9 +72,11 @@ class PlayQueue : public Wt::WTemplate bool _repeatAll = false; bool _radioMode = false; boost::optional _tracklistId; - Wt::WContainerWidget* _entriesContainer; - Wt::WPushButton* _showMore; - Wt::WText* _nbTracks; + Wt::WContainerWidget* _entriesContainer = nullptr; + Wt::WPushButton* _showMore = nullptr; + Wt::WText* _nbTracks = nullptr; + Wt::WText* _repeatBtn = nullptr; + Wt::WText* _radioBtn = nullptr; boost::optional _trackPos; // current track position, if set }; diff --git a/src/ui/admin/UserView.cpp b/src/ui/admin/UserView.cpp index 07fdc8f7..de075452 100644 --- a/src/ui/admin/UserView.cpp +++ b/src/ui/admin/UserView.cpp @@ -274,6 +274,11 @@ UserView::refreshView() 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::TextFormat::Plain); + t->setCondition("if-has-last-login-attempt", true); + + Wt::WLineEdit *lastLoginAttempt = t->bindNew("last-login-attempt"); + lastLoginAttempt->setText(authUser.lastLoginAttempt().toString()); + lastLoginAttempt->setEnabled(false); } else { diff --git a/src/ui/explore/ReleaseView.cpp b/src/ui/explore/ReleaseView.cpp index f03ff4a0..e1c0e139 100644 --- a/src/ui/explore/ReleaseView.cpp +++ b/src/ui/explore/ReleaseView.cpp @@ -106,8 +106,8 @@ Release::refresh() Wt::WLink link(*copyrightURL); link.setTarget(Wt::LinkTarget::NewWindow); Wt::WAnchor* anchor = t->bindNew("copyright-url", link); - anchor->setTextFormat(Wt::TextFormat::Plain); - anchor->setText(Wt::WString::fromUTF8(*copyrightURL)); + anchor->setTextFormat(Wt::TextFormat::XHTML); + anchor->setText(Wt::WString::tr("Lms.Explore.Release.template.link-btn")); } if (copyright) diff --git a/tools/metadata/LmsMetadata.cpp b/tools/metadata/LmsMetadata.cpp index 6afd04ba..b67f8fdf 100644 --- a/tools/metadata/LmsMetadata.cpp +++ b/tools/metadata/LmsMetadata.cpp @@ -20,6 +20,8 @@ int main(int argc, char *argv[]) { MetaData::TagLibParser parser; + parser.setClusterTypeNames( {"MOOD", "GENRE"} ); + boost::optional items = parser.parse(argv[1], true); if (!items) {