From d4e60a9e3ea4d40997438c257efd15e3fd118fd3 Mon Sep 17 00:00:00 2001 From: David Roman Date: Tue, 7 May 2024 14:33:18 +0200 Subject: [PATCH 01/14] UpperCaseValidator: add missing header --- src/lms/ui/common/UppercaseValidator.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lms/ui/common/UppercaseValidator.cpp b/src/lms/ui/common/UppercaseValidator.cpp index 7bb3dbf6..5d872a0f 100644 --- a/src/lms/ui/common/UppercaseValidator.cpp +++ b/src/lms/ui/common/UppercaseValidator.cpp @@ -19,6 +19,7 @@ #include "UppercaseValidator.hpp" +#include #include #include From 2bbf15c41342eacb6ad4b807a77b53a5f89e8fef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Moczulski?= Date: Tue, 7 May 2024 15:38:19 +0200 Subject: [PATCH 02/14] Add polish localization. --- approot/messages_pl.xml | 344 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 344 insertions(+) create mode 100644 approot/messages_pl.xml diff --git a/approot/messages_pl.xml b/approot/messages_pl.xml new file mode 100644 index 00000000..2707e0b3 --- /dev/null +++ b/approot/messages_pl.xml @@ -0,0 +1,344 @@ + + + + +Dodaj +Zarządzanie +Cofnij +Znaczniki +Utwórz +Usuń +Odrzuć +Zmień +Wartość musi się zaczynać wielką literą +Wczytywanie... +Login + Wyloguj +Ok +Hasło +Błędny login lub hasło +Logowanie spowolnione, spróbuj później +Potwierdź hasło +Hasło musi się zgadzać z loginem! +Nowe hasło +Stare hasło +Hasło zbyt słabe +Hasła się nie zgadzają +Rozpoczęto inną sesję. Odtworzyć tę? +Zapisz +Ustawienia zapisane! + + {1} ścieżka + {1} ścieżki + {1} ścieżek + +Użytkownik + + +Artysta nie odnaleziony +Wystąpił błąd! +Strona główna +Wydanie nie odnalezione +Lista odtwarzania nie odnaleziona +Brak uprawnień by wykonać tę operację +Użytkownik nie odnaleziony + + + Biblioteki + Ustawienia skanowania + Skaner + Śledzenie + Użytkownicy + + +Biblioteki muzyczne +Utwórz bibliotekę +Usunąć bibliotekę? +Edytuj bibliotekę +Biblioteka utworzona! +Biblioteka usunięta! +Nazwa biblioteki +Nazwa biblioteki już istnieje +Ścieżka musi być bezwzględna +Ścieżka nie może się zazębiać z innymi bibliotekami +Ścieżka musi prowadzić do istniejącego katalogu +Katalog główny + + +Znak rozdzielający artystów +Codziennie +Znak rozdzielający inne oznaczenia +Szukaj dodatkowych znaczników (użyj ; do rozdzielania) +Co godzinę +Skanuj teraz! +Co miesiąc +Nigdy +Skanowanie przerwane! +Skanowanie ukończone: {1} wszystkich plików, {2} dodane, {3} zmienione, {4} usunięte, {5} duplikaty, {6} błędy +Skanowanie uruchomione! +Ustawienia skanowania +Metoda sprawdzania podobieństwa +Oparta o znaczniki +Żadna +Rozdzielacz nie może się składać z samych białych znaków +Okres aktualizacji +Czas startu aktualizacji +Co tydzień + + +Nie udało się ustalić długości ścieżki +Nie udało się przeparsować pliku +Nie udało się odczytać pliku +Sprasuj bazę danych. Uwaga: może to trochę zająć, a cała aplikacja będzie w tym czasie zablokowana! + + {1} zduplikowany plik: + {1} zduplikowane pliki: + {1} zduplikowanych plików: + + + {1} błąd: + {1} błędy: + {1} błędów: + +Wymuś optymalizację bazy danych +Ponownie przeskanuj wszystkie pliki +Pokaż raport +Ostatnie skanowanie +Niedostępne +Przeskanowano {1} plików w {2} o {3} ({4} błędów, {5} duplikatów) +Brak ścieżki dźwiękowej +Zduplikowny hash pliku +Zduplikowany MBID pliku +Skanuj teraz +Opcje skanowania +Skaner +Status +Nie zaplanowano +Zaplanowano na {1} +Skanowanie: krok {1}/{2} + + Sprawdzanie duplikatów... {1} plik + Sprawdzanie duplikatów... {1} pliki + Sprawdzanie duplikatów... {1} plików + +Sprawdzanie plików... {1}% +Prasowanie bazy danych... +Obliczanie statystyk... {1}% + + Odkrywanie plików: {1} plik + Odkrywanie plików: {1} pliki + Odkrywanie plików: {1} plików + +Pobieranie danych o ścieżce z AcousticBrainz: {1}/{2} ścieżek ({3}%)... +Optymalizowanie bazy danych... {1}/{2} wpisów ({3}%)... +Przeładowywanie silnika podobieństw: {1}%... +Skanowanie plików: {1}/{2} plików ({3}%)... +Obecny krok + + +Eksportuj ślady +Śledzenie + + +Nowy użytkownik +Admin +Usunąć użytkownika? +Demo +Użytkownicy + + +Konto demonstacyjne +Konto demonstacyjne już istnieje! +Ostatnie logowanie +Użytkownik już istnieje! +Nowy użytkownik +Użytkownik utworzony! +Użytkownik "{1}" +Użytkownik zaktualizowany! + + +Konto administratora utworzone. Proszę odświerzyć stronę! +Utwórz konto administratora + + +Zapamiętaj mnie +Witam! + + +Dodaj filtr +Wszystko +Artyści +Przepływność +Kodek +Pobierz +Długość +Filtr dodany +Filtry +Biblioteka muzyczna +Najczęściej odtwarzane +Artysta w MusicBrainz +Wydanie w MusicBrainz +Odtwarzaj +Odtwórz na końcu +Odtwórz po obecnym +Odtwarzaj losowo +Liczba odtworzeń +Losowo +Ostatnio dodane +Ostatnio zmienione +Ostatnio odtwarzane +Informacje o wydaniu +Albumy +Szukaj +Wyróżnij +Wyróżnione +Informacje o ścieżce +Listy odtwarzania +Ścieżki +Rodzaj +Przestań wyróżniać +Wartość +Różni artyści + + +Pojawia się na +Podobni artyści + + +Wszyscy artyści + + Artysta ze ścieżki + Artyści ze ścieżki + Artyści ze ścieżki + + + Kompozytor + Kompozytorzy + Kompozytorzy + + + Dyrygent + Dyrygenci + Dyrygenci + + + Tekściarz + Tekściarze + Tekściarze + + + Realizator + Realizatorzy + Realizatorzy + + + Wykonawca + Wykonawcy + Wykonawcy + + + Producent + Producenci + Producenci + + + Artysta z albumu + Artyści z albumu + Artyści z albumu + + + Remixer + Remikserzy + Remikserzy + + + +Podobne albumy +Prawa autorskie +Dysk {1} +Typ +Album +Audycja +EP +Inny +Singiel +Audiobook +Audiodrama +Kompilacja +Demo +DJ-mix +Nagranie polowe +Wywiad +Na żywo +Mixtape/Street +Remix +Ścieżka dźwiękowa +Mówione + + +Usunąć listę odtwarzania? + + +Szukaj... + + +Transkodowanie włączone + + +Wyczyść +Utwórz nową listę odtwarzania +Odtwarzaj kolejkę +Tryb radiowy +Powtarzaj +Zastąp obecną listę +Przemieszaj + + +Historia odtwarzania + + +Dźwięk +Te ustawienia dotyczą wyłącznie tej przeglądarki! +Wewnętrzny +ListenBrainz +ListenBrainz API token +Zmień hasło +Domyślna przepływność transkodowania +Domyślny format wyjściowy transkodowania +Nie można zapisywać na koncie demonstracyjnym! +Aktywuj domyślnie transkodowanie +Feedback + Ustawienia +Błędne hasło +Należy podać stare hasło +Tryb ReplayGain +Bez ReplayGain +Auto +Ścieżka +Album +ReplayGain preamp +ReplayGain preamp (jeśli brak informacji) +Scrobbling +Usługi +Ustawienia +Tryb listy artystów +Wszyscy artyści +Artyści z albumów +Artyści ze ścieżek +Subsonic API +Transkodowanie +Przepływność transkodowania +Format wyjściowy transkodowania +Matroska/Opus +MP3 +Ogg/Opus +Ogg/Vorbis +WebM/Vorbis +Aktywuj transkodowanie +Zawsze +Tylko gdy przeglądarka nie wspiera formatu +Nigdy +Ustawienia zapisane! + + From c6104c06eafa9e1ee0b2b0fc4d51d959c70e6767 Mon Sep 17 00:00:00 2001 From: emeric Date: Wed, 8 May 2024 16:01:16 +0200 Subject: [PATCH 03/14] Added a unit test to check for migration --- src/libs/database/impl/Session.cpp | 5 + .../database/include/database/Session.hpp | 2 + src/libs/database/test/CMakeLists.txt | 1 + src/libs/database/test/Migration.cpp | 324 ++++++++++++++++++ 4 files changed, 332 insertions(+) create mode 100644 src/libs/database/test/Migration.cpp diff --git a/src/libs/database/impl/Session.cpp b/src/libs/database/impl/Session.cpp index 8201588c..97ea7126 100644 --- a/src/libs/database/impl/Session.cpp +++ b/src/libs/database/impl/Session.cpp @@ -121,6 +121,11 @@ namespace lms::db return ReadTransaction{ _session }; } + void Session::execute(std::string_view statement) + { + _session.execute(std::string{ statement }); + } + void Session::prepareTablesIfNeeded() { LMS_LOG(DB, INFO, "Preparing tables..."); diff --git a/src/libs/database/include/database/Session.hpp b/src/libs/database/include/database/Session.hpp index 7983e5d5..cecc7225 100644 --- a/src/libs/database/include/database/Session.hpp +++ b/src/libs/database/include/database/Session.hpp @@ -86,6 +86,8 @@ namespace lms::db #endif } + void execute(std::string_view statement); + // All these methods will acquire transactions void fullAnalyze(); // helper for retrieveEntriesToAnalyze + analyzeEntry void retrieveEntriesToAnalyze(std::vector& entryList); diff --git a/src/libs/database/test/CMakeLists.txt b/src/libs/database/test/CMakeLists.txt index 4ce77ebe..451581c8 100644 --- a/src/libs/database/test/CMakeLists.txt +++ b/src/libs/database/test/CMakeLists.txt @@ -5,6 +5,7 @@ add_executable(test-database Common.cpp DatabaseTest.cpp Listen.cpp + Migration.cpp Release.cpp StarredArtist.cpp StarredRelease.cpp diff --git a/src/libs/database/test/Migration.cpp b/src/libs/database/test/Migration.cpp new file mode 100644 index 00000000..69a9970c --- /dev/null +++ b/src/libs/database/test/Migration.cpp @@ -0,0 +1,324 @@ +/* + * Copyright (C) 2021 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 "Common.hpp" +#include "core/String.hpp" +#include "database/Db.hpp" + +namespace lms::db::tests +{ + namespace + { + void executeStatements(db::Session& session, std::string_view statements) + { + auto transaction{ session.createWriteTransaction() }; + + for (std::string_view statement : core::stringUtils::splitString(statements, ';')) + { + statement = core::stringUtils::stringTrim(statement, " \t\r\n"); + if (!statement.empty()) + session.execute(statement); + } + } + } + + TEST(Database, migration) + { + TmpDatabase tmpDatabase; + + auto& db{ tmpDatabase.getDb() }; + + // Create tables and indexes as they were in version 33: + const std::string_view schemaV33{ R"( +CREATE TABLE IF NOT EXISTS "cluster_type" ( + "id" integer primary key autoincrement, + "version" integer not null, + "name" text not null, + "scan_settings_id" bigint, + constraint "fk_cluster_type_scan_settings" foreign key ("scan_settings_id") references "scan_settings" ("id") on delete cascade deferrable initially deferred +); +CREATE TABLE IF NOT EXISTS "version_info" ( + "id" integer primary key autoincrement, + "version" integer not null, + "db_version" integer not null +); +CREATE TABLE IF NOT EXISTS "scan_settings" ( + "id" integer primary key autoincrement, + "version" integer not null, + "scan_version" integer not null, + "media_directory" text not null, + "start_time" integer, + "update_period" integer not null, + "audio_file_extensions" text not null, + "similarity_engine_type" integer not null +); +CREATE TABLE IF NOT EXISTS "track_features" ( + "id" integer primary key autoincrement, + "version" integer not null, + "data" text not null, + "track_id" bigint, + constraint "fk_track_features_track" foreign key ("track_id") references "track" ("id") on delete cascade deferrable initially deferred +); +CREATE TABLE IF NOT EXISTS "tracklist_entry" ( + "id" integer primary key autoincrement, + "version" integer not null, + "track_id" bigint, + "tracklist_id" bigint, date_time TEXT, + constraint "fk_tracklist_entry_track" foreign key ("track_id") references "track" ("id") on delete cascade deferrable initially deferred, + constraint "fk_tracklist_entry_tracklist" foreign key ("tracklist_id") references "tracklist" ("id") on delete cascade deferrable initially deferred +); +CREATE TABLE IF NOT EXISTS "track_artist_link" ( + "id" integer primary key autoincrement, + "version" integer not null, + "type" integer not null, + "name" integer not null, + "track_id" bigint, + "artist_id" bigint, + constraint "fk_track_artist_link_track" foreign key ("track_id") references "track" ("id") on delete cascade deferrable initially deferred, + constraint "fk_track_artist_link_artist" foreign key ("artist_id") references "artist" ("id") on delete cascade deferrable initially deferred +); +CREATE TABLE IF NOT EXISTS "artist" ( + "id" integer primary key autoincrement, + "version" integer not null, + "name" text not null, + "sort_name" text not null, + "mbid" text not null +); +CREATE TABLE IF NOT EXISTS "cluster" ( + "id" integer primary key autoincrement, + "version" integer not null, + "name" text not null, + "cluster_type_id" bigint, + constraint "fk_cluster_cluster_type" foreign key ("cluster_type_id") references "cluster_type" ("id") on delete cascade deferrable initially deferred +); +CREATE TABLE IF NOT EXISTS "auth_token" ( + "id" integer primary key autoincrement, + "version" integer not null, + "value" text not null, + "expiry" text, + "user_id" bigint, + constraint "fk_auth_token_user" foreign key ("user_id") references "user" ("id") on delete cascade deferrable initially deferred +); +CREATE TABLE IF NOT EXISTS "tracklist" ( + "id" integer primary key autoincrement, + "version" integer not null, + "name" text not null, + "type" integer not null, + "public" boolean not null, + "user_id" bigint, + constraint "fk_tracklist_user" foreign key ("user_id") references "user" ("id") on delete cascade deferrable initially deferred +); +CREATE TABLE IF NOT EXISTS "track_cluster" ( + "track_id" bigint, + "cluster_id" bigint, + primary key ("track_id", "cluster_id"), + constraint "fk_track_cluster_key1" foreign key ("track_id") references "track" ("id") on delete cascade deferrable initially deferred, + constraint "fk_track_cluster_key2" foreign key ("cluster_id") references "cluster" ("id") on delete cascade deferrable initially deferred +); +CREATE TABLE IF NOT EXISTS "track_bookmark" ( + "id" integer primary key autoincrement, + "version" integer not null, + "offset" integer, + "comment" text not null, + "track_id" bigint, + "user_id" bigint, + constraint "fk_track_bookmark_track" foreign key ("track_id") references "track" ("id") on delete cascade deferrable initially deferred, + constraint "fk_track_bookmark_user" foreign key ("user_id") references "user" ("id") on delete cascade deferrable initially deferred +); +CREATE TABLE IF NOT EXISTS "release" ( + "id" integer primary key autoincrement, + "version" integer not null, + "name" text not null, + "mbid" text not null +); +CREATE INDEX "track_cluster_track" on "track_cluster" ("track_id"); +CREATE INDEX "track_cluster_cluster" on "track_cluster" ("cluster_id"); +CREATE INDEX artist_name_idx ON artist(name); +CREATE INDEX artist_sort_name_nocase_idx ON artist(sort_name COLLATE NOCASE); +CREATE INDEX artist_mbid_idx ON artist(mbid); +CREATE INDEX auth_token_user_idx ON auth_token(user_id); +CREATE INDEX auth_token_expiry_idx ON auth_token(expiry); +CREATE INDEX auth_token_value_idx ON auth_token(value); +CREATE INDEX cluster_name_idx ON cluster(name); +CREATE INDEX cluster_cluster_type_idx ON cluster(cluster_type_id); +CREATE INDEX cluster_type_name_idx ON cluster_type(name); +CREATE INDEX tracklist_name_idx ON tracklist(name); +CREATE INDEX tracklist_user_idx ON tracklist(user_id); +CREATE INDEX track_features_track_idx ON track_features(track_id); +CREATE INDEX track_artist_link_artist_idx ON track_artist_link(artist_id); +CREATE INDEX track_artist_link_name_idx ON track_artist_link(name); +CREATE INDEX track_artist_link_track_idx ON track_artist_link(track_id); +CREATE INDEX track_artist_link_type_idx ON track_artist_link(type); +CREATE INDEX track_bookmark_track_idx ON track_bookmark(track_id); +CREATE INDEX track_bookmark_user_idx ON track_bookmark(user_id); +CREATE INDEX track_bookmark_user_track_idx ON track_bookmark(user_id,track_id); +CREATE INDEX release_name_idx ON release(name); +CREATE INDEX release_name_nocase_idx ON release(name COLLATE NOCASE); +CREATE INDEX release_mbid_idx ON release(mbid); +CREATE INDEX tracklist_entry_track_idx ON tracklist_entry(track_id); +CREATE TABLE IF NOT EXISTS "user" ( + "id" integer primary key autoincrement, + "version" integer not null, + "type" integer not null, + "login_name" text not null, + "password_salt" text not null, + "password_hash" text not null, + "last_login" text, + "subsonic_transcode_enable" boolean not null, + "subsonic_transcode_format" integer not null, + "subsonic_transcode_bitrate" integer not null, + "subsonic_artist_list_mode" integer not null, + "ui_theme" integer not null, + "cur_playing_track_pos" integer not null, + "repeat_all" boolean not null, + "radio" boolean not null +, listenbrainz_token TEXT, scrobbler INTEGER NOT NULL DEFAULT(0)); +CREATE TABLE IF NOT EXISTS "track" ( + "id" integer primary key autoincrement, + "version" integer not null, + "scan_version" integer not null, + "track_number" integer not null, + "disc_number" integer not null, + "name" text not null, + "duration" integer, + "date" integer text, + "original_date" integer text, + "file_path" text not null, + "file_last_write" text, + "file_added" text, + "has_cover" boolean not null, + "mbid" text not null, + "copyright" text not null, + "copyright_url" text not null, + "release_id" bigint, total_disc INTEGER NOT NULL DEFAULT(0), total_track INTEGER NOT NULL DEFAULT(0), track_replay_gain REAL, release_replay_gain REAL, disc_subtitle TEXT NOT NULL DEFAULT '', recording_mbid TEXT, + constraint "fk_track_release" foreign key ("release_id") references "release" ("id") on delete cascade deferrable initially deferred +); +CREATE INDEX track_file_last_write_idx ON track(file_last_write); +CREATE INDEX track_path_idx ON track(file_path); +CREATE INDEX track_name_idx ON track(name); +CREATE INDEX track_name_nocase_idx ON track(name COLLATE NOCASE); +CREATE INDEX track_mbid_idx ON track(mbid); +CREATE INDEX track_recording_mbid_idx ON track(recording_mbid); +CREATE INDEX track_release_idx ON track(release_id); +CREATE INDEX track_date_idx ON track(date); +CREATE INDEX track_original_date_idx ON track(original_date); +CREATE TABLE IF NOT EXISTS "starred_artist" ( + "id" integer primary key autoincrement, + "version" integer not null, + "scrobbler" integer not null, + "date_time" text, + "artist_id" bigint, + "user_id" bigint, + constraint "fk_starred_artist_artist" foreign key ("artist_id") references "artist" ("id") on delete cascade deferrable initially deferred, + constraint "fk_starred_artist_user" foreign key ("user_id") references "user" ("id") on delete cascade deferrable initially deferred +); +CREATE TABLE IF NOT EXISTS "starred_release" ( + "id" integer primary key autoincrement, + "version" integer not null, + "scrobbler" integer not null, + "date_time" text, + "release_id" bigint, + "user_id" bigint, + constraint "fk_starred_release_release" foreign key ("release_id") references "release" ("id") on delete cascade deferrable initially deferred, + constraint "fk_starred_release_user" foreign key ("user_id") references "user" ("id") on delete cascade deferrable initially deferred +); +CREATE TABLE IF NOT EXISTS "starred_track" ( + "id" integer primary key autoincrement, + "version" integer not null, + "scrobbler" integer not null, + "date_time" text, + "track_id" bigint, + "user_id" bigint, + constraint "fk_starred_track_track" foreign key ("track_id") references "track" ("id") on delete cascade deferrable initially deferred, + constraint "fk_starred_track_user" foreign key ("user_id") references "user" ("id") on delete cascade deferrable initially deferred +); +CREATE TABLE IF NOT EXISTS "listen" ( + "id" integer primary key autoincrement, + "version" integer not null, + "date_time" text, + "scrobbler" integer not null, + "scrobbling_state" integer not null, + "track_id" bigint, + "user_id" bigint, + constraint "fk_listen_track" foreign key ("track_id") references "track" ("id") on delete cascade deferrable initially deferred, + constraint "fk_listen_user" foreign key ("user_id") references "user" ("id") on delete cascade deferrable initially deferred +); +CREATE INDEX listen_scrobbler_idx ON listen(scrobbler); +CREATE INDEX listen_user_scrobbler_idx ON listen(user_id,scrobbler); +CREATE INDEX starred_artist_user_scrobbler_idx ON starred_artist(user_id,scrobbler); +CREATE INDEX starred_release_user_scrobbler_idx ON starred_release(user_id,scrobbler); +CREATE INDEX starred_track_user_scrobbler_idx ON starred_track(user_id,scrobbler);)" }; + + const std::string_view createDummyData{R"( +-- Inserting artists +INSERT INTO artist (version, name, sort_name, mbid) VALUES +(1, 'Artist A', 'Artist A', 'mbid_artist_a'), +(2, 'Artist B', 'Artist B', 'mbid_artist_b'); + +-- Inserting releases +INSERT INTO release (version, name, mbid) VALUES +(1, 'Release X', 'mbid_release_x'), +(2, 'Release Y', 'mbid_release_y'); + +-- Inserting tracks without any associated artists or releases (Orphan Tracks) +INSERT INTO track (version, scan_version, track_number, disc_number, name, duration, date, original_date, file_path, file_last_write, file_added, has_cover, mbid, recording_mbid, copyright, copyright_url) +VALUES +(1, 1, 1, 1, 'Orphan Track 1', 180, '2024-05-08', '2024-05-08', '/path/to/orphan_track_1.mp3', '2024-05-08', '2024-05-08', 1, 'mbid_orphan_track_1', 'mbid_recording_orphan_track_1', 'Copyright 2024', 'http://example.com/copyright'), +(2, 1, 2, 1, 'Orphan Track 2', 210, '2024-05-08', '2024-05-08', '/path/to/orphan_track_2.mp3', '2024-05-08', '2024-05-08', 1, 'mbid_orphan_track_2', 'mbid_recording_orphan_track_2', 'Copyright 2024', 'http://example.com/copyright'); + +-- Inserting tracks with artists but no releases +INSERT INTO track (version, scan_version, track_number, disc_number, name, duration, date, original_date, file_path, file_last_write, file_added, has_cover, mbid, recording_mbid, copyright, copyright_url) +VALUES +(1, 1, 3, 1, 'Track with Artist A', 200, '2024-05-08', '2024-05-08', '/path/to/track_with_artist_a.mp3', '2024-05-08', '2024-05-08', 1, 'mbid_track_with_artist_a', 'mbid_recording_track_with_artist_a', 'Copyright 2024', 'http://example.com/copyright'), +(2, 1, 4, 1, 'Track with Artist B', 220, '2024-05-08', '2024-05-08', '/path/to/track_with_artist_b.mp3', '2024-05-08', '2024-05-08', 1, 'mbid_track_with_artist_b', 'mbid_recording_track_with_artist_b', 'Copyright 2024', 'http://example.com/copyright'); + +-- Inserting tracks with artists linked +INSERT INTO track_artist_link (version, type, name, track_id, artist_id) +VALUES +(1, 1, 'Artist A', 3, 1), +(2, 1, 'Artist B', 4, 2); + +-- Inserting tracks with artists and releases +INSERT INTO track (version, scan_version, track_number, disc_number, name, duration, date, original_date, file_path, file_last_write, file_added, has_cover, mbid, recording_mbid, copyright, copyright_url, release_id, total_disc, total_track, track_replay_gain, release_replay_gain) +VALUES +(1, 1, 5, 1, 'Track with Artist and Release X', 180, '2024-05-08', '2024-05-08', '/path/to/track_with_artist_and_release_x.mp3', '2024-05-08', '2024-05-08', 1, 'mbid_track_with_artist_and_release_x', 'mbid_recording_track_with_artist_and_release_x', 'Copyright 2024', 'http://example.com/copyright', 1, 1, 10, 0, 0), +(1, 1, 6, 1, 'Track with Artist and Release Y', 210, '2024-05-08', '2024-05-08', '/path/to/track_with_artist_and_release_y.mp3', '2024-05-08', '2024-05-08', 1, 'mbid_track_with_artist_and_release_y', 'mbid_recording_track_with_artist_and_release_y', 'Copyright 2024', 'http://example.com/copyright', 1, 1, 10, 0, 0); + +-- Inserting tracks with artists and releases linked +INSERT INTO track_artist_link (version, type, name, track_id, artist_id) +VALUES +(1, 1, 'Artist A', 5, 1), +(2, 1, 'Artist B', 6, 2);)"}; + + Session session{ db }; + + { + auto transaction{ session.createWriteTransaction() }; + + executeStatements(session, schemaV33); + session.execute("INSERT INTO version_info (version, db_version) VALUES (1, 33)"); + + // Insert some base data + executeStatements(session, createDummyData); + } + + // Now perform full migration + db.getTLSSession().migrateSchemaIfNeeded(); + } +} \ No newline at end of file From 06b071553c85a75194fe12a6fdd5701f86d63270 Mon Sep 17 00:00:00 2001 From: emeric Date: Wed, 8 May 2024 16:37:43 +0200 Subject: [PATCH 04/14] Minor db cleanup --- src/libs/database/impl/Db.cpp | 16 +++------------- src/libs/database/impl/Migration.cpp | 3 +-- src/libs/database/impl/Session.cpp | 2 -- src/libs/database/test/Common.cpp | 18 ++++++++++-------- src/libs/database/test/Migration.cpp | 2 -- 5 files changed, 14 insertions(+), 27 deletions(-) diff --git a/src/libs/database/impl/Db.cpp b/src/libs/database/impl/Db.cpp index 23afed43..253d82c7 100644 --- a/src/libs/database/impl/Db.cpp +++ b/src/libs/database/impl/Db.cpp @@ -50,12 +50,6 @@ namespace lms::db prepare(); } - ~Connection() override - { - // make use of per-connection usage stats to optimize - optimize(); - } - private: Connection& operator=(const Connection&) = delete; @@ -72,13 +66,6 @@ namespace lms::db LMS_LOG(DB, DEBUG, "Setting per-connection settings done!"); } - void optimize() - { - LMS_LOG(DB, DEBUG, "connection close: Running pragma optimize..."); - executeSql("PRAGMA optimize"); - LMS_LOG(DB, DEBUG, "connection close: pragma optimize complete"); - } - std::filesystem::path _dbPath; }; } @@ -119,6 +106,9 @@ namespace lms::db } } + // For now, multiple databases are not handled + assert(&tlsSession->getDb() == this); + return *tlsSession; } diff --git a/src/libs/database/impl/Migration.cpp b/src/libs/database/impl/Migration.cpp index 1bcc8724..7533ae6a 100644 --- a/src/libs/database/impl/Migration.cpp +++ b/src/libs/database/impl/Migration.cpp @@ -73,13 +73,12 @@ namespace lms::db::Migration { _db.executeSql("PRAGMA foreign_keys=ON"); } - + private: ScopedNoForeignKeys(const ScopedNoForeignKeys&) = delete; ScopedNoForeignKeys(ScopedNoForeignKeys&&) = delete; ScopedNoForeignKeys& operator=(const ScopedNoForeignKeys&) = delete; ScopedNoForeignKeys& operator=(ScopedNoForeignKeys&&) = delete; - private: Db& _db; }; diff --git a/src/libs/database/impl/Session.cpp b/src/libs/database/impl/Session.cpp index 97ea7126..a61fa823 100644 --- a/src/libs/database/impl/Session.cpp +++ b/src/libs/database/impl/Session.cpp @@ -19,8 +19,6 @@ #include "database/Session.hpp" -#include - #include "core/Exception.hpp" #include "core/ILogger.hpp" #include "core/ITraceLogger.hpp" diff --git a/src/libs/database/test/Common.cpp b/src/libs/database/test/Common.cpp index d78a8557..4ffe33d2 100644 --- a/src/libs/database/test/Common.cpp +++ b/src/libs/database/test/Common.cpp @@ -91,10 +91,18 @@ namespace lms::db::tests EXPECT_EQ(User::getCount(session), 0); } + TEST_F(DatabaseFixture, vacuum) + { + session.vacuum(); + } + + TEST_F(DatabaseFixture, analyze) + { + session.fullAnalyze(); + } + TEST_F(DatabaseFixture, Common_subRangeEmpty) { - using namespace db; - RangeResults results; results.range = Range{ 0, 0 }; results.results = {}; @@ -115,8 +123,6 @@ namespace lms::db::tests TEST_F(DatabaseFixture, Common_subRangeForeach) { - using namespace db; - struct TestCase { Range range; @@ -153,8 +159,6 @@ namespace lms::db::tests TEST_F(DatabaseFixture, Common_IdType) { - using namespace db; - { const IdType id{}; EXPECT_FALSE(id.isValid()); @@ -182,8 +186,6 @@ namespace lms::db::tests TEST_F(DatabaseFixture, Common_subRange) { - using namespace db; - RangeResults results; results.range = Range{ 0, 2 }; results.results = { 5, 6 }; diff --git a/src/libs/database/test/Migration.cpp b/src/libs/database/test/Migration.cpp index 69a9970c..b7158bcc 100644 --- a/src/libs/database/test/Migration.cpp +++ b/src/libs/database/test/Migration.cpp @@ -27,8 +27,6 @@ namespace lms::db::tests { void executeStatements(db::Session& session, std::string_view statements) { - auto transaction{ session.createWriteTransaction() }; - for (std::string_view statement : core::stringUtils::splitString(statements, ';')) { statement = core::stringUtils::stringTrim(statement, " \t\r\n"); From 91812469a9d4900277ec24c61f09560a8e43db64 Mon Sep 17 00:00:00 2001 From: emeric Date: Sat, 11 May 2024 11:50:29 +0200 Subject: [PATCH 05/14] Fixed bad optional acces, fixes #459 --- src/libs/services/scanner/impl/ScannerService.cpp | 4 ++-- src/lms/ui/admin/ScannerController.cpp | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libs/services/scanner/impl/ScannerService.cpp b/src/libs/services/scanner/impl/ScannerService.cpp index cf48be8d..f29a9b52 100644 --- a/src/libs/services/scanner/impl/ScannerService.cpp +++ b/src/libs/services/scanner/impl/ScannerService.cpp @@ -263,11 +263,9 @@ namespace lms::scanner { std::unique_lock lock{ _statusMutex }; - _curState = State::InProgress; _nextScheduledScan = {}; } - LMS_LOG(UI, INFO, "New scan started!"); refreshScanSettings(); @@ -396,6 +394,8 @@ namespace lms::scanner { { std::unique_lock lock{ _statusMutex }; + + _curState = State::InProgress; _currentScanStepStats = stepStats; } diff --git a/src/lms/ui/admin/ScannerController.cpp b/src/lms/ui/admin/ScannerController.cpp index 8fcb8501..467504ec 100644 --- a/src/lms/ui/admin/ScannerController.cpp +++ b/src/lms/ui/admin/ScannerController.cpp @@ -249,6 +249,8 @@ namespace lms::ui break; case IScannerService::State::InProgress: + assert(status.currentScanStepStats); + _status->setText(Wt::WString::tr("Lms.Admin.ScannerController.status-in-progress") .arg(status.currentScanStepStats->stepIndex + 1) .arg(scanner::ScanProgressStepCount)); From 02a0d4a59364bdcf63d04e0b9ae07082ad6495a6 Mon Sep 17 00:00:00 2001 From: emeric Date: Sat, 11 May 2024 11:57:12 +0200 Subject: [PATCH 06/14] Fixed mimetype for dsf files, ref #462 --- src/libs/av/impl/AudioFile.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/av/impl/AudioFile.cpp b/src/libs/av/impl/AudioFile.cpp index 6c4948dc..5075af50 100644 --- a/src/libs/av/impl/AudioFile.cpp +++ b/src/libs/av/impl/AudioFile.cpp @@ -300,7 +300,7 @@ namespace lms::av // List should be sync with the demuxers shipped in the lms's docker version // + the _audioFileExtensions in ScanSettings // std::filesystem::path does not seem to have std::hash specialization on freebsd - static const std::unordered_map entries + static const std::unordered_map entries { {".mp3", "audio/mpeg"}, {".ogg", "audio/ogg"}, @@ -321,7 +321,7 @@ namespace lms::av {".aiff", "audio/x-aiff"}, {".m3u", "audio/x-mpegurl"}, {".pls", "audio/x-scpls"}, - {".dsf", "audio/dsd"}, + {".dsf", "audio/x-dsd"}, {".wv", "audio/x-wavpack"}, {".wvp", "audio/x-wavpack"}, {".mka", "audio/x-matroska"}, From 87222f9e9d9384551c485b14c546acdba83f3d22 Mon Sep 17 00:00:00 2001 From: emeric Date: Sun, 12 May 2024 15:24:55 +0200 Subject: [PATCH 07/14] Added some missing info --- src/libs/av/impl/AudioFile.cpp | 39 +++++++++++++++------------ src/libs/av/include/av/IAudioFile.hpp | 22 ++++++++------- 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/src/libs/av/impl/AudioFile.cpp b/src/libs/av/impl/AudioFile.cpp index 5075af50..7a92a65e 100644 --- a/src/libs/av/impl/AudioFile.cpp +++ b/src/libs/av/impl/AudioFile.cpp @@ -72,22 +72,27 @@ namespace lms::av { switch (codec) { - case AV_CODEC_ID_MP3: return DecodingCodec::MP3; - case AV_CODEC_ID_AAC: return DecodingCodec::AAC; - case AV_CODEC_ID_AC3: return DecodingCodec::AC3; - case AV_CODEC_ID_VORBIS: return DecodingCodec::VORBIS; - case AV_CODEC_ID_WMAV1: return DecodingCodec::WMAV1; - case AV_CODEC_ID_WMAV2: return DecodingCodec::WMAV2; - case AV_CODEC_ID_FLAC: return DecodingCodec::FLAC; - case AV_CODEC_ID_ALAC: return DecodingCodec::ALAC; - case AV_CODEC_ID_WAVPACK: return DecodingCodec::WAVPACK; - case AV_CODEC_ID_MUSEPACK7: return DecodingCodec::MUSEPACK7; - case AV_CODEC_ID_MUSEPACK8: return DecodingCodec::MUSEPACK8; - case AV_CODEC_ID_APE: return DecodingCodec::APE; - case AV_CODEC_ID_EAC3: return DecodingCodec::EAC3; - case AV_CODEC_ID_MP4ALS: return DecodingCodec::MP4ALS; - case AV_CODEC_ID_OPUS: return DecodingCodec::OPUS; - case AV_CODEC_ID_SHORTEN: return DecodingCodec::SHORTEN; + case AV_CODEC_ID_MP3: return DecodingCodec::MP3; + case AV_CODEC_ID_AAC: return DecodingCodec::AAC; + case AV_CODEC_ID_AC3: return DecodingCodec::AC3; + case AV_CODEC_ID_VORBIS: return DecodingCodec::VORBIS; + case AV_CODEC_ID_WMAV1: return DecodingCodec::WMAV1; + case AV_CODEC_ID_WMAV2: return DecodingCodec::WMAV2; + case AV_CODEC_ID_FLAC: return DecodingCodec::FLAC; + case AV_CODEC_ID_ALAC: return DecodingCodec::ALAC; + case AV_CODEC_ID_WAVPACK: return DecodingCodec::WAVPACK; + case AV_CODEC_ID_MUSEPACK7: return DecodingCodec::MUSEPACK7; + case AV_CODEC_ID_MUSEPACK8: return DecodingCodec::MUSEPACK8; + case AV_CODEC_ID_APE: return DecodingCodec::APE; + case AV_CODEC_ID_EAC3: return DecodingCodec::EAC3; + case AV_CODEC_ID_MP4ALS: return DecodingCodec::MP4ALS; + case AV_CODEC_ID_OPUS: return DecodingCodec::OPUS; + case AV_CODEC_ID_SHORTEN: return DecodingCodec::SHORTEN; + case AV_CODEC_ID_DSD_LSBF: return DecodingCodec::DSD_LSBF; + case AV_CODEC_ID_DSD_LSBF_PLANAR: return DecodingCodec::DSD_LSBF_PLANAR; + case AV_CODEC_ID_DSD_MSBF: return DecodingCodec::DSD_MSBF; + case AV_CODEC_ID_DSD_MSBF_PLANAR: return DecodingCodec::DSD_MSBF_PLANAR; + default: return DecodingCodec::UNKNOWN; } @@ -300,7 +305,7 @@ namespace lms::av // List should be sync with the demuxers shipped in the lms's docker version // + the _audioFileExtensions in ScanSettings // std::filesystem::path does not seem to have std::hash specialization on freebsd - static const std::unordered_map entries + static const std::unordered_map entries { {".mp3", "audio/mpeg"}, {".ogg", "audio/ogg"}, diff --git a/src/libs/av/include/av/IAudioFile.hpp b/src/libs/av/include/av/IAudioFile.hpp index 6d9915c9..51988d33 100644 --- a/src/libs/av/include/av/IAudioFile.hpp +++ b/src/libs/av/include/av/IAudioFile.hpp @@ -44,16 +44,20 @@ namespace lms::av VORBIS, WMAV1, WMAV2, - FLAC, // Flac - ALAC, // Apple Lossless Audio Codec (ALAC) - WAVPACK, // WavPack - MUSEPACK7, // Musepack + FLAC, // Flac + ALAC, // Apple Lossless Audio Codec (ALAC) + WAVPACK, // WavPack + MUSEPACK7, // Musepack MUSEPACK8, - APE, // // Monkey's Audio - EAC3, // Enhanced AC-3 - MP4ALS, // MPEG-4 Audio Lossless Coding - OPUS, // Opus - SHORTEN, // Shorten (shn) + APE, // Monkey's Audio + EAC3, // Enhanced AC-3 + MP4ALS, // MPEG-4 Audio Lossless Coding + OPUS, // Opus + SHORTEN, // Shorten (shn) + DSD_LSBF, // DSD (Direct Stream Digital), least significant bit first + DSD_LSBF_PLANAR, // DSD (Direct Stream Digital), least significant bit first, planar + DSD_MSBF, // DSD (Direct Stream Digital), most significant bit first + DSD_MSBF_PLANAR, // DSD (Direct Stream Digital), most significant bit first, planar // TODO add PCM codecs }; From 50c8a33653194000414942a0347852fef6ab6951 Mon Sep 17 00:00:00 2001 From: emeric Date: Fri, 24 May 2024 22:21:00 +0200 Subject: [PATCH 08/14] Split file to fix compilation --- src/libs/metadata/impl/ITagReader.hpp | 20 +-- .../metadata/include/metadata/IParser.hpp | 103 +------------- src/libs/metadata/include/metadata/Types.hpp | 131 ++++++++++++++++++ 3 files changed, 144 insertions(+), 110 deletions(-) create mode 100644 src/libs/metadata/include/metadata/Types.hpp diff --git a/src/libs/metadata/impl/ITagReader.hpp b/src/libs/metadata/impl/ITagReader.hpp index ee80933a..da1a0d8b 100644 --- a/src/libs/metadata/impl/ITagReader.hpp +++ b/src/libs/metadata/impl/ITagReader.hpp @@ -22,6 +22,8 @@ #include #include +#include "metadata/Types.hpp" + namespace lms::metadata { // using picard internal names @@ -48,11 +50,11 @@ namespace lms::metadata Compilation, Composer, ComposerSortOrder, - Composers, // non standard + Composers, // non standard ComposersSortOrder, // non standard Conductor, - ConductorSortOrder, // non standard - Conductors, // non standard + ConductorSortOrder, // non standard + Conductors, // non standard ConductorsSortOrder, // non standard Copyright, CopyrightURL, // non standard @@ -71,15 +73,15 @@ namespace lms::metadata Language, License, Lyricist, - LyricistSortOrder, // non standard - Lyricists, // non standard + LyricistSortOrder, // non standard + Lyricists, // non standard LyricistsSortOrder, // non standard Lyrics, Media, MixDJ, Mixer, - MixerSortOrder, // non standard - Mixers, // non standard + MixerSortOrder, // non standard + Mixers, // non standard MixersSortOrder, // non standard Mood, Movement, @@ -105,8 +107,8 @@ namespace lms::metadata Podcast, PodcastURL, Producer, - ProducerSortOrder, // non standard - Producers, // non standard + ProducerSortOrder, // non standard + Producers, // non standard ProducersSortOrder, // non standard Rating, RecordLabel, diff --git a/src/libs/metadata/include/metadata/IParser.hpp b/src/libs/metadata/include/metadata/IParser.hpp index 821b99a9..47b6c908 100644 --- a/src/libs/metadata/include/metadata/IParser.hpp +++ b/src/libs/metadata/include/metadata/IParser.hpp @@ -19,113 +19,14 @@ #pragma once -#include #include -#include -#include +#include #include -#include -#include -#include -#include -#include "core/UUID.hpp" +#include "metadata/Types.hpp" namespace lms::metadata { - using Tags = std::map /* values */>; - - // Very simplified version of https://musicbrainz.org/doc/MusicBrainz_Database/Schema - - struct Artist - { - std::optional mbid; - std::string name; - std::optional sortName; - - Artist(std::string_view _name) : name{ _name } {} - Artist(std::optional _mbid, std::string_view _name, std::optional _sortName) : mbid{ std::move(_mbid) }, name{ _name }, sortName{ std::move(_sortName) } {} - - auto operator<=>(const Artist&) const = default; - }; - - using PerformerContainer = std::map>; - - struct Release - { - std::optional mbid; - std::optional groupMBID; - std::string name; - std::string sortName; - std::string artistDisplayName; - std::vector artists; - std::optional mediumCount; - std::vector releaseTypes; - - auto operator<=>(const Release&) const = default; - }; - - struct Medium - { - std::string media; // CD, etc. - std::string name; - std::optional release; - std::optional position; // in release - std::optional trackCount; - std::optional replayGain; - - auto operator<=>(const Medium&) const = default; - - bool isDefault() const - { - static Medium defaultMedium; - return *this == defaultMedium; - } - }; - - struct AudioProperties - { - std::size_t bitrate{}; - std::size_t bitsPerSample{}; - std::size_t channelCount{}; - std::chrono::milliseconds duration{}; - std::size_t sampleRate{}; - }; - - struct Track - { - AudioProperties audioProperties; - std::optional mbid; - std::optional recordingMBID; - std::string title; - std::optional medium; - std::optional position; // in medium - std::vector groupings; - std::vector genres; - std::vector moods; - std::vector labels; - std::vector languages; - Tags userExtraTags; - std::optional year{}; - Wt::WDate date; - std::optional originalYear{}; - Wt::WDate originalDate; - bool hasCover{}; - std::optional acoustID; - std::string copyright; - std::string copyrightURL; - std::optional replayGain; - std::string artistDisplayName; - std::vector artists; - std::vector conductorArtists; - std::vector composerArtists; - std::vector lyricistArtists; - std::vector mixerArtists; - PerformerContainer performerArtists; - std::vector producerArtists; - std::vector remixerArtists; - }; - class IParser { public: diff --git a/src/libs/metadata/include/metadata/Types.hpp b/src/libs/metadata/include/metadata/Types.hpp new file mode 100644 index 00000000..9f69fb19 --- /dev/null +++ b/src/libs/metadata/include/metadata/Types.hpp @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2024 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 +#include +#include +#include + +#include + +#include "core/UUID.hpp" + +namespace lms::metadata +{ + using Tags = std::map /* values */>; + + // Very simplified version of https://musicbrainz.org/doc/MusicBrainz_Database/Schema + + struct Artist + { + std::optional mbid; + std::string name; + std::optional sortName; + + Artist(std::string_view _name) + : name{ _name } {} + Artist(std::optional _mbid, std::string_view _name, std::optional _sortName) + : mbid{ std::move(_mbid) } + , name{ _name } + , sortName{ std::move(_sortName) } {} + + auto operator<=>(const Artist&) const = default; + }; + + using PerformerContainer = std::map>; + + struct Release + { + std::optional mbid; + std::optional groupMBID; + std::string name; + std::string sortName; + std::string artistDisplayName; + std::vector artists; + std::optional mediumCount; + std::vector releaseTypes; + + auto operator<=>(const Release&) const = default; + }; + + struct Medium + { + std::string media; // CD, etc. + std::string name; + std::optional release; + std::optional position; // in release + std::optional trackCount; + std::optional replayGain; + + auto operator<=>(const Medium&) const = default; + + bool isDefault() const + { + static Medium defaultMedium; + return *this == defaultMedium; + } + }; + + struct AudioProperties + { + std::size_t bitrate{}; + std::size_t bitsPerSample{}; + std::size_t channelCount{}; + std::chrono::milliseconds duration{}; + std::size_t sampleRate{}; + }; + + struct Track + { + AudioProperties audioProperties; + std::optional mbid; + std::optional recordingMBID; + std::string title; + std::optional medium; + std::optional position; // in medium + std::vector groupings; + std::vector genres; + std::vector moods; + std::vector labels; + std::vector languages; + Tags userExtraTags; + std::optional year{}; + Wt::WDate date; + std::optional originalYear{}; + Wt::WDate originalDate; + bool hasCover{}; + std::optional acoustID; + std::string copyright; + std::string copyrightURL; + std::optional replayGain; + std::string artistDisplayName; + std::vector artists; + std::vector conductorArtists; + std::vector composerArtists; + std::vector lyricistArtists; + std::vector mixerArtists; + PerformerContainer performerArtists; + std::vector producerArtists; + std::vector remixerArtists; + }; +} // namespace lms::metadata \ No newline at end of file From 83b868673c083179259ecc0233b5d6bd1c41e657 Mon Sep 17 00:00:00 2001 From: emeric Date: Fri, 24 May 2024 23:31:02 +0200 Subject: [PATCH 09/14] Added a clang-format def file, ref #470 --- .clang-format | 30 ++++++++++++++++++++++++ src/libs/core/bench/TraceLoggerBench.cpp | 1 + 2 files changed, 31 insertions(+) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..bb47648f --- /dev/null +++ b/.clang-format @@ -0,0 +1,30 @@ +Language: Cpp +BasedOnStyle: Microsoft +Standard: c++20 +AccessModifierOffset: -4 +AlignAfterOpenBracket: DontAlign +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignOperands: AlignAfterOperator +AlignTrailingComments: true +AllowAllConstructorInitializersOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortFunctionsOnASingleLine: InlineOnly +AllowShortIfStatementsOnASingleLine: true +AlwaysBreakTemplateDeclarations: Yes +BraceWrapping: + AfterUnion: true +BreakBeforeBinaryOperators: All +BreakBeforeTernaryOperators: false +BreakConstructorInitializers: BeforeComma +ColumnLimit: 0 +ConstructorInitializerAllOnOneLineOrOnePerLine: true +Cpp11BracedListStyle: false +IndentCaseBlocks: true +IndentPPDirectives: BeforeHash +KeepEmptyLinesAtTheStartOfBlocks: false +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: All +PointerAlignment: Left +SortIncludes: true +SpaceAfterTemplateKeyword: false \ No newline at end of file diff --git a/src/libs/core/bench/TraceLoggerBench.cpp b/src/libs/core/bench/TraceLoggerBench.cpp index 34652885..f340fa1c 100644 --- a/src/libs/core/bench/TraceLoggerBench.cpp +++ b/src/libs/core/bench/TraceLoggerBench.cpp @@ -17,6 +17,7 @@ * along with LMS. If not, see . */ +#include #include #include #include From 39941d90a36a2d8f21d50a0307b4f0a6fd523467 Mon Sep 17 00:00:00 2001 From: emeric Date: Fri, 24 May 2024 23:31:52 +0200 Subject: [PATCH 10/14] Auto reformatted the base, ref #470 --- src/libs/av/impl/AudioFile.cpp | 121 +-- src/libs/av/impl/AudioFile.hpp | 21 +- .../av/impl/RawResourceHandlerCreator.cpp | 2 +- src/libs/av/impl/Transcoder.cpp | 32 +- src/libs/av/impl/Transcoder.hpp | 18 +- .../av/impl/TranscodingResourceHandler.cpp | 18 +- .../av/impl/TranscodingResourceHandler.hpp | 6 +- src/libs/av/include/av/IAudioFile.hpp | 47 +- .../av/include/av/TranscodingParameters.hpp | 13 +- .../av/TranscodingResourceHandlerCreator.hpp | 8 +- src/libs/av/include/av/Types.hpp | 2 +- src/libs/core/bench/TraceLoggerBench.cpp | 7 +- src/libs/core/impl/ArchiveZipper.cpp | 30 +- src/libs/core/impl/ArchiveZipper.hpp | 3 +- src/libs/core/impl/ChildProcess.cpp | 19 +- src/libs/core/impl/ChildProcess.hpp | 22 +- src/libs/core/impl/ChildProcessManager.cpp | 2 +- src/libs/core/impl/ChildProcessManager.hpp | 2 +- src/libs/core/impl/Config.cpp | 6 +- src/libs/core/impl/Config.hpp | 15 +- src/libs/core/impl/FileResourceHandler.cpp | 4 +- src/libs/core/impl/FileResourceHandler.hpp | 13 +- src/libs/core/impl/IOContextRunner.cpp | 33 +- src/libs/core/impl/Logger.cpp | 77 +- src/libs/core/impl/NetAddress.cpp | 30 +- src/libs/core/impl/Path.cpp | 15 +- src/libs/core/impl/Random.cpp | 2 +- src/libs/core/impl/RecursiveSharedMutex.cpp | 2 +- src/libs/core/impl/StreamLogger.cpp | 2 +- src/libs/core/impl/String.cpp | 33 +- src/libs/core/impl/TraceLogger.cpp | 17 +- src/libs/core/impl/TraceLogger.hpp | 2 +- src/libs/core/impl/UUID.cpp | 15 +- src/libs/core/impl/WtLogger.cpp | 24 +- src/libs/core/impl/http/Client.cpp | 2 +- src/libs/core/impl/http/Client.hpp | 10 +- src/libs/core/impl/http/ClientRequest.hpp | 17 +- src/libs/core/impl/http/SendQueue.cpp | 60 +- src/libs/core/impl/http/SendQueue.hpp | 26 +- .../core/include/core/Crc32Calculator.hpp | 4 +- src/libs/core/include/core/EnumSet.hpp | 13 +- src/libs/core/include/core/Exception.hpp | 5 +- src/libs/core/include/core/IChildProcess.hpp | 8 +- .../include/core/IChildProcessManager.hpp | 3 +- src/libs/core/include/core/IConfig.hpp | 14 +- src/libs/core/include/core/ILogger.hpp | 18 +- .../core/include/core/IOContextRunner.hpp | 7 +- .../core/include/core/IResourceHandler.hpp | 18 +- src/libs/core/include/core/ITraceLogger.hpp | 22 +- src/libs/core/include/core/IZipper.hpp | 4 +- src/libs/core/include/core/LiteralString.hpp | 36 +- src/libs/core/include/core/NetAddress.hpp | 13 +- src/libs/core/include/core/Path.hpp | 4 +- src/libs/core/include/core/Random.hpp | 10 +- .../include/core/RecursiveSharedMutex.hpp | 2 +- src/libs/core/include/core/Service.hpp | 6 +- src/libs/core/include/core/StreamLogger.hpp | 2 +- src/libs/core/include/core/String.hpp | 8 +- src/libs/core/include/core/Tuple.hpp | 46 +- src/libs/core/include/core/UUID.hpp | 6 +- src/libs/core/include/core/Utils.hpp | 29 +- src/libs/core/include/core/WtLogger.hpp | 2 +- .../core/http/ClientRequestParameters.hpp | 4 +- src/libs/core/include/core/http/IClient.hpp | 19 +- src/libs/core/test/EnumSet.cpp | 2 +- src/libs/core/test/LiteralString.cpp | 8 +- src/libs/core/test/Path.cpp | 64 +- src/libs/core/test/RecursiveSharedMutex.cpp | 49 +- src/libs/core/test/String.cpp | 143 ++-- src/libs/core/test/TraceLogger.cpp | 12 +- src/libs/core/test/UUID.cpp | 2 +- src/libs/core/test/Utils.cpp | 7 +- src/libs/database/impl/Artist.cpp | 91 +-- src/libs/database/impl/AuthToken.cpp | 8 +- src/libs/database/impl/Cluster.cpp | 46 +- src/libs/database/impl/Db.cpp | 8 +- src/libs/database/impl/EnumSetTraits.hpp | 4 +- src/libs/database/impl/IdTypeTraits.hpp | 4 +- src/libs/database/impl/Listen.cpp | 100 +-- src/libs/database/impl/MediaLibrary.cpp | 12 +- src/libs/database/impl/Migration.cpp | 84 +- src/libs/database/impl/Migration.hpp | 2 +- src/libs/database/impl/PathTraits.hpp | 6 +- src/libs/database/impl/Release.cpp | 168 ++-- src/libs/database/impl/ScanSettings.cpp | 3 +- src/libs/database/impl/Session.cpp | 12 +- src/libs/database/impl/SqlQuery.cpp | 13 +- src/libs/database/impl/SqlQuery.hpp | 38 +- src/libs/database/impl/StarredArtist.cpp | 16 +- src/libs/database/impl/StarredRelease.cpp | 16 +- src/libs/database/impl/StarredTrack.cpp | 23 +- src/libs/database/impl/StringViewTraits.hpp | 4 +- src/libs/database/impl/Track.cpp | 96 ++- src/libs/database/impl/TrackArtistLink.cpp | 34 +- src/libs/database/impl/TrackBookmark.cpp | 18 +- src/libs/database/impl/TrackFeatures.cpp | 22 +- src/libs/database/impl/TrackList.cpp | 80 +- src/libs/database/impl/TransactionChecker.cpp | 5 +- src/libs/database/impl/Types.cpp | 6 +- src/libs/database/impl/User.cpp | 8 +- src/libs/database/impl/Utils.cpp | 3 +- src/libs/database/impl/Utils.hpp | 32 +- src/libs/database/include/database/Artist.hpp | 118 ++- .../database/include/database/ArtistId.hpp | 1 - .../database/include/database/AuthToken.hpp | 59 +- .../database/include/database/Cluster.hpp | 102 ++- .../database/include/database/ClusterId.hpp | 1 - src/libs/database/include/database/Db.hpp | 4 +- src/libs/database/include/database/IdType.hpp | 54 +- src/libs/database/include/database/Listen.hpp | 145 ++-- .../database/include/database/ListenId.hpp | 1 - .../include/database/MediaLibrary.hpp | 6 +- src/libs/database/include/database/Object.hpp | 29 +- .../database/include/database/Release.hpp | 173 +++-- .../include/database/ScanSettings.hpp | 32 +- .../database/include/database/Session.hpp | 15 +- .../include/database/StarredArtist.hpp | 29 +- .../include/database/StarredRelease.hpp | 17 +- .../include/database/StarredTrack.hpp | 60 +- src/libs/database/include/database/Track.hpp | 295 +++++--- .../include/database/TrackArtistLink.hpp | 61 +- .../include/database/TrackBookmark.hpp | 24 +- .../include/database/TrackFeatures.hpp | 12 +- .../database/include/database/TrackList.hpp | 109 +-- .../include/database/TransactionChecker.hpp | 11 +- src/libs/database/include/database/Types.hpp | 18 +- src/libs/database/include/database/User.hpp | 112 +-- src/libs/database/test/Artist.cpp | 133 ++-- src/libs/database/test/Cluster.cpp | 55 +- src/libs/database/test/Common.cpp | 50 +- src/libs/database/test/Common.hpp | 11 +- src/libs/database/test/DatabaseTest.cpp | 8 +- src/libs/database/test/Listen.cpp | 92 ++- src/libs/database/test/Migration.cpp | 8 +- src/libs/database/test/Release.cpp | 120 ++- src/libs/database/test/StarredArtist.cpp | 19 +- src/libs/database/test/StarredRelease.cpp | 19 +- src/libs/database/test/StarredTrack.cpp | 19 +- src/libs/database/test/Track.cpp | 65 +- src/libs/database/test/TrackBookmark.cpp | 2 +- src/libs/database/test/TrackFeatures.cpp | 2 +- src/libs/database/test/TrackList.cpp | 40 +- src/libs/database/test/User.cpp | 16 +- src/libs/image/impl/SvgImage.cpp | 3 +- src/libs/image/impl/SvgImage.hpp | 5 +- .../image/impl/graphicsmagick/JPEGImage.cpp | 55 +- .../image/impl/graphicsmagick/JPEGImage.hpp | 24 +- .../image/impl/graphicsmagick/RawImage.cpp | 178 +++-- .../image/impl/graphicsmagick/RawImage.hpp | 31 +- src/libs/image/impl/stb/JPEGImage.cpp | 56 +- src/libs/image/impl/stb/JPEGImage.hpp | 24 +- src/libs/image/impl/stb/RawImage.cpp | 25 +- src/libs/image/impl/stb/RawImage.hpp | 3 +- src/libs/image/include/image/Exception.hpp | 6 +- .../image/include/image/IEncodedImage.hpp | 2 +- src/libs/image/include/image/IRawImage.hpp | 3 +- src/libs/image/include/image/Image.hpp | 2 +- src/libs/metadata/impl/AvFormatTagReader.cpp | 26 +- src/libs/metadata/impl/AvFormatTagReader.hpp | 4 +- src/libs/metadata/impl/Parser.cpp | 118 ++- src/libs/metadata/impl/Parser.hpp | 2 +- src/libs/metadata/impl/TagLibTagReader.cpp | 73 +- src/libs/metadata/impl/TagLibTagReader.hpp | 1 + src/libs/metadata/impl/Utils.cpp | 32 +- src/libs/metadata/impl/Utils.hpp | 23 +- .../metadata/include/metadata/Exception.hpp | 2 +- .../metadata/include/metadata/IParser.hpp | 2 +- src/libs/metadata/test/Metadata.cpp | 7 +- src/libs/metadata/test/Parser.cpp | 26 +- src/libs/metadata/test/TestTagReader.hpp | 8 +- src/libs/metadata/test/Utils.cpp | 85 +-- .../services/auth/impl/AuthServiceBase.cpp | 8 +- .../services/auth/impl/AuthServiceBase.hpp | 11 +- .../services/auth/impl/AuthTokenService.cpp | 164 ++-- .../services/auth/impl/AuthTokenService.hpp | 37 +- src/libs/services/auth/impl/EnvService.cpp | 17 +- .../services/auth/impl/LoginThrottler.cpp | 8 +- .../services/auth/impl/LoginThrottler.hpp | 46 +- .../auth/impl/PasswordServiceBase.cpp | 99 ++- .../auth/impl/PasswordServiceBase.hpp | 48 +- .../http-headers/HttpHeadersEnvService.hpp | 20 +- .../impl/internal/InternalPasswordService.cpp | 14 +- .../impl/internal/InternalPasswordService.hpp | 21 +- .../auth/impl/pam/PAMPasswordService.cpp | 14 +- .../auth/impl/pam/PAMPasswordService.hpp | 22 +- .../services/auth/IAuthTokenService.hpp | 70 +- .../include/services/auth/IEnvService.hpp | 50 +- .../services/auth/IPasswordService.hpp | 80 +- .../auth/include/services/auth/Types.hpp | 78 +- src/libs/services/cover/impl/CoverService.cpp | 109 ++- src/libs/services/cover/impl/CoverService.hpp | 34 +- src/libs/services/cover/impl/ImageCache.cpp | 7 +- src/libs/services/cover/impl/ImageCache.hpp | 8 +- .../include/services/cover/ICoverService.hpp | 3 +- .../feedback/impl/FeedbackService.cpp | 5 +- .../feedback/impl/FeedbackService.hpp | 13 +- .../feedback/impl/FeedbackService.impl.hpp | 10 +- .../feedback/impl/IFeedbackBackend.hpp | 2 +- .../impl/internal/InternalBackend.cpp | 11 +- .../impl/internal/InternalBackend.hpp | 3 +- .../feedback/impl/listenbrainz/Exception.hpp | 12 +- .../impl/listenbrainz/FeedbackTypes.cpp | 13 +- .../impl/listenbrainz/FeedbackTypes.hpp | 32 +- .../impl/listenbrainz/FeedbacksParser.cpp | 13 +- .../impl/listenbrainz/FeedbacksParser.hpp | 22 +- .../listenbrainz/FeedbacksSynchronizer.cpp | 184 +++-- .../listenbrainz/FeedbacksSynchronizer.hpp | 39 +- .../impl/listenbrainz/ListenBrainzBackend.cpp | 17 +- .../impl/listenbrainz/ListenBrainzBackend.hpp | 12 +- .../feedback/impl/listenbrainz/Utils.cpp | 2 +- .../feedback/impl/listenbrainz/Utils.hpp | 8 +- .../include/services/feedback/Exception.hpp | 2 +- .../services/feedback/IFeedbackService.hpp | 97 ++- .../impl/ClustersEngineCreator.hpp | 9 +- .../impl/FeaturesEngineCreator.hpp | 6 +- .../services/recommendation/impl/IEngine.hpp | 36 +- .../impl/PlaylistGeneratorService.cpp | 5 +- .../impl/PlaylistGeneratorService.hpp | 25 +- .../impl/RecommendationService.cpp | 19 +- .../impl/RecommendationService.hpp | 4 +- .../impl/clusters/ClustersEngine.cpp | 7 +- .../impl/clusters/ClustersEngine.hpp | 36 +- .../impl/features/FeaturesDefs.cpp | 715 +++++++++--------- .../impl/features/FeaturesDefs.hpp | 37 +- .../impl/features/FeaturesEngine.cpp | 78 +- .../impl/features/FeaturesEngine.hpp | 61 +- .../impl/features/FeaturesEngineCache.cpp | 6 +- .../impl/features/FeaturesEngineCache.hpp | 4 +- .../ConsecutiveArtists.cpp | 98 ++- .../ConsecutiveArtists.hpp | 21 +- .../ConsecutiveReleases.cpp | 74 +- .../ConsecutiveReleases.hpp | 23 +- .../playlist-constraints/DuplicateTracks.cpp | 14 +- .../playlist-constraints/DuplicateTracks.hpp | 13 +- .../impl/playlist-constraints/IConstraint.hpp | 22 +- .../IPlaylistGeneratorService.hpp | 24 +- .../recommendation/IRecommendationService.hpp | 28 +- .../include/services/recommendation/Types.hpp | 23 +- src/libs/services/scanner/impl/IScanStep.hpp | 2 +- .../services/scanner/impl/ScanStepBase.hpp | 54 +- .../impl/ScanStepCheckDuplicatedDbFiles.cpp | 8 +- .../impl/ScanStepCheckDuplicatedDbFiles.hpp | 20 +- .../services/scanner/impl/ScanStepCompact.cpp | 2 +- .../services/scanner/impl/ScanStepCompact.hpp | 20 +- .../impl/ScanStepComputeClusterStats.cpp | 82 +- .../impl/ScanStepComputeClusterStats.hpp | 2 +- .../scanner/impl/ScanStepDiscoverFiles.cpp | 9 +- .../scanner/impl/ScanStepDiscoverFiles.hpp | 20 +- .../scanner/impl/ScanStepOptimize.cpp | 2 +- .../scanner/impl/ScanStepOptimize.hpp | 20 +- .../impl/ScanStepRemoveOrphanDbFiles.cpp | 30 +- .../impl/ScanStepRemoveOrphanDbFiles.hpp | 32 +- .../scanner/impl/ScanStepScanFiles.cpp | 86 +-- .../scanner/impl/ScanStepScanFiles.hpp | 41 +- .../services/scanner/impl/ScannerService.cpp | 65 +- .../services/scanner/impl/ScannerService.hpp | 40 +- .../services/scanner/impl/ScannerSettings.hpp | 22 +- .../services/scanner/impl/ScannerStats.cpp | 7 +- .../services/scanner/IScannerService.hpp | 10 +- .../services/scanner/ScannerEvents.hpp | 13 +- .../services/scanner/ScannerOptions.hpp | 6 +- .../include/services/scanner/ScannerStats.hpp | 53 +- .../scrobbling/impl/IScrobblingBackend.hpp | 5 +- .../scrobbling/impl/ScrobblingService.cpp | 7 +- .../scrobbling/impl/ScrobblingService.hpp | 4 +- .../impl/internal/InternalBackend.cpp | 6 +- .../impl/internal/InternalBackend.hpp | 3 +- .../impl/listenbrainz/Exception.hpp | 12 +- .../impl/listenbrainz/ListenBrainzBackend.cpp | 12 +- .../impl/listenbrainz/ListenBrainzBackend.hpp | 16 +- .../impl/listenbrainz/ListenTypes.cpp | 33 +- .../impl/listenbrainz/ListenTypes.hpp | 29 +- .../impl/listenbrainz/ListensParser.cpp | 5 +- .../impl/listenbrainz/ListensParser.hpp | 22 +- .../impl/listenbrainz/ListensSynchronizer.cpp | 188 +++-- .../impl/listenbrainz/ListensSynchronizer.hpp | 115 +-- .../scrobbling/impl/listenbrainz/Utils.cpp | 2 +- .../scrobbling/impl/listenbrainz/Utils.hpp | 8 +- .../include/services/scrobbling/Exception.hpp | 2 +- .../scrobbling/IScrobblingService.hpp | 73 +- .../include/services/scrobbling/Listen.hpp | 3 +- .../services/scrobbling/test/Listenbrainz.cpp | 18 +- .../services/scrobbling/test/Scrobbling.cpp | 3 +- src/libs/som/bench/SomBench.cpp | 3 +- src/libs/som/impl/DataNormalizer.cpp | 141 ++-- src/libs/som/impl/Network.cpp | 458 ++++++----- src/libs/som/include/som/DataNormalizer.hpp | 44 +- src/libs/som/include/som/InputVector.hpp | 264 ++++--- src/libs/som/include/som/Matrix.hpp | 17 +- src/libs/som/include/som/Network.hpp | 9 +- src/libs/som/test/SomTest.cpp | 177 ++--- src/libs/subsonic/bench/SubsonicBench.cpp | 7 +- src/libs/subsonic/impl/ClientInfo.hpp | 3 +- src/libs/subsonic/impl/ParameterParsing.cpp | 2 +- src/libs/subsonic/impl/ParameterParsing.hpp | 8 +- src/libs/subsonic/impl/ProtocolVersion.cpp | 3 +- src/libs/subsonic/impl/ProtocolVersion.hpp | 3 +- src/libs/subsonic/impl/RequestContext.hpp | 8 +- src/libs/subsonic/impl/SubsonicId.cpp | 2 +- src/libs/subsonic/impl/SubsonicId.hpp | 9 +- src/libs/subsonic/impl/SubsonicResource.cpp | 238 +++--- src/libs/subsonic/impl/SubsonicResource.hpp | 35 +- src/libs/subsonic/impl/SubsonicResponse.cpp | 110 +-- src/libs/subsonic/impl/SubsonicResponse.hpp | 58 +- .../impl/SubsonicResponseAllocator.hpp | 20 +- .../impl/TLSMonotonicMemoryResource.hpp | 6 +- src/libs/subsonic/impl/Utils.cpp | 3 +- src/libs/subsonic/impl/Utils.hpp | 2 +- .../impl/entrypoints/AlbumSongLists.cpp | 25 +- .../impl/entrypoints/AlbumSongLists.hpp | 2 +- .../subsonic/impl/entrypoints/Bookmarks.cpp | 9 +- .../subsonic/impl/entrypoints/Bookmarks.hpp | 2 +- .../subsonic/impl/entrypoints/Browsing.cpp | 59 +- .../subsonic/impl/entrypoints/Browsing.hpp | 2 +- .../impl/entrypoints/MediaAnnotation.cpp | 9 +- .../impl/entrypoints/MediaAnnotation.hpp | 2 +- .../impl/entrypoints/MediaLibraryScanning.cpp | 7 +- .../impl/entrypoints/MediaLibraryScanning.hpp | 3 +- .../impl/entrypoints/MediaRetrieval.cpp | 44 +- .../impl/entrypoints/MediaRetrieval.hpp | 3 +- .../subsonic/impl/entrypoints/Playlists.cpp | 7 +- .../subsonic/impl/entrypoints/Playlists.hpp | 2 +- .../subsonic/impl/entrypoints/Searching.cpp | 95 ++- .../subsonic/impl/entrypoints/Searching.hpp | 2 +- src/libs/subsonic/impl/entrypoints/System.cpp | 2 +- src/libs/subsonic/impl/entrypoints/System.hpp | 2 +- .../impl/entrypoints/UserManagement.cpp | 32 +- .../impl/entrypoints/UserManagement.hpp | 2 +- src/libs/subsonic/impl/responses/Album.cpp | 38 +- src/libs/subsonic/impl/responses/Album.hpp | 3 +- src/libs/subsonic/impl/responses/Artist.cpp | 48 +- src/libs/subsonic/impl/responses/Artist.hpp | 8 +- src/libs/subsonic/impl/responses/Bookmark.cpp | 2 +- src/libs/subsonic/impl/responses/Bookmark.hpp | 1 + .../subsonic/impl/responses/Contributor.cpp | 3 +- .../subsonic/impl/responses/Contributor.hpp | 3 +- .../subsonic/impl/responses/DiscTitle.cpp | 2 +- .../subsonic/impl/responses/DiscTitle.hpp | 1 + src/libs/subsonic/impl/responses/Genre.cpp | 2 +- src/libs/subsonic/impl/responses/Genre.hpp | 1 + src/libs/subsonic/impl/responses/ItemDate.cpp | 2 +- src/libs/subsonic/impl/responses/ItemDate.hpp | 1 + .../subsonic/impl/responses/ItemGenre.cpp | 2 +- .../subsonic/impl/responses/ItemGenre.hpp | 1 + src/libs/subsonic/impl/responses/Playlist.cpp | 5 +- src/libs/subsonic/impl/responses/Playlist.hpp | 3 +- .../subsonic/impl/responses/ReplayGain.cpp | 2 +- .../subsonic/impl/responses/ReplayGain.hpp | 1 + src/libs/subsonic/impl/responses/Song.cpp | 54 +- src/libs/subsonic/impl/responses/Song.hpp | 3 +- src/libs/subsonic/impl/responses/User.cpp | 2 +- src/libs/subsonic/impl/responses/User.hpp | 1 + .../include/subsonic/SubsonicResource.hpp | 6 +- src/lms/main.cpp | 135 ++-- src/lms/ui/Auth.cpp | 45 +- src/lms/ui/Auth.hpp | 15 +- src/lms/ui/LmsApplication.cpp | 198 +++-- src/lms/ui/LmsApplication.hpp | 33 +- src/lms/ui/LmsApplicationException.hpp | 70 +- src/lms/ui/LmsApplicationManager.cpp | 36 +- src/lms/ui/LmsApplicationManager.hpp | 30 +- src/lms/ui/LmsTheme.cpp | 68 +- src/lms/ui/LmsTheme.hpp | 38 +- src/lms/ui/MediaPlayer.cpp | 50 +- src/lms/ui/MediaPlayer.hpp | 49 +- src/lms/ui/ModalManager.cpp | 23 +- src/lms/ui/ModalManager.hpp | 24 +- src/lms/ui/Notification.hpp | 33 +- src/lms/ui/NotificationContainer.cpp | 13 +- src/lms/ui/NotificationContainer.hpp | 13 +- src/lms/ui/PlayQueue.cpp | 373 +++++---- src/lms/ui/PlayQueue.hpp | 129 ++-- src/lms/ui/SettingsView.cpp | 157 ++-- src/lms/ui/SettingsView.hpp | 18 +- src/lms/ui/Utils.cpp | 52 +- src/lms/ui/Utils.hpp | 44 +- src/lms/ui/admin/InitWizardView.cpp | 193 +++-- src/lms/ui/admin/InitWizardView.hpp | 15 +- src/lms/ui/admin/MediaLibrariesView.cpp | 133 ++-- src/lms/ui/admin/MediaLibrariesView.hpp | 4 +- src/lms/ui/admin/MediaLibraryModal.cpp | 78 +- src/lms/ui/admin/MediaLibraryModal.hpp | 3 +- src/lms/ui/admin/ScanSettingsView.cpp | 80 +- src/lms/ui/admin/ScannerController.cpp | 101 +-- src/lms/ui/admin/ScannerController.hpp | 4 +- src/lms/ui/admin/TracingView.cpp | 7 +- src/lms/ui/admin/UserView.cpp | 50 +- src/lms/ui/admin/UserView.hpp | 19 +- src/lms/ui/admin/UsersView.cpp | 129 ++-- src/lms/ui/admin/UsersView.hpp | 21 +- src/lms/ui/common/DoubleValidator.cpp | 25 +- src/lms/ui/common/DoubleValidator.hpp | 3 +- .../ui/common/InfiniteScrollingContainer.cpp | 15 +- .../ui/common/InfiniteScrollingContainer.hpp | 60 +- src/lms/ui/common/LoadingIndicator.cpp | 5 +- src/lms/ui/common/LoadingIndicator.hpp | 3 +- src/lms/ui/common/LoginNameValidator.cpp | 3 +- src/lms/ui/common/LoginNameValidator.hpp | 3 +- src/lms/ui/common/MandatoryValidator.cpp | 24 +- src/lms/ui/common/MandatoryValidator.hpp | 3 +- src/lms/ui/common/PasswordValidator.cpp | 14 +- src/lms/ui/common/PasswordValidator.hpp | 10 +- src/lms/ui/common/Template.hpp | 16 +- src/lms/ui/common/UUIDValidator.cpp | 24 +- src/lms/ui/common/UUIDValidator.hpp | 3 +- src/lms/ui/common/UppercaseValidator.cpp | 2 +- src/lms/ui/common/ValueStringModel.hpp | 2 +- src/lms/ui/explore/ArtistCollector.cpp | 125 +-- src/lms/ui/explore/ArtistCollector.hpp | 29 +- src/lms/ui/explore/ArtistListHelpers.cpp | 3 +- src/lms/ui/explore/ArtistListHelpers.hpp | 15 +- src/lms/ui/explore/ArtistView.cpp | 121 ++- src/lms/ui/explore/ArtistView.hpp | 15 +- src/lms/ui/explore/ArtistsView.cpp | 40 +- src/lms/ui/explore/ArtistsView.hpp | 6 +- src/lms/ui/explore/DatabaseCollectorBase.cpp | 3 +- src/lms/ui/explore/DatabaseCollectorBase.hpp | 8 +- src/lms/ui/explore/DropDownMenuSelector.hpp | 22 +- src/lms/ui/explore/Explore.cpp | 28 +- src/lms/ui/explore/Explore.hpp | 1 - src/lms/ui/explore/Filters.cpp | 104 ++- src/lms/ui/explore/Filters.hpp | 2 +- src/lms/ui/explore/PlayQueueController.cpp | 12 +- src/lms/ui/explore/PlayQueueController.hpp | 65 +- src/lms/ui/explore/ReleaseCollector.cpp | 114 +-- src/lms/ui/explore/ReleaseCollector.hpp | 25 +- src/lms/ui/explore/ReleaseHelpers.cpp | 74 +- src/lms/ui/explore/ReleaseHelpers.hpp | 12 +- src/lms/ui/explore/ReleaseTypes.cpp | 44 +- src/lms/ui/explore/ReleaseView.cpp | 415 +++++----- src/lms/ui/explore/ReleaseView.hpp | 38 +- src/lms/ui/explore/ReleasesView.cpp | 67 +- src/lms/ui/explore/ReleasesView.hpp | 5 +- src/lms/ui/explore/SortModeSelector.hpp | 1 - .../explore/TrackArtistLinkTypeSelector.hpp | 3 +- src/lms/ui/explore/TrackCollector.cpp | 111 +-- src/lms/ui/explore/TrackCollector.hpp | 26 +- src/lms/ui/explore/TrackListHelpers.cpp | 135 ++-- src/lms/ui/explore/TrackListHelpers.hpp | 16 +- src/lms/ui/explore/TrackListView.cpp | 130 ++-- src/lms/ui/explore/TrackListView.hpp | 37 +- src/lms/ui/explore/TrackListsView.cpp | 128 ++-- src/lms/ui/explore/TrackListsView.hpp | 2 +- src/lms/ui/explore/TracksView.cpp | 68 +- src/lms/ui/explore/TracksView.hpp | 5 +- src/lms/ui/resource/AudioFileResource.cpp | 12 +- src/lms/ui/resource/AudioFileResource.hpp | 18 +- .../ui/resource/AudioTranscodingResource.cpp | 30 +- .../ui/resource/AudioTranscodingResource.hpp | 26 +- src/lms/ui/resource/CoverResource.cpp | 17 +- src/lms/ui/resource/CoverResource.hpp | 34 +- src/lms/ui/resource/DownloadResource.cpp | 15 +- src/lms/ui/resource/DownloadResource.hpp | 89 ++- src/tools/cover/LmsCover.cpp | 11 +- src/tools/db-generator/LmsDbGenerator.cpp | 38 +- src/tools/metadata/LmsMetadata.cpp | 11 +- .../recommendation/LmsRecommendation.cpp | 94 +-- .../GeneticAlgorithm.hpp | 98 ++- .../LmsSimilarityParameters.cpp | 315 ++++---- .../similarity-parameters/ParallelFor.hpp | 32 +- 460 files changed, 8583 insertions(+), 8514 deletions(-) diff --git a/src/libs/av/impl/AudioFile.cpp b/src/libs/av/impl/AudioFile.cpp index 7a92a65e..31ad7267 100644 --- a/src/libs/av/impl/AudioFile.cpp +++ b/src/libs/av/impl/AudioFile.cpp @@ -53,7 +53,8 @@ namespace lms::av public: AudioFileException(int avError) : Exception{ "AudioFileException: " + averror_to_string(avError) } - {} + { + } }; void getMetaDataFromDictionnary(AVDictionary* dictionnary, AudioFile::MetadataMap& res) @@ -72,32 +73,52 @@ namespace lms::av { switch (codec) { - case AV_CODEC_ID_MP3: return DecodingCodec::MP3; - case AV_CODEC_ID_AAC: return DecodingCodec::AAC; - case AV_CODEC_ID_AC3: return DecodingCodec::AC3; - case AV_CODEC_ID_VORBIS: return DecodingCodec::VORBIS; - case AV_CODEC_ID_WMAV1: return DecodingCodec::WMAV1; - case AV_CODEC_ID_WMAV2: return DecodingCodec::WMAV2; - case AV_CODEC_ID_FLAC: return DecodingCodec::FLAC; - case AV_CODEC_ID_ALAC: return DecodingCodec::ALAC; - case AV_CODEC_ID_WAVPACK: return DecodingCodec::WAVPACK; - case AV_CODEC_ID_MUSEPACK7: return DecodingCodec::MUSEPACK7; - case AV_CODEC_ID_MUSEPACK8: return DecodingCodec::MUSEPACK8; - case AV_CODEC_ID_APE: return DecodingCodec::APE; - case AV_CODEC_ID_EAC3: return DecodingCodec::EAC3; - case AV_CODEC_ID_MP4ALS: return DecodingCodec::MP4ALS; - case AV_CODEC_ID_OPUS: return DecodingCodec::OPUS; - case AV_CODEC_ID_SHORTEN: return DecodingCodec::SHORTEN; - case AV_CODEC_ID_DSD_LSBF: return DecodingCodec::DSD_LSBF; - case AV_CODEC_ID_DSD_LSBF_PLANAR: return DecodingCodec::DSD_LSBF_PLANAR; - case AV_CODEC_ID_DSD_MSBF: return DecodingCodec::DSD_MSBF; - case AV_CODEC_ID_DSD_MSBF_PLANAR: return DecodingCodec::DSD_MSBF_PLANAR; + case AV_CODEC_ID_MP3: + return DecodingCodec::MP3; + case AV_CODEC_ID_AAC: + return DecodingCodec::AAC; + case AV_CODEC_ID_AC3: + return DecodingCodec::AC3; + case AV_CODEC_ID_VORBIS: + return DecodingCodec::VORBIS; + case AV_CODEC_ID_WMAV1: + return DecodingCodec::WMAV1; + case AV_CODEC_ID_WMAV2: + return DecodingCodec::WMAV2; + case AV_CODEC_ID_FLAC: + return DecodingCodec::FLAC; + case AV_CODEC_ID_ALAC: + return DecodingCodec::ALAC; + case AV_CODEC_ID_WAVPACK: + return DecodingCodec::WAVPACK; + case AV_CODEC_ID_MUSEPACK7: + return DecodingCodec::MUSEPACK7; + case AV_CODEC_ID_MUSEPACK8: + return DecodingCodec::MUSEPACK8; + case AV_CODEC_ID_APE: + return DecodingCodec::APE; + case AV_CODEC_ID_EAC3: + return DecodingCodec::EAC3; + case AV_CODEC_ID_MP4ALS: + return DecodingCodec::MP4ALS; + case AV_CODEC_ID_OPUS: + return DecodingCodec::OPUS; + case AV_CODEC_ID_SHORTEN: + return DecodingCodec::SHORTEN; + case AV_CODEC_ID_DSD_LSBF: + return DecodingCodec::DSD_LSBF; + case AV_CODEC_ID_DSD_LSBF_PLANAR: + return DecodingCodec::DSD_LSBF_PLANAR; + case AV_CODEC_ID_DSD_MSBF: + return DecodingCodec::DSD_MSBF; + case AV_CODEC_ID_DSD_MSBF_PLANAR: + return DecodingCodec::DSD_MSBF_PLANAR; default: return DecodingCodec::UNKNOWN; } } - } + } // namespace std::unique_ptr parseAudioFile(const std::filesystem::path& p) { @@ -183,8 +204,8 @@ namespace lms::av { int res = ::av_find_best_stream(_context, AVMEDIA_TYPE_AUDIO, - -1, // Auto - -1, // Auto + -1, // Auto + -1, // Auto NULL, 0); @@ -218,8 +239,7 @@ namespace lms::av void AudioFile::visitAttachedPictures(std::function func) const { - static const std::unordered_map codecMimeMap = - { + static const std::unordered_map codecMimeMap{ { AV_CODEC_ID_BMP, "image/x-bmp" }, { AV_CODEC_ID_GIF, "image/gif" }, { AV_CODEC_ID_MJPEG, "image/jpeg" }, @@ -305,31 +325,30 @@ namespace lms::av // List should be sync with the demuxers shipped in the lms's docker version // + the _audioFileExtensions in ScanSettings // std::filesystem::path does not seem to have std::hash specialization on freebsd - static const std::unordered_map entries - { - {".mp3", "audio/mpeg"}, - {".ogg", "audio/ogg"}, - {".oga", "audio/ogg"}, - {".opus", "audio/opus"}, - {".aac", "audio/aac"}, - {".alac", "audio/mp4"}, - {".m4a", "audio/mp4"}, - {".m4b", "audio/mp4"}, - {".flac", "audio/flac"}, - {".webm", "audio/webm"}, - {".wav", "audio/x-wav"}, - {".wma", "audio/x-ms-wma"}, - {".ape", "audio/x-monkeys-audio"}, - {".mpc", "audio/x-musepack"}, - {".shn", "audio/x-shn"}, - {".aif", "audio/x-aiff"}, - {".aiff", "audio/x-aiff"}, - {".m3u", "audio/x-mpegurl"}, - {".pls", "audio/x-scpls"}, - {".dsf", "audio/x-dsd"}, - {".wv", "audio/x-wavpack"}, - {".wvp", "audio/x-wavpack"}, - {".mka", "audio/x-matroska"}, + static const std::unordered_map entries{ + { ".mp3", "audio/mpeg" }, + { ".ogg", "audio/ogg" }, + { ".oga", "audio/ogg" }, + { ".opus", "audio/opus" }, + { ".aac", "audio/aac" }, + { ".alac", "audio/mp4" }, + { ".m4a", "audio/mp4" }, + { ".m4b", "audio/mp4" }, + { ".flac", "audio/flac" }, + { ".webm", "audio/webm" }, + { ".wav", "audio/x-wav" }, + { ".wma", "audio/x-ms-wma" }, + { ".ape", "audio/x-monkeys-audio" }, + { ".mpc", "audio/x-musepack" }, + { ".shn", "audio/x-shn" }, + { ".aif", "audio/x-aiff" }, + { ".aiff", "audio/x-aiff" }, + { ".m3u", "audio/x-mpegurl" }, + { ".pls", "audio/x-scpls" }, + { ".dsf", "audio/x-dsd" }, + { ".wv", "audio/x-wavpack" }, + { ".wvp", "audio/x-wavpack" }, + { ".mka", "audio/x-matroska" }, }; auto it{ entries.find(core::stringUtils::stringToLower(fileExtension.string())) }; diff --git a/src/libs/av/impl/AudioFile.hpp b/src/libs/av/impl/AudioFile.hpp index 838e6302..b1b7f1b6 100644 --- a/src/libs/av/impl/AudioFile.hpp +++ b/src/libs/av/impl/AudioFile.hpp @@ -17,8 +17,6 @@ * along with LMS. If not, see . */ - /* This file contains some classes in order to get info from file using the libavconv */ - #pragma once #include "av/IAudioFile.hpp" @@ -35,23 +33,22 @@ namespace lms::av ~AudioFile(); const std::filesystem::path& getPath() const override; - ContainerInfo getContainerInfo() const override; - MetadataMap getMetaData() const override; - std::vector getStreamInfo() const override; - std::optional getBestStreamInfo() const override; - std::optional getBestStreamIndex() const override; - bool hasAttachedPictures() const override; - void visitAttachedPictures(std::function func) const override; + ContainerInfo getContainerInfo() const override; + MetadataMap getMetaData() const override; + std::vector getStreamInfo() const override; + std::optional getBestStreamInfo() const override; + std::optional getBestStreamIndex() const override; + bool hasAttachedPictures() const override; + void visitAttachedPictures(std::function func) const override; private: AudioFile(const AudioFile&) = delete; AudioFile& operator=(const AudioFile&) = delete; - std::optional getStreamInfo(std::size_t streamIndex) const; + std::optional getStreamInfo(std::size_t streamIndex) const; - const std::filesystem::path _p; + const std::filesystem::path _p; AVFormatContext* _context{}; }; } // namespace lms::av - diff --git a/src/libs/av/impl/RawResourceHandlerCreator.cpp b/src/libs/av/impl/RawResourceHandlerCreator.cpp index 5d446743..42c200b8 100644 --- a/src/libs/av/impl/RawResourceHandlerCreator.cpp +++ b/src/libs/av/impl/RawResourceHandlerCreator.cpp @@ -29,4 +29,4 @@ namespace lms::av std::string_view mimeType{ getMimeType(path.extension()) }; return createFileResourceHandler(path, mimeType.empty() ? "application/octet-stream" : mimeType); } -} +} // namespace lms::av diff --git a/src/libs/av/impl/Transcoder.cpp b/src/libs/av/impl/Transcoder.cpp index 663c94b2..760376ef 100644 --- a/src/libs/av/impl/Transcoder.cpp +++ b/src/libs/av/impl/Transcoder.cpp @@ -24,27 +24,32 @@ #include "core/IChildProcessManager.hpp" #include "core/IConfig.hpp" -#include "core/Path.hpp" #include "core/ILogger.hpp" +#include "core/Path.hpp" #include "core/Service.hpp" namespace lms::av::transcoding { -#define LOG(severity, message) LMS_LOG(TRANSCODING, severity, "[" << _debugId << "] - " << message) +#define LOG(severity, message) LMS_LOG(TRANSCODING, severity, "[" << _debugId << "] - " << message) - static std::atomic globalId{}; - static std::filesystem::path ffmpegPath; + static std::atomic globalId{}; + static std::filesystem::path ffmpegPath; std::string_view formatToMimetype(OutputFormat format) { switch (format) { - case OutputFormat::MP3: return "audio/mpeg"; - case OutputFormat::OGG_OPUS: return "audio/opus"; - case OutputFormat::MATROSKA_OPUS: return "audio/x-matroska"; - case OutputFormat::OGG_VORBIS: return "audio/ogg"; - case OutputFormat::WEBM_VORBIS: return "audio/webm"; + case OutputFormat::MP3: + return "audio/mpeg"; + case OutputFormat::OGG_OPUS: + return "audio/opus"; + case OutputFormat::MATROSKA_OPUS: + return "audio/x-matroska"; + case OutputFormat::OGG_VORBIS: + return "audio/ogg"; + case OutputFormat::WEBM_VORBIS: + return "audio/webm"; } throw Exception{ "Invalid encoding" }; @@ -195,10 +200,9 @@ namespace lms::av::transcoding { assert(_childProcess); - return _childProcess->asyncRead(buffer, bufferSize, [readCallback{ std::move(readCallback) }](core::IChildProcess::ReadResult /*res*/, std::size_t nbBytesRead) - { - readCallback(nbBytesRead); - }); + return _childProcess->asyncRead(buffer, bufferSize, [readCallback{ std::move(readCallback) }](core::IChildProcess::ReadResult /*res*/, std::size_t nbBytesRead) { + readCallback(nbBytesRead); + }); } std::size_t Transcoder::readSome(std::byte* buffer, std::size_t bufferSize) @@ -215,4 +219,4 @@ namespace lms::av::transcoding return _childProcess->finished(); } -} // namespace lms::av::Transcoding +} // namespace lms::av::transcoding diff --git a/src/libs/av/impl/Transcoder.hpp b/src/libs/av/impl/Transcoder.hpp index febc37d5..4e24c4f3 100644 --- a/src/libs/av/impl/Transcoder.hpp +++ b/src/libs/av/impl/Transcoder.hpp @@ -45,24 +45,24 @@ namespace lms::av::transcoding // non blocking calls using ReadCallback = std::function; - void asyncRead(std::byte* buffer, std::size_t bufferSize, ReadCallback); - std::size_t readSome(std::byte* buffer, std::size_t bufferSize); + void asyncRead(std::byte* buffer, std::size_t bufferSize, ReadCallback); + std::size_t readSome(std::byte* buffer, std::size_t bufferSize); const std::string& getOutputMimeType() const { return _outputMimeType; } const OutputParameters& getOutputParameters() const { return _outputParameters; } - bool finished() const; + bool finished() const; private: static void init(); void start(); - const std::size_t _debugId{}; - const InputParameters _inputParameters; - const OutputParameters _outputParameters; - std::string _outputMimeType; + const std::size_t _debugId{}; + const InputParameters _inputParameters; + const OutputParameters _outputParameters; + std::string _outputMimeType; - std::unique_ptr _childProcess; + std::unique_ptr _childProcess; }; -} \ No newline at end of file +} // namespace lms::av::transcoding \ No newline at end of file diff --git a/src/libs/av/impl/TranscodingResourceHandler.cpp b/src/libs/av/impl/TranscodingResourceHandler.cpp index d8882103..09932835 100644 --- a/src/libs/av/impl/TranscodingResourceHandler.cpp +++ b/src/libs/av/impl/TranscodingResourceHandler.cpp @@ -29,7 +29,7 @@ namespace lms::av::transcoding const std::size_t estimatedContentLength{ outputParameters.bitrate / 8 * static_cast(std::chrono::duration_cast(inputParameters.duration).count()) / 1000 }; return estimatedContentLength; } - } + } // namespace std::unique_ptr createResourceHandler(const InputParameters& inputParameters, const OutputParameters& outputParameters, bool estimateContentLength) { @@ -68,14 +68,13 @@ namespace lms::av::transcoding { Wt::Http::ResponseContinuation* continuation{ response.createContinuation() }; continuation->waitForMoreData(); - _transcoder.asyncRead(_buffer.data(), _buffer.size(), [this, continuation](std::size_t nbBytesRead) - { - LMS_LOG(TRANSCODING, DEBUG, "Have " << nbBytesRead << " more bytes to send back"); + _transcoder.asyncRead(_buffer.data(), _buffer.size(), [this, continuation](std::size_t nbBytesRead) { + LMS_LOG(TRANSCODING, DEBUG, "Have " << nbBytesRead << " more bytes to send back"); - assert(_bytesReadyCount == 0); - _bytesReadyCount = nbBytesRead; - continuation->haveMoreData(); - }); + assert(_bytesReadyCount == 0); + _bytesReadyCount = nbBytesRead; + continuation->haveMoreData(); + }); return continuation; } @@ -99,5 +98,4 @@ namespace lms::av::transcoding return {}; } -} - +} // namespace lms::av::transcoding diff --git a/src/libs/av/impl/TranscodingResourceHandler.hpp b/src/libs/av/impl/TranscodingResourceHandler.hpp index 8da15af5..037ebe16 100644 --- a/src/libs/av/impl/TranscodingResourceHandler.hpp +++ b/src/libs/av/impl/TranscodingResourceHandler.hpp @@ -25,6 +25,7 @@ #include "av/TranscodingParameters.hpp" #include "core/IResourceHandler.hpp" + #include "Transcoder.hpp" namespace lms::av::transcoding @@ -36,7 +37,7 @@ namespace lms::av::transcoding private: Wt::Http::ResponseContinuation* processRequest(const Wt::Http::Request& request, Wt::Http::Response& reponse) override; - void abort() override {}; + void abort() override{}; static constexpr std::size_t _chunkSize{ 262'144 }; std::optional _estimatedContentLength; @@ -45,5 +46,4 @@ namespace lms::av::transcoding std::size_t _totalServedByteCount{}; Transcoder _transcoder; }; -} - +} // namespace lms::av::transcoding diff --git a/src/libs/av/include/av/IAudioFile.hpp b/src/libs/av/include/av/IAudioFile.hpp index 51988d33..d6618da6 100644 --- a/src/libs/av/include/av/IAudioFile.hpp +++ b/src/libs/av/include/av/IAudioFile.hpp @@ -17,17 +17,15 @@ * along with LMS. If not, see . */ - /* This file contains some classes in order to get info from file using the libavconv */ - #pragma once #include #include #include -#include #include #include #include +#include #include #include "Types.hpp" @@ -44,13 +42,13 @@ namespace lms::av VORBIS, WMAV1, WMAV2, - FLAC, // Flac - ALAC, // Apple Lossless Audio Codec (ALAC) - WAVPACK, // WavPack - MUSEPACK7, // Musepack + FLAC, // Flac + ALAC, // Apple Lossless Audio Codec (ALAC) + WAVPACK, // WavPack + MUSEPACK7, // Musepack MUSEPACK8, APE, // Monkey's Audio - EAC3, // Enhanced AC-3 + EAC3, // Enhanced AC-3 MP4ALS, // MPEG-4 Audio Lossless Coding OPUS, // Opus SHORTEN, // Shorten (shn) @@ -63,9 +61,9 @@ namespace lms::av struct Picture { - std::string mimeType; + std::string mimeType; const std::byte* data{}; - std::size_t dataSize{}; + std::size_t dataSize{}; }; struct ContainerInfo @@ -77,13 +75,13 @@ namespace lms::av struct StreamInfo { - size_t index{}; - std::size_t bitrate{}; - std::size_t bitsPerSample{}; - std::size_t channelCount{}; - std::size_t sampleRate{}; - DecodingCodec codec; - std::string codecName; + size_t index{}; + std::size_t bitrate{}; + std::size_t bitsPerSample{}; + std::size_t channelCount{}; + std::size_t sampleRate{}; + DecodingCodec codec; + std::string codecName; }; class IAudioFile @@ -95,13 +93,13 @@ namespace lms::av using MetadataMap = std::unordered_map; virtual const std::filesystem::path& getPath() const = 0; - virtual ContainerInfo getContainerInfo() const = 0; - virtual MetadataMap getMetaData() const = 0; - virtual std::vector getStreamInfo() const = 0; - virtual std::optional getBestStreamInfo() const = 0; // none if failure/unknown - virtual std::optional getBestStreamIndex() const = 0; // none if failure/unknown - virtual bool hasAttachedPictures() const = 0; - virtual void visitAttachedPictures(std::function func) const = 0; + virtual ContainerInfo getContainerInfo() const = 0; + virtual MetadataMap getMetaData() const = 0; + virtual std::vector getStreamInfo() const = 0; + virtual std::optional getBestStreamInfo() const = 0; // none if failure/unknown + virtual std::optional getBestStreamIndex() const = 0; // none if failure/unknown + virtual bool hasAttachedPictures() const = 0; + virtual void visitAttachedPictures(std::function func) const = 0; }; std::unique_ptr parseAudioFile(const std::filesystem::path& p); @@ -115,4 +113,3 @@ namespace lms::av std::string_view getMimeType(const std::filesystem::path& fileExtension); } // namespace lms::av - diff --git a/src/libs/av/include/av/TranscodingParameters.hpp b/src/libs/av/include/av/TranscodingParameters.hpp index 2fd7e358..cc2a9a79 100644 --- a/src/libs/av/include/av/TranscodingParameters.hpp +++ b/src/libs/av/include/av/TranscodingParameters.hpp @@ -46,11 +46,10 @@ namespace lms::av::transcoding struct OutputParameters { - OutputFormat format; - std::size_t bitrate{ 128000 }; - std::optional stream; // Id of the stream to be transcoded (auto detect by default) - std::chrono::milliseconds offset{ 0 }; - bool stripMetadata{ true }; + OutputFormat format; + std::size_t bitrate{ 128000 }; + std::optional stream; // Id of the stream to be transcoded (auto detect by default) + std::chrono::milliseconds offset{ 0 }; + bool stripMetadata{ true }; }; -} // namespace lms::av::Transcoding - +} // namespace lms::av::transcoding diff --git a/src/libs/av/include/av/TranscodingResourceHandlerCreator.hpp b/src/libs/av/include/av/TranscodingResourceHandlerCreator.hpp index 35c13ed7..553ab5ea 100644 --- a/src/libs/av/include/av/TranscodingResourceHandlerCreator.hpp +++ b/src/libs/av/include/av/TranscodingResourceHandlerCreator.hpp @@ -25,8 +25,8 @@ namespace lms::av::transcoding { - struct InputParameters; - struct OutputParameters; + struct InputParameters; + struct OutputParameters; - std::unique_ptr createResourceHandler(const InputParameters& inputParameters, const OutputParameters& outputParameters, bool estimateContentLength); -} + std::unique_ptr createResourceHandler(const InputParameters& inputParameters, const OutputParameters& outputParameters, bool estimateContentLength); +} // namespace lms::av::transcoding diff --git a/src/libs/av/include/av/Types.hpp b/src/libs/av/include/av/Types.hpp index 3de4d3fe..baf7809b 100644 --- a/src/libs/av/include/av/Types.hpp +++ b/src/libs/av/include/av/Types.hpp @@ -28,4 +28,4 @@ namespace lms::av public: using LmsException::LmsException; }; -} +} // namespace lms::av diff --git a/src/libs/core/bench/TraceLoggerBench.cpp b/src/libs/core/bench/TraceLoggerBench.cpp index f340fa1c..1134fb42 100644 --- a/src/libs/core/bench/TraceLoggerBench.cpp +++ b/src/libs/core/bench/TraceLoggerBench.cpp @@ -17,9 +17,9 @@ * along with LMS. If not, see . */ -#include #include #include + #include #include "core/ILogger.hpp" @@ -59,8 +59,7 @@ namespace lms::core static void BM_TraceLogger_Detailed_withArg(benchmark::State& state) { - auto someExpensiveArgComputation{ []() -> std::string - { + auto someExpensiveArgComputation{ []() -> std::string { std::this_thread::sleep_for(std::chrono::microseconds{ 1 }); return "foo"; } }; @@ -77,6 +76,6 @@ namespace lms::core BENCHMARK(BM_TraceLogger_Detailed)->Threads(1)->Threads(std::thread::hardware_concurrency()); BENCHMARK(BM_TraceLogger_Detailed_withArg)->Threads(1)->Threads(std::thread::hardware_concurrency()); -} +} // namespace lms::core BENCHMARK_MAIN(); \ No newline at end of file diff --git a/src/libs/core/impl/ArchiveZipper.cpp b/src/libs/core/impl/ArchiveZipper.cpp index 91102262..5f3fcecd 100644 --- a/src/libs/core/impl/ArchiveZipper.cpp +++ b/src/libs/core/impl/ArchiveZipper.cpp @@ -23,6 +23,7 @@ #include #include // strerror #include + #include #include @@ -39,12 +40,14 @@ namespace lms::zip { public: FileException(const std::filesystem::path& p, std::string_view message) - : Exception{ "File '" + p.string() + "': " + std::string {message} } - {} + : Exception{ "File '" + p.string() + "': " + std::string{ message } } + { + } FileException(const std::filesystem::path& p, std::string_view message, int err) - : Exception{ "File '" + p.string() + "': " + std::string {message} + ": " + ::strerror(err) } - {} + : Exception{ "File '" + p.string() + "': " + std::string{ message } + ": " + ::strerror(err) } + { + } }; class ArchiveException : public Exception @@ -52,7 +55,8 @@ namespace lms::zip public: ArchiveException(struct ::archive* arch) : Exception{ getError(arch) } - {} + { + } static std::string_view getError(struct ::archive* arch) { @@ -88,19 +92,16 @@ namespace lms::zip if (!_archive) throw Exception{ "Cannot create archive control struct" }; - auto archiveOpen{ [](struct ::archive*, void*) - { + auto archiveOpen{ [](struct ::archive*, void*) { return ARCHIVE_OK; } }; - auto archiveWrite{ [](struct ::archive*, void* clientData, const void* buff, ::size_t n) -> la_ssize_t - { - ArchiveZipper* zipper {static_cast(clientData)}; + auto archiveWrite{ [](struct ::archive*, void* clientData, const void* buff, ::size_t n) -> la_ssize_t { + ArchiveZipper* zipper{ static_cast(clientData) }; return zipper->onWriteCallback(static_cast(buff), n); } }; - auto archiveClose{ [](struct ::archive*, void*) - { + auto archiveClose{ [](struct ::archive*, void*) { return ARCHIVE_OK; } }; @@ -183,8 +184,7 @@ namespace lms::zip using std::filesystem::perms; ::mode_t mode{}; - auto testPerm{ [](perms p, perms permToTest) - { + auto testPerm{ [](perms p, perms permToTest) { return (p & permToTest) == permToTest; } }; @@ -295,4 +295,4 @@ namespace lms::zip return bufferSize; } -} +} // namespace lms::zip diff --git a/src/libs/core/impl/ArchiveZipper.hpp b/src/libs/core/impl/ArchiveZipper.hpp index 43fead7e..5d5b97e5 100644 --- a/src/libs/core/impl/ArchiveZipper.hpp +++ b/src/libs/core/impl/ArchiveZipper.hpp @@ -21,6 +21,7 @@ #include #include + #include "core/IZipper.hpp" extern "C" @@ -77,4 +78,4 @@ namespace lms::zip std::uint64_t _bytesWrittenInCurrentOutputStream{}; }; -} \ No newline at end of file +} // namespace lms::zip \ No newline at end of file diff --git a/src/libs/core/impl/ChildProcess.cpp b/src/libs/core/impl/ChildProcess.cpp index 3c9cd158..d2956a3d 100644 --- a/src/libs/core/impl/ChildProcess.cpp +++ b/src/libs/core/impl/ChildProcess.cpp @@ -19,21 +19,21 @@ #include "ChildProcess.hpp" -#include #include +#include #include +#include #include #include #include -#include #include #include #include #include -#include #include +#include #include "core/Exception.hpp" #include "core/ILogger.hpp" @@ -47,13 +47,15 @@ namespace lms::core public: SystemException(int err, const std::string& errMsg) : ChildProcessException{ errMsg + ": " + ::strerror(err) } - {} + { + } SystemException(boost::system::error_code ec, const std::string& errMsg) : ChildProcessException{ errMsg + ": " + ec.message() } - {} + { + } }; - } + } // namespace ChildProcess::ChildProcess(boost::asio::io_context& ioContext, const std::filesystem::path& path, const Args& args) : _ioContext{ ioContext } @@ -170,8 +172,7 @@ namespace lms::core LMS_LOG(CHILDPROCESS, DEBUG, "Async read, bufferSize = " << bufferSize); boost::asio::async_read(_childStdout, boost::asio::buffer(data, bufferSize), - [this, callback{ std::move(callback) }](const boost::system::error_code& error, std::size_t bytesTransferred) - { + [this, callback{ std::move(callback) }](const boost::system::error_code& error, std::size_t bytesTransferred) { LMS_LOG(CHILDPROCESS, DEBUG, "Async read cb - ec = '" << error.message() << "' (" << error.value() << "), bytesTransferred = " << bytesTransferred); ReadResult readResult{ ReadResult::Success }; @@ -206,4 +207,4 @@ namespace lms::core { return _finished; } -} \ No newline at end of file +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/core/impl/ChildProcess.hpp b/src/libs/core/impl/ChildProcess.hpp index 9f5aea09..a1628e14 100644 --- a/src/libs/core/impl/ChildProcess.hpp +++ b/src/libs/core/impl/ChildProcess.hpp @@ -40,20 +40,20 @@ namespace lms::core ChildProcess(boost::asio::io_context& ioContext, const std::filesystem::path& path, const Args& args); private: - void asyncRead(std::byte* data, std::size_t bufferSize, ReadCallback callback) override; - std::size_t readSome(std::byte* data, std::size_t bufferSize) override; - bool finished() const override; + void asyncRead(std::byte* data, std::size_t bufferSize, ReadCallback callback) override; + std::size_t readSome(std::byte* data, std::size_t bufferSize) override; + bool finished() const override; - void kill(); - bool wait(bool block); // return true if waited + void kill(); + bool wait(bool block); // return true if waited using FileDescriptor = boost::asio::posix::stream_descriptor; boost::asio::io_context& _ioContext; - FileDescriptor _childStdout; - ::pid_t _childPID{}; - bool _waited{}; - bool _finished{}; - std::optional _exitCode; + FileDescriptor _childStdout; + ::pid_t _childPID{}; + bool _waited{}; + bool _finished{}; + std::optional _exitCode; }; -} \ No newline at end of file +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/core/impl/ChildProcessManager.cpp b/src/libs/core/impl/ChildProcessManager.cpp index e7dc459e..3afa7d60 100644 --- a/src/libs/core/impl/ChildProcessManager.cpp +++ b/src/libs/core/impl/ChildProcessManager.cpp @@ -39,4 +39,4 @@ namespace lms::core { return std::make_unique(_ioContext, path, args); } -} \ No newline at end of file +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/core/impl/ChildProcessManager.hpp b/src/libs/core/impl/ChildProcessManager.hpp index 39a56998..d7e5bc29 100644 --- a/src/libs/core/impl/ChildProcessManager.hpp +++ b/src/libs/core/impl/ChildProcessManager.hpp @@ -44,4 +44,4 @@ namespace lms::core boost::asio::io_context& _ioContext; }; -} \ No newline at end of file +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/core/impl/Config.cpp b/src/libs/core/impl/Config.cpp index 334f634a..c4523171 100644 --- a/src/libs/core/impl/Config.cpp +++ b/src/libs/core/impl/Config.cpp @@ -65,7 +65,7 @@ namespace lms::core { try { - const libconfig::Setting& values{ _config.lookup(std::string {setting}) }; + const libconfig::Setting& values{ _config.lookup(std::string{ setting }) }; for (int i{}; i < values.getLength(); ++i) _func(static_cast(values[i])); } @@ -83,7 +83,7 @@ namespace lms::core { try { - const char* res{ _config.lookup(std::string {setting}) }; + const char* res{ _config.lookup(std::string{ setting }) }; return std::filesystem::path{ std::string(res) }; } catch (libconfig::ConfigException&) @@ -127,4 +127,4 @@ namespace lms::core return def; } } -} \ No newline at end of file +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/core/impl/Config.hpp b/src/libs/core/impl/Config.hpp index a267d47b..b1d323ff 100644 --- a/src/libs/core/impl/Config.hpp +++ b/src/libs/core/impl/Config.hpp @@ -37,15 +37,14 @@ namespace lms::core Config& operator=(Config&&) = delete; // Default values are returned in case of setting not found - std::string_view getString(std::string_view setting, std::string_view def = "") override; - void visitStrings(std::string_view setting, std::function _func, std::initializer_list defs) override; - std::filesystem::path getPath(std::string_view setting, const std::filesystem::path& def = std::filesystem::path()) override; - unsigned long getULong(std::string_view setting, unsigned long def = 0) override; - long getLong(std::string_view setting, long def = 0) override; - bool getBool(std::string_view setting, bool def = false) override; + std::string_view getString(std::string_view setting, std::string_view def = "") override; + void visitStrings(std::string_view setting, std::function _func, std::initializer_list defs) override; + std::filesystem::path getPath(std::string_view setting, const std::filesystem::path& def = std::filesystem::path()) override; + unsigned long getULong(std::string_view setting, unsigned long def = 0) override; + long getLong(std::string_view setting, long def = 0) override; + bool getBool(std::string_view setting, bool def = false) override; private: - libconfig::Config _config; }; -} \ No newline at end of file +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/core/impl/FileResourceHandler.cpp b/src/libs/core/impl/FileResourceHandler.cpp index 5a5ef8b8..49f871c5 100644 --- a/src/libs/core/impl/FileResourceHandler.cpp +++ b/src/libs/core/impl/FileResourceHandler.cpp @@ -80,7 +80,7 @@ namespace lms std::ostringstream contentRange; contentRange << "bytes " << startByte << "-" - << _beyondLastByte - 1 << "/" << fileSize; + << _beyondLastByte - 1 << "/" << fileSize; response.addHeader("Content-Range", contentRange.str()); response.setContentLength(_beyondLastByte - startByte); @@ -134,4 +134,4 @@ namespace lms LMS_LOG(UTILS, DEBUG, "Job complete!"); return nullptr; } -} \ No newline at end of file +} // namespace lms \ No newline at end of file diff --git a/src/libs/core/impl/FileResourceHandler.hpp b/src/libs/core/impl/FileResourceHandler.hpp index 5c239277..6b79d4e5 100644 --- a/src/libs/core/impl/FileResourceHandler.hpp +++ b/src/libs/core/impl/FileResourceHandler.hpp @@ -22,6 +22,7 @@ #include #include #include + #include "core/IResourceHandler.hpp" namespace lms @@ -33,13 +34,13 @@ namespace lms private: Wt::Http::ResponseContinuation* processRequest(const Wt::Http::Request& request, Wt::Http::Response& response) override; - void abort() override {}; + void abort() override{}; static constexpr std::size_t _chunkSize{ 262'144 }; - std::filesystem::path _path; - std::string _mimeType; - ::uint64_t _beyondLastByte{}; - ::uint64_t _offset{}; + std::filesystem::path _path; + std::string _mimeType; + ::uint64_t _beyondLastByte{}; + ::uint64_t _offset{}; }; -} \ No newline at end of file +} // namespace lms \ No newline at end of file diff --git a/src/libs/core/impl/IOContextRunner.cpp b/src/libs/core/impl/IOContextRunner.cpp index c78fcd80..2094f691 100644 --- a/src/libs/core/impl/IOContextRunner.cpp +++ b/src/libs/core/impl/IOContextRunner.cpp @@ -41,24 +41,23 @@ namespace lms::core threadName += std::to_string(i); } - _threads.emplace_back([this, threadName] + _threads.emplace_back([this, threadName] { + if (!threadName.empty()) { - if (!threadName.empty()) - { - if (auto * traceLogger{ Service::get() }) - traceLogger->setThreadName(std::this_thread::get_id(), threadName); - } + if (auto* traceLogger{ Service::get() }) + traceLogger->setThreadName(std::this_thread::get_id(), threadName); + } - try - { - _ioService.run(); - } - catch (const std::exception& e) - { - LMS_LOG(UTILS, FATAL, "Exception caught in IO context: " << e.what()); - std::abort(); - } - }); + try + { + _ioService.run(); + } + catch (const std::exception& e) + { + LMS_LOG(UTILS, FATAL, "Exception caught in IO context: " << e.what()); + std::abort(); + } + }); } } @@ -82,4 +81,4 @@ namespace lms::core for (std::thread& t : _threads) t.join(); } -} \ No newline at end of file +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/core/impl/Logger.cpp b/src/libs/core/impl/Logger.cpp index a859e730..a4765e44 100644 --- a/src/libs/core/impl/Logger.cpp +++ b/src/libs/core/impl/Logger.cpp @@ -25,25 +25,44 @@ namespace lms::core::logging { switch (mod) { - case Module::API_SUBSONIC: return "API_SUBSONIC"; - case Module::AUTH: return "AUTH"; - case Module::AV: return "AV"; - case Module::CHILDPROCESS: return "CHILDPROC"; - case Module::COVER: return "COVER"; - case Module::DB: return "DB"; - case Module::DBUPDATER: return "DB UPDATER"; - case Module::FEATURE: return "FEATURE"; - case Module::FEEDBACK: return "FEEDBACK"; - case Module::HTTP: return "HTTP"; - case Module::MAIN: return "MAIN"; - case Module::METADATA: return "METADATA"; - case Module::REMOTE: return "REMOTE"; - case Module::SCROBBLING: return "SCROBBLING"; - case Module::SERVICE: return "SERVICE"; - case Module::RECOMMENDATION: return "RECOMMENDATION"; - case Module::TRANSCODING: return "TRANSCODING"; - case Module::UI: return "UI"; - case Module::UTILS: return "UTILS"; + case Module::API_SUBSONIC: + return "API_SUBSONIC"; + case Module::AUTH: + return "AUTH"; + case Module::AV: + return "AV"; + case Module::CHILDPROCESS: + return "CHILDPROC"; + case Module::COVER: + return "COVER"; + case Module::DB: + return "DB"; + case Module::DBUPDATER: + return "DB UPDATER"; + case Module::FEATURE: + return "FEATURE"; + case Module::FEEDBACK: + return "FEEDBACK"; + case Module::HTTP: + return "HTTP"; + case Module::MAIN: + return "MAIN"; + case Module::METADATA: + return "METADATA"; + case Module::REMOTE: + return "REMOTE"; + case Module::SCROBBLING: + return "SCROBBLING"; + case Module::SERVICE: + return "SERVICE"; + case Module::RECOMMENDATION: + return "RECOMMENDATION"; + case Module::TRANSCODING: + return "TRANSCODING"; + case Module::UI: + return "UI"; + case Module::UTILS: + return "UTILS"; } return ""; } @@ -52,11 +71,16 @@ namespace lms::core::logging { switch (sev) { - case Severity::FATAL: return "fatal"; - case Severity::ERROR: return "error"; - case Severity::WARNING: return "warning"; - case Severity::INFO: return "info"; - case Severity::DEBUG: return "debug"; + case Severity::FATAL: + return "fatal"; + case Severity::ERROR: + return "error"; + case Severity::WARNING: + return "warning"; + case Severity::INFO: + return "info"; + case Severity::DEBUG: + return "debug"; } return ""; } @@ -66,7 +90,8 @@ namespace lms::core::logging , _module{ module } , _severity{ severity } - {} + { + } Log::~Log() { @@ -78,4 +103,4 @@ namespace lms::core::logging { return _oss.str(); } -} \ No newline at end of file +} // namespace lms::core::logging \ No newline at end of file diff --git a/src/libs/core/impl/NetAddress.cpp b/src/libs/core/impl/NetAddress.cpp index 7b8bc427..565ee410 100644 --- a/src/libs/core/impl/NetAddress.cpp +++ b/src/libs/core/impl/NetAddress.cpp @@ -23,24 +23,24 @@ namespace std { - std::size_t hash::operator()(const boost::asio::ip::address& ipAddr) const - { - if (ipAddr.is_v4()) - return ipAddr.to_v4().to_ulong(); + std::size_t hash::operator()(const boost::asio::ip::address& ipAddr) const + { + if (ipAddr.is_v4()) + return ipAddr.to_v4().to_ulong(); - if (ipAddr.is_v6()) - { - const auto& range {ipAddr.to_v6().to_bytes()}; - std::size_t res {}; + if (ipAddr.is_v6()) + { + const auto& range{ ipAddr.to_v6().to_bytes() }; + std::size_t res{}; - for (auto b : range) - res ^= std::hash{}(static_cast(b)); + for (auto b : range) + res ^= std::hash{}(static_cast(b)); - return res; - } + return res; + } - return std::hash{}(ipAddr.to_string()); - } -} + return std::hash{}(ipAddr.to_string()); + } +} // namespace std #endif // BOOST_ASIO_HAS_STD_HASH diff --git a/src/libs/core/impl/Path.cpp b/src/libs/core/impl/Path.cpp index 5e55bf72..75b30c5a 100644 --- a/src/libs/core/impl/Path.cpp +++ b/src/libs/core/impl/Path.cpp @@ -19,12 +19,11 @@ #include "core/Path.hpp" -#include -#include -#include - #include #include +#include +#include +#include #include @@ -44,7 +43,7 @@ namespace lms::core::pathUtils { do { - std::array buffer; + std::array buffer; ifs.read(buffer.data(), buffer.size()); crc32.processBytes(reinterpret_cast(buffer.data()), ifs.gcount()); @@ -69,7 +68,9 @@ namespace lms::core::pathUtils Wt::WDateTime getLastWriteTime(const std::filesystem::path& file) { - struct stat sb {}; + struct stat sb + { + }; if (stat(file.string().c_str(), &sb) == -1) throw LmsException("Failed to get stats on file '" + file.string() + "'"); @@ -183,4 +184,4 @@ namespace lms::core::pathUtils return longestCommonPath; } -} +} // namespace lms::core::pathUtils diff --git a/src/libs/core/impl/Random.cpp b/src/libs/core/impl/Random.cpp index 18b65462..3a7ae737 100644 --- a/src/libs/core/impl/Random.cpp +++ b/src/libs/core/impl/Random.cpp @@ -35,4 +35,4 @@ namespace lms::core::random return RandGenerator{ seed }; } -} \ No newline at end of file +} // namespace lms::core::random \ No newline at end of file diff --git a/src/libs/core/impl/RecursiveSharedMutex.cpp b/src/libs/core/impl/RecursiveSharedMutex.cpp index 74ff9bab..cd7b9856 100644 --- a/src/libs/core/impl/RecursiveSharedMutex.cpp +++ b/src/libs/core/impl/RecursiveSharedMutex.cpp @@ -131,4 +131,4 @@ namespace lms::core return _sharedCounts[thisThreadId] > 0; } #endif -} \ No newline at end of file +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/core/impl/StreamLogger.cpp b/src/libs/core/impl/StreamLogger.cpp index 4e6e26d5..e8d23736 100644 --- a/src/libs/core/impl/StreamLogger.cpp +++ b/src/libs/core/impl/StreamLogger.cpp @@ -35,4 +35,4 @@ namespace lms::core::logging assert(isSeverityActive(log.getSeverity())); _os << std::this_thread::get_id() << " [" << getSeverityName(log.getSeverity()) << "] [" << getModuleName(log.getModule()) << "] " << log.getMessage() << std::endl; } -} \ No newline at end of file +} // namespace lms::core::logging \ No newline at end of file diff --git a/src/libs/core/impl/String.cpp b/src/libs/core/impl/String.cpp index 35fb876e..a891e766 100644 --- a/src/libs/core/impl/String.cpp +++ b/src/libs/core/impl/String.cpp @@ -23,15 +23,14 @@ #include #include -#include #include +#include namespace lms::core::stringUtils { namespace details { - constexpr std::pair jsEscapeChars[] - { + constexpr std::pair jsEscapeChars[]{ { '\\', "\\\\" }, { '\n', "\\n" }, { '\r', "\\r" }, @@ -40,8 +39,7 @@ namespace lms::core::stringUtils { '\'', "\\\'" }, }; - constexpr std::pair jsonEscapeChars[] - { + constexpr std::pair jsonEscapeChars[]{ { '\\', "\\\\" }, { '\n', "\\n" }, { '\r', "\\r" }, @@ -49,8 +47,8 @@ namespace lms::core::stringUtils { '"', "\\\"" }, }; - template - std::string escape(std::string_view str, const std::pair(&charsToEscape)[N]) + template + std::string escape(std::string_view str, const std::pair (&charsToEscape)[N]) { std::string escaped; escaped.reserve(str.length()); @@ -70,12 +68,12 @@ namespace lms::core::stringUtils return escaped; } - template - void writeEscapedString(std::ostream& os, std::string_view str, const std::pair(&charsToEscape)[N]) + template + void writeEscapedString(std::ostream& os, std::string_view str, const std::pair (&charsToEscape)[N]) { for (const char c : str) { - auto itEntry{ std::find_if(std::cbegin(charsToEscape), std::cend(charsToEscape), [=](const auto& entry) { return entry.first == c;}) }; + auto itEntry{ std::find_if(std::cbegin(charsToEscape), std::cend(charsToEscape), [=](const auto& entry) { return entry.first == c; }) }; if (itEntry != std::cend(charsToEscape)) os << itEntry->second; else @@ -83,7 +81,7 @@ namespace lms::core::stringUtils } } - template + template std::string joinStrings(std::span strings, std::string_view delimiter) { std::string res; @@ -99,7 +97,7 @@ namespace lms::core::stringUtils return res; } - } + } // namespace details template<> std::optional readAs(std::string_view str) @@ -198,7 +196,8 @@ namespace lms::core::stringUtils for (char c : str) { - if (escaped) { + if (escaped) + { current.push_back(c); escaped = false; } @@ -248,14 +247,14 @@ namespace lms::core::stringUtils std::string res; res.reserve(str.size()); - std::transform(std::cbegin(str), std::cend(str), std::back_inserter(res), [](unsigned char c) { return std::tolower(c);}); + std::transform(std::cbegin(str), std::cend(str), std::back_inserter(res), [](unsigned char c) { return std::tolower(c); }); return res; } void stringToLower(std::string& str) { - std::transform(std::cbegin(str), std::cend(str), std::begin(str), [](unsigned char c) { return std::tolower(c);}); + std::transform(std::cbegin(str), std::cend(str), std::begin(str), [](unsigned char c) { return std::tolower(c); }); } std::string stringToUpper(const std::string& str) @@ -263,7 +262,7 @@ namespace lms::core::stringUtils std::string res; res.reserve(str.size()); - std::transform(std::cbegin(str), std::cend(str), std::back_inserter(res), [](char c) { return std::toupper(c);}); + std::transform(std::cbegin(str), std::cend(str), std::back_inserter(res), [](char c) { return std::toupper(c); }); return res; } @@ -436,4 +435,4 @@ namespace lms::core::stringUtils // assume UTC return date.toString("yyyy-MM-dd").toUTF8(); } -} +} // namespace lms::core::stringUtils diff --git a/src/libs/core/impl/TraceLogger.cpp b/src/libs/core/impl/TraceLogger.cpp index adddad9d..88b0f269 100644 --- a/src/libs/core/impl/TraceLogger.cpp +++ b/src/libs/core/impl/TraceLogger.cpp @@ -22,6 +22,7 @@ #include #include #include + #include "core/Exception.hpp" #include "core/ILogger.hpp" @@ -32,7 +33,8 @@ namespace lms::core::tracing class CurrentThreadUnregisterer { public: - CurrentThreadUnregisterer(TraceLogger* logger) : _logger{ logger } {} + CurrentThreadUnregisterer(TraceLogger* logger) + : _logger{ logger } {} ~CurrentThreadUnregisterer() { if (_logger) @@ -45,7 +47,7 @@ namespace lms::core::tracing TraceLogger* _logger; }; - } + } // namespace thread_local TraceLogger::Buffer* TraceLogger::_currentBuffer{}; @@ -71,11 +73,11 @@ namespace lms::core::tracing LMS_LOG(UTILS, INFO, "TraceLogger: using " << _buffers.size() << " buffers. Buffer size = " << std::to_string(BufferSize) << ", entry size = " << sizeof(CompleteEventEntry) << ", entry count per buffer = " << Buffer::CompleteEventCount); setMetadata("cpu_count", std::to_string(std::thread::hardware_concurrency())); - setMetadata("build_type", + setMetadata("build_type", #ifndef NDEBUG - "debug" + "debug" #else - "release" + "release" #endif ); } @@ -182,7 +184,8 @@ namespace lms::core::tracing if (first) first = false; else - os << ", " << std::endl;; + os << ", " << std::endl; + ; os << "\t\t{ "; os << "\"name\" : \"" << event.name << "\", "; @@ -297,4 +300,4 @@ namespace lms::core::tracing return static_cast(id); } -} \ No newline at end of file +} // namespace lms::core::tracing \ No newline at end of file diff --git a/src/libs/core/impl/TraceLogger.hpp b/src/libs/core/impl/TraceLogger.hpp index 79cc256b..4e338fdd 100644 --- a/src/libs/core/impl/TraceLogger.hpp +++ b/src/libs/core/impl/TraceLogger.hpp @@ -103,4 +103,4 @@ namespace lms::core::tracing static thread_local Buffer* _currentBuffer; }; -} \ No newline at end of file +} // namespace lms::core::tracing \ No newline at end of file diff --git a/src/libs/core/impl/UUID.cpp b/src/libs/core/impl/UUID.cpp index 6573b44a..756bcb1a 100644 --- a/src/libs/core/impl/UUID.cpp +++ b/src/libs/core/impl/UUID.cpp @@ -31,13 +31,13 @@ namespace lms::core { namespace stringUtils { - template <> + template<> std::optional - readAs(std::string_view str) + readAs(std::string_view str) { return UUID::fromString(str); } - } + } // namespace stringUtils namespace { bool stringIsUUID(std::string_view str) @@ -46,7 +46,7 @@ namespace lms::core return std::regex_match(std::cbegin(str), std::cend(str), re); } - } + } // namespace UUID::UUID(std::string_view str) : _value{ stringUtils::stringToLower(str) } @@ -68,9 +68,8 @@ namespace lms::core std::ostringstream oss; - auto concatRandomBytes{ [](std::ostream& os, std::size_t byteCount) - { - for (std::size_t i {}; i < byteCount; ++i) + auto concatRandomBytes{ [](std::ostream& os, std::size_t byteCount) { + for (std::size_t i{}; i < byteCount; ++i) os << std::hex << std::setfill('0') << std::setw(2) << static_cast(random::getRandom(0, 255)); } }; @@ -88,4 +87,4 @@ namespace lms::core assert(uuid); return uuid.value(); } -} \ No newline at end of file +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/core/impl/WtLogger.cpp b/src/libs/core/impl/WtLogger.cpp index 6d7ac150..4714e669 100644 --- a/src/libs/core/impl/WtLogger.cpp +++ b/src/libs/core/impl/WtLogger.cpp @@ -19,10 +19,11 @@ #include "core/WtLogger.hpp" -#include #include -#include +#include + #include +#include #include "core/Exception.hpp" @@ -36,7 +37,7 @@ namespace lms::core::logging oss << id; return oss.str(); } - } + } // namespace WtLogger::WtLogger(Severity minSeverity) : _minSeverity{ minSeverity } @@ -47,11 +48,16 @@ namespace lms::core::logging { switch (minSeverity) { - case Severity::DEBUG: return "*"; - case Severity::INFO: return "* -debug"; - case Severity::WARNING: return "* -debug -info"; - case Severity::ERROR: return "* -debug -info -warning"; - case Severity::FATAL: return "* -debug -info -warning -error"; + case Severity::DEBUG: + return "*"; + case Severity::INFO: + return "* -debug"; + case Severity::WARNING: + return "* -debug -info"; + case Severity::ERROR: + return "* -debug -info -warning"; + case Severity::FATAL: + return "* -debug -info -warning -error"; } throw LmsException{ "Unhandled severity" }; @@ -66,4 +72,4 @@ namespace lms::core::logging { Wt::log(getSeverityName(log.getSeverity())) << Wt::WLogger::sep << to_string(std::this_thread::get_id()) << Wt::WLogger::sep << "[" << getModuleName(log.getModule()) << "]" << Wt::WLogger::sep << log.getMessage(); } -} \ No newline at end of file +} // namespace lms::core::logging \ No newline at end of file diff --git a/src/libs/core/impl/http/Client.cpp b/src/libs/core/impl/http/Client.cpp index c49dc433..a6040122 100644 --- a/src/libs/core/impl/http/Client.cpp +++ b/src/libs/core/impl/http/Client.cpp @@ -36,4 +36,4 @@ namespace lms::core::http { _sendQueue.sendRequest(std::make_unique(std::move(POSTParams))); } -} \ No newline at end of file +} // namespace lms::core::http \ No newline at end of file diff --git a/src/libs/core/impl/http/Client.hpp b/src/libs/core/impl/http/Client.hpp index 6d00dac3..c7cf32e1 100644 --- a/src/libs/core/impl/http/Client.hpp +++ b/src/libs/core/impl/http/Client.hpp @@ -19,11 +19,12 @@ #pragma once -#include -#include #include +#include +#include #include "core/http/IClient.hpp" + #include "SendQueue.hpp" namespace lms::core::http @@ -33,7 +34,8 @@ namespace lms::core::http public: Client(boost::asio::io_context& ioContext, std::string_view baseUrl) : _sendQueue{ ioContext, baseUrl } - {} + { + } private: void sendGETRequest(ClientGETRequestParameters&& request) override; @@ -41,4 +43,4 @@ namespace lms::core::http SendQueue _sendQueue; }; -} \ No newline at end of file +} // namespace lms::core::http \ No newline at end of file diff --git a/src/libs/core/impl/http/ClientRequest.hpp b/src/libs/core/impl/http/ClientRequest.hpp index e5bd12d7..81b7e38a 100644 --- a/src/libs/core/impl/http/ClientRequest.hpp +++ b/src/libs/core/impl/http/ClientRequest.hpp @@ -21,6 +21,7 @@ #include #include + #include "core/http/ClientRequestParameters.hpp" namespace lms::core::http @@ -28,8 +29,10 @@ namespace lms::core::http class ClientRequest { public: - ClientRequest(ClientGETRequestParameters&& GETParams) : _parameters{ std::move(GETParams) } {} - ClientRequest(ClientPOSTRequestParameters&& POSTParams) : _parameters{ std::move(POSTParams) } {} + ClientRequest(ClientGETRequestParameters&& GETParams) + : _parameters{ std::move(GETParams) } {} + ClientRequest(ClientPOSTRequestParameters&& POSTParams) + : _parameters{ std::move(POSTParams) } {} std::size_t retryCount{}; @@ -37,10 +40,10 @@ namespace lms::core::http { const ClientRequestParameters* res; - std::visit([&](const auto& parameters) - { - res = &static_cast(parameters); - }, _parameters); + std::visit([&](const auto& parameters) { + res = &static_cast(parameters); + }, + _parameters); return *res; } @@ -71,4 +74,4 @@ namespace lms::core::http private: std::variant _parameters; }; -} +} // namespace lms::core::http diff --git a/src/libs/core/impl/http/SendQueue.cpp b/src/libs/core/impl/http/SendQueue.cpp index 221273af..3ed4655c 100644 --- a/src/libs/core/impl/http/SendQueue.cpp +++ b/src/libs/core/impl/http/SendQueue.cpp @@ -19,15 +19,15 @@ #include "SendQueue.hpp" -#include #include +#include #include "core/Exception.hpp" #include "core/ILogger.hpp" #include "core/ITraceLogger.hpp" #include "core/String.hpp" -#define LOG(sev, message) LMS_LOG(SCROBBLING, sev, "[Http SendQueue] - " << message) +#define LOG(sev, message) LMS_LOG(SCROBBLING, sev, "[Http SendQueue] - " << message) namespace lms::core::stringUtils { @@ -41,35 +41,33 @@ namespace lms::core::stringUtils return res; } -} +} // namespace lms::core::stringUtils namespace lms::core::http { namespace { - template + template std::optional headerReadAs(const Wt::Http::Message& msg, std::string_view headerName) { std::optional res; - if (const std::string * headerValue{ msg.getHeader(std::string {headerName}) }) + if (const std::string * headerValue{ msg.getHeader(std::string{ headerName }) }) res = stringUtils::readAs(*headerValue); return res; } - } + } // namespace SendQueue::SendQueue(boost::asio::io_context& ioContext, std::string_view baseUrl) : _ioContext{ ioContext } , _baseUrl{ baseUrl } { - _client.done().connect([this](Wt::AsioWrapper::error_code ec, const Wt::Http::Message& msg) - { - _strand.dispatch([this, ec, msg = std::move(msg)] - { - onClientDone(ec, msg); - }); + _client.done().connect([this](Wt::AsioWrapper::error_code ec, const Wt::Http::Message& msg) { + _strand.dispatch([this, ec, msg = std::move(msg)] { + onClientDone(ec, msg); }); + }); } SendQueue::~SendQueue() @@ -79,13 +77,12 @@ namespace lms::core::http void SendQueue::sendRequest(std::unique_ptr request) { - boost::asio::dispatch(_strand, [this, request = std::move(request)]() mutable - { - _sendQueue[request->getParameters().priority].emplace_back(std::move(request)); + boost::asio::dispatch(_strand, [this, request = std::move(request)]() mutable { + _sendQueue[request->getParameters().priority].emplace_back(std::move(request)); - if (_state == State::Idle) - sendNextQueuedRequest(); - }); + if (_state == State::Idle) + sendNextQueuedRequest(); + }); } void SendQueue::sendNextQueuedRequest() @@ -220,21 +217,20 @@ namespace lms::core::http LOG(DEBUG, "Throttling for " << duration.count() << " seconds"); _throttleTimer.expires_after(duration); - _throttleTimer.async_wait([this](const boost::system::error_code& ec) + _throttleTimer.async_wait([this](const boost::system::error_code& ec) { + if (ec == boost::asio::error::operation_aborted) { - if (ec == boost::asio::error::operation_aborted) - { - LOG(DEBUG, "Throttle aborted"); - return; - } - else if (ec) - { - throw LmsException{ "Throttle timer failure: " + std::string {ec.message()} }; - } + LOG(DEBUG, "Throttle aborted"); + return; + } + else if (ec) + { + throw LmsException{ "Throttle timer failure: " + std::string{ ec.message() } }; + } - _state = State::Idle; - sendNextQueuedRequest(); - }); + _state = State::Idle; + sendNextQueuedRequest(); + }); _state = State::Throttled; } -} +} // namespace lms::core::http diff --git a/src/libs/core/impl/http/SendQueue.hpp b/src/libs/core/impl/http/SendQueue.hpp index 439ef480..8da04d9c 100644 --- a/src/libs/core/impl/http/SendQueue.hpp +++ b/src/libs/core/impl/http/SendQueue.hpp @@ -20,14 +20,14 @@ #pragma once #include -#include #include +#include +#include #include #include #include -#include #include "ClientRequest.hpp" namespace lms::core::http @@ -53,15 +53,15 @@ namespace lms::core::http void onClientDoneSuccess(std::unique_ptr request, const Wt::Http::Message& msg); void throttle(std::chrono::seconds duration); - const std::size_t _maxRetryCount{ 2 }; - const std::chrono::seconds _defaultRetryWaitDuration{ 30 }; - const std::chrono::seconds _minRetryWaitDuration{ 1 }; - const std::chrono::seconds _maxRetryWaitDuration{ 300 }; + const std::size_t _maxRetryCount{ 2 }; + const std::chrono::seconds _defaultRetryWaitDuration{ 30 }; + const std::chrono::seconds _minRetryWaitDuration{ 1 }; + const std::chrono::seconds _maxRetryWaitDuration{ 300 }; boost::asio::io_context& _ioContext; - boost::asio::io_context::strand _strand{ _ioContext }; - boost::asio::steady_timer _throttleTimer{ _ioContext }; - std::string _baseUrl; + boost::asio::io_context::strand _strand{ _ioContext }; + boost::asio::steady_timer _throttleTimer{ _ioContext }; + std::string _baseUrl; enum class State { @@ -69,10 +69,10 @@ namespace lms::core::http Throttled, Sending, }; - State _state{ State::Idle }; - Wt::Http::Client _client{ _ioContext }; + State _state{ State::Idle }; + Wt::Http::Client _client{ _ioContext }; std::map>> _sendQueue; - std::unique_ptr _currentRequest; + std::unique_ptr _currentRequest; }; -} \ No newline at end of file +} // namespace lms::core::http \ No newline at end of file diff --git a/src/libs/core/include/core/Crc32Calculator.hpp b/src/libs/core/include/core/Crc32Calculator.hpp index e9d081ba..604910cf 100644 --- a/src/libs/core/include/core/Crc32Calculator.hpp +++ b/src/libs/core/include/core/Crc32Calculator.hpp @@ -19,7 +19,7 @@ #pragma once -#include // for boost::crc_32_type +#include // for boost::crc_32_type namespace lms::core { @@ -40,4 +40,4 @@ namespace lms::core using Crc32Type = boost::crc_32_type; Crc32Type _result; }; -} +} // namespace lms::core diff --git a/src/libs/core/include/core/EnumSet.hpp b/src/libs/core/include/core/EnumSet.hpp index d880dff7..dc035610 100644 --- a/src/libs/core/include/core/EnumSet.hpp +++ b/src/libs/core/include/core/EnumSet.hpp @@ -27,7 +27,7 @@ namespace lms::core { - template + template class EnumSet { static_assert(std::is_enum::value); @@ -45,13 +45,13 @@ namespace lms::core insert(value); } - template + template constexpr EnumSet(It begin, It end) { assign(begin, end); } - template + template constexpr void assign(It begin, It end) { clear(); @@ -158,7 +158,10 @@ namespace lms::core private: static_assert(std::numeric_limits::max() >= sizeof(underlying_type) * 8); - enum : IndexType { npos = sizeof(underlying_type) * 8 }; + enum : IndexType + { + npos = sizeof(underlying_type) * 8 + }; constexpr IndexType getFirstBitSetIndex(IndexType start = {}) const { @@ -190,4 +193,4 @@ namespace lms::core underlying_type _bitfield{}; }; -} \ No newline at end of file +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/core/include/core/Exception.hpp b/src/libs/core/include/core/Exception.hpp index 8c68e165..77a3aafd 100644 --- a/src/libs/core/include/core/Exception.hpp +++ b/src/libs/core/include/core/Exception.hpp @@ -29,6 +29,7 @@ namespace lms::core class LmsException : public std::runtime_error { public: - LmsException(std::string_view error = "") : std::runtime_error{ std::string{ error } } {} + LmsException(std::string_view error = "") + : std::runtime_error{ std::string{ error } } {} }; -} \ No newline at end of file +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/core/include/core/IChildProcess.hpp b/src/libs/core/include/core/IChildProcess.hpp index 40fc573a..5f9bb0cb 100644 --- a/src/libs/core/include/core/IChildProcess.hpp +++ b/src/libs/core/include/core/IChildProcess.hpp @@ -48,9 +48,9 @@ namespace lms::core }; using ReadCallback = std::function; - virtual void asyncRead(std::byte* data, std::size_t bufferSize, ReadCallback callback) = 0; + virtual void asyncRead(std::byte* data, std::size_t bufferSize, ReadCallback callback) = 0; - virtual std::size_t readSome(std::byte* data, std::size_t bufferSize) = 0; - virtual bool finished() const = 0; + virtual std::size_t readSome(std::byte* data, std::size_t bufferSize) = 0; + virtual bool finished() const = 0; }; -} \ No newline at end of file +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/core/include/core/IChildProcessManager.hpp b/src/libs/core/include/core/IChildProcessManager.hpp index 26c64df8..1df237dd 100644 --- a/src/libs/core/include/core/IChildProcessManager.hpp +++ b/src/libs/core/include/core/IChildProcessManager.hpp @@ -20,6 +20,7 @@ #include #include + #include #include "IChildProcess.hpp" @@ -35,4 +36,4 @@ namespace lms::core }; std::unique_ptr createChildProcessManager(boost::asio::io_service& ioService); -} \ No newline at end of file +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/core/include/core/IConfig.hpp b/src/libs/core/include/core/IConfig.hpp index 07e4b862..2d703552 100644 --- a/src/libs/core/include/core/IConfig.hpp +++ b/src/libs/core/include/core/IConfig.hpp @@ -31,13 +31,13 @@ namespace lms::core virtual ~IConfig() = default; // Default values are returned in case of setting not found - virtual std::string_view getString(std::string_view setting, std::string_view def = "") = 0; - virtual void visitStrings(std::string_view setting, std::function _func, std::initializer_list def = {}) = 0; - virtual std::filesystem::path getPath(std::string_view setting, const std::filesystem::path& def = std::filesystem::path()) = 0; - virtual unsigned long getULong(std::string_view setting, unsigned long def = 0) = 0; - virtual long getLong(std::string_view setting, long def = 0) = 0; - virtual bool getBool(std::string_view setting, bool def = false) = 0; + virtual std::string_view getString(std::string_view setting, std::string_view def = "") = 0; + virtual void visitStrings(std::string_view setting, std::function _func, std::initializer_list def = {}) = 0; + virtual std::filesystem::path getPath(std::string_view setting, const std::filesystem::path& def = std::filesystem::path()) = 0; + virtual unsigned long getULong(std::string_view setting, unsigned long def = 0) = 0; + virtual long getLong(std::string_view setting, long def = 0) = 0; + virtual bool getBool(std::string_view setting, bool def = false) = 0; }; std::unique_ptr createConfig(const std::filesystem::path& p); -} \ No newline at end of file +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/core/include/core/ILogger.hpp b/src/libs/core/include/core/ILogger.hpp index 339978ac..8c7ee446 100644 --- a/src/libs/core/include/core/ILogger.hpp +++ b/src/libs/core/include/core/ILogger.hpp @@ -19,11 +19,11 @@ #pragma once -#include #include +#include +#include "core/Service.hpp" #include "core/String.hpp" -#include "Service.hpp" namespace lms::core::logging { @@ -93,11 +93,11 @@ namespace lms::core::logging virtual bool isSeverityActive(Severity severity) const = 0; virtual void processLog(const Log& log) = 0; }; -} +} // namespace lms::core::logging -#define LMS_LOG(module, severity, message) \ - do \ - { \ - if (auto* logger_ {::lms::core::Service<::lms::core::logging::ILogger>::get()}; logger_ && logger_->isSeverityActive(::lms::core::logging::Severity::severity)) \ - ::lms::core::logging::Log{ *logger_, ::lms::core::logging::Module::module, ::lms::core::logging::Severity::severity }.getOstream() << message; \ - } while(0) +#define LMS_LOG(module, severity, message) \ + do \ + { \ + if (auto* logger_{ ::lms::core::Service<::lms::core::logging::ILogger>::get() }; logger_ && logger_->isSeverityActive(::lms::core::logging::Severity::severity)) \ + ::lms::core::logging::Log{ *logger_, ::lms::core::logging::Module::module, ::lms::core::logging::Severity::severity }.getOstream() << message; \ + } while (0) diff --git a/src/libs/core/include/core/IOContextRunner.hpp b/src/libs/core/include/core/IOContextRunner.hpp index 9beeec6e..a3fb30e0 100644 --- a/src/libs/core/include/core/IOContextRunner.hpp +++ b/src/libs/core/include/core/IOContextRunner.hpp @@ -21,6 +21,7 @@ #include #include + #include namespace lms::core @@ -39,7 +40,7 @@ namespace lms::core IOContextRunner& operator=(const IOContextRunner&) = delete; boost::asio::io_service& _ioService; - std::optional _work; - std::vector _threads; + std::optional _work; + std::vector _threads; }; -} \ No newline at end of file +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/core/include/core/IResourceHandler.hpp b/src/libs/core/include/core/IResourceHandler.hpp index 7fbc8396..49433b65 100644 --- a/src/libs/core/include/core/IResourceHandler.hpp +++ b/src/libs/core/include/core/IResourceHandler.hpp @@ -25,13 +25,13 @@ // TODO, move elsewhere namespace lms { - // Helper class to serve a resource (must be saved as continuation data if not complete) - class IResourceHandler - { - public: - virtual ~IResourceHandler() = default; + // Helper class to serve a resource (must be saved as continuation data if not complete) + class IResourceHandler + { + public: + virtual ~IResourceHandler() = default; - [[nodiscard]] virtual Wt::Http::ResponseContinuation* processRequest(const Wt::Http::Request& request, Wt::Http::Response& response) = 0; - virtual void abort() = 0; - }; -} \ No newline at end of file + [[nodiscard]] virtual Wt::Http::ResponseContinuation* processRequest(const Wt::Http::Request& request, Wt::Http::Response& response) = 0; + virtual void abort() = 0; + }; +} // namespace lms \ No newline at end of file diff --git a/src/libs/core/include/core/ITraceLogger.hpp b/src/libs/core/include/core/ITraceLogger.hpp index aad89edf..e0e19874 100644 --- a/src/libs/core/include/core/ITraceLogger.hpp +++ b/src/libs/core/include/core/ITraceLogger.hpp @@ -34,20 +34,20 @@ #define LMS_CONCAT_IMPL(x, y) x##y #define LMS_CONCAT(x, y) LMS_CONCAT_IMPL(x, y) -#if LMS_SUPPORT_TRACING -#define LMS_SCOPED_TRACE(CATEGORY, LEVEL, NAME, ARGTYPE, ARGVALUE) \ -std::optional<::lms::core::tracing::ScopedTrace> LMS_CONCAT(ScopedTrace_, __LINE__); \ -if (::lms::core::tracing::ITraceLogger* traceLogger{ ::lms::core::Service<::lms::core::tracing::ITraceLogger>::get() }; traceLogger && traceLogger->isLevelActive(LEVEL)) \ - LMS_CONCAT(ScopedTrace_, __LINE__).emplace(CATEGORY, LEVEL, NAME, ARGTYPE, ARGVALUE, traceLogger); +#if LMS_SUPPORT_TRACING + #define LMS_SCOPED_TRACE(CATEGORY, LEVEL, NAME, ARGTYPE, ARGVALUE) \ + std::optional<::lms::core::tracing::ScopedTrace> LMS_CONCAT(ScopedTrace_, __LINE__); \ + if (::lms::core::tracing::ITraceLogger * traceLogger{ ::lms::core::Service<::lms::core::tracing::ITraceLogger>::get() }; traceLogger && traceLogger->isLevelActive(LEVEL)) \ + LMS_CONCAT(ScopedTrace_, __LINE__).emplace(CATEGORY, LEVEL, NAME, ARGTYPE, ARGVALUE, traceLogger); #else -#define LMS_SCOPED_TRACE(CATEGORY, LEVEL, NAME) (void)0 + #define LMS_SCOPED_TRACE(CATEGORY, LEVEL, NAME) (void)0 #endif -#define LMS_SCOPED_TRACE_OVERVIEW_WITH_ARG(CATEGORY, NAME, ARGTYPE, ARGVALUE) LMS_SCOPED_TRACE(CATEGORY, ::lms::core::tracing::Level::Overview, NAME, ARGTYPE, ARGVALUE) -#define LMS_SCOPED_TRACE_DETAILED_WITH_ARG(CATEGORY, NAME, ARGTYPE, ARGVALUE) LMS_SCOPED_TRACE(CATEGORY, ::lms::core::tracing::Level::Detailed, NAME, ARGTYPE, ARGVALUE) +#define LMS_SCOPED_TRACE_OVERVIEW_WITH_ARG(CATEGORY, NAME, ARGTYPE, ARGVALUE) LMS_SCOPED_TRACE(CATEGORY, ::lms::core::tracing::Level::Overview, NAME, ARGTYPE, ARGVALUE) +#define LMS_SCOPED_TRACE_DETAILED_WITH_ARG(CATEGORY, NAME, ARGTYPE, ARGVALUE) LMS_SCOPED_TRACE(CATEGORY, ::lms::core::tracing::Level::Detailed, NAME, ARGTYPE, ARGVALUE) -#define LMS_SCOPED_TRACE_OVERVIEW(CATEGORY, NAME) LMS_SCOPED_TRACE_OVERVIEW_WITH_ARG(CATEGORY, NAME, "", "") -#define LMS_SCOPED_TRACE_DETAILED(CATEGORY, NAME) LMS_SCOPED_TRACE_DETAILED_WITH_ARG(CATEGORY, NAME, "", "") +#define LMS_SCOPED_TRACE_OVERVIEW(CATEGORY, NAME) LMS_SCOPED_TRACE_OVERVIEW_WITH_ARG(CATEGORY, NAME, "", "") +#define LMS_SCOPED_TRACE_DETAILED(CATEGORY, NAME) LMS_SCOPED_TRACE_DETAILED_WITH_ARG(CATEGORY, NAME, "", "") namespace lms::core::tracing { @@ -124,4 +124,4 @@ namespace lms::core::tracing ITraceLogger* _traceLogger; ITraceLogger::CompleteEvent _event; }; -} \ No newline at end of file +} // namespace lms::core::tracing \ No newline at end of file diff --git a/src/libs/core/include/core/IZipper.hpp b/src/libs/core/include/core/IZipper.hpp index f8542a0b..cd796226 100644 --- a/src/libs/core/include/core/IZipper.hpp +++ b/src/libs/core/include/core/IZipper.hpp @@ -25,7 +25,7 @@ #include "Exception.hpp" - // TODO, move elsewhere? +// TODO, move elsewhere? namespace lms::zip { struct Entry @@ -51,4 +51,4 @@ namespace lms::zip }; std::unique_ptr createArchiveZipper(const EntryContainer& entries); -} +} // namespace lms::zip diff --git a/src/libs/core/include/core/LiteralString.hpp b/src/libs/core/include/core/LiteralString.hpp index 11b7f668..1d570971 100644 --- a/src/libs/core/include/core/LiteralString.hpp +++ b/src/libs/core/include/core/LiteralString.hpp @@ -31,7 +31,11 @@ namespace lms::core public: constexpr LiteralString() noexcept = default; template - constexpr LiteralString(const char(&str)[N]) noexcept : _str{ str, N - 1 } { static_assert(N > 0); } + constexpr LiteralString(const char (&str)[N]) noexcept + : _str{ str, N - 1 } + { + static_assert(N > 0); + } constexpr bool empty() const noexcept { return _str.empty(); } constexpr const char* c_str() const noexcept { return _str.data(); } @@ -48,7 +52,7 @@ namespace lms::core os << str.str(); return os; } -} +} // namespace lms::core namespace std { @@ -60,7 +64,7 @@ namespace std return hash{}(str.str()); } }; -} +} // namespace std namespace lms::core { @@ -69,15 +73,18 @@ namespace lms::core using hash_type = std::hash; using is_transparent = void; - [[nodiscard]] size_t operator()(const LiteralString& str) const { + [[nodiscard]] size_t operator()(const LiteralString& str) const + { return hash_type{}(str.str()); } - [[nodiscard]] size_t operator()(std::string_view str) const { + [[nodiscard]] size_t operator()(std::string_view str) const + { return hash_type{}(str); } - [[nodiscard]] size_t operator()(const std::string& str) const { + [[nodiscard]] size_t operator()(const std::string& str) const + { return hash_type{}(str); } }; @@ -86,24 +93,29 @@ namespace lms::core { using is_transparent = void; - [[nodiscard]] bool operator()(const LiteralString& lhs, const LiteralString& rhs) const { + [[nodiscard]] bool operator()(const LiteralString& lhs, const LiteralString& rhs) const + { return lhs == rhs; } - [[nodiscard]] bool operator()(const LiteralString& lhs, const std::string& rhs) const { + [[nodiscard]] bool operator()(const LiteralString& lhs, const std::string& rhs) const + { return lhs.str() == rhs; } - [[nodiscard]] bool operator()(const LiteralString& lhs, std::string_view rhs) const { + [[nodiscard]] bool operator()(const LiteralString& lhs, std::string_view rhs) const + { return lhs.str() == rhs; } - [[nodiscard]] bool operator()(const std::string_view& lhs, LiteralString rhs) const { + [[nodiscard]] bool operator()(const std::string_view& lhs, LiteralString rhs) const + { return lhs == rhs.str(); } - [[nodiscard]] bool operator()(const std::string& lhs, const LiteralString& rhs) const { + [[nodiscard]] bool operator()(const std::string& lhs, const LiteralString& rhs) const + { return lhs == rhs.str(); } }; -} \ No newline at end of file +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/core/include/core/NetAddress.hpp b/src/libs/core/include/core/NetAddress.hpp index 86575e1a..98292495 100644 --- a/src/libs/core/include/core/NetAddress.hpp +++ b/src/libs/core/include/core/NetAddress.hpp @@ -22,15 +22,16 @@ #include #ifndef BOOST_ASIO_HAS_STD_HASH -#include + #include namespace std { - template<> struct hash - { - std::size_t operator()(const boost::asio::ip::address& ipAddr) const; - }; + template<> + struct hash + { + std::size_t operator()(const boost::asio::ip::address& ipAddr) const; + }; -} +} // namespace std #endif // BOOST_ASIO_HAS_STD_HASH diff --git a/src/libs/core/include/core/Path.hpp b/src/libs/core/include/core/Path.hpp index 8f8d11df..f49edaf4 100644 --- a/src/libs/core/include/core/Path.hpp +++ b/src/libs/core/include/core/Path.hpp @@ -49,7 +49,7 @@ namespace lms::core::pathUtils std::filesystem::path getLongestCommonPath(const std::filesystem::path& path1, const std::filesystem::path& path2); - template + template std::filesystem::path getLongestCommonPath(Iterator first, Iterator last) { std::filesystem::path longestCommonPath; @@ -64,4 +64,4 @@ namespace lms::core::pathUtils return longestCommonPath; } -} +} // namespace lms::core::pathUtils diff --git a/src/libs/core/include/core/Random.hpp b/src/libs/core/include/core/Random.hpp index 7bfa03d4..898a49bc 100644 --- a/src/libs/core/include/core/Random.hpp +++ b/src/libs/core/include/core/Random.hpp @@ -29,27 +29,27 @@ namespace lms::core::random RandGenerator createSeededGenerator(uint_fast32_t seed); - template + template T getRandom(T min, T max) { std::uniform_int_distribution<> dist{ min, max }; return dist(getRandGenerator()); } - template + template T getRealRandom(T min, T max) { std::uniform_real_distribution<> dist{ min, max }; return dist(getRandGenerator()); } - template + template void shuffleContainer(Container& container) { std::shuffle(std::begin(container), std::end(container), getRandGenerator()); } - template + template typename Container::const_iterator pickRandom(const Container& container) { if (container.empty()) @@ -57,4 +57,4 @@ namespace lms::core::random return std::next(std::begin(container), getRandom(0, static_cast(container.size() - 1))); } -} \ No newline at end of file +} // namespace lms::core::random \ No newline at end of file diff --git a/src/libs/core/include/core/RecursiveSharedMutex.hpp b/src/libs/core/include/core/RecursiveSharedMutex.hpp index b38a0dec..aa8c669e 100644 --- a/src/libs/core/include/core/RecursiveSharedMutex.hpp +++ b/src/libs/core/include/core/RecursiveSharedMutex.hpp @@ -48,4 +48,4 @@ namespace lms::core std::mutex _sharedCountMutex; std::unordered_map _sharedCounts; }; -} \ No newline at end of file +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/core/include/core/Service.hpp b/src/libs/core/include/core/Service.hpp index 02141740..b6603fc2 100644 --- a/src/libs/core/include/core/Service.hpp +++ b/src/libs/core/include/core/Service.hpp @@ -24,7 +24,7 @@ namespace lms::core { - template + template class Service { public: @@ -57,7 +57,7 @@ namespace lms::core static Class* get() { return _service.get(); } static bool exists() { return _service.get(); } - template + template static Class& assign(std::unique_ptr service) { assert(!_service); @@ -70,4 +70,4 @@ namespace lms::core static inline std::unique_ptr _service; }; -} \ No newline at end of file +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/core/include/core/StreamLogger.hpp b/src/libs/core/include/core/StreamLogger.hpp index f82d728a..2e694fe2 100644 --- a/src/libs/core/include/core/StreamLogger.hpp +++ b/src/libs/core/include/core/StreamLogger.hpp @@ -39,4 +39,4 @@ namespace lms::core::logging std::ostream& _os; const EnumSet _severities; }; -} \ No newline at end of file +} // namespace lms::core::logging \ No newline at end of file diff --git a/src/libs/core/include/core/String.hpp b/src/libs/core/include/core/String.hpp index 88122a49..2cf47885 100644 --- a/src/libs/core/include/core/String.hpp +++ b/src/libs/core/include/core/String.hpp @@ -22,9 +22,9 @@ #include #include #include +#include #include #include -#include #include #define QUOTEME(x) QUOTEME_1(x) @@ -34,7 +34,7 @@ namespace Wt { class WDate; class WDateTime; -} +} // namespace Wt namespace lms::core::stringUtils { @@ -67,7 +67,7 @@ namespace lms::core::stringUtils { T res; - std::istringstream iss{ std::string {str} }; + std::istringstream iss{ std::string{ str } }; iss >> res; if (iss.fail()) return std::nullopt; @@ -100,4 +100,4 @@ namespace lms::core::stringUtils [[nodiscard]] std::string toISO8601String(const Wt::WDateTime& dateTime); [[nodiscard]] std::string toISO8601String(const Wt::WDate& date); -} \ No newline at end of file +} // namespace lms::core::stringUtils \ No newline at end of file diff --git a/src/libs/core/include/core/Tuple.hpp b/src/libs/core/include/core/Tuple.hpp index ad2f6adf..128ad0e3 100644 --- a/src/libs/core/include/core/Tuple.hpp +++ b/src/libs/core/include/core/Tuple.hpp @@ -23,27 +23,33 @@ namespace lms::core { - namespace details - { - template - struct Seq { }; + namespace details + { + template + struct Seq + { + }; - template - struct GenSeq : GenSeq { }; + template + struct GenSeq : GenSeq + { + }; - template - struct GenSeq<0, Is...> : Seq { }; + template + struct GenSeq<0, Is...> : Seq + { + }; - template - void forEachTypeInTuple(T&& t, Func f, Seq) - { - auto l = { (f(std::get(t)), 0)... }; - } - } + template + void forEachTypeInTuple(T&& t, Func f, Seq) + { + auto l = { (f(std::get(t)), 0)... }; + } + } // namespace details - template - void forEachTypeInTuple(std::tuple const& t, Func f) - { - details::forEachTypeInTuple(t, f, details::GenSeq()); - } -} \ No newline at end of file + template + void forEachTypeInTuple(std::tuple const& t, Func f) + { + details::forEachTypeInTuple(t, f, details::GenSeq()); + } +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/core/include/core/UUID.hpp b/src/libs/core/include/core/UUID.hpp index 1b47a416..b57d4628 100644 --- a/src/libs/core/include/core/UUID.hpp +++ b/src/libs/core/include/core/UUID.hpp @@ -41,11 +41,11 @@ namespace lms::core UUID(std::string_view value); std::string _value; }; -} +} // namespace lms::core namespace lms::core::stringUtils { - template <> + template<> std::optional - readAs(std::string_view str); + readAs(std::string_view str); } diff --git a/src/libs/core/include/core/Utils.hpp b/src/libs/core/include/core/Utils.hpp index 3965859f..1a13f33f 100644 --- a/src/libs/core/include/core/Utils.hpp +++ b/src/libs/core/include/core/Utils.hpp @@ -24,18 +24,19 @@ namespace lms::core::utils { - template> - constexpr T clamp(T v, T lo, T hi, Compare comp = {}) - { - assert(!comp(hi, lo)); - return comp(v, lo) ? lo : comp(hi, v) ? hi : v; - } + template> + constexpr T clamp(T v, T lo, T hi, Compare comp = {}) + { + assert(!comp(hi, lo)); + return comp(v, lo) ? lo : comp(hi, v) ? hi : + v; + } - template - void - push_back_if_not_present(Container& container, const T& val) - { - if (std::find(std::cbegin(container), std::cend(container), val) == std::cend(container)) - container.push_back(val); - } -} \ No newline at end of file + template + void + push_back_if_not_present(Container& container, const T& val) + { + if (std::find(std::cbegin(container), std::cend(container), val) == std::cend(container)) + container.push_back(val); + } +} // namespace lms::core::utils \ No newline at end of file diff --git a/src/libs/core/include/core/WtLogger.hpp b/src/libs/core/include/core/WtLogger.hpp index 6cb7b2be..af615ab9 100644 --- a/src/libs/core/include/core/WtLogger.hpp +++ b/src/libs/core/include/core/WtLogger.hpp @@ -37,4 +37,4 @@ namespace lms::core::logging void processLog(const Log& log) override; const Severity _minSeverity; }; -} \ No newline at end of file +} // namespace lms::core::logging \ No newline at end of file diff --git a/src/libs/core/include/core/http/ClientRequestParameters.hpp b/src/libs/core/include/core/http/ClientRequestParameters.hpp index ced63f9a..9e7e49e9 100644 --- a/src/libs/core/include/core/http/ClientRequestParameters.hpp +++ b/src/libs/core/include/core/http/ClientRequestParameters.hpp @@ -36,7 +36,7 @@ namespace lms::core::http Low, }; - Priority priority{ Priority::Normal }; + Priority priority{ Priority::Normal }; std::string relativeUrl; // relative to baseUrl used by the client using OnSuccessFunc = std::function; @@ -56,4 +56,4 @@ namespace lms::core::http Wt::Http::Message message; }; -} \ No newline at end of file +} // namespace lms::core::http \ No newline at end of file diff --git a/src/libs/core/include/core/http/IClient.hpp b/src/libs/core/include/core/http/IClient.hpp index 30cc2d01..f32cc2ab 100644 --- a/src/libs/core/include/core/http/IClient.hpp +++ b/src/libs/core/include/core/http/IClient.hpp @@ -20,20 +20,21 @@ #pragma once #include + #include #include "core/http/ClientRequestParameters.hpp" namespace lms::core::http { - class IClient - { - public: - virtual ~IClient() = default; + class IClient + { + public: + virtual ~IClient() = default; - virtual void sendGETRequest(ClientGETRequestParameters&& request) = 0; - virtual void sendPOSTRequest(ClientPOSTRequestParameters&& request) = 0; - }; + virtual void sendGETRequest(ClientGETRequestParameters&& request) = 0; + virtual void sendPOSTRequest(ClientPOSTRequestParameters&& request) = 0; + }; - std::unique_ptr createClient(boost::asio::io_context& ioContext, std::string_view baseUrl); -} \ No newline at end of file + std::unique_ptr createClient(boost::asio::io_context& ioContext, std::string_view baseUrl); +} // namespace lms::core::http \ No newline at end of file diff --git a/src/libs/core/test/EnumSet.cpp b/src/libs/core/test/EnumSet.cpp index ad83ea11..cc37ce8e 100644 --- a/src/libs/core/test/EnumSet.cpp +++ b/src/libs/core/test/EnumSet.cpp @@ -60,4 +60,4 @@ namespace lms::core EXPECT_EQ(test, test2); } } -} \ No newline at end of file +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/core/test/LiteralString.cpp b/src/libs/core/test/LiteralString.cpp index 4997b7e2..90085089 100644 --- a/src/libs/core/test/LiteralString.cpp +++ b/src/libs/core/test/LiteralString.cpp @@ -18,6 +18,7 @@ */ #include + #include #include "core/LiteralString.hpp" @@ -53,7 +54,7 @@ namespace lms::core TEST(LiteralString, unordered_map) { { - std::unordered_map myMap{ {"abc", 42} }; + std::unordered_map myMap{ { "abc", 42 } }; EXPECT_TRUE(myMap.contains("abc")); EXPECT_TRUE(myMap.contains(LiteralString{ "abc" })); @@ -61,12 +62,11 @@ namespace lms::core } { - std::unordered_map myMap{ {"abc", 42} }; + std::unordered_map myMap{ { "abc", 42 } }; EXPECT_TRUE(myMap.contains(std::string{ "abc" })); EXPECT_TRUE(myMap.contains(std::string_view{ "abc" })); EXPECT_FALSE(myMap.contains(std::string{ "abcd" })); EXPECT_FALSE(myMap.contains(std::string_view{ "abcd" })); } - } -} \ No newline at end of file +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/core/test/Path.cpp b/src/libs/core/test/Path.cpp index 83fc7087..56cf530e 100644 --- a/src/libs/core/test/Path.cpp +++ b/src/libs/core/test/Path.cpp @@ -32,14 +32,13 @@ namespace lms::core::pathUtils::tests std::filesystem::path expectedCommonPath; }; - TestCase tests[] - { - {"foo.txt", "/foo/foo.txt", ""}, - {"/", "/file.txt", "/"}, - {"/foo/bar/file1.txt", "/foo/bar/file2.txt", "/foo/bar"}, - {"/foo/bar/file.txt", "/foo/bar/file.txt", "/foo/bar/file.txt"}, - {"/dir1/file.txt", "/dir2/file.txt", "/"}, - {"/prefix/folder/file.txt", "/prefix/folder/subfolder/file.txt", "/prefix/folder"}, + TestCase tests[]{ + { "foo.txt", "/foo/foo.txt", "" }, + { "/", "/file.txt", "/" }, + { "/foo/bar/file1.txt", "/foo/bar/file2.txt", "/foo/bar" }, + { "/foo/bar/file.txt", "/foo/bar/file.txt", "/foo/bar/file.txt" }, + { "/dir1/file.txt", "/dir2/file.txt", "/" }, + { "/prefix/folder/file.txt", "/prefix/folder/subfolder/file.txt", "/prefix/folder" }, }; for (const TestCase& test : tests) @@ -48,7 +47,6 @@ namespace lms::core::pathUtils::tests } } - TEST(Path, getLongestCommonPathIterator) { struct TestCase @@ -57,17 +55,16 @@ namespace lms::core::pathUtils::tests std::filesystem::path expectedCommonPath; }; - TestCase tests[] - { - {{}, ""}, - {{"/"}, "/"}, - {{"/foo", "/bar"}, "/"}, - {{"/foo/bar/file1.txt", "/foo/bar/file2.txt"}, "/foo/bar"}, - {{"/foo", "/foo/"}, "/foo"}, - {{"/foo", "/foo"}, "/foo"}, - {{"/foo/", "/foo/"}, "/foo/"}, - {{"/foo/", "/foo/", "/bar"}, "/"}, - {{"/foo/", "/foo/", "/foo/bar"}, "/foo"}, + TestCase tests[]{ + { {}, "" }, + { { "/" }, "/" }, + { { "/foo", "/bar" }, "/" }, + { { "/foo/bar/file1.txt", "/foo/bar/file2.txt" }, "/foo/bar" }, + { { "/foo", "/foo/" }, "/foo" }, + { { "/foo", "/foo" }, "/foo" }, + { { "/foo/", "/foo/" }, "/foo/" }, + { { "/foo/", "/foo/", "/bar" }, "/" }, + { { "/foo/", "/foo/", "/foo/bar" }, "/foo" }, }; for (const TestCase& test : tests) @@ -85,19 +82,18 @@ namespace lms::core::pathUtils::tests bool expectedResult; }; - TestCase tests[] - { - {"/file.txt", "/", true}, - {"/root/folder/file.txt", "/root", true}, - {"/root/file.txt", "/root", true}, - {"/root/file.txt", "/root/", true}, - {"/root", "/root", true}, - {"/root", "/root/", true}, - {"/root/", "/root", true}, - {"/root/", "/root/", true}, - {"/folder/file.txt", "/root", false}, - {"/folder/file.txt", "/root/", false}, - {"", "/root", false}, + TestCase tests[]{ + { "/file.txt", "/", true }, + { "/root/folder/file.txt", "/root", true }, + { "/root/file.txt", "/root", true }, + { "/root/file.txt", "/root/", true }, + { "/root", "/root", true }, + { "/root", "/root/", true }, + { "/root/", "/root", true }, + { "/root/", "/root/", true }, + { "/folder/file.txt", "/root", false }, + { "/folder/file.txt", "/root/", false }, + { "", "/root", false }, }; for (const TestCase& test : tests) @@ -105,4 +101,4 @@ namespace lms::core::pathUtils::tests EXPECT_EQ(core::pathUtils::isPathInRootPath(test.path, test.rootPath), test.expectedResult) << "Failed: path = " << test.path << ", rootPath = " << test.rootPath; } } -} \ No newline at end of file +} // namespace lms::core::pathUtils::tests \ No newline at end of file diff --git a/src/libs/core/test/RecursiveSharedMutex.cpp b/src/libs/core/test/RecursiveSharedMutex.cpp index cb60d26c..6d3127b7 100644 --- a/src/libs/core/test/RecursiveSharedMutex.cpp +++ b/src/libs/core/test/RecursiveSharedMutex.cpp @@ -66,40 +66,39 @@ namespace lms::core std::atomic nbShared{}; for (std::size_t i{}; i < nbThreads; ++i) { - threads.emplace_back([&] + threads.emplace_back([&] { { - { - std::unique_lock lock{ mutex }; + std::unique_lock lock{ mutex }; - std::shared_lock lock2{ mutex }; + std::shared_lock lock2{ mutex }; - assert(nbUnique == 0); - assert(nbShared == 0); - nbUnique++; - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - assert(nbUnique == 1); - assert(nbShared == 0); - nbUnique--; - } + assert(nbUnique == 0); + assert(nbShared == 0); + nbUnique++; + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + assert(nbUnique == 1); + assert(nbShared == 0); + nbUnique--; + } - { - std::shared_lock lock{ mutex }; - std::shared_lock lock2{ mutex }; + { + std::shared_lock lock{ mutex }; + std::shared_lock lock2{ mutex }; - assert(nbUnique == 0); - nbShared++; + assert(nbUnique == 0); + nbShared++; - std::this_thread::sleep_for(std::chrono::milliseconds(15)); + std::this_thread::sleep_for(std::chrono::milliseconds(15)); - assert(nbShared > 0); - assert(nbShared <= nbThreads); - assert(nbUnique == 0); - nbShared--; - } - }); + assert(nbShared > 0); + assert(nbShared <= nbThreads); + assert(nbUnique == 0); + nbShared--; + } + }); } for (std::thread& t : threads) t.join(); } -} \ No newline at end of file +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/core/test/String.cpp b/src/libs/core/test/String.cpp index 71c45cde..a71bcdb6 100644 --- a/src/libs/core/test/String.cpp +++ b/src/libs/core/test/String.cpp @@ -19,9 +19,10 @@ #include -#include #include +#include #include + #include "core/String.hpp" namespace lms::core::stringUtils::tests @@ -35,30 +36,29 @@ namespace lms::core::stringUtils::tests std::vector expectedOutput; }; - TestCase tests[] - { - {"abc", '-', {"abc"}}, - {"a", '-', {"a"}}, - {"", '-', {""}}, - {"a-b-c", '-', {"a", "b", "c"}}, - {"a|b|c", '|', {"a", "b", "c"}}, - {"a;b;c", ';', {"a", "b", "c"}}, - {";b;c", ';', {"", "b", "c"}}, - {" ;b;c", ';', {" ", "b", "c"}}, - {" ;;c", ';', {" ", "", "c"}}, - {" ; ;c", ';', {" ", " ", "c"}}, - {"a;b; ", ';', {"a", "b", " "}}, - {"a;b", ';', {"a", "b"}}, - {";b", ';', {"", "b"}}, - {";", ';', {"", ""}}, - {";;", ';', {"", "", ""}}, - {";;;", ';', {"", "", "", ""}}, - {";;a;;b;;", ';', {"", "", "a", "", "b", "", ""}}, - {"a b", ' ', {"a", "b"}}, - {"", ' ', {""}}, - {"a-b|c", '-', {"a","b|c"}}, - {"a|b-c", '-', {"a|b", "c"}}, - {"test=foo bar", '=', {"test", "foo bar"}}, + TestCase tests[]{ + { "abc", '-', { "abc" } }, + { "a", '-', { "a" } }, + { "", '-', { "" } }, + { "a-b-c", '-', { "a", "b", "c" } }, + { "a|b|c", '|', { "a", "b", "c" } }, + { "a;b;c", ';', { "a", "b", "c" } }, + { ";b;c", ';', { "", "b", "c" } }, + { " ;b;c", ';', { " ", "b", "c" } }, + { " ;;c", ';', { " ", "", "c" } }, + { " ; ;c", ';', { " ", " ", "c" } }, + { "a;b; ", ';', { "a", "b", " " } }, + { "a;b", ';', { "a", "b" } }, + { ";b", ';', { "", "b" } }, + { ";", ';', { "", "" } }, + { ";;", ';', { "", "", "" } }, + { ";;;", ';', { "", "", "", "" } }, + { ";;a;;b;;", ';', { "", "", "a", "", "b", "", "" } }, + { "a b", ' ', { "a", "b" } }, + { "", ' ', { "" } }, + { "a-b|c", '-', { "a", "b|c" } }, + { "a|b-c", '-', { "a|b", "c" } }, + { "test=foo bar", '=', { "test", "foo bar" } }, }; for (const TestCase& test : tests) @@ -77,19 +77,18 @@ namespace lms::core::stringUtils::tests std::vector expectedOutput; }; - TestCase tests[] - { - {"abc", "", {"abc"}}, - {"abc", "-", {"abc"}}, - {"abc", "b", {"a", "c"}}, - {"ab/cd", "/", {"ab", "cd"}}, - {"ab/cd", "/ ", {"ab/cd"}}, - {"ab/cd", " /", {"ab/cd"}}, - {"ab /cd", " /", {"ab", "cd"}}, - {"ab/ cd", "/ ", {"ab", "cd"}}, - {"ab / cd", " / ", {"ab", "cd"}}, - {"ab/cd", " / ", {"ab/cd"}}, - {"ab/cd / ", " / ", {"ab/cd", ""}}, + TestCase tests[]{ + { "abc", "", { "abc" } }, + { "abc", "-", { "abc" } }, + { "abc", "b", { "a", "c" } }, + { "ab/cd", "/", { "ab", "cd" } }, + { "ab/cd", "/ ", { "ab/cd" } }, + { "ab/cd", " /", { "ab/cd" } }, + { "ab /cd", " /", { "ab", "cd" } }, + { "ab/ cd", "/ ", { "ab", "cd" } }, + { "ab / cd", " / ", { "ab", "cd" } }, + { "ab/cd", " / ", { "ab/cd" } }, + { "ab/cd / ", " / ", { "ab/cd", "" } }, }; for (const TestCase& test : tests) @@ -108,15 +107,14 @@ namespace lms::core::stringUtils::tests std::string expectedOutput; }; - TestCase tests[] - { - {{"a", "b", "c"}, "-", "a-b-c"}, - {{"a", "b", "c"}, ",", "a,b,c"}, - {{"a", "b", "c"}, "***", "a***b***c"}, - {{"a", "", "c"}, "-", "a--c"}, - {{"", "b", "c"}, "-", "-b-c"}, - {{"a"}, "-", "a"}, - {{"a"}, ",", "a"}, + TestCase tests[]{ + { { "a", "b", "c" }, "-", "a-b-c" }, + { { "a", "b", "c" }, ",", "a,b,c" }, + { { "a", "b", "c" }, "***", "a***b***c" }, + { { "a", "", "c" }, "-", "a--c" }, + { { "", "b", "c" }, "-", "-b-c" }, + { { "a" }, "-", "a" }, + { { "a" }, ",", "a" }, }; for (const TestCase& test : tests) @@ -136,13 +134,12 @@ namespace lms::core::stringUtils::tests std::string expectedOutput; }; - TestCase tests[] - { - {{""}, ';', '\\', ""}, - {{";"}, ';', '\\', "\\;"}, - {{";;"}, ';', '\\', "\\;\\;"}, - {{"a;", "b"}, ';', '\\', "a\\;;b"}, - {{"a;", "b;"}, ';', '\\', "a\\;;b\\;"}, + TestCase tests[]{ + { { "" }, ';', '\\', "" }, + { { ";" }, ';', '\\', "\\;" }, + { { ";;" }, ';', '\\', "\\;\\;" }, + { { "a;", "b" }, ';', '\\', "a\\;;b" }, + { { "a;", "b;" }, ';', '\\', "a\\;;b\\;" }, }; for (const TestCase& test : tests) @@ -162,13 +159,12 @@ namespace lms::core::stringUtils::tests std::vector expectedOutput; }; - TestCase tests[] - { - {"", ';', '\\', {}}, - {"\\;", ';', '\\', {";"}}, - {"\\;\\;", ';', '\\', {";;"}}, - {"a\\;;b", ';', '\\', {"a;", "b"}}, - {"a\\;;b\\;", ';', '\\', {"a;", "b;"}}, + TestCase tests[]{ + { "", ';', '\\', {} }, + { "\\;", ';', '\\', { ";" } }, + { "\\;\\;", ';', '\\', { ";;" } }, + { "a\\;;b", ';', '\\', { "a;", "b" } }, + { "a\\;;b\\;", ';', '\\', { "a;", "b;" } }, }; for (const TestCase& test : tests) @@ -250,17 +246,16 @@ namespace lms::core::stringUtils::tests std::string expectedOutput; }; - TestCase tests[] - { - {"", ""}, - {"C", "C"}, - {"c", "C"}, - {" c", " C"}, - {" cc", " Cc"}, - {"(c", "(c"}, - {"1c", "1c"}, - {"&c", "&c"}, - {"c c", "C c"} + TestCase tests[]{ + { "", "" }, + { "C", "C" }, + { "c", "C" }, + { " c", " C" }, + { " cc", " Cc" }, + { "(c", "(c" }, + { "1c", "1c" }, + { "&c", "&c" }, + { "c c", "C c" } }; for (const TestCase& test : tests) @@ -279,7 +274,7 @@ namespace lms::core::stringUtils::tests TEST(Stringutils, dateTime) { - const Wt::WDateTime dateTime{ Wt::WDate {2020, 01, 03 }, Wt::WTime{9, 8, 11, 75} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 2020, 01, 03 }, Wt::WTime{ 9, 8, 11, 75 } }; EXPECT_EQ(toISO8601String(dateTime), "2020-01-03T09:08:11.075"); } @@ -294,4 +289,4 @@ namespace lms::core::stringUtils::tests EXPECT_FALSE(stringEndsWith("FooBar", "1FooBar")); EXPECT_FALSE(stringEndsWith("FooBar", "R")); } -} \ No newline at end of file +} // namespace lms::core::stringUtils::tests \ No newline at end of file diff --git a/src/libs/core/test/TraceLogger.cpp b/src/libs/core/test/TraceLogger.cpp index fcee9ea2..592faf33 100644 --- a/src/libs/core/test/TraceLogger.cpp +++ b/src/libs/core/test/TraceLogger.cpp @@ -19,6 +19,7 @@ #include #include + #include #include "core/ITraceLogger.hpp" @@ -33,11 +34,10 @@ namespace lms::core::tracing::tests std::vector threads; for (std::size_t i{}; i < 16; ++i) { - threads.emplace_back([&] - { - ScopedTrace loggedEvent{ "MyCategory", Level::Overview, "MyEventLogged", "SomeArgType", "SomeArg", traceLogger.get() }; - ScopedTrace notLoggedEvent{ "MyNotLoggedCategory", Level::Detailed, "MyEventNotLogged", "SomeNotLoggedArgType", "SomeNotLoggedArg", traceLogger.get() }; - }); + threads.emplace_back([&] { + ScopedTrace loggedEvent{ "MyCategory", Level::Overview, "MyEventLogged", "SomeArgType", "SomeArg", traceLogger.get() }; + ScopedTrace notLoggedEvent{ "MyNotLoggedCategory", Level::Detailed, "MyEventNotLogged", "SomeNotLoggedArgType", "SomeNotLoggedArg", traceLogger.get() }; + }); } for (std::thread& t : threads) @@ -56,4 +56,4 @@ namespace lms::core::tracing::tests EXPECT_EQ(oss.str().find("SomeNotLoggedArgType"), std::string::npos); EXPECT_EQ(oss.str().find("SomeNotLoggedArg"), std::string::npos); } -} \ No newline at end of file +} // namespace lms::core::tracing::tests \ No newline at end of file diff --git a/src/libs/core/test/UUID.cpp b/src/libs/core/test/UUID.cpp index 8e61d71a..9dad6f09 100644 --- a/src/libs/core/test/UUID.cpp +++ b/src/libs/core/test/UUID.cpp @@ -37,4 +37,4 @@ namespace lms::core EXPECT_TRUE(uuid1 >= uuid2); EXPECT_TRUE(uuid1 <= uuid2); } -} \ No newline at end of file +} // namespace lms::core \ No newline at end of file diff --git a/src/libs/core/test/Utils.cpp b/src/libs/core/test/Utils.cpp index 88325e8b..dc673372 100644 --- a/src/libs/core/test/Utils.cpp +++ b/src/libs/core/test/Utils.cpp @@ -19,9 +19,8 @@ #include -int main(int argc, char **argv) +int main(int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } - diff --git a/src/libs/database/impl/Artist.cpp b/src/libs/database/impl/Artist.cpp index 92a0e307..ae93df40 100644 --- a/src/libs/database/impl/Artist.cpp +++ b/src/libs/database/impl/Artist.cpp @@ -20,22 +20,23 @@ #include +#include "core/ILogger.hpp" #include "database/Cluster.hpp" #include "database/Release.hpp" #include "database/Session.hpp" #include "database/Track.hpp" #include "database/User.hpp" -#include "core/ILogger.hpp" -#include "SqlQuery.hpp" -#include "Utils.hpp" + #include "EnumSetTraits.hpp" #include "IdTypeTraits.hpp" +#include "SqlQuery.hpp" +#include "Utils.hpp" namespace lms::db { namespace { - template + template Wt::Dbo::Query createQuery(Session& session, std::string_view itemToSelect, const Artist::FindParameters& params) { session.checkReadTransaction(); @@ -97,21 +98,25 @@ namespace lms::db { assert(params.feedbackBackend); query.join("starred_artist s_a ON s_a.artist_id = a.id") - .where("s_a.user_id = ?").bind(params.starringUser) - .where("s_a.backend = ?").bind(*params.feedbackBackend) - .where("s_a.sync_state <> ?").bind(SyncState::PendingRemove); + .where("s_a.user_id = ?") + .bind(params.starringUser) + .where("s_a.backend = ?") + .bind(*params.feedbackBackend) + .where("s_a.sync_state <> ?") + .bind(SyncState::PendingRemove); } if (params.clusters.size() == 1) { query.join("track_cluster t_c ON t_c.track_id = t_a_l.track_id") - .where("t_c.cluster_id = ?").bind(params.clusters.front()); + .where("t_c.cluster_id = ?") + .bind(params.clusters.front()); } else if (params.clusters.size() > 1) { std::ostringstream oss; oss << "a.id IN (SELECT DISTINCT t_a_l.artist_id FROM track_artist_link t_a_l" - " INNER JOIN track_cluster t_c ON t_c.track_id = t_a_l.track_id"; + " INNER JOIN track_cluster t_c ON t_c.track_id = t_a_l.track_id"; WhereClause clusterClause; for (const ClusterId clusterId : params.clusters) @@ -159,7 +164,7 @@ namespace lms::db return query; } - template + template Wt::Dbo::Query createQuery(Session& session, const Artist::FindParameters& params) { std::string_view itemToSelect; @@ -173,12 +178,12 @@ namespace lms::db return createQuery(session, itemToSelect, params); } - } + } // namespace Artist::Artist(const std::string& name, const std::optional& MBID) - : _name{ std::string(name, 0 , _maxNameLength) }, - _sortName{ _name }, - _MBID{ MBID ? MBID->getAsString() : "" } + : _name{ std::string(name, 0, _maxNameLength) } + , _sortName{ _name } + , _MBID{ MBID ? MBID->getAsString() : "" } { } @@ -198,10 +203,7 @@ namespace lms::db { session.checkReadTransaction(); - auto query{ session.getDboSession()->query>("SELECT a FROM artist a") - .orderBy("a.id") - .where("a.id > ?").bind(lastRetrievedArtist) - .limit(static_cast(count)) }; + auto query{ session.getDboSession()->query>("SELECT a FROM artist a").orderBy("a.id").where("a.id > ?").bind(lastRetrievedArtist).limit(static_cast(count)) }; if (library.isValid()) { @@ -209,20 +211,17 @@ namespace lms::db query.where("EXISTS (SELECT 1 FROM track_artist_link t_a_l JOIN track t ON t.id = t_a_l.track_id WHERE t_a_l.artist_id = a.id AND t.media_library_id = ?)").bind(library); } - utils::forEachQueryResult(query, [&](const Artist::pointer& artist) - { - func(artist); - lastRetrievedArtist = artist->getId(); - }); + utils::forEachQueryResult(query, [&](const Artist::pointer& artist) { + func(artist); + lastRetrievedArtist = artist->getId(); + }); } std::vector Artist::find(Session& session, std::string_view name) { session.checkReadTransaction(); - return utils::fetchQueryResults(session.getDboSession()->find() - .where("name = ?").bind(std::string{ name, 0, _maxNameLength }) - .orderBy("LENGTH(mbid) DESC")); // put mbid entries first + return utils::fetchQueryResults(session.getDboSession()->find().where("name = ?").bind(std::string{ name, 0, _maxNameLength }).orderBy("LENGTH(mbid) DESC")); // put mbid entries first } Artist::pointer Artist::find(Session& session, const core::UUID& mbid) @@ -279,19 +278,18 @@ namespace lms::db assert(session()); std::ostringstream oss; - oss << - "SELECT a.id FROM artist a" - " INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id" - " INNER JOIN track t ON t.id = t_a_l.track_id" - " INNER JOIN track_cluster t_c ON t_c.track_id = t.id" - " WHERE " - " t_c.cluster_id IN (SELECT DISTINCT c.id from cluster c" - " INNER JOIN track t ON c.id = t_c.cluster_id" - " INNER JOIN track_cluster t_c ON t_c.track_id = t.id" - " INNER JOIN artist a ON a.id = t_a_l.artist_id" - " INNER JOIN track_artist_link t_a_l ON t_a_l.track_id = t.id" - " WHERE a.id = ?)" - " AND a.id <> ?"; + oss << "SELECT a.id FROM artist a" + " INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id" + " INNER JOIN track t ON t.id = t_a_l.track_id" + " INNER JOIN track_cluster t_c ON t_c.track_id = t.id" + " WHERE " + " t_c.cluster_id IN (SELECT DISTINCT c.id from cluster c" + " INNER JOIN track t ON c.id = t_c.cluster_id" + " INNER JOIN track_cluster t_c ON t_c.track_id = t.id" + " INNER JOIN artist a ON a.id = t_a_l.artist_id" + " INNER JOIN track_artist_link t_a_l ON t_a_l.track_id = t.id" + " WHERE a.id = ?)" + " AND a.id <> ?"; if (!artistLinkTypes.empty()) { @@ -309,11 +307,7 @@ namespace lms::db oss << ")"; } - auto query{ session()->query(oss.str()) - .bind(getId()) - .bind(getId()) - .groupBy("a.id") - .orderBy("COUNT(*) DESC, RANDOM()") }; + auto query{ session()->query(oss.str()).bind(getId()).bind(getId()).groupBy("a.id").orderBy("COUNT(*) DESC, RANDOM()") }; for (const TrackArtistLinkType type : artistLinkTypes) query.bind(type); @@ -347,11 +341,10 @@ namespace lms::db query.bind(bindArg); std::map> clustersByType; - utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster) - { - if (clustersByType[cluster->getType()->getId()].size() < size) - clustersByType[cluster->getType()->getId()].push_back(cluster); - }); + utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster) { + if (clustersByType[cluster->getType()->getId()].size() < size) + clustersByType[cluster->getType()->getId()].push_back(cluster); + }); std::vector> res; for (const auto& [clusterTypeId, clusters] : clustersByType) diff --git a/src/libs/database/impl/AuthToken.cpp b/src/libs/database/impl/AuthToken.cpp index acdf936d..79bc2abb 100644 --- a/src/libs/database/impl/AuthToken.cpp +++ b/src/libs/database/impl/AuthToken.cpp @@ -20,10 +20,12 @@ #include "database/AuthToken.hpp" #include + #include "database/Session.hpp" #include "database/User.hpp" -#include "StringViewTraits.hpp" + #include "IdTypeTraits.hpp" +#include "StringViewTraits.hpp" #include "Utils.hpp" namespace lms::db @@ -37,7 +39,7 @@ namespace lms::db AuthToken::pointer AuthToken::create(Session& session, std::string_view value, const Wt::WDateTime& expiry, ObjectPtr user) { - return session.getDboSession()->add(std::unique_ptr {new AuthToken{ value, expiry, user }}); + return session.getDboSession()->add(std::unique_ptr{ new AuthToken{ value, expiry, user } }); } void AuthToken::removeExpiredTokens(Session& session, const Wt::WDateTime& now) @@ -53,4 +55,4 @@ namespace lms::db return utils::fetchQuerySingleResult(session.getDboSession()->find().where("value = ?").bind(value)); } -} +} // namespace lms::db diff --git a/src/libs/database/impl/Cluster.cpp b/src/libs/database/impl/Cluster.cpp index ee1dab9b..c84a9149 100644 --- a/src/libs/database/impl/Cluster.cpp +++ b/src/libs/database/impl/Cluster.cpp @@ -25,16 +25,17 @@ #include "database/ScanSettings.hpp" #include "database/Session.hpp" #include "database/Track.hpp" + #include "IdTypeTraits.hpp" -#include "StringViewTraits.hpp" #include "SqlQuery.hpp" +#include "StringViewTraits.hpp" #include "Utils.hpp" namespace lms::db { namespace { - template + template Wt::Dbo::Query createQuery(Session& session, std::string_view itemToSelect, const Cluster::FindParameters& params) { session.checkReadTransaction(); @@ -44,7 +45,7 @@ namespace lms::db if (params.track.isValid() || params.release.isValid()) query.join("track_cluster t_c ON t_c.cluster_id = c.id"); - + if (!params.clusterTypeName.empty()) query.join("cluster_type c_t ON c_t.id = c.cluster_type_id"); @@ -77,7 +78,7 @@ namespace lms::db return query; } - template + template Wt::Dbo::Query createQuery(Session& session, const Cluster::FindParameters& params) { std::string_view itemToSelect; @@ -91,17 +92,17 @@ namespace lms::db return createQuery(session, itemToSelect, params); } - } + } // namespace Cluster::Cluster(ObjectPtr type, std::string_view name) - : _name{ std::string {name, 0, _maxNameLength} }, - _clusterType{ getDboPtr(type) } + : _name{ std::string{ name, 0, _maxNameLength } } + , _clusterType{ getDboPtr(type) } { } Cluster::pointer Cluster::create(Session& session, ObjectPtr type, std::string_view name) { - return session.getDboSession()->add(std::unique_ptr {new Cluster{ type, name }}); + return session.getDboSession()->add(std::unique_ptr{ new Cluster{ type, name } }); } std::size_t Cluster::getCount(Session& session) @@ -154,16 +155,14 @@ namespace lms::db { session.checkReadTransaction(); - return utils::fetchQuerySingleResult(session.getDboSession()->query("SELECT COUNT(t.id) FROM track t INNER JOIN track_cluster t_c ON t_c.track_id = t.id") - .where("t_c.cluster_id = ?").bind(id)); + return utils::fetchQuerySingleResult(session.getDboSession()->query("SELECT COUNT(t.id) FROM track t INNER JOIN track_cluster t_c ON t_c.track_id = t.id").where("t_c.cluster_id = ?").bind(id)); } std::size_t Cluster::computeReleaseCount(Session& session, ClusterId id) { session.checkReadTransaction(); - return utils::fetchQuerySingleResult(session.getDboSession()->query("SELECT COUNT(DISTINCT r.id) FROM release r INNER JOIN track t on t.release_id = r.id INNER JOIN track_cluster t_c ON t_c.track_id = t.id") - .where("t_c.cluster_id = ?").bind(id)); + return utils::fetchQuerySingleResult(session.getDboSession()->query("SELECT COUNT(DISTINCT r.id) FROM release r INNER JOIN track t on t.release_id = r.id INNER JOIN track_cluster t_c ON t_c.track_id = t.id").where("t_c.cluster_id = ?").bind(id)); } void Cluster::addTrack(ObjectPtr track) @@ -175,8 +174,7 @@ namespace lms::db { assert(session()); - auto query{ session()->query("SELECT t.id FROM track t INNER JOIN cluster c ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id") - .where("c.id = ?").bind(getId()) }; + auto query{ session()->query("SELECT t.id FROM track t INNER JOIN cluster c ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id").where("c.id = ?").bind(getId()) }; return utils::execRangeQuery(query, range); } @@ -188,7 +186,7 @@ namespace lms::db ClusterType::pointer ClusterType::create(Session& session, std::string_view name) { - return session.getDboSession()->add(std::unique_ptr {new ClusterType{ name }}); + return session.getDboSession()->add(std::unique_ptr{ new ClusterType{ name } }); } std::size_t ClusterType::getCount(Session& session) @@ -203,9 +201,9 @@ namespace lms::db session.checkReadTransaction(); auto query{ session.getDboSession()->query( - "SELECT c_t.id from cluster_type c_t" - " LEFT OUTER JOIN cluster c ON c_t.id = c.cluster_type_id") - .where("c.id IS NULL") }; + "SELECT c_t.id from cluster_type c_t" + " LEFT OUTER JOIN cluster c ON c_t.id = c.cluster_type_id") + .where("c.id IS NULL") }; return utils::execRangeQuery(query, range); } @@ -215,8 +213,8 @@ namespace lms::db session.checkReadTransaction(); auto query{ session.getDboSession()->query( - "SELECT DISTINCT c_t.id from cluster_type c_t") - .join("cluster c ON c_t.id = c.cluster_type_id") }; + "SELECT DISTINCT c_t.id from cluster_type c_t") + .join("cluster c ON c_t.id = c.cluster_type_id") }; return utils::execRangeQuery(query, range); } @@ -255,9 +253,7 @@ namespace lms::db assert(self()); assert(session()); - return utils::fetchQuerySingleResult(session()->find() - .where("name = ?").bind(name) - .where("cluster_type_id = ?").bind(getId())); + return utils::fetchQuerySingleResult(session()->find().where("name = ?").bind(name).where("cluster_type_id = ?").bind(getId())); } std::vector ClusterType::getClusters() const @@ -265,8 +261,6 @@ namespace lms::db assert(self()); assert(session()); - return utils::fetchQueryResults(session()->find() - .where("cluster_type_id = ?").bind(getId()) - .orderBy("name")); + return utils::fetchQueryResults(session()->find().where("cluster_type_id = ?").bind(getId()).orderBy("name")); } } // namespace lms::db diff --git a/src/libs/database/impl/Db.cpp b/src/libs/database/impl/Db.cpp index 253d82c7..e4d95a71 100644 --- a/src/libs/database/impl/Db.cpp +++ b/src/libs/database/impl/Db.cpp @@ -22,12 +22,12 @@ #include #include -#include "database/Session.hpp" -#include "database/User.hpp" #include "core/IConfig.hpp" #include "core/ILogger.hpp" #include "core/ITraceLogger.hpp" #include "core/Service.hpp" +#include "database/Session.hpp" +#include "database/User.hpp" namespace lms::db { @@ -68,7 +68,7 @@ namespace lms::db std::filesystem::path _dbPath; }; - } + } // namespace // Session living class handling the database and the login Db::Db(const std::filesystem::path& dbPath, std::size_t connectionCount) @@ -76,7 +76,7 @@ namespace lms::db LMS_LOG(DB, INFO, "Creating connection pool on file " << dbPath.string()); auto connection{ std::make_unique(dbPath.string()) }; - if (core::IConfig * config{ core::Service::get() })// may not be here on testU + if (core::IConfig * config{ core::Service::get() }) // may not be here on testU connection->setProperty("show-queries", config->getBool("db-show-queries", false) ? "true" : "false"); auto connectionPool{ std::make_unique(std::move(connection), connectionCount) }; diff --git a/src/libs/database/impl/EnumSetTraits.hpp b/src/libs/database/impl/EnumSetTraits.hpp index 3852babd..6e2547ae 100644 --- a/src/libs/database/impl/EnumSetTraits.hpp +++ b/src/libs/database/impl/EnumSetTraits.hpp @@ -20,6 +20,7 @@ #pragma once #include + #include #include "core/EnumSet.hpp" @@ -49,5 +50,4 @@ namespace Wt::Dbo return false; } }; -} - +} // namespace Wt::Dbo diff --git a/src/libs/database/impl/IdTypeTraits.hpp b/src/libs/database/impl/IdTypeTraits.hpp index 8158d50a..2313bb4b 100644 --- a/src/libs/database/impl/IdTypeTraits.hpp +++ b/src/libs/database/impl/IdTypeTraits.hpp @@ -20,6 +20,7 @@ #pragma once #include + #include #include "database/Types.hpp" @@ -55,5 +56,4 @@ namespace Wt::Dbo return false; } }; -} - +} // namespace Wt::Dbo diff --git a/src/libs/database/impl/Listen.cpp b/src/libs/database/impl/Listen.cpp index dc67f690..bc862b5b 100644 --- a/src/libs/database/impl/Listen.cpp +++ b/src/libs/database/impl/Listen.cpp @@ -21,6 +21,7 @@ #include "database/Session.hpp" #include "database/Track.hpp" #include "database/User.hpp" + #include "IdTypeTraits.hpp" #include "SqlQuery.hpp" #include "Utils.hpp" @@ -31,9 +32,7 @@ namespace lms::db { Wt::Dbo::Query createArtistsQuery(Session& session, const Listen::ArtistStatsFindParameters& params) { - auto query{ session.getDboSession()->query("SELECT a.id from artist a") - .join("track_artist_link t_a_l ON t_a_l.artist_id = a.id") - .join("listen l ON l.track_id = t_a_l.track_id") }; + auto query{ session.getDboSession()->query("SELECT a.id from artist a").join("track_artist_link t_a_l ON t_a_l.artist_id = a.id").join("listen l ON l.track_id = t_a_l.track_id") }; if (params.user.isValid()) query.where("l.user_id = ?").bind(params.user); @@ -56,7 +55,7 @@ namespace lms::db { std::ostringstream oss; oss << "a.id IN (SELECT DISTINCT t_a_l.artist_id FROM track_artist_link t_a_l" - " INNER JOIN track_cluster t_c ON t_c.track_id = t_a_l.track_id"; + " INNER JOIN track_cluster t_c ON t_c.track_id = t_a_l.track_id"; WhereClause clusterClause; for (auto id : params.clusters) @@ -96,9 +95,7 @@ namespace lms::db Wt::Dbo::Query createReleasesQuery(Session& session, const Listen::StatsFindParameters& params) { - auto query{ session.getDboSession()->query("SELECT r.id from release r") - .join("track t ON t.release_id = r.id") - .join("listen l ON l.track_id = t.id") }; + auto query{ session.getDboSession()->query("SELECT r.id from release r").join("track t ON t.release_id = r.id").join("listen l ON l.track_id = t.id") }; if (params.user.isValid()) query.where("l.user_id = ?").bind(params.user); @@ -109,7 +106,8 @@ namespace lms::db if (params.artist.isValid()) { query.join("track_artist_link t_a_l ON t_a_l.track_id = t.id") - .where("t_a_l.artist_id = ?").bind(params.artist); + .where("t_a_l.artist_id = ?") + .bind(params.artist); } if (params.library.isValid()) @@ -119,9 +117,9 @@ namespace lms::db { std::ostringstream oss; oss << "r.id IN (SELECT DISTINCT r.id FROM release r" - " INNER JOIN track t ON t.release_id = r.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 track t ON t.release_id = r.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"; WhereClause clusterClause; for (ClusterId id : params.clusters) @@ -144,8 +142,7 @@ namespace lms::db Wt::Dbo::Query createTracksQuery(Session& session, const Listen::StatsFindParameters& params) { - auto query{ session.getDboSession()->query("SELECT t.id from track t") - .join("listen l ON l.track_id = t.id") }; + auto query{ session.getDboSession()->query("SELECT t.id from track t").join("listen l ON l.track_id = t.id") }; if (params.user.isValid()) query.where("l.user_id = ?").bind(params.user); @@ -156,7 +153,8 @@ namespace lms::db if (params.artist.isValid()) { query.join("track_artist_link t_a_l ON t_a_l.track_id = t.id") - .where("t_a_l.artist_id = ?").bind(params.artist); + .where("t_a_l.artist_id = ?") + .bind(params.artist); } if (params.library.isValid()) @@ -166,8 +164,8 @@ namespace lms::db { std::ostringstream oss; oss << "t.id IN (SELECT DISTINCT t.id FROM track t" - " INNER JOIN track_cluster t_c ON t_c.track_id = t.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 cluster c ON c.id = t_c.cluster_id"; WhereClause clusterClause; for (auto id : params.clusters) @@ -187,19 +185,20 @@ namespace lms::db return query; } - } + } // namespace Listen::Listen(ObjectPtr user, ObjectPtr track, ScrobblingBackend backend, const Wt::WDateTime& dateTime) : _dateTime{ Wt::WDateTime::fromTime_t(dateTime.toTime_t()) } , _backend{ backend } , _user{ getDboPtr(user) } , _track{ getDboPtr(track) } - {} + { + } Listen::pointer Listen::create(Session& session, ObjectPtr user, ObjectPtr track, ScrobblingBackend backend, const Wt::WDateTime& dateTime) { session.checkWriteTransaction(); - return session.getDboSession()->add(std::unique_ptr {new Listen{ user, track, backend, dateTime }}); + return session.getDboSession()->add(std::unique_ptr{ new Listen{ user, track, backend, dateTime } }); } std::size_t Listen::getCount(Session& session) @@ -218,8 +217,7 @@ namespace lms::db { session.checkReadTransaction(); - auto query{ session.getDboSession()->query("SELECT id FROM listen") - .orderBy("date_time") }; + auto query{ session.getDboSession()->query("SELECT id FROM listen").orderBy("date_time") }; if (parameters.user.isValid()) query.where("user_id = ?").bind(parameters.user); @@ -237,11 +235,7 @@ namespace lms::db { session.checkReadTransaction(); - return utils::fetchQuerySingleResult(session.getDboSession()->find() - .where("user_id = ?").bind(userId) - .where("track_id = ?").bind(trackId) - .where("backend = ?").bind(backend) - .where("date_time = ?").bind(Wt::WDateTime::fromTime_t(dateTime.toTime_t()))); + return utils::fetchQuerySingleResult(session.getDboSession()->find().where("user_id = ?").bind(userId).where("track_id = ?").bind(trackId).where("backend = ?").bind(backend).where("date_time = ?").bind(Wt::WDateTime::fromTime_t(dateTime.toTime_t()))); } RangeResults Listen::getTopArtists(Session& session, const ArtistStatsFindParameters& params) @@ -250,8 +244,8 @@ namespace lms::db auto query{ createArtistsQuery(session, params) }; auto collection{ query - .orderBy("COUNT(a.id) DESC") - .groupBy("a.id") }; + .orderBy("COUNT(a.id) DESC") + .groupBy("a.id") }; return utils::execRangeQuery(query, params.range); } @@ -280,7 +274,8 @@ namespace lms::db { session.checkReadTransaction(); auto query{ createArtistsQuery(session, params) - .groupBy("a.id").having("l.date_time = MAX(l.date_time)") + .groupBy("a.id") + .having("l.date_time = MAX(l.date_time)") .orderBy("l.date_time DESC") }; return utils::execRangeQuery(query, params.range); @@ -290,7 +285,8 @@ namespace lms::db { session.checkReadTransaction(); auto query{ createReleasesQuery(session, params) - .groupBy("r.id").having("l.date_time = MAX(l.date_time)") + .groupBy("r.id") + .having("l.date_time = MAX(l.date_time)") .orderBy("l.date_time DESC") }; return utils::execRangeQuery(query, params.range); @@ -300,7 +296,8 @@ namespace lms::db { session.checkReadTransaction(); auto query{ createTracksQuery(session, params) - .groupBy("t.id").having("l.date_time = MAX(l.date_time)") + .groupBy("t.id") + .having("l.date_time = MAX(l.date_time)") .orderBy("l.date_time DESC") }; return utils::execRangeQuery(query, params.range); @@ -310,11 +307,7 @@ namespace lms::db { session.checkReadTransaction(); - return utils::fetchQuerySingleResult(session.getDboSession()->query("SELECT COUNT(*) from listen l") - .join("user u ON u.id = l.user_id") - .where("l.track_id = ?").bind(trackId) - .where("l.user_id = ?").bind(userId) - .where("l.backend = u.scrobbling_backend")); + return utils::fetchQuerySingleResult(session.getDboSession()->query("SELECT COUNT(*) from listen l").join("user u ON u.id = l.user_id").where("l.track_id = ?").bind(trackId).where("l.user_id = ?").bind(userId).where("l.backend = u.scrobbling_backend")); } std::size_t Listen::getCount(Session& session, UserId userId, ReleaseId releaseId) @@ -322,16 +315,16 @@ namespace lms::db session.checkReadTransaction(); return utils::fetchQuerySingleResult(session.getDboSession()->query( - "SELECT IFNULL(MIN(count_result), 0)" - " FROM (" - " SELECT COUNT(l.track_id) AS count_result" - " FROM track t" - " LEFT JOIN listen l ON t.id = l.track_id AND l.backend = (SELECT scrobbling_backend FROM user WHERE id = ?) AND l.user_id = ?" - " WHERE t.release_id = ?" - " GROUP BY t.id)") - .bind(userId) - .bind(userId) - .bind(releaseId)); + "SELECT IFNULL(MIN(count_result), 0)" + " FROM (" + " SELECT COUNT(l.track_id) AS count_result" + " FROM track t" + " LEFT JOIN listen l ON t.id = l.track_id AND l.backend = (SELECT scrobbling_backend FROM user WHERE id = ?) AND l.user_id = ?" + " WHERE t.release_id = ?" + " GROUP BY t.id)") + .bind(userId) + .bind(userId) + .bind(releaseId)); } Listen::pointer Listen::getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, ReleaseId releaseId) @@ -339,24 +332,13 @@ namespace lms::db session.checkReadTransaction(); // TODO not pending remove? - return utils::fetchQuerySingleResult(session.getDboSession()->query>("SELECT l from listen l") - .join("track t ON l.track_id = t.id") - .where("t.release_id = ?").bind(releaseId) - .where("l.user_id = ?").bind(userId) - .where("l.backend = ?").bind(backend) - .orderBy("l.date_time DESC") - .limit(1)); + return utils::fetchQuerySingleResult(session.getDboSession()->query>("SELECT l from listen l").join("track t ON l.track_id = t.id").where("t.release_id = ?").bind(releaseId).where("l.user_id = ?").bind(userId).where("l.backend = ?").bind(backend).orderBy("l.date_time DESC").limit(1)); } Listen::pointer Listen::getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, TrackId trackId) { session.checkReadTransaction(); // TODO not pending remove? - return utils::fetchQuerySingleResult(session.getDboSession()->query>("SELECT l from listen l") - .where("l.track_id = ?").bind(trackId) - .where("l.user_id = ?").bind(userId) - .where("l.backend = ?").bind(backend) - .orderBy("l.date_time DESC") - .limit(1)); + return utils::fetchQuerySingleResult(session.getDboSession()->query>("SELECT l from listen l").where("l.track_id = ?").bind(trackId).where("l.user_id = ?").bind(userId).where("l.backend = ?").bind(backend).orderBy("l.date_time DESC").limit(1)); } } // namespace lms::db diff --git a/src/libs/database/impl/MediaLibrary.cpp b/src/libs/database/impl/MediaLibrary.cpp index f30105c7..74a7a2e1 100644 --- a/src/libs/database/impl/MediaLibrary.cpp +++ b/src/libs/database/impl/MediaLibrary.cpp @@ -22,6 +22,7 @@ #include "database/ScanSettings.hpp" #include "database/Session.hpp" #include "database/Track.hpp" + #include "IdTypeTraits.hpp" #include "PathTraits.hpp" #include "StringViewTraits.hpp" @@ -30,8 +31,8 @@ namespace lms::db { MediaLibrary::MediaLibrary(const std::filesystem::path& p, std::string_view name) - : _path{ p }, - _name{ std::string {name, 0, maxNameLength} } + : _path{ p } + , _name{ std::string{ name, 0, maxNameLength } } { } @@ -72,9 +73,8 @@ namespace lms::db { session.checkReadTransaction(); - utils::forEachQueryResult(session.getDboSession()->find(), [&](const MediaLibrary::pointer& mediaLibrary) - { - func(mediaLibrary); - }); + utils::forEachQueryResult(session.getDboSession()->find(), [&](const MediaLibrary::pointer& mediaLibrary) { + func(mediaLibrary); + }); } } // namespace lms::db diff --git a/src/libs/database/impl/Migration.cpp b/src/libs/database/impl/Migration.cpp index 7533ae6a..4dacba8b 100644 --- a/src/libs/database/impl/Migration.cpp +++ b/src/libs/database/impl/Migration.cpp @@ -21,13 +21,14 @@ #include +#include "core/Exception.hpp" +#include "core/ILogger.hpp" +#include "core/ITraceLogger.hpp" #include "database/Db.hpp" #include "database/ScanSettings.hpp" #include "database/Session.hpp" #include "database/User.hpp" -#include "core/Exception.hpp" -#include "core/ILogger.hpp" -#include "core/ITraceLogger.hpp" + #include "Utils.hpp" namespace lms::db @@ -39,7 +40,8 @@ namespace lms::db VersionInfo::VersionInfo() : _version{ LMS_DATABASE_VERSION } - {} + { + } VersionInfo::pointer VersionInfo::getOrCreate(Session& session) { @@ -58,14 +60,15 @@ namespace lms::db return utils::fetchQuerySingleResult(session.getDboSession()->find()); } -} +} // namespace lms::db namespace lms::db::Migration { class ScopedNoForeignKeys { public: - ScopedNoForeignKeys(Db& db) : _db{ db } + ScopedNoForeignKeys(Db& db) + : _db{ db } { _db.executeSql("PRAGMA foreign_keys=OFF"); } @@ -73,6 +76,7 @@ namespace lms::db::Migration { _db.executeSql("PRAGMA foreign_keys=ON"); } + private: ScopedNoForeignKeys(const ScopedNoForeignKeys&) = delete; ScopedNoForeignKeys(ScopedNoForeignKeys&&) = delete; @@ -106,9 +110,9 @@ CREATE TABLE IF NOT EXISTS "track_artist_link_backup" ( { // Add scrobbling state // By default, everything needs to be sent - session.getDboSession()->execute("ALTER TABLE starred_artist ADD scrobbling_state INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast(/*ScrobblingState::PendingAdd*/0)) + ")"); - session.getDboSession()->execute("ALTER TABLE starred_release ADD scrobbling_state INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast(/*ScrobblingState::PendingAdd*/0)) + ")"); - session.getDboSession()->execute("ALTER TABLE starred_track ADD scrobbling_state INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast(/*ScrobblingState::PendingAdd*/0)) + ")"); + session.getDboSession()->execute("ALTER TABLE starred_artist ADD scrobbling_state INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast(/*ScrobblingState::PendingAdd*/ 0)) + ")"); + session.getDboSession()->execute("ALTER TABLE starred_release ADD scrobbling_state INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast(/*ScrobblingState::PendingAdd*/ 0)) + ")"); + session.getDboSession()->execute("ALTER TABLE starred_track ADD scrobbling_state INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast(/*ScrobblingState::PendingAdd*/ 0)) + ")"); } static void migrateFromV35(Session& session) @@ -251,7 +255,7 @@ CREATE TABLE IF NOT EXISTS "track_backup" ( void migrateFromV45(Session& session) { // add subsonic_enable_transcoding_by_default, default is disabled - session.getDboSession()->execute("ALTER TABLE user ADD subsonic_enable_transcoding_by_default INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast(/*User::defaultSubsonicEnableTranscodingByDefault*/0)) + ")"); + session.getDboSession()->execute("ALTER TABLE user ADD subsonic_enable_transcoding_by_default INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast(/*User::defaultSubsonicEnableTranscodingByDefault*/ 0)) + ")"); } void migrateFromV46(Session& session) @@ -330,7 +334,8 @@ CREATE TABLE IF NOT EXISTS "track_backup" ( session.getDboSession()->execute(R"(INSERT INTO "media_library" ("id", "version", "path", "name") SELECT 1, 0, s_s.media_directory, "Main" FROM scan_settings s_s -WHERE id = ?)").bind(scanSettingsId); +WHERE id = ?)") + .bind(scanSettingsId); // Remove the outdated column in scan_settings session.getDboSession()->execute("ALTER TABLE scan_settings DROP media_directory"); @@ -479,34 +484,33 @@ SELECT using MigrationFunction = std::function; - const std::map migrationFunctions - { - {33, migrateFromV33}, - {34, migrateFromV34}, - {35, migrateFromV35}, - {36, migrateFromV36}, - {37, migrateFromV37}, - {38, migrateFromV38}, - {39, migrateFromV39}, - {40, migrateFromV40}, - {41, migrateFromV41}, - {42, migrateFromV42}, - {43, migrateFromV43}, - {44, migrateFromV44}, - {45, migrateFromV45}, - {46, migrateFromV46}, - {47, migrateFromV47}, - {48, migrateFromV48}, - {49, migrateFromV49}, - {50, migrateFromV50}, - {51, migrateFromV51}, - {52, migrateFromV52}, - {53, migrateFromV53}, - {54, migrateFromV54}, - {55, migrateFromV55}, - {56, migrateFromV56}, - {57, migrateFromV57}, - {58, migrateFromV58}, + const std::map migrationFunctions{ + { 33, migrateFromV33 }, + { 34, migrateFromV34 }, + { 35, migrateFromV35 }, + { 36, migrateFromV36 }, + { 37, migrateFromV37 }, + { 38, migrateFromV38 }, + { 39, migrateFromV39 }, + { 40, migrateFromV40 }, + { 41, migrateFromV41 }, + { 42, migrateFromV42 }, + { 43, migrateFromV43 }, + { 44, migrateFromV44 }, + { 45, migrateFromV45 }, + { 46, migrateFromV46 }, + { 47, migrateFromV47 }, + { 48, migrateFromV48 }, + { 49, migrateFromV49 }, + { 50, migrateFromV50 }, + { 51, migrateFromV51 }, + { 52, migrateFromV52 }, + { 53, migrateFromV53 }, + { 54, migrateFromV54 }, + { 55, migrateFromV55 }, + { 56, migrateFromV56 }, + { 57, migrateFromV57 }, + { 58, migrateFromV58 }, }; bool migrationPerformed{}; @@ -550,4 +554,4 @@ SELECT return migrationPerformed; } -} +} // namespace lms::db::Migration diff --git a/src/libs/database/impl/Migration.hpp b/src/libs/database/impl/Migration.hpp index ac528c8f..57b75861 100644 --- a/src/libs/database/impl/Migration.hpp +++ b/src/libs/database/impl/Migration.hpp @@ -54,4 +54,4 @@ namespace lms::db { bool doDbMigration(Session& session); // return true if migration was performed } -} +} // namespace lms::db diff --git a/src/libs/database/impl/PathTraits.hpp b/src/libs/database/impl/PathTraits.hpp index 7ea12684..2fccde63 100644 --- a/src/libs/database/impl/PathTraits.hpp +++ b/src/libs/database/impl/PathTraits.hpp @@ -19,8 +19,9 @@ #pragma once -#include #include +#include + #include namespace Wt::Dbo @@ -50,5 +51,4 @@ namespace Wt::Dbo return true; } }; -} - +} // namespace Wt::Dbo diff --git a/src/libs/database/impl/Release.cpp b/src/libs/database/impl/Release.cpp index fea7ffe8..75810ff3 100644 --- a/src/libs/database/impl/Release.cpp +++ b/src/libs/database/impl/Release.cpp @@ -21,15 +21,16 @@ #include +#include "core/ILogger.hpp" #include "database/Artist.hpp" #include "database/Cluster.hpp" #include "database/Session.hpp" #include "database/Track.hpp" #include "database/User.hpp" -#include "core/ILogger.hpp" -#include "SqlQuery.hpp" + #include "EnumSetTraits.hpp" #include "IdTypeTraits.hpp" +#include "SqlQuery.hpp" #include "StringViewTraits.hpp" #include "Utils.hpp" @@ -37,7 +38,7 @@ namespace lms::db { namespace { - template + template Wt::Dbo::Query createQuery(Session& session, std::string_view itemToSelect, const Release::FindParameters& params) { auto query{ session.getDboSession()->query("SELECT " + std::string{ itemToSelect } + " from release r") }; @@ -63,7 +64,8 @@ namespace lms::db { query.join("release_release_type r_r_t ON r_r_t.release_id = r.id"); query.join("release_type r_t ON r_t.id = r_r_t.release_type_id") - .where("r_t.name = ?").bind(params.releaseType); + .where("r_t.name = ?") + .bind(params.releaseType); } if (params.writtenAfter.isValid()) @@ -82,9 +84,12 @@ namespace lms::db { assert(params.feedbackBackend); query.join("starred_release s_r ON s_r.release_id = r.id") - .where("s_r.user_id = ?").bind(params.starringUser) - .where("s_r.backend = ?").bind(*params.feedbackBackend) - .where("s_r.sync_state <> ?").bind(SyncState::PendingRemove); + .where("s_r.user_id = ?") + .bind(params.starringUser) + .where("s_r.backend = ?") + .bind(*params.feedbackBackend) + .where("s_r.sync_state <> ?") + .bind(SyncState::PendingRemove); } if (params.artist.isValid() @@ -119,9 +124,9 @@ namespace lms::db { std::ostringstream oss; oss << "r.id NOT IN (SELECT DISTINCT r.id FROM release r" - " INNER JOIN track_artist_link t_a_l ON t_a_l.track_id = t.id" - " INNER JOIN track t ON t.release_id = r.id" - " WHERE (t_a_l.artist_id = ? AND ("; + " INNER JOIN track_artist_link t_a_l ON t_a_l.track_id = t.id" + " INNER JOIN track t ON t.release_id = r.id" + " WHERE (t_a_l.artist_id = ? AND ("; query.bind(params.artist); @@ -143,13 +148,14 @@ namespace lms::db if (params.clusters.size() == 1) { query.join("track_cluster t_c ON t_c.track_id = t.id") - .where("t_c.cluster_id = ?").bind(params.clusters.front()); + .where("t_c.cluster_id = ?") + .bind(params.clusters.front()); } else if (params.clusters.size() > 1) { std::ostringstream oss; oss << "r.id IN (SELECT DISTINCT t.release_id FROM track t" - " INNER JOIN track_cluster t_c ON t_c.track_id = t.id"; + " INNER JOIN track_cluster t_c ON t_c.track_id = t.id"; WhereClause clusterClause; for (const ClusterId clusterId : params.clusters) @@ -200,69 +206,62 @@ namespace lms::db return query; } - } + } // namespace ReleaseType::ReleaseType(std::string_view name) - : _name{ std::string(name, 0 , _maxNameLength) } + : _name{ std::string(name, 0, _maxNameLength) } { } ReleaseType::pointer ReleaseType::create(Session& session, std::string_view name) { - return session.getDboSession()->add(std::unique_ptr {new ReleaseType{ name }}); + return session.getDboSession()->add(std::unique_ptr{ new ReleaseType{ name } }); } ReleaseType::pointer ReleaseType::find(Session& session, ReleaseTypeId id) { session.checkReadTransaction(); - return utils::fetchQuerySingleResult(session.getDboSession()->find() - .where("id = ?").bind(id)); + return utils::fetchQuerySingleResult(session.getDboSession()->find().where("id = ?").bind(id)); } ReleaseType::pointer ReleaseType::find(Session& session, std::string_view name) { session.checkReadTransaction(); - return utils::fetchQuerySingleResult(session.getDboSession()->find() - .where("name = ?").bind(name)); + return utils::fetchQuerySingleResult(session.getDboSession()->find().where("name = ?").bind(name)); } Release::Release(const std::string& name, const std::optional& MBID) - : _name{ std::string(name, 0 , _maxNameLength) }, - _MBID{ MBID ? MBID->getAsString() : "" } + : _name{ std::string(name, 0, _maxNameLength) } + , _MBID{ MBID ? MBID->getAsString() : "" } { } Release::pointer Release::create(Session& session, const std::string& name, const std::optional& MBID) { - return session.getDboSession()->add(std::unique_ptr {new Release{ name, MBID }}); + return session.getDboSession()->add(std::unique_ptr{ new Release{ name, MBID } }); } std::vector Release::find(Session& session, const std::string& name, const std::filesystem::path& releaseDirectory) { session.checkReadTransaction(); - return utils::fetchQueryResults(session.getDboSession()->query>("SELECT DISTINCT r from release r") - .join("track t ON t.release_id = r.id") - .where("r.name = ?").bind(std::string(name, 0, _maxNameLength)) - .where("t.absolute_file_path LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'").bind(utils::escapeLikeKeyword(releaseDirectory.string()) + "%")); + return utils::fetchQueryResults(session.getDboSession()->query>("SELECT DISTINCT r from release r").join("track t ON t.release_id = r.id").where("r.name = ?").bind(std::string(name, 0, _maxNameLength)).where("t.absolute_file_path LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'").bind(utils::escapeLikeKeyword(releaseDirectory.string()) + "%")); } Release::pointer Release::find(Session& session, const core::UUID& mbid) { session.checkReadTransaction(); - return utils::fetchQuerySingleResult(session.getDboSession()->find() - .where("mbid = ?").bind(mbid.getAsString())); + return utils::fetchQuerySingleResult(session.getDboSession()->find().where("mbid = ?").bind(mbid.getAsString())); } Release::pointer Release::find(Session& session, ReleaseId id) { session.checkReadTransaction(); - return utils::fetchQuerySingleResult(session.getDboSession()->find() - .where("id = ?").bind(id)); + return utils::fetchQuerySingleResult(session.getDboSession()->find().where("id = ?").bind(id)); } bool Release::exists(Session& session, ReleaseId id) @@ -290,10 +289,7 @@ namespace lms::db { session.checkReadTransaction(); - auto query{ session.getDboSession()->query>("SELECT r FROM release r") - .orderBy("r.id") - .where("r.id > ?").bind(lastRetrievedRelease) - .limit(static_cast(count)) }; + auto query{ session.getDboSession()->query>("SELECT r FROM release r").orderBy("r.id").where("r.id > ?").bind(lastRetrievedRelease).limit(static_cast(count)) }; if (library.isValid()) { @@ -301,11 +297,10 @@ namespace lms::db query.where("EXISTS (SELECT 1 FROM track t WHERE t.release_id = r.id AND t.media_library_id = ?)").bind(library); } - utils::forEachQueryResult(query, [&](const Release::pointer& release) - { - func(release); - lastRetrievedRelease = release->getId(); - }); + utils::forEachQueryResult(query, [&](const Release::pointer& release) { + func(release); + lastRetrievedRelease = release->getId(); + }); } RangeResults Release::find(Session& session, const FindParameters& params) @@ -342,8 +337,7 @@ namespace lms::db std::size_t Release::getDiscCount() const { assert(session()); - int res{ utils::fetchQuerySingleResult(session()->query("SELECT COUNT(DISTINCT disc_number) FROM track t") - .where("t.release_id = ?").bind(getId()))}; + int res{ utils::fetchQuerySingleResult(session()->query("SELECT COUNT(DISTINCT disc_number) FROM track t").where("t.release_id = ?").bind(getId())) }; return res; } @@ -352,15 +346,12 @@ namespace lms::db assert(session()); using ResultType = std::tuple; - const auto query{ session()->query("SELECT DISTINCT disc_number, disc_subtitle FROM track t") - .where("t.release_id = ?").bind(getId()) - .orderBy("disc_number")}; + const auto query{ session()->query("SELECT DISTINCT disc_number, disc_subtitle FROM track t").where("t.release_id = ?").bind(getId()).orderBy("disc_number") }; std::vector discs; - utils::forEachQueryResult(query, [&](ResultType&& res) - { - discs.emplace_back(DiscInfo{ static_cast(std::get(res)), std::move(std::get(res)) }); - }); + utils::forEachQueryResult(query, [&](ResultType&& res) { + discs.emplace_back(DiscInfo{ static_cast(std::get(res)), std::move(std::get(res)) }); + }); return discs; } @@ -380,10 +371,7 @@ namespace lms::db assert(session()); const char* field{ original ? "original_date" : "date" }; - auto query{ (session()->query(std::string {"SELECT "} + "t." + field + " FROM track t") - .where("t.release_id = ?") - .groupBy(field) - .bind(getId())) }; + auto query{ (session()->query(std::string{ "SELECT " } + "t." + field + " FROM track t").where("t.release_id = ?").groupBy(field).bind(getId())) }; const auto dates{ utils::fetchQueryResults(query) }; @@ -409,9 +397,7 @@ namespace lms::db assert(session()); const char* field{ original ? "original_year" : "year" }; - auto query{ session()->query>(std::string {"SELECT "} + "t." + field + " FROM track t") - .where("t.release_id = ?").bind(getId()) - .groupBy(field) }; + auto query{ session()->query>(std::string{ "SELECT " } + "t." + field + " FROM track t").where("t.release_id = ?").bind(getId()).groupBy(field) }; const auto years{ utils::fetchQueryResults(query) }; @@ -427,10 +413,7 @@ namespace lms::db { assert(session()); - auto query{ session()->query("SELECT copyright FROM track t INNER JOIN release r ON r.id = t.release_id") - .where("r.id = ?") - .groupBy("copyright") - .bind(getId()) }; + auto query{ session()->query("SELECT copyright FROM track t INNER JOIN release r ON r.id = t.release_id").where("r.id = ?").groupBy("copyright").bind(getId()) }; const auto copyrights{ utils::fetchQueryResults(query) }; @@ -445,10 +428,7 @@ namespace lms::db { assert(session()); - const auto query{ session()->query - ("SELECT copyright_url FROM track t INNER JOIN release r ON r.id = t.release_id") - .where("r.id = ?").bind(getId()) - .groupBy("copyright_url") }; + const auto query{ session()->query("SELECT copyright_url FROM track t INNER JOIN release r ON r.id = t.release_id").where("r.id = ?").bind(getId()).groupBy("copyright_url") }; const auto copyrights{ utils::fetchQueryResults(query) }; @@ -463,9 +443,7 @@ namespace lms::db { assert(session()); - return utils::fetchQuerySingleResult(session()->query("SELECT COALESCE(AVG(t.bitrate), 0) FROM track t") - .where("release_id = ?").bind(getId()) - .where("bitrate > 0")); + return utils::fetchQuerySingleResult(session()->query("SELECT COALESCE(AVG(t.bitrate), 0) FROM track t").where("release_id = ?").bind(getId()).where("bitrate > 0")); } std::vector Release::getArtists(TrackArtistLinkType linkType) const @@ -473,12 +451,14 @@ namespace lms::db assert(session()); const auto query{ session()->query>( - "SELECT a FROM artist a" - " INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id" - " INNER JOIN track t ON t.id = t_a_l.track_id") - .where("t.release_id = ?").bind(getId()) - .where("+t_a_l.type = ?").bind(linkType) // adding + since the query planner does not a good job when analyze is not performed - .groupBy("a.id") }; + "SELECT a FROM artist a" + " INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id" + " INNER JOIN track t ON t.id = t_a_l.track_id") + .where("t.release_id = ?") + .bind(getId()) + .where("+t_a_l.type = ?") + .bind(linkType) // adding + since the query planner does not a good job when analyze is not performed + .groupBy("a.id") }; return utils::fetchQueryResults(query); } @@ -489,24 +469,23 @@ namespace lms::db // Select the similar releases using the 5 most used clusters of the release auto query{ session()->query>( - "SELECT r FROM release r" - " INNER JOIN track t ON t.release_id = r.id" - " INNER JOIN track_cluster t_c ON t_c.track_id = t.id" - " WHERE " - " t_c.cluster_id IN " - "(SELECT DISTINCT c.id FROM cluster c" - " INNER JOIN track t 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" - " WHERE r.id = ?)" - " AND r.id <> ?" - ) - .bind(getId()) - .bind(getId()) - .groupBy("r.id") - .orderBy("COUNT(*) DESC, RANDOM()") - .limit(count ? static_cast(*count) : -1) - .offset(offset ? static_cast(*offset) : -1) }; + "SELECT r FROM release r" + " INNER JOIN track t ON t.release_id = r.id" + " INNER JOIN track_cluster t_c ON t_c.track_id = t.id" + " WHERE " + " t_c.cluster_id IN " + "(SELECT DISTINCT c.id FROM cluster c" + " INNER JOIN track t 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" + " WHERE r.id = ?)" + " AND r.id <> ?") + .bind(getId()) + .bind(getId()) + .groupBy("r.id") + .orderBy("COUNT(*) DESC, RANDOM()") + .limit(count ? static_cast(*count) : -1) + .offset(offset ? static_cast(*offset) : -1) }; return utils::fetchQueryResults(query); } @@ -530,8 +509,7 @@ namespace lms::db std::size_t Release::getTrackCount() const { assert(session()); - return utils::fetchQuerySingleResult(session()->query("SELECT COUNT(t.id) FROM track t INNER JOIN release r ON r.id = t.release_id") - .where("r.id = ?").bind(getId())); + return utils::fetchQuerySingleResult(session()->query("SELECT COUNT(t.id) FROM track t INNER JOIN release r ON r.id = t.release_id").where("r.id = ?").bind(getId())); } std::vector Release::getReleaseTypes() const @@ -556,16 +534,14 @@ namespace lms::db using milli = std::chrono::duration; - return utils::fetchQuerySingleResult(session()->query("SELECT COALESCE(SUM(duration), 0) FROM track t") - .where("t.release_id = ?").bind(getId())); + return utils::fetchQuerySingleResult(session()->query("SELECT COALESCE(SUM(duration), 0) FROM track t").where("t.release_id = ?").bind(getId())); } Wt::WDateTime Release::getLastWritten() const { assert(session()); - return utils::fetchQuerySingleResult(session()->query("SELECT COALESCE(MAX(file_last_write), '1970-01-01T00:00:00') FROM track t") - .where("t.release_id = ?").bind(getId())); + return utils::fetchQuerySingleResult(session()->query("SELECT COALESCE(MAX(file_last_write), '1970-01-01T00:00:00') FROM track t").where("t.release_id = ?").bind(getId())); } std::vector> Release::getClusterGroups(const std::vector& clusterTypeIds, std::size_t size) const diff --git a/src/libs/database/impl/ScanSettings.cpp b/src/libs/database/impl/ScanSettings.cpp index 40c39b81..5196f82c 100644 --- a/src/libs/database/impl/ScanSettings.cpp +++ b/src/libs/database/impl/ScanSettings.cpp @@ -21,9 +21,10 @@ #include +#include "core/String.hpp" #include "database/MediaLibrary.hpp" #include "database/Session.hpp" -#include "core/String.hpp" + #include "Utils.hpp" namespace lms::db diff --git a/src/libs/database/impl/Session.cpp b/src/libs/database/impl/Session.cpp index a61fa823..d0c5c90d 100644 --- a/src/libs/database/impl/Session.cpp +++ b/src/libs/database/impl/Session.cpp @@ -22,7 +22,6 @@ #include "core/Exception.hpp" #include "core/ILogger.hpp" #include "core/ITraceLogger.hpp" - #include "database/Artist.hpp" #include "database/AuthToken.hpp" #include "database/Cluster.hpp" @@ -35,22 +34,23 @@ #include "database/StarredRelease.hpp" #include "database/StarredTrack.hpp" #include "database/Track.hpp" -#include "database/TrackBookmark.hpp" #include "database/TrackArtistLink.hpp" -#include "database/TrackList.hpp" +#include "database/TrackBookmark.hpp" #include "database/TrackFeatures.hpp" +#include "database/TrackList.hpp" #include "database/TransactionChecker.hpp" #include "database/User.hpp" + #include "EnumSetTraits.hpp" -#include "PathTraits.hpp" #include "Migration.hpp" +#include "PathTraits.hpp" #include "Utils.hpp" namespace lms::db { WriteTransaction::WriteTransaction(core::RecursiveSharedMutex& mutex, Wt::Dbo::Session& session) - : _lock{ mutex }, - _transaction{ session } + : _lock{ mutex } + , _transaction{ session } { #if LMS_CHECK_TRANSACTION_ACCESSES TransactionChecker::pushWriteTransaction(_transaction.session()); diff --git a/src/libs/database/impl/SqlQuery.cpp b/src/libs/database/impl/SqlQuery.cpp index ca88032c..430e0b36 100644 --- a/src/libs/database/impl/SqlQuery.cpp +++ b/src/libs/database/impl/SqlQuery.cpp @@ -27,7 +27,8 @@ namespace lms::db { WhereClause& WhereClause::And(const WhereClause& otherClause) { - if (!otherClause._clause.empty()) { + if (!otherClause._clause.empty()) + { if (!_clause.empty()) _clause += " AND "; _clause += "(" + otherClause._clause + ")"; @@ -43,7 +44,8 @@ namespace lms::db WhereClause& WhereClause::Or(const WhereClause& otherClause) { - if (!otherClause._clause.empty()) { + if (!otherClause._clause.empty()) + { if (!_clause.empty()) _clause += " OR "; _clause += "(" + otherClause._clause + ")"; @@ -75,7 +77,7 @@ namespace lms::db } InnerJoinClause::InnerJoinClause(const std::string& clause) - :_clause(clause) + : _clause(clause) { } @@ -154,7 +156,8 @@ namespace lms::db if (!_clause.empty()) { oss << "FROM "; - for (auto it = _clause.begin(); it != _clause.end(); ++it) { + for (auto it = _clause.begin(); it != _clause.end(); ++it) + { if (it != _clause.begin()) oss << ","; @@ -185,4 +188,4 @@ namespace lms::db return oss.str(); } -} \ No newline at end of file +} // namespace lms::db \ No newline at end of file diff --git a/src/libs/database/impl/SqlQuery.hpp b/src/libs/database/impl/SqlQuery.hpp index cd3afeec..507c07af 100644 --- a/src/libs/database/impl/SqlQuery.hpp +++ b/src/libs/database/impl/SqlQuery.hpp @@ -19,8 +19,8 @@ #pragma once -#include #include +#include namespace lms::db { @@ -40,8 +40,8 @@ namespace lms::db const std::vector& getBindArgs() const { return _bindArgs; } private: - std::string _clause; // WHERE clause - std::vector _bindArgs; + std::string _clause; // WHERE clause + std::vector _bindArgs; }; class InnerJoinClause @@ -68,13 +68,13 @@ namespace lms::db std::string get() const { return _statement; } private: - std::string _statement; // SELECT statement + std::string _statement; // SELECT statement }; class SelectStatement { public: - SelectStatement() {}; + SelectStatement(){}; SelectStatement(const std::string& item); SelectStatement& And(const std::string& item); @@ -82,7 +82,7 @@ namespace lms::db std::string get() const; private: - std::vector _statement; + std::vector _statement; }; class FromClause @@ -96,16 +96,24 @@ namespace lms::db std::string get() const; private: - std::vector _clause; + std::vector _clause; }; class SqlQuery { public: SelectStatement& select() { return _selectStatement; } - SelectStatement& select(const std::string& statement) { _selectStatement = SelectStatement(statement); return _selectStatement; } + SelectStatement& select(const std::string& statement) + { + _selectStatement = SelectStatement(statement); + return _selectStatement; + } FromClause& from() { return _fromClause; } - FromClause& from(const std::string& clause) { _whereClause = WhereClause(clause); return _fromClause; } + FromClause& from(const std::string& clause) + { + _whereClause = WhereClause(clause); + return _fromClause; + } InnerJoinClause& innerJoin() { return _innerJoinClause; } WhereClause& where() { return _whereClause; } const WhereClause& where() const { return _whereClause; } @@ -115,10 +123,10 @@ namespace lms::db std::string get() const; private: - SelectStatement _selectStatement; // SELECT statement - InnerJoinClause _innerJoinClause; // INNER JOIN - FromClause _fromClause; // FROM tables - WhereClause _whereClause; // WHERE clause - GroupByStatement _groupByStatement; // GROUP BY statement + SelectStatement _selectStatement; // SELECT statement + InnerJoinClause _innerJoinClause; // INNER JOIN + FromClause _fromClause; // FROM tables + WhereClause _whereClause; // WHERE clause + GroupByStatement _groupByStatement; // GROUP BY statement }; -} \ No newline at end of file +} // namespace lms::db \ No newline at end of file diff --git a/src/libs/database/impl/StarredArtist.cpp b/src/libs/database/impl/StarredArtist.cpp index 69b7e340..df53f6f6 100644 --- a/src/libs/database/impl/StarredArtist.cpp +++ b/src/libs/database/impl/StarredArtist.cpp @@ -24,6 +24,7 @@ #include "database/Artist.hpp" #include "database/Session.hpp" #include "database/User.hpp" + #include "IdTypeTraits.hpp" #include "Utils.hpp" @@ -38,7 +39,7 @@ namespace lms::db StarredArtist::pointer StarredArtist::create(Session& session, ObjectPtr artist, ObjectPtr user, FeedbackBackend backend) { - return session.getDboSession()->add(std::unique_ptr {new StarredArtist{ artist, user, backend }}); + return session.getDboSession()->add(std::unique_ptr{ new StarredArtist{ artist, user, backend } }); } std::size_t StarredArtist::getCount(Session& session) @@ -56,24 +57,17 @@ namespace lms::db StarredArtist::pointer StarredArtist::find(Session& session, ArtistId artistId, UserId userId) { session.checkReadTransaction(); - return utils::fetchQuerySingleResult(session.getDboSession()->query>("SELECT s_a from starred_artist s_a") - .join("user u ON u.id = s_a.user_id") - .where("s_a.artist_id = ?").bind(artistId) - .where("s_a.user_id = ?").bind(userId) - .where("s_a.backend = u.feedback_backend")); + return utils::fetchQuerySingleResult(session.getDboSession()->query>("SELECT s_a from starred_artist s_a").join("user u ON u.id = s_a.user_id").where("s_a.artist_id = ?").bind(artistId).where("s_a.user_id = ?").bind(userId).where("s_a.backend = u.feedback_backend")); } StarredArtist::pointer StarredArtist::find(Session& session, ArtistId artistId, UserId userId, FeedbackBackend backend) { session.checkReadTransaction(); - return utils::fetchQuerySingleResult(session.getDboSession()->find() - .where("artist_id = ?").bind(artistId) - .where("user_id = ?").bind(userId) - .where("backend = ?").bind(backend)); + return utils::fetchQuerySingleResult(session.getDboSession()->find().where("artist_id = ?").bind(artistId).where("user_id = ?").bind(userId).where("backend = ?").bind(backend)); } void StarredArtist::setDateTime(const Wt::WDateTime& dateTime) { _dateTime = utils::normalizeDateTime(dateTime); } -} +} // namespace lms::db diff --git a/src/libs/database/impl/StarredRelease.cpp b/src/libs/database/impl/StarredRelease.cpp index 1b42407a..18311213 100644 --- a/src/libs/database/impl/StarredRelease.cpp +++ b/src/libs/database/impl/StarredRelease.cpp @@ -24,6 +24,7 @@ #include "database/Release.hpp" #include "database/Session.hpp" #include "database/User.hpp" + #include "IdTypeTraits.hpp" #include "Utils.hpp" @@ -38,7 +39,7 @@ namespace lms::db StarredRelease::pointer StarredRelease::create(Session& session, ObjectPtr release, ObjectPtr user, FeedbackBackend backend) { - return session.getDboSession()->add(std::unique_ptr{new StarredRelease{ release, user, backend }}); + return session.getDboSession()->add(std::unique_ptr{ new StarredRelease{ release, user, backend } }); } std::size_t StarredRelease::getCount(Session& session) @@ -56,24 +57,17 @@ namespace lms::db StarredRelease::pointer StarredRelease::find(Session& session, ReleaseId releaseId, UserId userId) { session.checkReadTransaction(); - return utils::fetchQuerySingleResult(session.getDboSession()->query>("SELECT s_r from starred_release s_r") - .join("user u ON u.id = s_r.user_id") - .where("s_r.release_id = ?").bind(releaseId) - .where("s_r.user_id = ?").bind(userId) - .where("s_r.backend = u.feedback_backend")); + return utils::fetchQuerySingleResult(session.getDboSession()->query>("SELECT s_r from starred_release s_r").join("user u ON u.id = s_r.user_id").where("s_r.release_id = ?").bind(releaseId).where("s_r.user_id = ?").bind(userId).where("s_r.backend = u.feedback_backend")); } StarredRelease::pointer StarredRelease::find(Session& session, ReleaseId releaseId, UserId userId, FeedbackBackend backend) { session.checkReadTransaction(); - return utils::fetchQuerySingleResult(session.getDboSession()->find() - .where("release_id = ?").bind(releaseId) - .where("user_id = ?").bind(userId) - .where("backend = ?").bind(backend)); + return utils::fetchQuerySingleResult(session.getDboSession()->find().where("release_id = ?").bind(releaseId).where("user_id = ?").bind(userId).where("backend = ?").bind(backend)); } void StarredRelease::setDateTime(const Wt::WDateTime& dateTime) { _dateTime = utils::normalizeDateTime(dateTime); } -} +} // namespace lms::db diff --git a/src/libs/database/impl/StarredTrack.cpp b/src/libs/database/impl/StarredTrack.cpp index f2b42ed1..e9e3ae4e 100644 --- a/src/libs/database/impl/StarredTrack.cpp +++ b/src/libs/database/impl/StarredTrack.cpp @@ -21,9 +21,10 @@ #include -#include "database/Track.hpp" #include "database/Session.hpp" +#include "database/Track.hpp" #include "database/User.hpp" + #include "IdTypeTraits.hpp" #include "Utils.hpp" @@ -38,7 +39,7 @@ namespace lms::db StarredTrack::pointer StarredTrack::create(Session& session, ObjectPtr track, ObjectPtr user, FeedbackBackend backend) { - return session.getDboSession()->add(std::unique_ptr {new StarredTrack{ track, user, backend }}); + return session.getDboSession()->add(std::unique_ptr{ new StarredTrack{ track, user, backend } }); } std::size_t StarredTrack::getCount(Session& session) @@ -56,28 +57,18 @@ namespace lms::db StarredTrack::pointer StarredTrack::find(Session& session, TrackId trackId, UserId userId) { session.checkReadTransaction(); - return utils::fetchQuerySingleResult(session.getDboSession()->query>("SELECT s_t from starred_track s_t") - .join("user u ON u.id = s_t.user_id") - .where("s_t.track_id = ?").bind(trackId) - .where("s_t.user_id = ?").bind(userId) - .where("s_t.backend = u.feedback_backend")); + return utils::fetchQuerySingleResult(session.getDboSession()->query>("SELECT s_t from starred_track s_t").join("user u ON u.id = s_t.user_id").where("s_t.track_id = ?").bind(trackId).where("s_t.user_id = ?").bind(userId).where("s_t.backend = u.feedback_backend")); } StarredTrack::pointer StarredTrack::find(Session& session, TrackId trackId, UserId userId, FeedbackBackend backend) { session.checkReadTransaction(); - return utils::fetchQuerySingleResult(session.getDboSession()->find() - .where("track_id = ?").bind(trackId) - .where("user_id = ?").bind(userId) - .where("backend = ?").bind(backend)); + return utils::fetchQuerySingleResult(session.getDboSession()->find().where("track_id = ?").bind(trackId).where("user_id = ?").bind(userId).where("backend = ?").bind(backend)); } bool StarredTrack::exists(Session& session, TrackId trackId, UserId userId, FeedbackBackend backend) { - return utils::fetchQuerySingleResult(session.getDboSession()->query("SELECT 1 from starred_track") - .where("track_id = ?").bind(trackId) - .where("user_id = ?").bind(userId) - .where("backend = ?").bind(backend)); + return utils::fetchQuerySingleResult(session.getDboSession()->query("SELECT 1 from starred_track").where("track_id = ?").bind(trackId).where("user_id = ?").bind(userId).where("backend = ?").bind(backend)); } RangeResults StarredTrack::find(Session& session, const FindParameters& params) @@ -100,4 +91,4 @@ namespace lms::db { _dateTime = utils::normalizeDateTime(dateTime); } -} +} // namespace lms::db diff --git a/src/libs/database/impl/StringViewTraits.hpp b/src/libs/database/impl/StringViewTraits.hpp index c82443c0..3092556c 100644 --- a/src/libs/database/impl/StringViewTraits.hpp +++ b/src/libs/database/impl/StringViewTraits.hpp @@ -20,6 +20,7 @@ #pragma once #include + #include namespace Wt::Dbo @@ -32,5 +33,4 @@ namespace Wt::Dbo statement->bind(column, std::string{ str }); } }; -} - +} // namespace Wt::Dbo diff --git a/src/libs/database/impl/Track.cpp b/src/libs/database/impl/Track.cpp index 5a459397..d0d2d1b9 100644 --- a/src/libs/database/impl/Track.cpp +++ b/src/libs/database/impl/Track.cpp @@ -21,15 +21,15 @@ #include +#include "core/ILogger.hpp" #include "database/Artist.hpp" #include "database/Cluster.hpp" #include "database/MediaLibrary.hpp" #include "database/Release.hpp" +#include "database/Session.hpp" #include "database/TrackArtistLink.hpp" #include "database/TrackFeatures.hpp" -#include "database/Session.hpp" #include "database/User.hpp" -#include "core/ILogger.hpp" #include "IdTypeTraits.hpp" #include "PathTraits.hpp" @@ -41,7 +41,7 @@ namespace lms::db { namespace { - template + template Wt::Dbo::Query createQuery(Session& session, std::string_view itemToSelect, const Track::FindParameters& params) { session.checkReadTransaction(); @@ -62,22 +62,26 @@ namespace lms::db { assert(params.feedbackBackend); query.join("starred_track s_t ON s_t.track_id = t.id") - .where("s_t.user_id = ?").bind(params.starringUser) - .where("s_t.backend = ?").bind(*params.feedbackBackend) - .where("s_t.sync_state <> ?").bind(SyncState::PendingRemove); + .where("s_t.user_id = ?") + .bind(params.starringUser) + .where("s_t.backend = ?") + .bind(*params.feedbackBackend) + .where("s_t.sync_state <> ?") + .bind(SyncState::PendingRemove); } if (params.clusters.size() == 1) { // optim query.join("track_cluster t_c ON t_c.track_id = t.id") - .where("t_c.cluster_id = ?").bind(params.clusters.front()); + .where("t_c.cluster_id = ?") + .bind(params.clusters.front()); } else if (params.clusters.size() > 1) { std::ostringstream oss; oss << "t.id IN (SELECT DISTINCT t.id FROM track t" - " INNER JOIN track_cluster t_c ON t_c.track_id = t.id"; + " INNER JOIN track_cluster t_c ON t_c.track_id = t.id"; WhereClause clusterClause; for (const ClusterId clusterId : params.clusters) @@ -183,7 +187,7 @@ namespace lms::db return query; } - template + template Wt::Dbo::Query createQuery(Session& session, const Track::FindParameters& params) { std::string_view itemToSelect; @@ -197,7 +201,7 @@ namespace lms::db return createQuery(session, itemToSelect, params); } - } + } // namespace Track::pointer Track::create(Session& session) { @@ -222,27 +226,22 @@ namespace lms::db { session.checkReadTransaction(); - return utils::fetchQuerySingleResult(session.getDboSession()->find() - .where("id = ?").bind(id)); + return utils::fetchQuerySingleResult(session.getDboSession()->find().where("id = ?").bind(id)); } void Track::find(Session& session, TrackId& lastRetrievedTrack, std::size_t count, const std::function& func, MediaLibraryId library) { session.checkReadTransaction(); - auto query{ session.getDboSession()->find() - .orderBy("id") - .where("id > ?").bind(lastRetrievedTrack) - .limit(static_cast(count)) }; + auto query{ session.getDboSession()->find().orderBy("id").where("id > ?").bind(lastRetrievedTrack).limit(static_cast(count)) }; if (library.isValid()) query.where("media_library_id = ?").bind(library); - utils::forEachQueryResult(query, [&](const Track::pointer& track) - { - func(track); - lastRetrievedTrack = track->getId(); - }); + utils::forEachQueryResult(query, [&](const Track::pointer& track) { + func(track); + lastRetrievedTrack = track->getId(); + }); } bool Track::exists(Session& session, TrackId id) @@ -256,24 +255,21 @@ namespace lms::db { session.checkReadTransaction(); - return utils::fetchQueryResults(session.getDboSession()->find() - .where("mbid = ?").bind(mbid.getAsString())); + return utils::fetchQueryResults(session.getDboSession()->find().where("mbid = ?").bind(mbid.getAsString())); } std::vector Track::findByRecordingMBID(Session& session, const core::UUID& mbid) { session.checkReadTransaction(); - return utils::fetchQueryResults(session.getDboSession()->find() - .where("recording_mbid = ?").bind(mbid.getAsString())); + return utils::fetchQueryResults(session.getDboSession()->find().where("recording_mbid = ?").bind(mbid.getAsString())); } RangeResults Track::findIdsTrackMBIDDuplicates(Session& session, std::optional range) { session.checkReadTransaction(); - auto query{ session.getDboSession()->query("SELECT track.id FROM track WHERE mbid in (SELECT mbid FROM track WHERE mbid <> '' GROUP BY mbid HAVING COUNT (*) > 1)") - .orderBy("track.release_id,track.disc_number,track.track_number,track.mbid") }; + auto query{ session.getDboSession()->query("SELECT track.id FROM track WHERE mbid in (SELECT mbid FROM track WHERE mbid <> '' GROUP BY mbid HAVING COUNT (*) > 1)").orderBy("track.release_id,track.disc_number,track.track_number,track.mbid") }; return utils::execRangeQuery(query, range); } @@ -282,9 +278,7 @@ namespace lms::db { session.checkReadTransaction(); - auto query{ session.getDboSession()->query("SELECT t.id FROM track t") - .where("LENGTH(t.recording_mbid) > 0") - .where("NOT EXISTS (SELECT * FROM track_features t_f WHERE t_f.track_id = t.id)") }; + auto query{ session.getDboSession()->query("SELECT t.id FROM track t").where("LENGTH(t.recording_mbid) > 0").where("NOT EXISTS (SELECT * FROM track_features t_f WHERE t_f.track_id = t.id)") }; return utils::execRangeQuery(query, range); } @@ -298,10 +292,7 @@ namespace lms::db { assert(session()); - const auto query{ session()->query - ("SELECT t_c.cluster_id FROM track_cluster t_c") - .where("t_c.track_id = ?").bind(getId()) - .groupBy("t_c.cluster_id") }; + const auto query{ session()->query("SELECT t_c.cluster_id FROM track_cluster t_c").where("t_c.track_id = ?").bind(getId()).groupBy("t_c.cluster_id") }; return utils::fetchQueryResults(query); } @@ -352,12 +343,14 @@ namespace lms::db } auto query{ session.getDboSession()->query( - "SELECT t.id FROM track t" - " INNER JOIN track_cluster t_c ON t_c.track_id = t.id" - " AND t_c.cluster_id IN (SELECT DISTINCT c.id FROM cluster c INNER JOIN track_cluster t_c ON t_c.cluster_id = c.id WHERE t_c.track_id IN (" + oss.str() + "))" - " AND t.id NOT IN (" + oss.str() + ")") - .groupBy("t.id") - .orderBy("COUNT(*) DESC, RANDOM()") }; + "SELECT t.id FROM track t" + " INNER JOIN track_cluster t_c ON t_c.track_id = t.id" + " AND t_c.cluster_id IN (SELECT DISTINCT c.id FROM cluster c INNER JOIN track_cluster t_c ON t_c.cluster_id = c.id WHERE t_c.track_id IN (" + + oss.str() + "))" + " AND t.id NOT IN (" + + oss.str() + ")") + .groupBy("t.id") + .orderBy("COUNT(*) DESC, RANDOM()") }; for (TrackId trackId : tracks) query.bind(trackId); @@ -412,10 +405,9 @@ namespace lms::db assert(session()); std::ostringstream oss; - oss << - "SELECT a from artist a" - " INNER JOIN track_artist_link t_a_l ON a.id = t_a_l.artist_id" - " INNER JOIN track t ON t.id = t_a_l.track_id"; + oss << "SELECT a from artist a" + " INNER JOIN track_artist_link t_a_l ON a.id = t_a_l.artist_id" + " INNER JOIN track t ON t.id = t_a_l.track_id"; if (!linkTypes.empty()) { @@ -447,9 +439,8 @@ namespace lms::db assert(session()); std::ostringstream oss; - oss << - "SELECT t_a_l.artist_id FROM track_artist_link t_a_l" - " INNER JOIN track t ON t.id = t_a_l.track_id"; + oss << "SELECT t_a_l.artist_id FROM track_artist_link t_a_l" + " INNER JOIN track t ON t.id = t_a_l.track_id"; if (!linkTypes.empty()) { @@ -507,11 +498,10 @@ namespace lms::db query.bind(bindArg); std::map> clusters; - utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster) - { - if (clusters[cluster->getType()->getId()].size() < size) - clusters[cluster->getType()->getId()].push_back(cluster); - }); + utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster) { + if (clusters[cluster->getType()->getId()].size() < size) + clusters[cluster->getType()->getId()].push_back(cluster); + }); std::vector> res; for (const auto& [type, clusters] : clusters) @@ -545,6 +535,6 @@ namespace lms::db return os; } - } + } // namespace Debug } // namespace lms::db diff --git a/src/libs/database/impl/TrackArtistLink.cpp b/src/libs/database/impl/TrackArtistLink.cpp index 06e2056e..0817df8d 100644 --- a/src/libs/database/impl/TrackArtistLink.cpp +++ b/src/libs/database/impl/TrackArtistLink.cpp @@ -53,7 +53,7 @@ namespace lms::db return query; } - } + } // namespace TrackArtistLink::TrackArtistLink(ObjectPtr track, ObjectPtr artist, TrackArtistLinkType type, std::string_view subType) : _type{ type } @@ -83,40 +83,34 @@ namespace lms::db { session.checkReadTransaction(); - using ResultType = std::tuple < Wt::Dbo::ptr, Wt::Dbo::ptr>; + using ResultType = std::tuple, Wt::Dbo::ptr>; - const auto query{ session.getDboSession()->query("SELECT t_a_l, a FROM track_artist_link t_a_l") - .join("artist a ON t_a_l.artist_id = a.id") - .where("t_a_l.track_id = ?").bind(trackId) }; + const auto query{ session.getDboSession()->query("SELECT t_a_l, a FROM track_artist_link t_a_l").join("artist a ON t_a_l.artist_id = a.id").where("t_a_l.track_id = ?").bind(trackId) }; - utils::forEachQueryResult(query, [&](const ResultType& result) - { - func(std::get>(result), std::get>(result)); - }); + utils::forEachQueryResult(query, [&](const ResultType& result) { + func(std::get>(result), std::get>(result)); + }); } void TrackArtistLink::find(Session& session, const FindParameters& parameters, const std::function& func) { const auto query{ createQuery(session, parameters) }; - utils::forEachQueryResult(query, [&](const TrackArtistLink::pointer& link) - { - func(link); - }); + utils::forEachQueryResult(query, [&](const TrackArtistLink::pointer& link) { + func(link); + }); } core::EnumSet TrackArtistLink::findUsedTypes(Session& session, ArtistId artistId) { session.checkReadTransaction(); - const auto query{ session.getDboSession()->query("SELECT DISTINCT type from track_artist_link") - .where("artist_id = ?").bind(artistId) }; + const auto query{ session.getDboSession()->query("SELECT DISTINCT type from track_artist_link").where("artist_id = ?").bind(artistId) }; core::EnumSet res; - utils::forEachQueryResult(query, [&](TrackArtistLinkType linkType) - { - res.insert(linkType); - }); + utils::forEachQueryResult(query, [&](TrackArtistLinkType linkType) { + res.insert(linkType); + }); return res; } -} +} // namespace lms::db diff --git a/src/libs/database/impl/TrackBookmark.cpp b/src/libs/database/impl/TrackBookmark.cpp index d63c63c4..601ce35c 100644 --- a/src/libs/database/impl/TrackBookmark.cpp +++ b/src/libs/database/impl/TrackBookmark.cpp @@ -22,20 +22,21 @@ #include "database/Session.hpp" #include "database/Track.hpp" #include "database/User.hpp" + #include "IdTypeTraits.hpp" #include "Utils.hpp" namespace lms::db { TrackBookmark::TrackBookmark(ObjectPtr user, ObjectPtr track) - : _user{ getDboPtr(user) }, - _track{ getDboPtr(track) } + : _user{ getDboPtr(user) } + , _track{ getDboPtr(track) } { } TrackBookmark::pointer TrackBookmark::create(Session& session, ObjectPtr user, ObjectPtr track) { - return session.getDboSession()->add(std::unique_ptr {new TrackBookmark{ user, track }}); + return session.getDboSession()->add(std::unique_ptr{ new TrackBookmark{ user, track } }); } std::size_t TrackBookmark::getCount(Session& session) @@ -49,8 +50,7 @@ namespace lms::db { session.checkReadTransaction(); - auto query{ session.getDboSession()->query("SELECT id from track_bookmark") - .where("user_id = ?").bind(userId) }; + auto query{ session.getDboSession()->query("SELECT id from track_bookmark").where("user_id = ?").bind(userId) }; return utils::execRangeQuery(query, range); } @@ -59,18 +59,14 @@ namespace lms::db { session.checkReadTransaction(); - return utils::fetchQuerySingleResult(session.getDboSession()->find() - .where("user_id = ?").bind(userId) - .where("track_id = ?").bind(trackId)); + return utils::fetchQuerySingleResult(session.getDboSession()->find().where("user_id = ?").bind(userId).where("track_id = ?").bind(trackId)); } TrackBookmark::pointer TrackBookmark::find(Session& session, TrackBookmarkId id) { session.checkReadTransaction(); - return utils::fetchQuerySingleResult(session.getDboSession()->find() - .where("id = ?").bind(id)); + return utils::fetchQuerySingleResult(session.getDboSession()->find().where("id = ?").bind(id)); } } // namespace lms::db - diff --git a/src/libs/database/impl/TrackFeatures.cpp b/src/libs/database/impl/TrackFeatures.cpp index 40a2a6d9..f2987081 100644 --- a/src/libs/database/impl/TrackFeatures.cpp +++ b/src/libs/database/impl/TrackFeatures.cpp @@ -19,26 +19,28 @@ #include "database/TrackFeatures.hpp" -#include #include +#include +#include "core/ILogger.hpp" #include "database/Session.hpp" #include "database/Track.hpp" -#include "core/ILogger.hpp" + #include "IdTypeTraits.hpp" #include "Utils.hpp" -namespace lms::db { +namespace lms::db +{ TrackFeatures::TrackFeatures(ObjectPtr track, const std::string& jsonEncodedFeatures) - : _data{ jsonEncodedFeatures }, - _track{ getDboPtr(track) } + : _data{ jsonEncodedFeatures } + , _track{ getDboPtr(track) } { } TrackFeatures::pointer TrackFeatures::create(Session& session, ObjectPtr track, const std::string& jsonEncodedFeatures) { - return session.getDboSession()->add(std::unique_ptr {new TrackFeatures{ track, jsonEncodedFeatures }}); + return session.getDboSession()->add(std::unique_ptr{ new TrackFeatures{ track, jsonEncodedFeatures } }); } std::size_t TrackFeatures::getCount(Session& session) @@ -52,16 +54,14 @@ namespace lms::db { { session.checkReadTransaction(); - return utils::fetchQuerySingleResult(session.getDboSession()->find() - .where("id = ?").bind(id)); + return utils::fetchQuerySingleResult(session.getDboSession()->find().where("id = ?").bind(id)); } TrackFeatures::pointer TrackFeatures::find(Session& session, TrackId trackId) { session.checkReadTransaction(); - return utils::fetchQuerySingleResult(session.getDboSession()->find() - .where("track_id = ?").bind(trackId)); + return utils::fetchQuerySingleResult(session.getDboSession()->find().where("track_id = ?").bind(trackId)); } RangeResults TrackFeatures::find(Session& session, std::optional range) @@ -75,7 +75,7 @@ namespace lms::db { FeatureValues TrackFeatures::getFeatureValues(const FeatureName& featureNode) const { - FeatureValuesMap featuresValuesMap{ getFeatureValuesMap({featureNode}) }; + FeatureValuesMap featuresValuesMap{ getFeatureValuesMap({ featureNode }) }; return std::move(featuresValuesMap[featureNode]); } diff --git a/src/libs/database/impl/TrackList.cpp b/src/libs/database/impl/TrackList.cpp index aa6d85db..454964d7 100644 --- a/src/libs/database/impl/TrackList.cpp +++ b/src/libs/database/impl/TrackList.cpp @@ -21,23 +21,23 @@ #include #include "core/ILogger.hpp" - #include "database/Artist.hpp" #include "database/Cluster.hpp" #include "database/Release.hpp" #include "database/Session.hpp" -#include "database/User.hpp" #include "database/Track.hpp" +#include "database/User.hpp" + +#include "IdTypeTraits.hpp" #include "SqlQuery.hpp" #include "StringViewTraits.hpp" -#include "IdTypeTraits.hpp" #include "Utils.hpp" namespace lms::db { namespace { - template + template Wt::Dbo::Query createQuery(Session& session, std::string_view itemToSelect, const TrackList::FindParameters& params) { auto query{ session.getDboSession()->query("SELECT DISTINCT " + std::string{ itemToSelect } + " FROM tracklist t_l") }; @@ -61,8 +61,8 @@ namespace lms::db { std::ostringstream oss; oss << "t_l_e.track_id IN (SELECT DISTINCT t.id FROM track t" - " INNER JOIN track_cluster t_c ON t_c.track_id = t.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 cluster c ON c.id = t_c.cluster_id"; WhereClause clusterClause; for (const ClusterId clusterId : params.clusters) @@ -92,7 +92,7 @@ namespace lms::db return query; } - template + template Wt::Dbo::Query createQuery(Session& session, const TrackList::FindParameters& params) { std::string_view itemToSelect; @@ -106,7 +106,7 @@ namespace lms::db return createQuery(session, itemToSelect, params); } - } + } // namespace TrackList::TrackList(std::string_view name, TrackListType type, bool isPublic, ObjectPtr user) : _name{ name } @@ -121,7 +121,7 @@ namespace lms::db TrackList::pointer TrackList::create(Session& session, std::string_view name, TrackListType type, bool isPublic, ObjectPtr user) { - return session.getDboSession()->add(std::unique_ptr {new TrackList{ name, type, isPublic, user }}); + return session.getDboSession()->add(std::unique_ptr{ new TrackList{ name, type, isPublic, user } }); } std::size_t TrackList::getCount(Session& session) @@ -136,10 +136,7 @@ namespace lms::db session.checkReadTransaction(); assert(userId.isValid()); - return utils::fetchQuerySingleResult(session.getDboSession()->find() - .where("name = ?").bind(name) - .where("type = ?").bind(type) - .where("user_id = ?").bind(userId)); + return utils::fetchQuerySingleResult(session.getDboSession()->find().where("name = ?").bind(name).where("type = ?").bind(type).where("user_id = ?").bind(userId)); } RangeResults TrackList::find(Session& session, const FindParameters& params) @@ -188,9 +185,7 @@ namespace lms::db { assert(session()); - auto query{session()->find() - .where("tracklist_id = ?").bind(getId()) - .orderBy("id") }; + auto query{ session()->find().where("tracklist_id = ?").bind(getId()).orderBy("id") }; return utils::execRangeQuery(query, range); } @@ -199,20 +194,14 @@ namespace lms::db { assert(session()); - return utils::fetchQuerySingleResult(session()->find() - .where("tracklist_id = ?").bind(getId()) - .where("track_id = ?").bind(track->getId()) - .where("date_time = ?").bind(utils::normalizeDateTime(dateTime))); + return utils::fetchQuerySingleResult(session()->find().where("tracklist_id = ?").bind(getId()).where("track_id = ?").bind(track->getId()).where("date_time = ?").bind(utils::normalizeDateTime(dateTime))); } std::vector TrackList::getClusters() const { assert(session()); - const auto query{ session()->query>("SELECT c from cluster c INNER JOIN track t ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id INNER JOIN tracklist_entry p_e ON p_e.track_id = t.id INNER JOIN tracklist p ON p.id = p_e.tracklist_id") - .where("p.id = ?").bind(getId()) - .groupBy("c.id") - .orderBy("COUNT(c.id) DESC") }; + const auto query{ session()->query>("SELECT c from cluster c INNER JOIN track t ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id INNER JOIN tracklist_entry p_e ON p_e.track_id = t.id INNER JOIN tracklist p ON p.id = p_e.tracklist_id").where("p.id = ?").bind(getId()).groupBy("c.id").orderBy("COUNT(c.id) DESC") }; return utils::fetchQueryResults(query); } @@ -232,7 +221,8 @@ namespace lms::db .join("cluster_type c_type ON c.cluster_type_id = c_type.id") .join("tracklist_entry t_l_e ON t_l_e.track_id = t.id") .join("tracklist t_l ON t_l.id = t_l_e.tracklist_id") - .where("t_l.id = ?").bind(getId()); + .where("t_l.id = ?") + .bind(getId()); { std::ostringstream oss; @@ -253,11 +243,10 @@ namespace lms::db query.orderBy("COUNT(c.id) DESC"); std::map> clustersByType; - utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster) - { - if (clustersByType[cluster->getType()->getId()].size() < size) - clustersByType[cluster->getType()->getId()].push_back(cluster); - }); + utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster) { + if (clustersByType[cluster->getType()->getId()].size() < size) + clustersByType[cluster->getType()->getId()].push_back(cluster); + }); for (const auto& [clusterTypeId, clusters] : clustersByType) res.push_back(clusters); @@ -270,18 +259,17 @@ namespace lms::db assert(session()); auto query{ session()->query>( - "SELECT t FROM track t" - " INNER JOIN track_cluster t_c ON t_c.track_id = t.id" - " WHERE " - " (t_c.cluster_id IN (SELECT DISTINCT c.id from cluster c INNER JOIN track t ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id INNER JOIN tracklist_entry p_e ON p_e.track_id = t.id INNER JOIN tracklist p ON p.id = p_e.tracklist_id WHERE p.id = ?)" - " AND t.id NOT IN (SELECT tracklist_t.id FROM track tracklist_t INNER JOIN tracklist_entry t_e ON t_e.track_id = tracklist_t.id WHERE t_e.tracklist_id = ?))" - ) - .bind(getId()) - .bind(getId()) - .groupBy("t.id") - .orderBy("COUNT(*) DESC, RANDOM()") - .limit(size ? static_cast(*size) : -1) - .offset(offset ? static_cast(*offset) : -1) }; + "SELECT t FROM track t" + " INNER JOIN track_cluster t_c ON t_c.track_id = t.id" + " WHERE " + " (t_c.cluster_id IN (SELECT DISTINCT c.id from cluster c INNER JOIN track t ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id INNER JOIN tracklist_entry p_e ON p_e.track_id = t.id INNER JOIN tracklist p ON p.id = p_e.tracklist_id WHERE p.id = ?)" + " AND t.id NOT IN (SELECT tracklist_t.id FROM track tracklist_t INNER JOIN tracklist_entry t_e ON t_e.track_id = tracklist_t.id WHERE t_e.tracklist_id = ?))") + .bind(getId()) + .bind(getId()) + .groupBy("t.id") + .orderBy("COUNT(*) DESC, RANDOM()") + .limit(size ? static_cast(*size) : -1) + .offset(offset ? static_cast(*offset) : -1) }; return utils::fetchQueryResults(query); } @@ -290,8 +278,7 @@ namespace lms::db { assert(session()); - auto query{ session()->query("SELECT p_e.track_id from tracklist_entry p_e INNER JOIN tracklist p ON p_e.tracklist_id = p.id") - .where("p.id = ?").bind(getId()) }; + auto query{ session()->query("SELECT p_e.track_id from tracklist_entry p_e INNER JOIN tracklist p ON p_e.tracklist_id = p.id").where("p.id = ?").bind(getId()) }; return utils::fetchQueryResults(query); } @@ -302,8 +289,7 @@ namespace lms::db using milli = std::chrono::duration; - return utils::fetchQuerySingleResult(session()->query("SELECT COALESCE(SUM(duration), 0) FROM track t INNER JOIN tracklist_entry p_e ON t.id = p_e.track_id") - .where("p_e.tracklist_id = ?").bind(getId())); + return utils::fetchQuerySingleResult(session()->query("SELECT COALESCE(SUM(duration), 0) FROM track t INNER JOIN tracklist_entry p_e ON t.id = p_e.track_id").where("p_e.tracklist_id = ?").bind(getId())); } void TrackList::setLastModifiedDateTime(const Wt::WDateTime& dateTime) @@ -322,7 +308,7 @@ namespace lms::db TrackListEntry::pointer TrackListEntry::create(Session& session, ObjectPtr track, ObjectPtr tracklist, const Wt::WDateTime& dateTime) { - return session.getDboSession()->add(std::unique_ptr {new TrackListEntry{ track, tracklist, dateTime }}); + return session.getDboSession()->add(std::unique_ptr{ new TrackListEntry{ track, tracklist, dateTime } }); } void TrackListEntry::onPostCreated() diff --git a/src/libs/database/impl/TransactionChecker.cpp b/src/libs/database/impl/TransactionChecker.cpp index 9966345d..003e84bf 100644 --- a/src/libs/database/impl/TransactionChecker.cpp +++ b/src/libs/database/impl/TransactionChecker.cpp @@ -22,6 +22,7 @@ static_assert(LMS_CHECK_TRANSACTION_ACCESSES, "File should be excluded from build"); #include + #include "database/Session.hpp" namespace lms::db @@ -35,7 +36,7 @@ namespace lms::db }; static thread_local std::vector transactionStack; - } + } // namespace void TransactionChecker::pushWriteTransaction(Wt::Dbo::Session& session) { @@ -93,4 +94,4 @@ namespace lms::db { checkReadTransaction(*session.getDboSession()); } -} \ No newline at end of file +} // namespace lms::db \ No newline at end of file diff --git a/src/libs/database/impl/Types.cpp b/src/libs/database/impl/Types.cpp index f40ac880..fb5220f9 100644 --- a/src/libs/database/impl/Types.cpp +++ b/src/libs/database/impl/Types.cpp @@ -23,8 +23,7 @@ namespace lms::db { - static const std::set allowedAudioBitrates - { + static const std::set allowedAudioBitrates{ 64000, 96000, 128000, @@ -47,5 +46,4 @@ namespace lms::db { return DateRange{ from, to }; } -} - +} // namespace lms::db diff --git a/src/libs/database/impl/User.cpp b/src/libs/database/impl/User.cpp index 97efe9d8..944a24f7 100644 --- a/src/libs/database/impl/User.cpp +++ b/src/libs/database/impl/User.cpp @@ -19,11 +19,12 @@ #include "database/User.hpp" +#include "core/ILogger.hpp" #include "database/Artist.hpp" #include "database/Release.hpp" #include "database/Session.hpp" #include "database/Track.hpp" -#include "core/ILogger.hpp" + #include "IdTypeTraits.hpp" #include "StringViewTraits.hpp" #include "Utils.hpp" @@ -37,7 +38,7 @@ namespace lms::db User::pointer User::create(Session& session, std::string_view loginName) { - return session.getDboSession()->add(std::unique_ptr {new User{ loginName }}); + return session.getDboSession()->add(std::unique_ptr{ new User{ loginName } }); } std::size_t User::getCount(Session& session) @@ -87,8 +88,7 @@ namespace lms::db User::pointer User::find(Session& session, std::string_view name) { - return utils::fetchQuerySingleResult(session.getDboSession()->find() - .where("login_name = ?").bind(name)); + return utils::fetchQuerySingleResult(session.getDboSession()->find().where("login_name = ?").bind(name)); } void User::setSubsonicDefaultTranscodingOutputBitrate(Bitrate bitrate) diff --git a/src/libs/database/impl/Utils.cpp b/src/libs/database/impl/Utils.cpp index 6bafab61..c3648b43 100644 --- a/src/libs/database/impl/Utils.cpp +++ b/src/libs/database/impl/Utils.cpp @@ -33,5 +33,4 @@ namespace lms::db::utils // force second resolution return Wt::WDateTime::fromTime_t(dateTime.toTime_t()); } -} // namespace lms::db::Utils - +} // namespace lms::db::utils diff --git a/src/libs/database/impl/Utils.hpp b/src/libs/database/impl/Utils.hpp index 56db65d8..2c7386d2 100644 --- a/src/libs/database/impl/Utils.hpp +++ b/src/libs/database/impl/Utils.hpp @@ -26,8 +26,8 @@ #include #include -#include "database/Types.hpp" #include "core/ITraceLogger.hpp" +#include "database/Types.hpp" namespace lms::db::utils { @@ -35,7 +35,7 @@ namespace lms::db::utils static inline constexpr char escapeChar{ '\\' }; std::string escapeLikeKeyword(std::string_view keywords); - template + template void applyRange(Query& query, std::optional range) { if (range) @@ -45,21 +45,21 @@ namespace lms::db::utils } } - template + template auto fetchFirstResult(const Wt::Dbo::collection& collection) { LMS_SCOPED_TRACE_DETAILED("Database", "FetchFirstResult"); return collection.begin(); } - template + template void fetchNextResult(typename Wt::Dbo::collection::const_iterator& it) { LMS_SCOPED_TRACE_DETAILED("Database", "FetchNextResult"); it++; } - template + template void forEachResult(const Wt::Dbo::collection& collection, Func&& func) { typename Wt::Dbo::collection::const_iterator it{ fetchFirstResult(collection) }; @@ -70,23 +70,23 @@ namespace lms::db::utils } } - template + template struct QueryResultType; - template + template struct QueryResultType> { using type = ResultType; }; - template + template void forEachQueryResult(const Query& query, UnaryFunc&& func) { LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "ForEachQueryResult", "Query", query.asString()); forEachResult(query.resultList(), std::forward(func)); } - template + template std::vector fetchQueryResults(const Query& query) { LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "FetchQueryResults", "Query", query.asString()); @@ -95,7 +95,7 @@ namespace lms::db::utils return std::vector(collection.begin(), collection.end()); } - template + template std::vector::type> fetchQueryResults(const Query& query) { LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "FetchQueryResults", "Query", query.asString()); @@ -103,15 +103,15 @@ namespace lms::db::utils auto collection{ query.resultList() }; return std::vector::type>(collection.begin(), collection.end()); } - - template + + template auto fetchQuerySingleResult(const Query& query) { LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "FetchQuerySingleResult", "Query", query.asString()); return query.resultValue(); } - template + template RangeResults execRangeQuery(Query& query, const std::optional range) { RangeResults res; @@ -137,7 +137,7 @@ namespace lms::db::utils return res; } - template + template void forEachQueryRangeResult(Query& query, std::optional range, UnaryFunc&& func) { if (range) @@ -146,7 +146,7 @@ namespace lms::db::utils forEachQueryResult(query, std::forward(func)); } - template + template void forEachQueryRangeResult(Query& query, std::optional range, bool& moreResults, UnaryFunc&& func) { using ResultType = typename QueryResultType::type; @@ -173,4 +173,4 @@ namespace lms::db::utils } Wt::WDateTime normalizeDateTime(const Wt::WDateTime& dateTime); -} \ No newline at end of file +} // namespace lms::db::utils \ No newline at end of file diff --git a/src/libs/database/include/database/Artist.hpp b/src/libs/database/include/database/Artist.hpp index 12f81161..2081f9d9 100644 --- a/src/libs/database/include/database/Artist.hpp +++ b/src/libs/database/include/database/Artist.hpp @@ -25,8 +25,8 @@ #include #include -#include #include +#include #include "core/EnumSet.hpp" #include "core/UUID.hpp" @@ -35,9 +35,9 @@ #include "database/MediaLibraryId.hpp" #include "database/Object.hpp" #include "database/ReleaseId.hpp" +#include "database/TrackId.hpp" #include "database/Types.hpp" #include "database/UserId.hpp" -#include "database/TrackId.hpp" namespace lms::db { @@ -56,51 +56,92 @@ namespace lms::db public: struct FindParameters { - std::vector clusters; // if non empty, at least one artist that belongs to these clusters - std::vector keywords; // if non empty, name must match all of these keywords (on either name field OR sort name field) - std::optional linkType; // if set, only artists that have produced at least one track with this link type - ArtistSortMethod sortMethod{ ArtistSortMethod::None }; - std::optional range; - Wt::WDateTime writtenAfter; - UserId starringUser; // only artists starred by this user - std::optional feedbackBackend; // and for this feedback backend - TrackId track; // artists involved in this track - ReleaseId release; // artists involved in this release - MediaLibraryId mediaLibrary; // artists that belong to this library + std::vector clusters; // if non empty, at least one artist that belongs to these clusters + std::vector keywords; // if non empty, name must match all of these keywords (on either name field OR sort name field) + std::optional linkType; // if set, only artists that have produced at least one track with this link type + ArtistSortMethod sortMethod{ ArtistSortMethod::None }; + std::optional range; + Wt::WDateTime writtenAfter; + UserId starringUser; // only artists starred by this user + std::optional feedbackBackend; // and for this feedback backend + TrackId track; // artists involved in this track + ReleaseId release; // artists involved in this release + MediaLibraryId mediaLibrary; // artists that belong to this library - FindParameters& setClusters(std::span _clusters) { clusters.assign(std::cbegin(_clusters), std::cend(_clusters)); return *this; } - FindParameters& setKeywords(const std::vector& _keywords) { keywords = _keywords; return *this; } - FindParameters& setLinkType(std::optional _linkType) { linkType = _linkType; return *this; } - FindParameters& setSortMethod(ArtistSortMethod _sortMethod) { sortMethod = _sortMethod; return *this; } - FindParameters& setRange(std::optional _range) { range = _range; return *this; } - FindParameters& setWrittenAfter(const Wt::WDateTime& _after) { writtenAfter = _after; return *this; } - FindParameters& setStarringUser(UserId _user, FeedbackBackend _feedbackBackend) { starringUser = _user; feedbackBackend = _feedbackBackend; return *this; } - FindParameters& setTrack(TrackId _track) { track = _track; return *this; } - FindParameters& setRelease(ReleaseId _release) { release = _release; return *this; } - FindParameters& setMediaLibrary(MediaLibraryId _mediaLibrary) { mediaLibrary = _mediaLibrary; return *this; } + FindParameters& setClusters(std::span _clusters) + { + clusters.assign(std::cbegin(_clusters), std::cend(_clusters)); + return *this; + } + FindParameters& setKeywords(const std::vector& _keywords) + { + keywords = _keywords; + return *this; + } + FindParameters& setLinkType(std::optional _linkType) + { + linkType = _linkType; + return *this; + } + FindParameters& setSortMethod(ArtistSortMethod _sortMethod) + { + sortMethod = _sortMethod; + return *this; + } + FindParameters& setRange(std::optional _range) + { + range = _range; + return *this; + } + FindParameters& setWrittenAfter(const Wt::WDateTime& _after) + { + writtenAfter = _after; + return *this; + } + FindParameters& setStarringUser(UserId _user, FeedbackBackend _feedbackBackend) + { + starringUser = _user; + feedbackBackend = _feedbackBackend; + return *this; + } + FindParameters& setTrack(TrackId _track) + { + track = _track; + return *this; + } + FindParameters& setRelease(ReleaseId _release) + { + release = _release; + return *this; + } + FindParameters& setMediaLibrary(MediaLibraryId _mediaLibrary) + { + mediaLibrary = _mediaLibrary; + return *this; + } }; Artist() = default; // Accessors - static std::size_t getCount(Session& session); - static pointer find(Session& session, const core::UUID& MBID); - static pointer find(Session& session, ArtistId id); - static std::vector find(Session& session, std::string_view name); // exact match on name field - static void find(Session& session, ArtistId& lastRetrievedArtist, std::size_t count, const std::function& func, MediaLibraryId library = {}); - static RangeResults find(Session& session, const FindParameters& parameters); - static void find(Session& session, const FindParameters& parameters, std::function func); - static RangeResults findIds(Session& session, const FindParameters& parameters); - static RangeResults findOrphanIds(Session& session, std::optional range = std::nullopt); // No track related - static bool exists(Session& session, ArtistId id); + static std::size_t getCount(Session& session); + static pointer find(Session& session, const core::UUID& MBID); + static pointer find(Session& session, ArtistId id); + static std::vector find(Session& session, std::string_view name); // exact match on name field + static void find(Session& session, ArtistId& lastRetrievedArtist, std::size_t count, const std::function& func, MediaLibraryId library = {}); + static RangeResults find(Session& session, const FindParameters& parameters); + static void find(Session& session, const FindParameters& parameters, std::function func); + static RangeResults findIds(Session& session, const FindParameters& parameters); + static RangeResults findOrphanIds(Session& session, std::optional range = std::nullopt); // No track related + static bool exists(Session& session, ArtistId id); // Accessors const std::string& getName() const { return _name; } const std::string& getSortName() const { return _sortName; } - std::optional getMBID() const { return core::UUID::fromString(_MBID); } + std::optional getMBID() const { return core::UUID::fromString(_MBID); } // No artistLinkTypes means get them all - RangeResults findSimilarArtistIds(core::EnumSet artistLinkTypes = {}, std::optional range = std::nullopt) const; + RangeResults findSimilarArtistIds(core::EnumSet artistLinkTypes = {}, std::optional range = std::nullopt) const; // Get the cluster of the tracks made by this artist // Each clusters are grouped by cluster type, sorted by the number of occurence @@ -132,11 +173,10 @@ namespace lms::db std::string _name; std::string _sortName; - std::string _MBID; // Musicbrainz Identifier + std::string _MBID; // Musicbrainz Identifier - Wt::Dbo::collection> _trackArtistLinks; // Tracks involving this artist - Wt::Dbo::collection> _starredArtists; // starred entries for this artist + Wt::Dbo::collection> _trackArtistLinks; // Tracks involving this artist + Wt::Dbo::collection> _starredArtists; // starred entries for this artist }; } // namespace lms::db - diff --git a/src/libs/database/include/database/ArtistId.hpp b/src/libs/database/include/database/ArtistId.hpp index 4735f37b..b9320263 100644 --- a/src/libs/database/include/database/ArtistId.hpp +++ b/src/libs/database/include/database/ArtistId.hpp @@ -22,4 +22,3 @@ #include "database/IdType.hpp" LMS_DECLARE_IDTYPE(ArtistId) - diff --git a/src/libs/database/include/database/AuthToken.hpp b/src/libs/database/include/database/AuthToken.hpp index 0648e2b8..474f0386 100644 --- a/src/libs/database/include/database/AuthToken.hpp +++ b/src/libs/database/include/database/AuthToken.hpp @@ -29,39 +29,38 @@ namespace lms::db { - class Session; + class Session; - class User; - class AuthToken final : public Object - { - public: - AuthToken() = default; + class User; + class AuthToken final : public Object + { + public: + AuthToken() = default; - // Utility - static void removeExpiredTokens(Session& session, const Wt::WDateTime& now); - static pointer find(Session& session, std::string_view value); + // Utility + static void removeExpiredTokens(Session& session, const Wt::WDateTime& now); + static pointer find(Session& session, std::string_view value); - // Accessors - const Wt::WDateTime& getExpiry() const { return _expiry; } - ObjectPtr getUser() const { return _user; } - const std::string& getValue() const { return _value; } + // Accessors + const Wt::WDateTime& getExpiry() const { return _expiry; } + ObjectPtr getUser() const { return _user; } + const std::string& getValue() const { return _value; } - template - void persist(Action& a) - { - Wt::Dbo::field(a, _value, "value"); - Wt::Dbo::field(a, _expiry, "expiry"); - Wt::Dbo::belongsTo(a, _user, "user", Wt::Dbo::OnDeleteCascade); - } + template + void persist(Action& a) + { + Wt::Dbo::field(a, _value, "value"); + Wt::Dbo::field(a, _expiry, "expiry"); + Wt::Dbo::belongsTo(a, _user, "user", Wt::Dbo::OnDeleteCascade); + } - private: - friend class Session; - AuthToken(std::string_view value, const Wt::WDateTime& expiry, ObjectPtr user); - static pointer create(Session& session, std::string_view value, const Wt::WDateTime&expiry, ObjectPtr user); - - std::string _value; - Wt::WDateTime _expiry; - Wt::Dbo::ptr _user; - }; -} // namespace Databas' + private: + friend class Session; + AuthToken(std::string_view value, const Wt::WDateTime& expiry, ObjectPtr user); + static pointer create(Session& session, std::string_view value, const Wt::WDateTime& expiry, ObjectPtr user); + std::string _value; + Wt::WDateTime _expiry; + Wt::Dbo::ptr _user; + }; +} // namespace lms::db diff --git a/src/libs/database/include/database/Cluster.hpp b/src/libs/database/include/database/Cluster.hpp index fbdc1a72..8b6ce020 100644 --- a/src/libs/database/include/database/Cluster.hpp +++ b/src/libs/database/include/database/Cluster.hpp @@ -45,41 +45,65 @@ namespace lms::db public: struct FindParameters { - std::optional range; - ClusterSortMethod sortMethod; - ClusterTypeId clusterType; // if non empty, clusters that belong to this cluster type - std::string clusterTypeName; // if non empty, clusters that belong to this cluster type - TrackId track; // if set, clusters involved in this track - ReleaseId release; // if set, clusters involved in this release + std::optional range; + ClusterSortMethod sortMethod; + ClusterTypeId clusterType; // if non empty, clusters that belong to this cluster type + std::string clusterTypeName; // if non empty, clusters that belong to this cluster type + TrackId track; // if set, clusters involved in this track + ReleaseId release; // if set, clusters involved in this release - FindParameters& setRange(std::optional _range) { range = _range; return *this; } - FindParameters& setSortMethod(ClusterSortMethod _method) { sortMethod = _method; return *this; } - FindParameters& setClusterType(ClusterTypeId _clusterType) { clusterType = _clusterType; return *this; } - FindParameters& setClusterTypeName(std::string_view _name) { clusterTypeName = _name; return *this; } - FindParameters& setTrack(TrackId _track) { track = _track; return *this; } - FindParameters& setRelease(ReleaseId _release) { release = _release; return *this; } + FindParameters& setRange(std::optional _range) + { + range = _range; + return *this; + } + FindParameters& setSortMethod(ClusterSortMethod _method) + { + sortMethod = _method; + return *this; + } + FindParameters& setClusterType(ClusterTypeId _clusterType) + { + clusterType = _clusterType; + return *this; + } + FindParameters& setClusterTypeName(std::string_view _name) + { + clusterTypeName = _name; + return *this; + } + FindParameters& setTrack(TrackId _track) + { + track = _track; + return *this; + } + FindParameters& setRelease(ReleaseId _release) + { + release = _release; + return *this; + } }; Cluster() = default; // Find utility - static std::size_t getCount(Session& session); - static RangeResults findIds(Session& session, const FindParameters& params); - static RangeResults find(Session& session, const FindParameters& params); - static void find(Session& session, const FindParameters& params, std::function _func); - static pointer find(Session& session, ClusterId id); - static RangeResults findOrphanIds(Session& session, std::optional range = std::nullopt); + static std::size_t getCount(Session& session); + static RangeResults findIds(Session& session, const FindParameters& params); + static RangeResults find(Session& session, const FindParameters& params); + static void find(Session& session, const FindParameters& params, std::function _func); + static pointer find(Session& session, ClusterId id); + static RangeResults findOrphanIds(Session& session, std::optional range = std::nullopt); // May be very slow - static std::size_t computeTrackCount(Session& session, ClusterId id); - static std::size_t computeReleaseCount(Session& session, ClusterId id); + static std::size_t computeTrackCount(Session& session, ClusterId id); + static std::size_t computeReleaseCount(Session& session, ClusterId id); // Accessors - std::string_view getName() const { return _name; } - ObjectPtr getType() const { return _clusterType; } - std::size_t getTrackCount() const { return _trackCount; } - RangeResults getTracks(std::optional range = std::nullopt) const; - std::size_t getReleasesCount() const { return _releaseCount; }; + std::string_view getName() const { return _name; } + ObjectPtr getType() const { return _clusterType; } + std::size_t getTrackCount() const { return _trackCount; } + RangeResults getTracks(std::optional range = std::nullopt) const; + std::size_t getReleasesCount() const { return _releaseCount; }; void setReleaseCount(std::size_t releaseCount) { _releaseCount = releaseCount; } void setTrackCount(std::size_t trackCount) { _trackCount = trackCount; } @@ -104,35 +128,34 @@ namespace lms::db static const std::size_t _maxNameLength = 128; - std::string _name; + std::string _name; int _trackCount{}; int _releaseCount{}; Wt::Dbo::ptr _clusterType; - Wt::Dbo::collection< Wt::Dbo::ptr > _tracks; + Wt::Dbo::collection> _tracks; }; - class ClusterType final : public Object { public: ClusterType() = default; // Getters - static std::size_t getCount(Session& session); - static RangeResults findIds(Session& session, std::optional range = std::nullopt); - static void find(Session& session, const std::function& func); - static pointer find(Session& session, std::string_view name); - static pointer find(Session& session, ClusterTypeId id); - static RangeResults findOrphanIds(Session& session, std::optional range = std::nullopt); - static RangeResults findUsed(Session& session, std::optional range = std::nullopt); + static std::size_t getCount(Session& session); + static RangeResults findIds(Session& session, std::optional range = std::nullopt); + static void find(Session& session, const std::function& func); + static pointer find(Session& session, std::string_view name); + static pointer find(Session& session, ClusterTypeId id); + static RangeResults findOrphanIds(Session& session, std::optional range = std::nullopt); + static RangeResults findUsed(Session& session, std::optional range = std::nullopt); static void remove(Session& session, const std::string& name); // Accessors std::string_view getName() const { return _name; } - std::vector getClusters() const; - Cluster::pointer getCluster(const std::string& name) const; + std::vector getClusters() const; + Cluster::pointer getCluster(const std::string& name) const; template void persist(Action& a) @@ -148,9 +171,8 @@ namespace lms::db static const std::size_t _maxNameLength = 128; - std::string _name; - Wt::Dbo::collection< Wt::Dbo::ptr > _clusters; + std::string _name; + Wt::Dbo::collection> _clusters; }; } // namespace lms::db - diff --git a/src/libs/database/include/database/ClusterId.hpp b/src/libs/database/include/database/ClusterId.hpp index c6ebbfd1..4ee31741 100644 --- a/src/libs/database/include/database/ClusterId.hpp +++ b/src/libs/database/include/database/ClusterId.hpp @@ -23,4 +23,3 @@ LMS_DECLARE_IDTYPE(ClusterId) LMS_DECLARE_IDTYPE(ClusterTypeId) - diff --git a/src/libs/database/include/database/Db.hpp b/src/libs/database/include/database/Db.hpp index fe444ebc..a90f319a 100644 --- a/src/libs/database/include/database/Db.hpp +++ b/src/libs/database/include/database/Db.hpp @@ -63,10 +63,10 @@ namespace lms::db }; core::RecursiveSharedMutex _sharedMutex; - std::unique_ptr _connectionPool; + std::unique_ptr _connectionPool; std::mutex _tlsSessionsMutex; std::vector> _tlsSessions; }; -} +} // namespace lms::db diff --git a/src/libs/database/include/database/IdType.hpp b/src/libs/database/include/database/IdType.hpp index 972c9c46..bbfb202a 100644 --- a/src/libs/database/include/database/IdType.hpp +++ b/src/libs/database/include/database/IdType.hpp @@ -19,10 +19,9 @@ #pragma once - +#include #include #include -#include namespace lms::db { @@ -32,38 +31,43 @@ namespace lms::db using ValueType = Wt::Dbo::dbo_default_traits::IdType; IdType() = default; - IdType(ValueType id) : _id{ id } { assert(isValid()); } + IdType(ValueType id) + : _id{ id } { assert(isValid()); } bool isValid() const { return _id != Wt::Dbo::dbo_default_traits::invalidId(); } - std::string toString() const { assert(isValid()); return std::to_string(_id); } + std::string toString() const + { + assert(isValid()); + return std::to_string(_id); + } ValueType getValue() const { return _id; } - auto operator<=>(const IdType& other) const = default; \ + auto operator<=>(const IdType& other) const = default; private: Wt::Dbo::dbo_default_traits::IdType _id{ Wt::Dbo::dbo_default_traits::invalidId() }; }; -#define LMS_DECLARE_IDTYPE(name) \ - namespace lms::db { \ - class name : public IdType \ - { \ - public: \ - using IdType::IdType; \ - auto operator<=>(const name& other) const = default; \ - };\ - } \ - namespace std \ - { \ - template<> \ - class hash \ - { \ - public: \ - size_t operator()(lms::db::name id) const \ - { \ +#define LMS_DECLARE_IDTYPE(name) \ + namespace lms::db \ + { \ + class name : public IdType \ + { \ + public: \ + using IdType::IdType; \ + auto operator<=>(const name& other) const = default; \ + }; \ + } \ + namespace std \ + { \ + template<> \ + class hash \ + { \ + public: \ + size_t operator()(lms::db::name id) const \ + { \ return std::hash()(id.getValue()); \ - } \ - }; \ + } \ + }; \ } // ns std } // namespace lms::db - diff --git a/src/libs/database/include/database/Listen.hpp b/src/libs/database/include/database/Listen.hpp index e4d41d69..8e55a025 100644 --- a/src/libs/database/include/database/Listen.hpp +++ b/src/libs/database/include/database/Listen.hpp @@ -47,76 +47,124 @@ namespace lms::db struct FindParameters { - UserId user; - std::optional backend; - std::optional syncState; - std::optional range; + UserId user; + std::optional backend; + std::optional syncState; + std::optional range; - FindParameters& setUser(UserId _user) { user = _user; return *this; } - FindParameters& setScrobblingBackend(ScrobblingBackend _backend) { backend = _backend; return *this; } - FindParameters& setSyncState(SyncState _syncState) { syncState = _syncState; return *this; } - FindParameters& setRange(Range _range) { range = _range; return *this; } + FindParameters& setUser(UserId _user) + { + user = _user; + return *this; + } + FindParameters& setScrobblingBackend(ScrobblingBackend _backend) + { + backend = _backend; + return *this; + } + FindParameters& setSyncState(SyncState _syncState) + { + syncState = _syncState; + return *this; + } + FindParameters& setRange(Range _range) + { + range = _range; + return *this; + } }; // Accessors - static std::size_t getCount(Session& session); - static pointer find(Session& session, ListenId id); - static pointer find(Session& session, UserId userId, TrackId trackId, ScrobblingBackend backend, const Wt::WDateTime& dateTime); - static RangeResults find(Session& session, const FindParameters& parameters); + static std::size_t getCount(Session& session); + static pointer find(Session& session, ListenId id); + static pointer find(Session& session, UserId userId, TrackId trackId, ScrobblingBackend backend, const Wt::WDateTime& dateTime); + static RangeResults find(Session& session, const FindParameters& parameters); // Stats struct StatsFindParameters { - UserId user; - std::optional backend; - std::vector clusters; // if non empty, entities that belong to these clusters - std::vector keywords; // if non empty, name must match all of these keywords - std::optional range; - ArtistId artist; // if set, matching this artist - MediaLibraryId library; + UserId user; + std::optional backend; + std::vector clusters; // if non empty, entities that belong to these clusters + std::vector keywords; // if non empty, name must match all of these keywords + std::optional range; + ArtistId artist; // if set, matching this artist + MediaLibraryId library; - StatsFindParameters& setUser(UserId _user) { user = _user; return *this; } - StatsFindParameters& setScrobblingBackend(std::optional _backend) { backend = _backend; return *this; } - StatsFindParameters& setClusters(const std::vector& _clusters) { clusters = _clusters; return *this; } - StatsFindParameters& setKeywords(const std::vector& _keywords) { keywords = _keywords; return *this; } - StatsFindParameters& setRange(std::optional _range) { range = _range; return *this; } - StatsFindParameters& setArtist(ArtistId _artist) { artist = _artist; return *this; } - StatsFindParameters& setMediaLibrary(MediaLibraryId _library) { library = _library; return *this; } + StatsFindParameters& setUser(UserId _user) + { + user = _user; + return *this; + } + StatsFindParameters& setScrobblingBackend(std::optional _backend) + { + backend = _backend; + return *this; + } + StatsFindParameters& setClusters(const std::vector& _clusters) + { + clusters = _clusters; + return *this; + } + StatsFindParameters& setKeywords(const std::vector& _keywords) + { + keywords = _keywords; + return *this; + } + StatsFindParameters& setRange(std::optional _range) + { + range = _range; + return *this; + } + StatsFindParameters& setArtist(ArtistId _artist) + { + artist = _artist; + return *this; + } + StatsFindParameters& setMediaLibrary(MediaLibraryId _library) + { + library = _library; + return *this; + } }; struct ArtistStatsFindParameters : public StatsFindParameters { - std::optional linkType; // if set, only artists that have produced at least one track with this link type + std::optional linkType; // if set, only artists that have produced at least one track with this link type - ArtistStatsFindParameters& setLinkType(std::optional _linkType) { linkType = _linkType; return *this; } + ArtistStatsFindParameters& setLinkType(std::optional _linkType) + { + linkType = _linkType; + return *this; + } }; - static RangeResults getTopArtists(Session& session, const ArtistStatsFindParameters& params); - static RangeResults getTopReleases(Session& session, const StatsFindParameters& params); - static RangeResults getTopTracks(Session& session, const StatsFindParameters& params); + static RangeResults getTopArtists(Session& session, const ArtistStatsFindParameters& params); + static RangeResults getTopReleases(Session& session, const StatsFindParameters& params); + static RangeResults getTopTracks(Session& session, const StatsFindParameters& params); - static RangeResults getRecentArtists(Session& session, const ArtistStatsFindParameters& params); - static RangeResults getRecentReleases(Session& session, const StatsFindParameters& params); - static RangeResults getRecentTracks(Session& session, const StatsFindParameters& params); + static RangeResults getRecentArtists(Session& session, const ArtistStatsFindParameters& params); + static RangeResults getRecentReleases(Session& session, const StatsFindParameters& params); + static RangeResults getRecentTracks(Session& session, const StatsFindParameters& params); - static std::size_t getCount(Session& session, UserId userId, TrackId trackId); // for the current backend - static std::size_t getCount(Session& session, UserId userId, ReleaseId trackId); // for the current backend + static std::size_t getCount(Session& session, UserId userId, TrackId trackId); // for the current backend + static std::size_t getCount(Session& session, UserId userId, ReleaseId trackId); // for the current backend - static pointer getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, ReleaseId releaseId); - static pointer getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, TrackId releaseId); + static pointer getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, ReleaseId releaseId); + static pointer getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, TrackId releaseId); - SyncState getSyncState() const { return _syncState; } - ObjectPtr getUser() const { return _user; } - ObjectPtr getTrack() const { return _track; } + SyncState getSyncState() const { return _syncState; } + ObjectPtr getUser() const { return _user; } + ObjectPtr getTrack() const { return _track; } const Wt::WDateTime& getDateTime() const { return _dateTime; } - void setSyncState(SyncState state) { _syncState = state; } + void setSyncState(SyncState state) { _syncState = state; } template void persist(Action& a) { Wt::Dbo::field(a, _dateTime, "date_time"); - Wt::Dbo::field(a, _backend, "backend"); // TODO rename + Wt::Dbo::field(a, _backend, "backend"); // TODO rename Wt::Dbo::field(a, _syncState, "sync_state"); // TODO rename Wt::Dbo::belongsTo(a, _track, "track", Wt::Dbo::OnDeleteCascade); @@ -128,13 +176,12 @@ namespace lms::db Listen(ObjectPtr user, ObjectPtr track, ScrobblingBackend backend, const Wt::WDateTime& dateTime); static pointer create(Session& session, ObjectPtr user, ObjectPtr track, ScrobblingBackend backend, const Wt::WDateTime& dateTime); - Wt::WDateTime _dateTime; - ScrobblingBackend _backend; - SyncState _syncState{ SyncState::PendingAdd }; + Wt::WDateTime _dateTime; + ScrobblingBackend _backend; + SyncState _syncState{ SyncState::PendingAdd }; - Wt::Dbo::ptr _user; - Wt::Dbo::ptr _track; + Wt::Dbo::ptr _user; + Wt::Dbo::ptr _track; }; } // namespace lms::db - diff --git a/src/libs/database/include/database/ListenId.hpp b/src/libs/database/include/database/ListenId.hpp index 690d2114..271a3357 100644 --- a/src/libs/database/include/database/ListenId.hpp +++ b/src/libs/database/include/database/ListenId.hpp @@ -22,4 +22,3 @@ #include "database/IdType.hpp" LMS_DECLARE_IDTYPE(ListenId) - diff --git a/src/libs/database/include/database/MediaLibrary.hpp b/src/libs/database/include/database/MediaLibrary.hpp index 1e452463..6d3c391c 100644 --- a/src/libs/database/include/database/MediaLibrary.hpp +++ b/src/libs/database/include/database/MediaLibrary.hpp @@ -44,7 +44,7 @@ namespace lms::db static pointer find(Session& session, MediaLibraryId id); static pointer find(Session& session, std::string_view name); static pointer find(Session& session, const std::filesystem::path& path); - static void find(Session& session, std::function func); + static void find(Session& session, std::function func); static std::vector find(Session& session); // getters @@ -67,7 +67,7 @@ namespace lms::db MediaLibrary(const std::filesystem::path& p, std::string_view name); static pointer create(Session& session, const std::filesystem::path& p = {}, std::string_view name = {}); - std::filesystem::path _path; - std::string _name; + std::filesystem::path _path; + std::string _name; }; } // namespace lms::db diff --git a/src/libs/database/include/database/Object.hpp b/src/libs/database/include/database/Object.hpp index 5fa33f69..187b0c3f 100644 --- a/src/libs/database/include/database/Object.hpp +++ b/src/libs/database/include/database/Object.hpp @@ -19,20 +19,23 @@ #pragma once -#include #include +#include + #include "database/IdType.hpp" #include "database/TransactionChecker.hpp" namespace lms::db { - template + template class ObjectPtr { public: ObjectPtr() = default; - ObjectPtr(const Wt::Dbo::ptr& obj) : _obj{ obj } {} - ObjectPtr(Wt::Dbo::ptr&& obj) : _obj{ std::move(obj) } {} + ObjectPtr(const Wt::Dbo::ptr& obj) + : _obj{ obj } {} + ObjectPtr(Wt::Dbo::ptr&& obj) + : _obj{ std::move(obj) } {} const T* operator->() const { return _obj.get(); } operator bool() const { return _obj.get(); } @@ -60,11 +63,12 @@ namespace lms::db } private: - template friend class Object; + template + friend class Object; Wt::Dbo::ptr _obj; }; - template + template class Object : public Wt::Dbo::Dbo { static_assert(std::is_base_of_v); @@ -80,7 +84,8 @@ namespace lms::db typename Wt::Dbo::dbo_traits::IdType id() const = delete; protected: - template friend class ObjectPtr; + template + friend class ObjectPtr; virtual bool hasOnPreRemove() const { return false; } virtual void onPreRemove() {} @@ -89,8 +94,10 @@ namespace lms::db virtual void onPostCreated() {} // Can get raw dbo ptr only from Objects - template - static - Wt::Dbo::ptr getDboPtr(ObjectPtr ptr) { return ptr._obj; } + template + static Wt::Dbo::ptr getDboPtr(ObjectPtr ptr) + { + return ptr._obj; + } }; -} +} // namespace lms::db diff --git a/src/libs/database/include/database/Release.hpp b/src/libs/database/include/database/Release.hpp index d2d3349c..7af4e2bc 100644 --- a/src/libs/database/include/database/Release.hpp +++ b/src/libs/database/include/database/Release.hpp @@ -26,8 +26,8 @@ #include #include -#include #include +#include #include "core/EnumSet.hpp" #include "core/UUID.hpp" @@ -54,8 +54,8 @@ namespace lms::db { public: ReleaseType() = default; - static pointer find(Session& session, ReleaseTypeId id); - static pointer find(Session& session, std::string_view name); + static pointer find(Session& session, ReleaseTypeId id); + static pointer find(Session& session, std::string_view name); // Accessors std::string_view getName() const { return _name; } @@ -75,7 +75,7 @@ namespace lms::db static pointer create(Session& session, std::string_view name); std::string _name; - Wt::Dbo::collection> _releases; // releases that match this type + Wt::Dbo::collection> _releases; // releases that match this type }; class Release final : public Object @@ -83,27 +83,56 @@ namespace lms::db public: struct FindParameters { - std::vector clusters; // if non empty, releases that belong to these clusters - std::vector keywords; // if non empty, name must match all of these keywords - ReleaseSortMethod sortMethod{ ReleaseSortMethod::None }; - std::optional range; - Wt::WDateTime writtenAfter; - std::optional dateRange; - UserId starringUser; // only releases starred by this user - std::optional feedbackBackend; // and for this backend - ArtistId artist; // only releases that involved this user - core::EnumSet trackArtistLinkTypes; // and for these link types - core::EnumSet excludedTrackArtistLinkTypes; // but not for these link types - std::string releaseType; // If set, albums that has this release type - MediaLibraryId mediaLibrary; // If set, releases that has at least a track in this library + std::vector clusters; // if non empty, releases that belong to these clusters + std::vector keywords; // if non empty, name must match all of these keywords + ReleaseSortMethod sortMethod{ ReleaseSortMethod::None }; + std::optional range; + Wt::WDateTime writtenAfter; + std::optional dateRange; + UserId starringUser; // only releases starred by this user + std::optional feedbackBackend; // and for this backend + ArtistId artist; // only releases that involved this user + core::EnumSet trackArtistLinkTypes; // and for these link types + core::EnumSet excludedTrackArtistLinkTypes; // but not for these link types + std::string releaseType; // If set, albums that has this release type + MediaLibraryId mediaLibrary; // If set, releases that has at least a track in this library - FindParameters& setClusters(std::span _clusters) { clusters.assign(std::cbegin(_clusters), std::cend(_clusters)); return *this; } - FindParameters& setKeywords(const std::vector& _keywords) { keywords = _keywords; return *this; } - FindParameters& setSortMethod(ReleaseSortMethod _sortMethod) { sortMethod = _sortMethod; return *this; } - FindParameters& setRange(std::optional _range) { range = _range; return *this; } - FindParameters& setWrittenAfter(const Wt::WDateTime& _after) { writtenAfter = _after; return *this; } - FindParameters& setDateRange(const std::optional& _dateRange) { dateRange = _dateRange; return *this; } - FindParameters& setStarringUser(UserId _user, FeedbackBackend _feedbackBackend) { starringUser = _user; feedbackBackend = _feedbackBackend; return *this; } + FindParameters& setClusters(std::span _clusters) + { + clusters.assign(std::cbegin(_clusters), std::cend(_clusters)); + return *this; + } + FindParameters& setKeywords(const std::vector& _keywords) + { + keywords = _keywords; + return *this; + } + FindParameters& setSortMethod(ReleaseSortMethod _sortMethod) + { + sortMethod = _sortMethod; + return *this; + } + FindParameters& setRange(std::optional _range) + { + range = _range; + return *this; + } + FindParameters& setWrittenAfter(const Wt::WDateTime& _after) + { + writtenAfter = _after; + return *this; + } + FindParameters& setDateRange(const std::optional& _dateRange) + { + dateRange = _dateRange; + return *this; + } + FindParameters& setStarringUser(UserId _user, FeedbackBackend _feedbackBackend) + { + starringUser = _user; + feedbackBackend = _feedbackBackend; + return *this; + } FindParameters& setArtist(ArtistId _artist, core::EnumSet _trackArtistLinkTypes = {}, core::EnumSet _excludedTrackArtistLinkTypes = {}) { artist = _artist; @@ -111,24 +140,32 @@ namespace lms::db excludedTrackArtistLinkTypes = _excludedTrackArtistLinkTypes; return *this; } - FindParameters& setReleaseType(std::string_view _releaseType) { releaseType = _releaseType; return *this; } - FindParameters& setMediaLibrary(MediaLibraryId _mediaLibrary) { mediaLibrary = _mediaLibrary; return *this; } + FindParameters& setReleaseType(std::string_view _releaseType) + { + releaseType = _releaseType; + return *this; + } + FindParameters& setMediaLibrary(MediaLibraryId _mediaLibrary) + { + mediaLibrary = _mediaLibrary; + return *this; + } }; Release() = default; // Accessors - static std::size_t getCount(Session& session); - static bool exists(Session& session, ReleaseId id); - static pointer find(Session& session, const core::UUID& MBID); - static std::vector find(Session& session, const std::string& name, const std::filesystem::path& releaseDirectory); - static pointer find(Session& session, ReleaseId id); - static void find(Session& session, ReleaseId& lastRetrievedRelease, std::size_t count, const std::function& func, MediaLibraryId library = {}); - static RangeResults find(Session& session, const FindParameters& parameters); - static void find(Session& session, const FindParameters& parameters, const std::function& func); - static RangeResults findIds(Session& session, const FindParameters& parameters); - static std::size_t getCount(Session& session, const FindParameters& parameters); - static RangeResults findOrphanIds(Session& session, std::optional range = std::nullopt); // not track related + static std::size_t getCount(Session& session); + static bool exists(Session& session, ReleaseId id); + static pointer find(Session& session, const core::UUID& MBID); + static std::vector find(Session& session, const std::string& name, const std::filesystem::path& releaseDirectory); + static pointer find(Session& session, ReleaseId id); + static void find(Session& session, ReleaseId& lastRetrievedRelease, std::size_t count, const std::function& func, MediaLibraryId library = {}); + static RangeResults find(Session& session, const FindParameters& parameters); + static void find(Session& session, const FindParameters& parameters, const std::function& func); + static RangeResults findIds(Session& session, const FindParameters& parameters); + static std::size_t getCount(Session& session, const FindParameters& parameters); + static RangeResults findOrphanIds(Session& session, std::optional range = std::nullopt); // not track related // Get the cluster of the tracks that belong to this release // Each clusters are grouped by cluster type, sorted by the number of occurence (max to min) @@ -136,28 +173,28 @@ namespace lms::db std::vector>> getClusterGroups(const std::vector& clusterTypeIds, std::size_t size) const; // Utility functions (if all tracks have the same values, which is legit to not be the case) - Wt::WDate getDate() const; - std::optional getYear() const; - Wt::WDate getOriginalDate() const; - std::optional getOriginalYear() const; - std::optional getCopyright() const; - std::optional getCopyrightURL() const; - std::size_t getMeanBitrate() const; + Wt::WDate getDate() const; + std::optional getYear() const; + Wt::WDate getOriginalDate() const; + std::optional getOriginalYear() const; + std::optional getCopyright() const; + std::optional getCopyrightURL() const; + std::size_t getMeanBitrate() const; // Accessors - std::string_view getName() const { return _name; } - std::string_view getSortName() const { return _sortName; } - std::optional getMBID() const { return core::UUID::fromString(_MBID); } - std::optional getGroupMBID() const { return core::UUID::fromString(_groupMBID); } - std::optional getTotalDisc() const { return _totalDisc; } - std::size_t getDiscCount() const; // may not be total disc (if incomplete for example) - std::vector getDiscs() const; - std::chrono::milliseconds getDuration() const; - Wt::WDateTime getLastWritten() const; - std::string_view getArtistDisplayName() const { return _artistDisplayName; } - std::size_t getTrackCount() const; + std::string_view getName() const { return _name; } + std::string_view getSortName() const { return _sortName; } + std::optional getMBID() const { return core::UUID::fromString(_MBID); } + std::optional getGroupMBID() const { return core::UUID::fromString(_groupMBID); } + std::optional getTotalDisc() const { return _totalDisc; } + std::size_t getDiscCount() const; // may not be total disc (if incomplete for example) + std::vector getDiscs() const; + std::chrono::milliseconds getDuration() const; + Wt::WDateTime getLastWritten() const; + std::string_view getArtistDisplayName() const { return _artistDisplayName; } + std::size_t getTrackCount() const; std::vector> getReleaseTypes() const; - std::vector getReleaseTypeNames() const; + std::vector getReleaseTypeNames() const; // Setters void setName(std::string_view name) { _name = name; } @@ -170,10 +207,10 @@ namespace lms::db void addReleaseType(ObjectPtr releaseType); // Get the artists of this release - std::vector> getArtists(TrackArtistLinkType type = TrackArtistLinkType::Artist) const; - std::vector> getReleaseArtists() const { return getArtists(TrackArtistLinkType::ReleaseArtist); } - bool hasVariousArtists() const; - std::vector getSimilarReleases(std::optional offset = {}, std::optional count = {}) const; + std::vector> getArtists(TrackArtistLinkType type = TrackArtistLinkType::Artist) const; + std::vector> getReleaseArtists() const { return getArtists(TrackArtistLinkType::ReleaseArtist); } + bool hasVariousArtists() const; + std::vector getSimilarReleases(std::optional offset = {}, std::optional count = {}) const; template void persist(Action& a) @@ -198,15 +235,15 @@ namespace lms::db static constexpr std::size_t _maxNameLength{ 256 }; - std::string _name; - std::string _sortName; - std::string _MBID; - std::string _groupMBID; - std::optional _totalDisc{}; - std::string _artistDisplayName; + std::string _name; + std::string _sortName; + std::string _MBID; + std::string _groupMBID; + std::optional _totalDisc{}; + std::string _artistDisplayName; - Wt::Dbo::collection> _tracks; // Tracks in the release - Wt::Dbo::collection> _releaseTypes; // Release types + Wt::Dbo::collection> _tracks; // Tracks in the release + Wt::Dbo::collection> _releaseTypes; // Release types }; } // namespace lms::db diff --git a/src/libs/database/include/database/ScanSettings.hpp b/src/libs/database/include/database/ScanSettings.hpp index 3275f2ad..91ffd438 100644 --- a/src/libs/database/include/database/ScanSettings.hpp +++ b/src/libs/database/include/database/ScanSettings.hpp @@ -63,14 +63,14 @@ namespace lms::db static pointer get(Session& session); // Getters - std::size_t getScanVersion() const { return _scanVersion; } - Wt::WTime getUpdateStartTime() const { return _startTime; } - UpdatePeriod getUpdatePeriod() const { return _updatePeriod; } - std::vector getExtraTagsToScan() const; - std::vector getAudioFileExtensions() const; - SimilarityEngineType getSimilarityEngineType() const { return _similarityEngineType; } - std::vector getArtistTagDelimiters() const; - std::vector getDefaultTagDelimiters() const; + std::size_t getScanVersion() const { return _scanVersion; } + Wt::WTime getUpdateStartTime() const { return _startTime; } + UpdatePeriod getUpdatePeriod() const { return _updatePeriod; } + std::vector getExtraTagsToScan() const; + std::vector getAudioFileExtensions() const; + SimilarityEngineType getSimilarityEngineType() const { return _similarityEngineType; } + std::vector getArtistTagDelimiters() const; + std::vector getDefaultTagDelimiters() const; // Setters void setUpdateStartTime(Wt::WTime t) { _startTime = t; } @@ -95,13 +95,13 @@ namespace lms::db } private: - int _scanVersion{}; - Wt::WTime _startTime = Wt::WTime{ 0,0,0 }; - UpdatePeriod _updatePeriod{ UpdatePeriod::Never }; - SimilarityEngineType _similarityEngineType{ SimilarityEngineType::Clusters }; - std::string _audioFileExtensions{ ".alac .mp3 .ogg .oga .aac .m4a .m4b .flac .wav .wma .aif .aiff .ape .mpc .shn .opus .wv .dsf" }; - std::string _extraTagsToScan; - std::string _artistTagDelimiters; - std::string _defaultTagDelimiters; + int _scanVersion{}; + Wt::WTime _startTime = Wt::WTime{ 0, 0, 0 }; + UpdatePeriod _updatePeriod{ UpdatePeriod::Never }; + SimilarityEngineType _similarityEngineType{ SimilarityEngineType::Clusters }; + std::string _audioFileExtensions{ ".alac .mp3 .ogg .oga .aac .m4a .m4b .flac .wav .wma .aif .aiff .ape .mpc .shn .opus .wv .dsf" }; + std::string _extraTagsToScan; + std::string _artistTagDelimiters; + std::string _defaultTagDelimiters; }; } // namespace lms::db diff --git a/src/libs/database/include/database/Session.hpp b/src/libs/database/include/database/Session.hpp index cecc7225..80aafd3f 100644 --- a/src/libs/database/include/database/Session.hpp +++ b/src/libs/database/include/database/Session.hpp @@ -24,6 +24,7 @@ #include #include + #include "core/ITraceLogger.hpp" #include "core/RecursiveSharedMutex.hpp" #include "database/Object.hpp" @@ -101,10 +102,16 @@ namespace lms::db void refreshTracingLoggerStats(); // returning a ptr here to ease further wrapping using operator-> - Wt::Dbo::Session* getDboSession() { return &_session; } - Db& getDb() { return _db; } + Wt::Dbo::Session* getDboSession() + { + return &_session; + } + Db& getDb() + { + return _db; + } - template + template typename Object::pointer create(Args&&... args) { checkWriteTransaction(); @@ -123,6 +130,6 @@ namespace lms::db Session& operator=(const Session&) = delete; Db& _db; - Wt::Dbo::Session _session; + Wt::Dbo::Session _session; }; } // namespace lms::db diff --git a/src/libs/database/include/database/StarredArtist.hpp b/src/libs/database/include/database/StarredArtist.hpp index acf6196a..0e05137e 100644 --- a/src/libs/database/include/database/StarredArtist.hpp +++ b/src/libs/database/include/database/StarredArtist.hpp @@ -19,8 +19,8 @@ #pragma once -#include #include +#include #include "database/ArtistId.hpp" #include "database/Object.hpp" @@ -40,17 +40,17 @@ namespace lms::db StarredArtist() = default; // Search utility - static std::size_t getCount(Session& session); - static pointer find(Session& session, StarredArtistId id); - static pointer find(Session& session, ArtistId artistId, UserId userId); // current backend - static pointer find(Session& session, ArtistId artistId, UserId userId, FeedbackBackend backend); + static std::size_t getCount(Session& session); + static pointer find(Session& session, StarredArtistId id); + static pointer find(Session& session, ArtistId artistId, UserId userId); // current backend + static pointer find(Session& session, ArtistId artistId, UserId userId, FeedbackBackend backend); // Accessors - ObjectPtr getArtist() const { return _artist; } - ObjectPtr getUser() const { return _user; } - FeedbackBackend getFeedbackBackend() const { return _backend; } + ObjectPtr getArtist() const { return _artist; } + ObjectPtr getUser() const { return _user; } + FeedbackBackend getFeedbackBackend() const { return _backend; } const Wt::WDateTime& getDateTime() const { return _dateTime; } - SyncState getSyncState() const { return _syncState; } + SyncState getSyncState() const { return _syncState; } // Setters void setDateTime(const Wt::WDateTime& dateTime); @@ -72,12 +72,11 @@ namespace lms::db StarredArtist(ObjectPtr artist, ObjectPtr user, FeedbackBackend scrobblingbackend); static pointer create(Session& session, ObjectPtr artist, ObjectPtr user, FeedbackBackend scrobblingbackend); - FeedbackBackend _backend; // for which backend - SyncState _syncState{ SyncState::PendingAdd }; - Wt::WDateTime _dateTime; // when it was starred + FeedbackBackend _backend; // for which backend + SyncState _syncState{ SyncState::PendingAdd }; + Wt::WDateTime _dateTime; // when it was starred - Wt::Dbo::ptr _artist; - Wt::Dbo::ptr _user; + Wt::Dbo::ptr _artist; + Wt::Dbo::ptr _user; }; } // namespace lms::db - diff --git a/src/libs/database/include/database/StarredRelease.hpp b/src/libs/database/include/database/StarredRelease.hpp index 13a9b7df..7894f990 100644 --- a/src/libs/database/include/database/StarredRelease.hpp +++ b/src/libs/database/include/database/StarredRelease.hpp @@ -19,8 +19,8 @@ #pragma once -#include #include +#include #include "database/Object.hpp" #include "database/ReleaseId.hpp" @@ -47,8 +47,8 @@ namespace lms::db // Accessors ObjectPtr getRelease() const { return _release; } - ObjectPtr getUser() const { return _user; } - FeedbackBackend getFeedbackBackend() const { return _backend; } + ObjectPtr getUser() const { return _user; } + FeedbackBackend getFeedbackBackend() const { return _backend; } const Wt::WDateTime& getDateTime() const { return _dateTime; } SyncState getSyncState() const { return _syncState; } @@ -72,12 +72,11 @@ namespace lms::db StarredRelease(ObjectPtr release, ObjectPtr user, FeedbackBackend backend); static pointer create(Session& session, ObjectPtr release, ObjectPtr user, FeedbackBackend backend); - FeedbackBackend _backend; // for which backend - SyncState _syncState{ SyncState::PendingAdd }; - Wt::WDateTime _dateTime; // when it was starred + FeedbackBackend _backend; // for which backend + SyncState _syncState{ SyncState::PendingAdd }; + Wt::WDateTime _dateTime; // when it was starred - Wt::Dbo::ptr _release; - Wt::Dbo::ptr _user; + Wt::Dbo::ptr _release; + Wt::Dbo::ptr _user; }; } // namespace lms::db - diff --git a/src/libs/database/include/database/StarredTrack.hpp b/src/libs/database/include/database/StarredTrack.hpp index 4b037f47..8ee2e3fb 100644 --- a/src/libs/database/include/database/StarredTrack.hpp +++ b/src/libs/database/include/database/StarredTrack.hpp @@ -19,13 +19,13 @@ #pragma once -#include #include +#include #include "core/EnumSet.hpp" -#include "database/TrackId.hpp" #include "database/Object.hpp" #include "database/StarredTrackId.hpp" +#include "database/TrackId.hpp" #include "database/Types.hpp" #include "database/UserId.hpp" @@ -42,30 +42,43 @@ namespace lms::db struct FindParameters { - std::optional backend; // for this backend - std::optional syncState; // and these states - UserId user; // and this user - std::optional range; + std::optional backend; // for this backend + std::optional syncState; // and these states + UserId user; // and this user + std::optional range; - FindParameters& setFeedbackBackend(FeedbackBackend _backend, SyncState _syncState) { backend = _backend; syncState = _syncState; return *this; } - FindParameters& setUser(UserId _user) { user = _user; return *this; } - FindParameters& setRange(std::optional _range) { range = _range; return *this; } + FindParameters& setFeedbackBackend(FeedbackBackend _backend, SyncState _syncState) + { + backend = _backend; + syncState = _syncState; + return *this; + } + FindParameters& setUser(UserId _user) + { + user = _user; + return *this; + } + FindParameters& setRange(std::optional _range) + { + range = _range; + return *this; + } }; // Search utility - static std::size_t getCount(Session& session); - static pointer find(Session& session, StarredTrackId id); - static pointer find(Session& session, TrackId trackId, UserId userId); // current feedback backend - static pointer find(Session& session, TrackId trackId, UserId userId, FeedbackBackend backend); - static bool exists(Session& session, TrackId trackId, UserId userId, FeedbackBackend backend); - static RangeResults find(Session& session, const FindParameters& findParams); + static std::size_t getCount(Session& session); + static pointer find(Session& session, StarredTrackId id); + static pointer find(Session& session, TrackId trackId, UserId userId); // current feedback backend + static pointer find(Session& session, TrackId trackId, UserId userId, FeedbackBackend backend); + static bool exists(Session& session, TrackId trackId, UserId userId, FeedbackBackend backend); + static RangeResults find(Session& session, const FindParameters& findParams); // Accessors - ObjectPtr getTrack() const { return _track; } - ObjectPtr getUser() const { return _user; } - FeedbackBackend getBackend() const { return _backend; } + ObjectPtr getTrack() const { return _track; } + ObjectPtr getUser() const { return _user; } + FeedbackBackend getBackend() const { return _backend; } const Wt::WDateTime& getDateTime() const { return _dateTime; } - SyncState getSyncState() const { return _syncState; } + SyncState getSyncState() const { return _syncState; } // Setters void setDateTime(const Wt::WDateTime& dateTime); @@ -87,12 +100,11 @@ namespace lms::db StarredTrack(ObjectPtr track, ObjectPtr user, FeedbackBackend backend); static pointer create(Session& session, ObjectPtr track, ObjectPtr user, FeedbackBackend backend); - FeedbackBackend _backend; // for which backend - SyncState _syncState{ SyncState::PendingAdd }; - Wt::WDateTime _dateTime; // when it was starred + FeedbackBackend _backend; // for which backend + SyncState _syncState{ SyncState::PendingAdd }; + Wt::WDateTime _dateTime; // when it was starred Wt::Dbo::ptr _track; - Wt::Dbo::ptr _user; + Wt::Dbo::ptr _user; }; } // namespace lms::db - diff --git a/src/libs/database/include/database/Track.hpp b/src/libs/database/include/database/Track.hpp index 9d197411..0df31aee 100644 --- a/src/libs/database/include/database/Track.hpp +++ b/src/libs/database/include/database/Track.hpp @@ -21,17 +21,17 @@ #include #include -#include #include +#include #include #include #include #include #include -#include #include #include +#include #include "core/EnumSet.hpp" #include "core/UUID.hpp" @@ -62,67 +62,134 @@ namespace lms::db public: struct FindParameters { - std::vector clusters; // if non empty, tracks that belong to these clusters - std::vector keywords; // if non empty, name must match all of these keywords - std::string name; // if non empty, must match this name - TrackSortMethod sortMethod{ TrackSortMethod::None }; - std::optional range; - Wt::WDateTime writtenAfter; - UserId starringUser; // only tracks starred by this user - std::optional feedbackBackend; // and for this feedback backend - ArtistId artist; // only tracks that involve this artist - std::string artistName; // only tracks that involve this artist name - core::EnumSet trackArtistLinkTypes; // and for these link types - bool nonRelease{}; // only tracks that do not belong to a release - ReleaseId release; // matching this release - std::string releaseName; // matching this release name - TrackListId trackList; // matching this trackList - std::optional trackNumber; // matching this track number - std::optional discNumber; // matching this disc number - MediaLibraryId mediaLibrary; // If set, tracks in this library + std::vector clusters; // if non empty, tracks that belong to these clusters + std::vector keywords; // if non empty, name must match all of these keywords + std::string name; // if non empty, must match this name + TrackSortMethod sortMethod{ TrackSortMethod::None }; + std::optional range; + Wt::WDateTime writtenAfter; + UserId starringUser; // only tracks starred by this user + std::optional feedbackBackend; // and for this feedback backend + ArtistId artist; // only tracks that involve this artist + std::string artistName; // only tracks that involve this artist name + core::EnumSet trackArtistLinkTypes; // and for these link types + bool nonRelease{}; // only tracks that do not belong to a release + ReleaseId release; // matching this release + std::string releaseName; // matching this release name + TrackListId trackList; // matching this trackList + std::optional trackNumber; // matching this track number + std::optional discNumber; // matching this disc number + MediaLibraryId mediaLibrary; // If set, tracks in this library - FindParameters& setClusters(std::span _clusters) { clusters.assign(std::cbegin(_clusters), std::cend(_clusters)); return *this; } - FindParameters& setKeywords(const std::vector& _keywords) { keywords = _keywords; return *this; } - FindParameters& setName(std::string_view _name) { name = _name; return *this; } - FindParameters& setSortMethod(TrackSortMethod _method) { sortMethod = _method; return *this; } - FindParameters& setRange(std::optional _range) { range = _range; return *this; } - FindParameters& setWrittenAfter(const Wt::WDateTime& _after) { writtenAfter = _after; return *this; } - FindParameters& setStarringUser(UserId _user, FeedbackBackend _feedbackBackend) { starringUser = _user; feedbackBackend = _feedbackBackend; return *this; } - FindParameters& setArtist(ArtistId _artist, core::EnumSet _trackArtistLinkTypes = {}) { artist = _artist; trackArtistLinkTypes = _trackArtistLinkTypes; return *this; } - FindParameters& setArtistName(std::string_view _artistName, core::EnumSet _trackArtistLinkTypes = {}) { artistName = _artistName; trackArtistLinkTypes = _trackArtistLinkTypes; return *this; } - FindParameters& setNonRelease(bool _nonRelease) { nonRelease = _nonRelease; return *this; } - FindParameters& setRelease(ReleaseId _release) { release = _release; return *this; } - FindParameters& setReleaseName(std::string_view _releaseName) { releaseName = _releaseName; return *this; } - FindParameters& setTrackList(TrackListId _trackList) { trackList = _trackList; return *this; } - FindParameters& setTrackNumber(int _trackNumber) { trackNumber = _trackNumber; return *this; } - FindParameters& setDiscNumber(int _discNumber) { discNumber = _discNumber; return *this; } - FindParameters& setMediaLibrary(MediaLibraryId _mediaLibrary) { mediaLibrary = _mediaLibrary; return *this; } + FindParameters& setClusters(std::span _clusters) + { + clusters.assign(std::cbegin(_clusters), std::cend(_clusters)); + return *this; + } + FindParameters& setKeywords(const std::vector& _keywords) + { + keywords = _keywords; + return *this; + } + FindParameters& setName(std::string_view _name) + { + name = _name; + return *this; + } + FindParameters& setSortMethod(TrackSortMethod _method) + { + sortMethod = _method; + return *this; + } + FindParameters& setRange(std::optional _range) + { + range = _range; + return *this; + } + FindParameters& setWrittenAfter(const Wt::WDateTime& _after) + { + writtenAfter = _after; + return *this; + } + FindParameters& setStarringUser(UserId _user, FeedbackBackend _feedbackBackend) + { + starringUser = _user; + feedbackBackend = _feedbackBackend; + return *this; + } + FindParameters& setArtist(ArtistId _artist, core::EnumSet _trackArtistLinkTypes = {}) + { + artist = _artist; + trackArtistLinkTypes = _trackArtistLinkTypes; + return *this; + } + FindParameters& setArtistName(std::string_view _artistName, core::EnumSet _trackArtistLinkTypes = {}) + { + artistName = _artistName; + trackArtistLinkTypes = _trackArtistLinkTypes; + return *this; + } + FindParameters& setNonRelease(bool _nonRelease) + { + nonRelease = _nonRelease; + return *this; + } + FindParameters& setRelease(ReleaseId _release) + { + release = _release; + return *this; + } + FindParameters& setReleaseName(std::string_view _releaseName) + { + releaseName = _releaseName; + return *this; + } + FindParameters& setTrackList(TrackListId _trackList) + { + trackList = _trackList; + return *this; + } + FindParameters& setTrackNumber(int _trackNumber) + { + trackNumber = _trackNumber; + return *this; + } + FindParameters& setDiscNumber(int _discNumber) + { + discNumber = _discNumber; + return *this; + } + FindParameters& setMediaLibrary(MediaLibraryId _mediaLibrary) + { + mediaLibrary = _mediaLibrary; + return *this; + } }; struct PathResult { - TrackId trackId; - std::filesystem::path path; + TrackId trackId; + std::filesystem::path path; }; Track() = default; // Find utility functions - static std::size_t getCount(Session& session); - static pointer findByPath(Session& session, const std::filesystem::path& p); - static pointer find(Session& session, TrackId id); - static void find(Session& session, TrackId& lastRetrievedTrack, std::size_t count, const std::function& func, MediaLibraryId library = {}); - static bool exists(Session& session, TrackId id); - static std::vector findByRecordingMBID(Session& session, const core::UUID& MBID); - static std::vector findByMBID(Session& session, const core::UUID& MBID); - static RangeResults findSimilarTrackIds(Session& session, const std::vector& trackIds, std::optional range = std::nullopt); + static std::size_t getCount(Session& session); + static pointer findByPath(Session& session, const std::filesystem::path& p); + static pointer find(Session& session, TrackId id); + static void find(Session& session, TrackId& lastRetrievedTrack, std::size_t count, const std::function& func, MediaLibraryId library = {}); + static bool exists(Session& session, TrackId id); + static std::vector findByRecordingMBID(Session& session, const core::UUID& MBID); + static std::vector findByMBID(Session& session, const core::UUID& MBID); + static RangeResults findSimilarTrackIds(Session& session, const std::vector& trackIds, std::optional range = std::nullopt); - static RangeResults findIds(Session& session, const FindParameters& parameters); - static RangeResults find(Session& session, const FindParameters& parameters); - static void find(Session& session, const FindParameters& parameters, const std::function& func); - static void find(Session& session, const FindParameters& parameters, bool& moreResults, const std::function& func); - static RangeResults findIdsTrackMBIDDuplicates(Session& session, std::optional range = std::nullopt); - static RangeResults findIdsWithRecordingMBIDAndMissingFeatures(Session& session, std::optional range = std::nullopt); + static RangeResults findIds(Session& session, const FindParameters& parameters); + static RangeResults find(Session& session, const FindParameters& parameters); + static void find(Session& session, const FindParameters& parameters, const std::function& func); + static void find(Session& session, const FindParameters& parameters, bool& moreResults, const std::function& func); + static RangeResults findIdsTrackMBIDDuplicates(Session& session, std::optional range = std::nullopt); + static RangeResults findIdsWithRecordingMBIDAndMissingFeatures(Session& session, std::optional range = std::nullopt); // Accessors void setScanVersion(std::size_t version) { _scanVersion = version; } @@ -159,43 +226,43 @@ namespace lms::db void setClusters(const std::vector>& clusters); void setMediaLibrary(ObjectPtr mediaLibrary) { _mediaLibrary = getDboPtr(mediaLibrary); } - std::size_t getScanVersion() const { return _scanVersion; } - std::optional getTrackNumber() const { return _trackNumber; } - std::optional getTotalTrack() const { return _totalTrack; } - std::optional getDiscNumber() const { return _discNumber; } + std::size_t getScanVersion() const { return _scanVersion; } + std::optional getTrackNumber() const { return _trackNumber; } + std::optional getTotalTrack() const { return _totalTrack; } + std::optional getDiscNumber() const { return _discNumber; } const std::string& getDiscSubtitle() const { return _discSubtitle; } - std::string getName() const { return _name; } + std::string getName() const { return _name; } const std::filesystem::path& getAbsoluteFilePath() const { return _absoluteFilePath; } const std::filesystem::path& getRelativeFilePath() const { return _relativeFilePath; } - long long getFileSize() const { return _fileSize; } - std::size_t getBitrate() const { return _bitrate; } - std::size_t getBitsPerSample() const { return _bitsPerSample; } - std::size_t getChannelCount() const { return _channelCount; } - std::chrono::milliseconds getDuration() const { return _duration; } - std::size_t getSampleRate() const { return _sampleRate; } + long long getFileSize() const { return _fileSize; } + std::size_t getBitrate() const { return _bitrate; } + std::size_t getBitsPerSample() const { return _bitsPerSample; } + std::size_t getChannelCount() const { return _channelCount; } + std::chrono::milliseconds getDuration() const { return _duration; } + std::size_t getSampleRate() const { return _sampleRate; } const Wt::WDateTime& getLastWritten() const { return _fileLastWrite; } const Wt::WDate& getDate() const { return _date; } - std::optional getYear() const { return _year; } + std::optional getYear() const { return _year; } const Wt::WDate& getOriginalDate() const { return _originalDate; } - std::optional getOriginalYear() const { return _originalYear; }; + std::optional getOriginalYear() const { return _originalYear; }; const Wt::WDateTime& getLastWriteTime() const { return _fileLastWrite; } const Wt::WDateTime& getAddedTime() const { return _fileAdded; } - bool hasCover() const { return _hasCover; } - std::optional getTrackMBID() const { return core::UUID::fromString(_trackMBID); } - std::optional getRecordingMBID() const { return core::UUID::fromString(_recordingMBID); } - std::optional getCopyright() const; - std::optional getCopyrightURL() const; - std::optional getTrackReplayGain() const { return _trackReplayGain; } - std::optional getReleaseReplayGain() const { return _releaseReplayGain; } - std::string_view getArtistDisplayName() const { return _artistDisplayName; } + bool hasCover() const { return _hasCover; } + std::optional getTrackMBID() const { return core::UUID::fromString(_trackMBID); } + std::optional getRecordingMBID() const { return core::UUID::fromString(_recordingMBID); } + std::optional getCopyright() const; + std::optional getCopyrightURL() const; + std::optional getTrackReplayGain() const { return _trackReplayGain; } + std::optional getReleaseReplayGain() const { return _releaseReplayGain; } + std::string_view getArtistDisplayName() const { return _artistDisplayName; } // no artistLinkTypes means get all - std::vector> getArtists(core::EnumSet artistLinkTypes) const; // no type means all - std::vector getArtistIds(core::EnumSet artistLinkTypes) const; // no type means all - std::vector> getArtistLinks() const; - ObjectPtr getRelease() const { return _release; } - std::vector> getClusters() const; - std::vector getClusterIds() const; - ObjectPtr getMediaLibrary() const { return _mediaLibrary; } + std::vector> getArtists(core::EnumSet artistLinkTypes) const; // no type means all + std::vector getArtistIds(core::EnumSet artistLinkTypes) const; // no type means all + std::vector> getArtistLinks() const; + ObjectPtr getRelease() const { return _release; } + std::vector> getClusters() const; + std::vector getClusterIds() const; + ObjectPtr getMediaLibrary() const { return _mediaLibrary; } std::vector>> getClusterGroups(const std::vector& clusterTypes, std::size_t size) const; @@ -205,7 +272,7 @@ namespace lms::db Wt::Dbo::field(a, _scanVersion, "scan_version"); Wt::Dbo::field(a, _trackNumber, "track_number"); Wt::Dbo::field(a, _discNumber, "disc_number"); - Wt::Dbo::field(a, _totalTrack, "total_track"); // here in Track since Release does not have concept of "disc" (yet?) + Wt::Dbo::field(a, _totalTrack, "total_track"); // here in Track since Release does not have concept of "disc" (yet?) Wt::Dbo::field(a, _discSubtitle, "disc_subtitle"); // here in Track since Release does not have concept of "disc" (yet?) Wt::Dbo::field(a, _name, "name"); Wt::Dbo::field(a, _duration, "duration"); @@ -244,39 +311,39 @@ namespace lms::db static constexpr std::size_t _maxCopyrightLength{ 256 }; static constexpr std::size_t _maxCopyrightURLLength{ 256 }; - int _scanVersion{}; - std::optional _trackNumber{}; - std::optional _discNumber{}; - std::optional _totalTrack{}; - std::string _discSubtitle; - std::string _name; - int _bitrate{}; // in bps - int _bitsPerSample{}; - int _channelCount{}; - std::chrono::duration _duration{}; - int _sampleRate{}; - Wt::WDate _date; - std::optional _year; - Wt::WDate _originalDate; - std::optional _originalYear; - std::filesystem::path _absoluteFilePath; // full path - std::filesystem::path _relativeFilePath; // relative to root (that may be deleted) - long long _fileSize{}; - Wt::WDateTime _fileLastWrite; - Wt::WDateTime _fileAdded; - bool _hasCover{}; - std::string _trackMBID; - std::string _recordingMBID; - std::string _copyright; - std::string _copyrightURL; - std::optional _trackReplayGain; - std::optional _releaseReplayGain; - std::string _artistDisplayName; + int _scanVersion{}; + std::optional _trackNumber{}; + std::optional _discNumber{}; + std::optional _totalTrack{}; + std::string _discSubtitle; + std::string _name; + int _bitrate{}; // in bps + int _bitsPerSample{}; + int _channelCount{}; + std::chrono::duration _duration{}; + int _sampleRate{}; + Wt::WDate _date; + std::optional _year; + Wt::WDate _originalDate; + std::optional _originalYear; + std::filesystem::path _absoluteFilePath; // full path + std::filesystem::path _relativeFilePath; // relative to root (that may be deleted) + long long _fileSize{}; + Wt::WDateTime _fileLastWrite; + Wt::WDateTime _fileAdded; + bool _hasCover{}; + std::string _trackMBID; + std::string _recordingMBID; + std::string _copyright; + std::string _copyrightURL; + std::optional _trackReplayGain; + std::optional _releaseReplayGain; + std::string _artistDisplayName; - Wt::Dbo::ptr _release; - Wt::Dbo::ptr _mediaLibrary; - Wt::Dbo::collection> _trackArtistLinks; - Wt::Dbo::collection> _clusters; + Wt::Dbo::ptr _release; + Wt::Dbo::ptr _mediaLibrary; + Wt::Dbo::collection> _trackArtistLinks; + Wt::Dbo::collection> _clusters; }; namespace Debug @@ -287,5 +354,5 @@ namespace lms::db TrackId trackId; }; std::ostream& operator<<(std::ostream& os, const TrackInfo& trackInfo); - } + } // namespace Debug } // namespace lms::db diff --git a/src/libs/database/include/database/TrackArtistLink.hpp b/src/libs/database/include/database/TrackArtistLink.hpp index dafae759..5e823b93 100644 --- a/src/libs/database/include/database/TrackArtistLink.hpp +++ b/src/libs/database/include/database/TrackArtistLink.hpp @@ -46,32 +46,52 @@ namespace lms::db public: struct FindParameters { - std::optional range; - std::optional linkType; // if set, only artists that have produced at least one track with this link type - ArtistId artist; // if set, links involved with this artist - ReleaseId release; // if set, artists involved in this release - TrackId track; // if set, artists involved in this track + std::optional range; + std::optional linkType; // if set, only artists that have produced at least one track with this link type + ArtistId artist; // if set, links involved with this artist + ReleaseId release; // if set, artists involved in this release + TrackId track; // if set, artists involved in this track - FindParameters& setRange(std::optional _range) { range = _range; return *this; } - FindParameters& setLinkType(std::optional _linkType) { linkType = _linkType; return *this; } - FindParameters& setArtist(ArtistId _artist) { artist = _artist; return *this; } - FindParameters& setRelease(ReleaseId _release) { release = _release; return *this; } - FindParameters& setTrack(TrackId _track) { track = _track; return *this; } + FindParameters& setRange(std::optional _range) + { + range = _range; + return *this; + } + FindParameters& setLinkType(std::optional _linkType) + { + linkType = _linkType; + return *this; + } + FindParameters& setArtist(ArtistId _artist) + { + artist = _artist; + return *this; + } + FindParameters& setRelease(ReleaseId _release) + { + release = _release; + return *this; + } + FindParameters& setTrack(TrackId _track) + { + track = _track; + return *this; + } }; TrackArtistLink() = default; TrackArtistLink(ObjectPtr track, ObjectPtr artist, TrackArtistLinkType type, std::string_view subType); - static void find(Session& session, TrackId trackId, const std::function&)>&); - static void find(Session& session, const FindParameters& parameters, const std::function&); - static pointer find(Session& session, TrackArtistLinkId linkId); - static pointer create(Session& session, ObjectPtr track, ObjectPtr artist, TrackArtistLinkType type, std::string_view subType = {}); - static core::EnumSet findUsedTypes(Session& session, ArtistId _artist); + static void find(Session& session, TrackId trackId, const std::function&)>&); + static void find(Session& session, const FindParameters& parameters, const std::function&); + static pointer find(Session& session, TrackArtistLinkId linkId); + static pointer create(Session& session, ObjectPtr track, ObjectPtr artist, TrackArtistLinkType type, std::string_view subType = {}); + static core::EnumSet findUsedTypes(Session& session, ArtistId _artist); - ObjectPtr getTrack() const { return _track; } - ObjectPtr getArtist() const { return _artist; } - TrackArtistLinkType getType() const { return _type; } - std::string_view getSubType() const { return _subType; } + ObjectPtr getTrack() const { return _track; } + ObjectPtr getArtist() const { return _artist; } + TrackArtistLinkType getType() const { return _type; } + std::string_view getSubType() const { return _subType; } template void persist(Action& a) @@ -90,5 +110,4 @@ namespace lms::db Wt::Dbo::ptr _track; Wt::Dbo::ptr _artist; }; -} - +} // namespace lms::db diff --git a/src/libs/database/include/database/TrackBookmark.hpp b/src/libs/database/include/database/TrackBookmark.hpp index d02287b0..61a606a2 100644 --- a/src/libs/database/include/database/TrackBookmark.hpp +++ b/src/libs/database/include/database/TrackBookmark.hpp @@ -44,20 +44,20 @@ namespace lms::db TrackBookmark() = default; // Find utility functions - static std::size_t getCount(Session& session); - static pointer find(Session& session, TrackBookmarkId id); - static RangeResults find(Session& session, UserId userId, std::optional range = std::nullopt); - static pointer find(Session& session, UserId userId, TrackId trackId); + static std::size_t getCount(Session& session); + static pointer find(Session& session, TrackBookmarkId id); + static RangeResults find(Session& session, UserId userId, std::optional range = std::nullopt); + static pointer find(Session& session, UserId userId, TrackId trackId); // Setters void setOffset(std::chrono::milliseconds offset) { _offset = offset; } void setComment(std::string_view comment) { _comment = comment; } // Getters - std::chrono::milliseconds getOffset() const { return _offset; } - std::string_view getComment() const { return _comment; } - ObjectPtr getTrack() const { return _track; } - ObjectPtr getUser() const { return _user; } + std::chrono::milliseconds getOffset() const { return _offset; } + std::string_view getComment() const { return _comment; } + ObjectPtr getTrack() const { return _track; } + ObjectPtr getUser() const { return _user; } template void persist(Action& a) @@ -75,11 +75,11 @@ namespace lms::db static const std::size_t _maxCommentLength = 128; - std::chrono::duration _offset; - std::string _comment; + std::chrono::duration _offset; + std::string _comment; - Wt::Dbo::ptr _user; - Wt::Dbo::ptr _track; + Wt::Dbo::ptr _user; + Wt::Dbo::ptr _track; }; } // namespace lms::db diff --git a/src/libs/database/include/database/TrackFeatures.hpp b/src/libs/database/include/database/TrackFeatures.hpp index 7c10ac80..4ff8e1e9 100644 --- a/src/libs/database/include/database/TrackFeatures.hpp +++ b/src/libs/database/include/database/TrackFeatures.hpp @@ -49,13 +49,13 @@ namespace lms::db TrackFeatures() = default; // Find utilities - static std::size_t getCount(Session& session); - static pointer find(Session& session, TrackFeaturesId id); - static pointer find(Session& session, TrackId trackId); - static RangeResults find(Session& session, std::optional range = std::nullopt); + static std::size_t getCount(Session& session); + static pointer find(Session& session, TrackFeaturesId id); + static pointer find(Session& session, TrackId trackId); + static RangeResults find(Session& session, std::optional range = std::nullopt); - FeatureValues getFeatureValues(const FeatureName& feature) const; - FeatureValuesMap getFeatureValuesMap(const std::unordered_set& featureNames) const; + FeatureValues getFeatureValues(const FeatureName& feature) const; + FeatureValuesMap getFeatureValuesMap(const std::unordered_set& featureNames) const; // Accessors Wt::Dbo::ptr getTrack() const { return _track; } diff --git a/src/libs/database/include/database/TrackList.hpp b/src/libs/database/include/database/TrackList.hpp index 91dc92e1..1284261a 100644 --- a/src/libs/database/include/database/TrackList.hpp +++ b/src/libs/database/include/database/TrackList.hpp @@ -55,48 +55,72 @@ namespace lms::db // Search utility struct FindParameters { - std::vector clusters; // if non empty, tracklists that have tracks that belong to these clusters - std::optional range; - std::optional type; - UserId user; // only tracklists owned by this user - MediaLibraryId mediaLibrary; // only tracklists that have songs in this media library - TrackListSortMethod sortMethod{ TrackListSortMethod::None }; + std::vector clusters; // if non empty, tracklists that have tracks that belong to these clusters + std::optional range; + std::optional type; + UserId user; // only tracklists owned by this user + MediaLibraryId mediaLibrary; // only tracklists that have songs in this media library + TrackListSortMethod sortMethod{ TrackListSortMethod::None }; - FindParameters& setClusters(std::span _clusters) { clusters.assign(std::cbegin(_clusters), std::cend(_clusters)); return *this; } - FindParameters& setRange(std::optional _range) { range = _range; return *this; } - FindParameters& setType(TrackListType _type) { type = _type; return *this; } - FindParameters& setUser(UserId _user) { user = _user; return *this; } - FindParameters& setMediaLibrary(MediaLibraryId _mediaLibrary) { mediaLibrary = _mediaLibrary; return *this; } - FindParameters& setSortMethod(TrackListSortMethod _sortMethod) { sortMethod = _sortMethod; return *this; } + FindParameters& setClusters(std::span _clusters) + { + clusters.assign(std::cbegin(_clusters), std::cend(_clusters)); + return *this; + } + FindParameters& setRange(std::optional _range) + { + range = _range; + return *this; + } + FindParameters& setType(TrackListType _type) + { + type = _type; + return *this; + } + FindParameters& setUser(UserId _user) + { + user = _user; + return *this; + } + FindParameters& setMediaLibrary(MediaLibraryId _mediaLibrary) + { + mediaLibrary = _mediaLibrary; + return *this; + } + FindParameters& setSortMethod(TrackListSortMethod _sortMethod) + { + sortMethod = _sortMethod; + return *this; + } }; - static std::size_t getCount(Session& session); - static pointer find(Session& session, std::string_view name, TrackListType type, UserId userId); - static pointer find(Session& session, TrackListId tracklistId); - static RangeResults find(Session& session, const FindParameters& params); - static void find(Session& session, const FindParameters& params, const std::function& func); + static std::size_t getCount(Session& session); + static pointer find(Session& session, std::string_view name, TrackListType type, UserId userId); + static pointer find(Session& session, TrackListId tracklistId); + static RangeResults find(Session& session, const FindParameters& params); + static void find(Session& session, const FindParameters& params, const std::function& func); // Accessors - std::string_view getName() const { return _name; } - bool isPublic() const { return _isPublic; } - TrackListType getType() const { return _type; } - ObjectPtr getUser() const { return _user; } + std::string_view getName() const { return _name; } + bool isPublic() const { return _isPublic; } + TrackListType getType() const { return _type; } + ObjectPtr getUser() const { return _user; } // Modifiers - void setName(const std::string& name) { _name = name; } - void setIsPublic(bool isPublic) { _isPublic = isPublic; } - void clear() { _entries.clear(); } + void setName(const std::string& name) { _name = name; } + void setIsPublic(bool isPublic) { _isPublic = isPublic; } + void clear() { _entries.clear(); } // Get tracks, ordered by position - bool isEmpty() const; - std::size_t getCount() const; - ObjectPtr getEntry(std::size_t pos) const; - RangeResults> getEntries(std::optional range = {}) const; - ObjectPtr getEntryByTrackAndDateTime(ObjectPtr track, const Wt::WDateTime& dateTime) const; + bool isEmpty() const; + std::size_t getCount() const; + ObjectPtr getEntry(std::size_t pos) const; + RangeResults> getEntries(std::optional range = {}) const; + ObjectPtr getEntryByTrackAndDateTime(ObjectPtr track, const Wt::WDateTime& dateTime) const; - std::vector getTrackIds() const; - std::chrono::milliseconds getDuration() const; + std::vector getTrackIds() const; + std::chrono::milliseconds getDuration() const; - void setLastModifiedDateTime(const Wt::WDateTime& dateTime); + void setLastModifiedDateTime(const Wt::WDateTime& dateTime); // Get clusters, order by occurence std::vector> getClusters() const; @@ -123,13 +147,13 @@ namespace lms::db TrackList(std::string_view name, TrackListType type, bool isPublic, ObjectPtr user); static pointer create(Session& session, std::string_view name, TrackListType type, bool isPublic, ObjectPtr user); - std::string _name; - TrackListType _type{ TrackListType::Playlist }; - bool _isPublic{ false }; - Wt::WDateTime _creationDateTime; - Wt::WDateTime _lastModifiedDateTime; + std::string _name; + TrackListType _type{ TrackListType::Playlist }; + bool _isPublic{ false }; + Wt::WDateTime _creationDateTime; + Wt::WDateTime _lastModifiedDateTime; - Wt::Dbo::ptr _user; + Wt::Dbo::ptr _user; Wt::Dbo::collection> _entries; }; @@ -148,7 +172,7 @@ namespace lms::db static pointer getById(Session& session, TrackListEntryId id); // Accessors - ObjectPtr getTrack() const { return _track; } + ObjectPtr getTrack() const { return _track; } const Wt::WDateTime& getDateTime() const { return _dateTime; } template @@ -166,10 +190,9 @@ namespace lms::db TrackListEntry(ObjectPtr track, ObjectPtr tracklist); static pointer create(Session& session, ObjectPtr track, ObjectPtr tracklist, const Wt::WDateTime& dateTime = {}); - Wt::WDateTime _dateTime; // optional date time - Wt::Dbo::ptr _track; - Wt::Dbo::ptr _tracklist; + Wt::WDateTime _dateTime; // optional date time + Wt::Dbo::ptr _track; + Wt::Dbo::ptr _tracklist; }; } // namespace lms::db - diff --git a/src/libs/database/include/database/TransactionChecker.hpp b/src/libs/database/include/database/TransactionChecker.hpp index 58128e00..fffeedb7 100644 --- a/src/libs/database/include/database/TransactionChecker.hpp +++ b/src/libs/database/include/database/TransactionChecker.hpp @@ -20,15 +20,14 @@ #pragma once #if !defined(NDEBUG) -#define LMS_CHECK_TRANSACTION_ACCESSES 1 + #define LMS_CHECK_TRANSACTION_ACCESSES 1 #else -#define LMS_CHECK_TRANSACTION_ACCESSES 0 + #define LMS_CHECK_TRANSACTION_ACCESSES 0 #endif #if LMS_CHECK_TRANSACTION_ACCESSES - -#include -#include + #include + #include namespace lms::db { @@ -58,6 +57,6 @@ namespace lms::db static void pushTransaction(TransactionType type, Wt::Dbo::Session& session); static void popTransaction(TransactionType type, Wt::Dbo::Session& session); }; -} +} // namespace lms::db #endif \ No newline at end of file diff --git a/src/libs/database/include/database/Types.hpp b/src/libs/database/include/database/Types.hpp index 17b6bd27..a6c323c8 100644 --- a/src/libs/database/include/database/Types.hpp +++ b/src/libs/database/include/database/Types.hpp @@ -19,9 +19,10 @@ #pragma once -#include #include +#include #include + #include namespace lms::db @@ -41,7 +42,7 @@ namespace lms::db }; // Func must return true to continue iterating - template + template void foreachSubRange(Range range, std::size_t subRangeSize, Func&& func) { assert(subRangeSize > 0); @@ -57,7 +58,7 @@ namespace lms::db } } - template + template struct RangeResults { Range range; @@ -152,13 +153,13 @@ namespace lms::db StarredDateDesc, Name, DateDescAndRelease, - Release, // order by disc/track number + Release, // order by disc/track number TrackList, // order by asc order in tracklist }; enum class TrackArtistLinkType { - Artist = 0, // regular track artist + Artist = 0, // regular track artist Arranger = 1, Composer = 2, Conductor = 3, @@ -227,8 +228,7 @@ namespace lms::db enum class TrackListType { - Playlist, // user controlled playlists - Internal, // internal usage (current playqueue, history, ...) + Playlist, // user controlled playlists + Internal, // internal usage (current playqueue, history, ...) }; -} - +} // namespace lms::db diff --git a/src/libs/database/include/database/User.hpp b/src/libs/database/include/database/User.hpp index aa5e00df..d26a29b9 100644 --- a/src/libs/database/include/database/User.hpp +++ b/src/libs/database/include/database/User.hpp @@ -47,43 +47,59 @@ namespace lms::db struct FindParameters { - std::optional scrobblingBackend; - std::optional feedbackBackend; - std::optional range; + std::optional scrobblingBackend; + std::optional feedbackBackend; + std::optional range; - FindParameters& setFeedbackBackend(FeedbackBackend _feedbackBackend) { feedbackBackend = _feedbackBackend; return *this; } - FindParameters& setScrobblingBackend(ScrobblingBackend _scrobblingBackend) { scrobblingBackend = _scrobblingBackend; return *this; } - FindParameters& setRange(std::optional _range) { range = _range; return *this; } + FindParameters& setFeedbackBackend(FeedbackBackend _feedbackBackend) + { + feedbackBackend = _feedbackBackend; + return *this; + } + FindParameters& setScrobblingBackend(ScrobblingBackend _scrobblingBackend) + { + scrobblingBackend = _scrobblingBackend; + return *this; + } + FindParameters& setRange(std::optional _range) + { + range = _range; + return *this; + } }; - static inline constexpr std::size_t MinNameLength{ 3 }; - static inline constexpr std::size_t MaxNameLength{ 15 }; - static inline constexpr bool defaultSubsonicEnableTranscodingByDefault{ false }; + static inline constexpr std::size_t MinNameLength{ 3 }; + static inline constexpr std::size_t MaxNameLength{ 15 }; + static inline constexpr bool defaultSubsonicEnableTranscodingByDefault{ false }; static inline constexpr TranscodingOutputFormat defaultSubsonicTranscodingOutputFormat{ TranscodingOutputFormat::OGG_OPUS }; - static inline constexpr Bitrate defaultSubsonicTranscodingOutputBitrate{ 128000 }; - static inline constexpr UITheme defaultUITheme{ UITheme::Dark }; - static inline constexpr SubsonicArtistListMode defaultSubsonicArtistListMode{ SubsonicArtistListMode::AllArtists }; - static inline constexpr ScrobblingBackend defaultScrobblingBackend{ ScrobblingBackend::Internal }; - static inline constexpr FeedbackBackend defaultFeedbackBackend{ FeedbackBackend::Internal }; + static inline constexpr Bitrate defaultSubsonicTranscodingOutputBitrate{ 128000 }; + static inline constexpr UITheme defaultUITheme{ UITheme::Dark }; + static inline constexpr SubsonicArtistListMode defaultSubsonicArtistListMode{ SubsonicArtistListMode::AllArtists }; + static inline constexpr ScrobblingBackend defaultScrobblingBackend{ ScrobblingBackend::Internal }; + static inline constexpr FeedbackBackend defaultFeedbackBackend{ FeedbackBackend::Internal }; User() = default; - static std::size_t getCount(Session& session); - static pointer find(Session& session, UserId id); - static pointer find(Session& session, std::string_view loginName); + static std::size_t getCount(Session& session); + static pointer find(Session& session, UserId id); + static pointer find(Session& session, std::string_view loginName); static RangeResults find(Session& session, const FindParameters& params); - static void find(Session& session, const FindParameters& params, const std::function& func); - static pointer findDemoUser(Session& session); + static void find(Session& session, const FindParameters& params, const std::function& func); + static pointer findDemoUser(Session& session); // accessors const std::string& getLoginName() const { return _loginName; } - PasswordHash getPasswordHash() const { return PasswordHash{ _passwordSalt, _passwordHash }; } + PasswordHash getPasswordHash() const { return PasswordHash{ _passwordSalt, _passwordHash }; } const Wt::WDateTime& getLastLogin() const { return _lastLogin; } - std::size_t getAuthTokensCount() const { return _authTokens.size(); } + std::size_t getAuthTokensCount() const { return _authTokens.size(); } // write void setLastLogin(const Wt::WDateTime& dateTime) { _lastLogin = dateTime; } - void setPasswordHash(const PasswordHash& passwordHash) { _passwordSalt = passwordHash.salt; _passwordHash = passwordHash.hash; } + void setPasswordHash(const PasswordHash& passwordHash) + { + _passwordSalt = passwordHash.salt; + _passwordHash = passwordHash.hash; + } void setType(UserType type) { _type = type; } void setSubsonicEnableTranscodingByDefault(bool value) { _subsonicEnableTranscodingByDefault = value; } void setSubsonicDefaultTranscodintOutputFormat(TranscodingOutputFormat encoding) { _subsonicDefaultTranscodingOutputFormat = encoding; } @@ -99,19 +115,19 @@ namespace lms::db void setListenBrainzToken(const std::optional& MBID) { _listenbrainzToken = MBID ? MBID->getAsString() : ""; } // read - bool isAdmin() const { return _type == UserType::ADMIN; } - bool isDemo() const { return _type == UserType::DEMO; } - UserType getType() const { return _type; } - bool getSubsonicEnableTranscodingByDefault() const { return _subsonicEnableTranscodingByDefault; } + bool isAdmin() const { return _type == UserType::ADMIN; } + bool isDemo() const { return _type == UserType::DEMO; } + UserType getType() const { return _type; } + bool getSubsonicEnableTranscodingByDefault() const { return _subsonicEnableTranscodingByDefault; } TranscodingOutputFormat getSubsonicDefaultTranscodingOutputFormat() const { return _subsonicDefaultTranscodingOutputFormat; } - Bitrate getSubsonicDefaultTranscodingOutputBitrate() const { return _subsonicDefaultTranscodingOutputBitrate; } - std::size_t getCurPlayingTrackPos() const { return _curPlayingTrackPos; } - bool isRepeatAllSet() const { return _repeatAll; } - bool isRadioSet() const { return _radio; } - UITheme getUITheme() const { return _uiTheme; } - SubsonicArtistListMode getSubsonicArtistListMode() const { return _subsonicArtistListMode; } - FeedbackBackend getFeedbackBackend() const { return _feedbackBackend; } - ScrobblingBackend getScrobblingBackend() const { return _scrobblingBackend; } + Bitrate getSubsonicDefaultTranscodingOutputBitrate() const { return _subsonicDefaultTranscodingOutputBitrate; } + std::size_t getCurPlayingTrackPos() const { return _curPlayingTrackPos; } + bool isRepeatAllSet() const { return _repeatAll; } + bool isRadioSet() const { return _radio; } + UITheme getUITheme() const { return _uiTheme; } + SubsonicArtistListMode getSubsonicArtistListMode() const { return _subsonicArtistListMode; } + FeedbackBackend getFeedbackBackend() const { return _feedbackBackend; } + ScrobblingBackend getScrobblingBackend() const { return _scrobblingBackend; } std::optional getListenBrainzToken() const { return core::UUID::fromString(_listenbrainzToken); } template @@ -144,30 +160,30 @@ namespace lms::db User(std::string_view loginName); static pointer create(Session& session, std::string_view loginName); - std::string _loginName; - std::string _passwordSalt; - std::string _passwordHash; - Wt::WDateTime _lastLogin; - UITheme _uiTheme{ defaultUITheme }; + std::string _loginName; + std::string _passwordSalt; + std::string _passwordHash; + Wt::WDateTime _lastLogin; + UITheme _uiTheme{ defaultUITheme }; FeedbackBackend _feedbackBackend{ defaultFeedbackBackend }; ScrobblingBackend _scrobblingBackend{ defaultScrobblingBackend }; - std::string _listenbrainzToken; // Musicbrainz Identifier + std::string _listenbrainzToken; // Musicbrainz Identifier // Admin defined settings - UserType _type{ UserType::REGULAR }; + UserType _type{ UserType::REGULAR }; // User defined settings - SubsonicArtistListMode _subsonicArtistListMode{ defaultSubsonicArtistListMode }; - bool _subsonicEnableTranscodingByDefault{ defaultSubsonicEnableTranscodingByDefault }; + SubsonicArtistListMode _subsonicArtistListMode{ defaultSubsonicArtistListMode }; + bool _subsonicEnableTranscodingByDefault{ defaultSubsonicEnableTranscodingByDefault }; TranscodingOutputFormat _subsonicDefaultTranscodingOutputFormat{ defaultSubsonicTranscodingOutputFormat }; - int _subsonicDefaultTranscodingOutputBitrate{ defaultSubsonicTranscodingOutputBitrate }; + int _subsonicDefaultTranscodingOutputBitrate{ defaultSubsonicTranscodingOutputBitrate }; // User's dynamic data (UI) - int _curPlayingTrackPos{}; // Current track position in queue - bool _repeatAll{}; - bool _radio{}; + int _curPlayingTrackPos{}; // Current track position in queue + bool _repeatAll{}; + bool _radio{}; Wt::Dbo::collection> _authTokens; }; -} // namespace Databas' +} // namespace lms::db diff --git a/src/libs/database/test/Artist.cpp b/src/libs/database/test/Artist.cpp index 49d3e729..abef4914 100644 --- a/src/libs/database/test/Artist.cpp +++ b/src/libs/database/test/Artist.cpp @@ -47,7 +47,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto artists{ Artist::findIds(session, Artist::FindParameters {}) }; + auto artists{ Artist::findIds(session, Artist::FindParameters{}) }; ASSERT_EQ(artists.results.size(), 1); EXPECT_EQ(artists.results.front(), artist.getId()); @@ -59,7 +59,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto artists{ Artist::find(session, Artist::FindParameters {}) }; + auto artists{ Artist::find(session, Artist::FindParameters{}) }; ASSERT_EQ(artists.results.size(), 1); EXPECT_EQ(artists.results.front()->getId(), artist.getId()); } @@ -68,11 +68,10 @@ namespace lms::db::tests auto transaction{ session.createReadTransaction() }; bool visited{}; - Artist::find(session, Artist::FindParameters{}, [&](const Artist::pointer& a) - { - visited = true; - EXPECT_EQ(a->getId(), artist.getId()); - }); + Artist::find(session, Artist::FindParameters{}, [&](const Artist::pointer& a) { + visited = true; + EXPECT_EQ(a->getId(), artist.getId()); + }); EXPECT_TRUE(visited); } } @@ -104,10 +103,9 @@ namespace lms::db::tests ArtistId lastRetrievedId; std::vector visitedArtists; - Artist::find(session, lastRetrievedId, 10, [&](const Artist::pointer& artist) - { - visitedArtists.push_back(artist); - }); + Artist::find(session, lastRetrievedId, 10, [&](const Artist::pointer& artist) { + visitedArtists.push_back(artist); + }); ASSERT_EQ(visitedArtists.size(), 3); EXPECT_EQ(visitedArtists[0]->getId(), artist1.getId()); EXPECT_EQ(visitedArtists[1]->getId(), artist2.getId()); @@ -120,10 +118,9 @@ namespace lms::db::tests ArtistId lastRetrievedId{ artist1.getId() }; std::vector visitedArtists; - Artist::find(session, lastRetrievedId, 1, [&](const Artist::pointer& artist) - { - visitedArtists.push_back(artist); - }); + Artist::find(session, lastRetrievedId, 1, [&](const Artist::pointer& artist) { + visitedArtists.push_back(artist); + }); ASSERT_EQ(visitedArtists.size(), 1); EXPECT_EQ(visitedArtists[0]->getId(), artist2.getId()); EXPECT_EQ(lastRetrievedId, artist2.getId()); @@ -134,10 +131,9 @@ namespace lms::db::tests ArtistId lastRetrievedId{ artist1.getId() }; std::vector visitedArtists; - Artist::find(session, lastRetrievedId, 0, [&](const Artist::pointer& artist) - { - visitedArtists.push_back(artist); - }); + Artist::find(session, lastRetrievedId, 0, [&](const Artist::pointer& artist) { + visitedArtists.push_back(artist); + }); ASSERT_EQ(visitedArtists.size(), 0); EXPECT_EQ(lastRetrievedId, artist1.getId()); } @@ -147,10 +143,11 @@ namespace lms::db::tests ArtistId lastRetrievedId; std::vector visitedArtists; - Artist::find(session, lastRetrievedId, 10, [&](const Artist::pointer& artist) - { + Artist::find( + session, lastRetrievedId, 10, [&](const Artist::pointer& artist) { visitedArtists.push_back(artist); - }, otherLibrary.getId()); + }, + otherLibrary.getId()); ASSERT_EQ(visitedArtists.size(), 0); EXPECT_EQ(lastRetrievedId, ArtistId{}); } @@ -160,10 +157,11 @@ namespace lms::db::tests ArtistId lastRetrievedId; std::vector visitedArtists; - Artist::find(session, lastRetrievedId, 10, [&](const Artist::pointer& artist) - { + Artist::find( + session, lastRetrievedId, 10, [&](const Artist::pointer& artist) { visitedArtists.push_back(artist); - }, library.getId()); + }, + library.getId()); ASSERT_EQ(visitedArtists.size(), 1); EXPECT_EQ(visitedArtists[0]->getId(), artist2.getId()); EXPECT_EQ(lastRetrievedId, artist2.getId()); @@ -175,7 +173,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto artists{ Artist::findIds(session, Artist::FindParameters {}) }; + auto artists{ Artist::findIds(session, Artist::FindParameters{}) }; ASSERT_EQ(artists.results.size(), 0); ASSERT_FALSE(artists.moreResults); ASSERT_EQ(artists.range.offset, 0); @@ -199,7 +197,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto artists{ Artist::findIds(session, Artist::FindParameters{}.setRange(Range{0,1})) }; + auto artists{ Artist::findIds(session, Artist::FindParameters{}.setRange(Range{ 0, 1 })) }; ASSERT_EQ(artists.results.size(), 1); ASSERT_TRUE(artists.moreResults); ASSERT_EQ(artists.range.offset, 0); @@ -210,7 +208,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto artists{ Artist::findIds(session, Artist::FindParameters{}.setRange(Range{1,1})) }; + auto artists{ Artist::findIds(session, Artist::FindParameters{}.setRange(Range{ 1, 1 })) }; ASSERT_EQ(artists.results.size(), 1); ASSERT_TRUE(artists.moreResults); ASSERT_EQ(artists.range.offset, 1); @@ -221,7 +219,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto artists{ Artist::findIds(session, Artist::FindParameters{}.setRange(Range{2,1})) }; + auto artists{ Artist::findIds(session, Artist::FindParameters{}.setRange(Range{ 2, 1 })) }; ASSERT_EQ(artists.results.size(), 1); ASSERT_FALSE(artists.moreResults); ASSERT_EQ(artists.range.offset, 2); @@ -250,7 +248,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto artists{ track->getArtists({TrackArtistLinkType::Artist}) }; + auto artists{ track->getArtists({ TrackArtistLinkType::Artist }) }; ASSERT_EQ(artists.size(), 1); EXPECT_EQ(artists.front()->getId(), artist.getId()); @@ -267,7 +265,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto artists{ track->getArtistIds({TrackArtistLinkType::Artist}) }; + auto artists{ track->getArtistIds({ TrackArtistLinkType::Artist }) }; ASSERT_EQ(artists.size(), 1); EXPECT_EQ(artists.front(), artist.getId()); @@ -362,7 +360,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto artists{ track->getArtists({TrackArtistLinkType::Artist}) }; + auto artists{ track->getArtists({ TrackArtistLinkType::Artist }) }; ASSERT_EQ(artists.size(), 1); EXPECT_EQ(artists.front()->getId(), artist.getId()); @@ -372,7 +370,7 @@ namespace lms::db::tests EXPECT_EQ(track->getArtistLinks().size(), 3); - auto tracks{ Track::findIds(session, Track::FindParameters {}.setArtist(artist.getId())) }; + auto tracks{ Track::findIds(session, Track::FindParameters{}.setArtist(artist.getId())) }; EXPECT_EQ(tracks.results.size(), 1); tracks = Track::findIds(session, Track::FindParameters{}.setArtist(artist.getId(), { TrackArtistLinkType::ReleaseArtist })); @@ -399,19 +397,17 @@ namespace lms::db::tests auto transaction{ session.createReadTransaction() }; std::vector visitedLinks; - TrackArtistLink::find(session, TrackArtistLink::FindParameters{}.setTrack(track.getId()), [&](const TrackArtistLink::pointer& link) - { - visitedLinks.push_back(link); - }); + TrackArtistLink::find(session, TrackArtistLink::FindParameters{}.setTrack(track.getId()), [&](const TrackArtistLink::pointer& link) { + visitedLinks.push_back(link); + }); ASSERT_EQ(visitedLinks.size(), 3); EXPECT_EQ(visitedLinks[0]->getArtist()->getId(), artist.getId()); EXPECT_EQ(visitedLinks[1]->getArtist()->getId(), artist.getId()); EXPECT_EQ(visitedLinks[2]->getArtist()->getId(), artist.getId()); - auto containsType = [&](TrackArtistLinkType type) - { - return std::any_of(std::cbegin(visitedLinks), std::cend(visitedLinks), [type](const TrackArtistLink::pointer& link) { return link->getType() == type;}); - }; + auto containsType = [&](TrackArtistLinkType type) { + return std::any_of(std::cbegin(visitedLinks), std::cend(visitedLinks), [type](const TrackArtistLink::pointer& link) { return link->getType() == type; }); + }; EXPECT_TRUE(containsType(TrackArtistLinkType::Artist)); EXPECT_TRUE(containsType(TrackArtistLinkType::ReleaseArtist)); @@ -441,10 +437,10 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto artists{ track->getArtists({TrackArtistLinkType::Artist}) }; + auto artists{ track->getArtists({ TrackArtistLinkType::Artist }) }; ASSERT_EQ(artists.size(), 2); EXPECT_TRUE((artists[0]->getId() == artist1.getId() && artists[1]->getId() == artist2.getId()) - || (artists[0]->getId() == artist2.getId() && artists[1]->getId() == artist1.getId())); + || (artists[0]->getId() == artist2.getId() && artists[1]->getId() == artist1.getId())); EXPECT_EQ(track->getArtists({}).size(), 2); EXPECT_EQ(track->getArtists({ TrackArtistLinkType::Artist }).size(), 2); @@ -456,7 +452,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto tracks{ Track::findIds(session, Track::FindParameters {}.setArtist(artist1->getId())) }; + auto tracks{ Track::findIds(session, Track::FindParameters{}.setArtist(artist1->getId())) }; ASSERT_EQ(tracks.results.size(), 1); EXPECT_EQ(tracks.results.front(), track->getId()); @@ -481,10 +477,9 @@ namespace lms::db::tests auto transaction{ session.createReadTransaction() }; std::vector visitedLinks; - TrackArtistLink::find(session, TrackArtistLink::FindParameters{}.setTrack(track.getId()), [&](const TrackArtistLink::pointer& link) - { - visitedLinks.push_back(link); - }); + TrackArtistLink::find(session, TrackArtistLink::FindParameters{}.setTrack(track.getId()), [&](const TrackArtistLink::pointer& link) { + visitedLinks.push_back(link); + }); ASSERT_EQ(visitedLinks.size(), 2); EXPECT_EQ(visitedLinks[0]->getArtist()->getId(), artist1.getId()); EXPECT_EQ(visitedLinks[1]->getArtist()->getId(), artist2.getId()); @@ -494,10 +489,9 @@ namespace lms::db::tests auto transaction{ session.createReadTransaction() }; std::vector visitedLinks; - TrackArtistLink::find(session, TrackArtistLink::FindParameters{}.setArtist(artist2.getId()), [&](const TrackArtistLink::pointer& link) - { - visitedLinks.push_back(link); - }); + TrackArtistLink::find(session, TrackArtistLink::FindParameters{}.setArtist(artist2.getId()), [&](const TrackArtistLink::pointer& link) { + visitedLinks.push_back(link); + }); ASSERT_EQ(visitedLinks.size(), 1); EXPECT_EQ(visitedLinks[0]->getArtist()->getId(), artist2.getId()); EXPECT_EQ(visitedLinks[0]->getTrack()->getId(), track.getId()); @@ -507,10 +501,9 @@ namespace lms::db::tests auto transaction{ session.createReadTransaction() }; std::vector> visitedEntries; - TrackArtistLink::find(session, track.getId(), [&](const TrackArtistLink::pointer& link, const Artist::pointer& artist) - { - visitedEntries.push_back(std::make_pair(link, artist)); - }); + TrackArtistLink::find(session, track.getId(), [&](const TrackArtistLink::pointer& link, const Artist::pointer& artist) { + visitedEntries.push_back(std::make_pair(link, artist)); + }); ASSERT_EQ(visitedEntries.size(), 2); EXPECT_EQ(visitedEntries[0].first->getArtist()->getId(), artist1.getId()); EXPECT_EQ(visitedEntries[0].second->getId(), artist1.getId()); @@ -535,11 +528,11 @@ namespace lms::db::tests EXPECT_EQ(Artist::findIds(session, Artist::FindParameters{}.setKeywords({ "N" })).results.size(), 0); - const auto artistsByAAA{ Artist::findIds(session, Artist::FindParameters {}.setKeywords({"A"})) }; + const auto artistsByAAA{ Artist::findIds(session, Artist::FindParameters{}.setKeywords({ "A" })) }; ASSERT_EQ(artistsByAAA.results.size(), 1); EXPECT_EQ(artistsByAAA.results.front(), artist.getId()); - const auto artistsByZZZ{ Artist::Artist::findIds(session, Artist::FindParameters {}.setKeywords({"Z"})) }; + const auto artistsByZZZ{ Artist::Artist::findIds(session, Artist::FindParameters{}.setKeywords({ "Z" })) }; ASSERT_EQ(artistsByZZZ.results.size(), 1); EXPECT_EQ(artistsByZZZ.results.front(), artist.getId()); @@ -583,26 +576,26 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; { - const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setKeywords({"MyArtist"})) }; + const auto artists{ Artist::findIds(session, Artist::FindParameters{}.setKeywords({ "MyArtist" })) }; EXPECT_EQ(artists.results.size(), 6); } { - const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setKeywords({"MyArtist%"}).setSortMethod(ArtistSortMethod::Name)) }; + const auto artists{ Artist::findIds(session, Artist::FindParameters{}.setKeywords({ "MyArtist%" }).setSortMethod(ArtistSortMethod::Name)) }; ASSERT_EQ(artists.results.size(), 2); EXPECT_EQ(artists.results[0], artist1.getId()); EXPECT_EQ(artists.results[1], artist4.getId()); } { - const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setKeywords({"%MyArtist"}).setSortMethod(ArtistSortMethod::Name)) }; + const auto artists{ Artist::findIds(session, Artist::FindParameters{}.setKeywords({ "%MyArtist" }).setSortMethod(ArtistSortMethod::Name)) }; ASSERT_EQ(artists.results.size(), 2); EXPECT_EQ(artists.results[0], artist2.getId()); EXPECT_EQ(artists.results[1], artist5.getId()); } { - const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setKeywords({"_MyArtist"}).setSortMethod(ArtistSortMethod::Name)) }; + const auto artists{ Artist::findIds(session, Artist::FindParameters{}.setKeywords({ "_MyArtist" }).setSortMethod(ArtistSortMethod::Name)) }; ASSERT_EQ(artists.results.size(), 1); EXPECT_EQ(artists.results[0], artist3.getId()); } @@ -624,8 +617,8 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto allArtistsByName{ Artist::findIds(session, Artist::FindParameters {}.setSortMethod(ArtistSortMethod::Name)) }; - auto allArtistsBySortName{ Artist::findIds(session, Artist::FindParameters {}.setSortMethod(ArtistSortMethod::SortName)) }; + auto allArtistsByName{ Artist::findIds(session, Artist::FindParameters{}.setSortMethod(ArtistSortMethod::Name)) }; + auto allArtistsBySortName{ Artist::findIds(session, Artist::FindParameters{}.setSortMethod(ArtistSortMethod::SortName)) }; ASSERT_EQ(allArtistsByName.results.size(), 2); EXPECT_EQ(allArtistsByName.results.front(), artistA.getId()); @@ -647,7 +640,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto tracks{ Track::findIds(session, Track::FindParameters {}.setNonRelease(true).setArtist(artist->getId())) }; + auto tracks{ Track::findIds(session, Track::FindParameters{}.setNonRelease(true).setArtist(artist->getId())) }; EXPECT_EQ(tracks.results.size(), 0); } @@ -663,7 +656,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - const auto tracks{ Track::findIds(session, Track::FindParameters {}.setArtist(artist.getId()).setNonRelease(true)) }; + const auto tracks{ Track::findIds(session, Track::FindParameters{}.setArtist(artist.getId()).setNonRelease(true)) }; ASSERT_EQ(tracks.results.size(), 1); EXPECT_EQ(tracks.results.front(), track2.getId()); } @@ -677,7 +670,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setRelease(release.getId())) }; + const auto artists{ Artist::findIds(session, Artist::FindParameters{}.setRelease(release.getId())) }; EXPECT_EQ(artists.results.size(), 0); } @@ -688,7 +681,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setRelease(release.getId())) }; + const auto artists{ Artist::findIds(session, Artist::FindParameters{}.setRelease(release.getId())) }; EXPECT_EQ(artists.results.size(), 0); } @@ -699,9 +692,9 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setRelease(release.getId())) }; + const auto artists{ Artist::findIds(session, Artist::FindParameters{}.setRelease(release.getId())) }; ASSERT_EQ(artists.results.size(), 1); EXPECT_EQ(artists.results.front(), artist.getId()); } } -} +} // namespace lms::db::tests diff --git a/src/libs/database/test/Cluster.cpp b/src/libs/database/test/Cluster.cpp index edb28da2..d6c5ac0e 100644 --- a/src/libs/database/test/Cluster.cpp +++ b/src/libs/database/test/Cluster.cpp @@ -49,7 +49,7 @@ namespace lms::db::tests EXPECT_EQ(cluster->getType()->getId(), clusterType.getId()); { - const auto clusters{ Cluster::findIds(session, Cluster::FindParameters {}) }; + const auto clusters{ Cluster::findIds(session, Cluster::FindParameters{}) }; ASSERT_EQ(clusters.results.size(), 1); EXPECT_EQ(clusters.results.front(), cluster.getId()); } @@ -118,7 +118,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto clusters{ Cluster::findIds(session, Cluster::FindParameters {}.setTrack(track.getId())) }; + auto clusters{ Cluster::findIds(session, Cluster::FindParameters{}.setTrack(track.getId())) }; ASSERT_EQ(clusters.results.size(), 1); EXPECT_EQ(clusters.results.front(), cluster1.getId()); EXPECT_EQ(Cluster::computeTrackCount(session, cluster1.getId()), 1); @@ -137,7 +137,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto tracks{ Track::findIds(session, Track::FindParameters {}.setClusters(std::initializer_list{cluster1.getId()})) }; + auto tracks{ Track::findIds(session, Track::FindParameters{}.setClusters(std::initializer_list{ cluster1.getId() })) }; ASSERT_EQ(tracks.results.size(), 1); EXPECT_EQ(tracks.results.front(), track.getId()); @@ -243,10 +243,9 @@ namespace lms::db::tests auto transaction{ session.createReadTransaction() }; bool visited{}; - ClusterType::find(session, [&](const ClusterType::pointer&) - { - visited = true; - }); + ClusterType::find(session, [&](const ClusterType::pointer&) { + visited = true; + }); EXPECT_FALSE(visited); } @@ -257,10 +256,9 @@ namespace lms::db::tests auto transaction{ session.createReadTransaction() }; std::vector visitedClusterTypes; - ClusterType::find(session, [&](const ClusterType::pointer& clusterType) - { - visitedClusterTypes.push_back(clusterType->getId()); - }); + ClusterType::find(session, [&](const ClusterType::pointer& clusterType) { + visitedClusterTypes.push_back(clusterType->getId()); + }); ASSERT_EQ(visitedClusterTypes.size(), 2); EXPECT_EQ(visitedClusterTypes[0], clusterType1->getId()); EXPECT_EQ(visitedClusterTypes[1], clusterType2->getId()); @@ -350,7 +348,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - const auto releases{ Release::findIds(session, Release::FindParameters {}.setClusters(std::initializer_list{cluster.getId()})) }; + const auto releases{ Release::findIds(session, Release::FindParameters{}.setClusters(std::initializer_list{ cluster.getId() })) }; ASSERT_EQ(releases.results.size(), 1); EXPECT_EQ(releases.results.front(), release.getId()); } @@ -358,7 +356,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - const auto releases{ Release::findIds(session, Release::FindParameters {}.setClusters(std::initializer_list{unusedCluster.getId()})) }; + const auto releases{ Release::findIds(session, Release::FindParameters{}.setClusters(std::initializer_list{ unusedCluster.getId() })) }; EXPECT_EQ(releases.results.size(), 0); } @@ -404,7 +402,7 @@ namespace lms::db::tests { auto transaction{ session.createWriteTransaction() }; - auto artists{ Artist::findIds(session, Artist::FindParameters {}.setClusters(std::initializer_list{cluster1.getId()})) }; + auto artists{ Artist::findIds(session, Artist::FindParameters{}.setClusters(std::initializer_list{ cluster1.getId() })) }; ASSERT_EQ(artists.results.size(), 1); EXPECT_EQ(artists.results.front(), artist.getId()); @@ -417,7 +415,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto artists{ Artist::findIds(session, Artist::FindParameters {}.setClusters(std::initializer_list{cluster1.getId()})) }; + auto artists{ Artist::findIds(session, Artist::FindParameters{}.setClusters(std::initializer_list{ cluster1.getId() })) }; ASSERT_EQ(artists.results.size(), 1); EXPECT_EQ(artists.results.front(), artist.getId()); @@ -458,7 +456,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto artists{ Artist::findIds(session, Artist::FindParameters {}.setClusters(std::initializer_list{cluster.getId()})) }; + auto artists{ Artist::findIds(session, Artist::FindParameters{}.setClusters(std::initializer_list{ cluster.getId() })) }; ASSERT_EQ(artists.results.size(), 1); EXPECT_EQ(artists.results.front(), artist.getId()); } @@ -500,13 +498,12 @@ namespace lms::db::tests std::vector clusterIds; std::transform(std::cbegin(clusters), std::cend(clusters), std::back_inserter(clusterIds), [](const ScopedCluster& cluster) { return cluster.getId(); }); - auto artists{ Artist::findIds(session, Artist::FindParameters {}.setClusters(clusterIds)) }; + auto artists{ Artist::findIds(session, Artist::FindParameters{}.setClusters(clusterIds)) }; ASSERT_EQ(artists.results.size(), 1); EXPECT_EQ(artists.results.front(), artist.getId()); } } - TEST_F(DatabaseFixture, MultipleTracksSingleClusterSimilarity) { std::list tracks; @@ -526,7 +523,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - const auto similarTracks{ Track::findSimilarTrackIds(session, {tracks.front().getId()}) }; + const auto similarTracks{ Track::findSimilarTrackIds(session, { tracks.front().getId() }) }; EXPECT_EQ(similarTracks.results.size(), tracks.size() - 1); for (const TrackId similarTrackId : similarTracks.results) { @@ -567,14 +564,14 @@ namespace lms::db::tests auto transaction{ session.createReadTransaction() }; { - auto similarTracks{ Track::findSimilarTrackIds(session, {tracks.back().getId()}, Range {0, 4}) }; + auto similarTracks{ Track::findSimilarTrackIds(session, { tracks.back().getId() }, Range{ 0, 4 }) }; EXPECT_EQ(similarTracks.results.size(), 4); for (const TrackId similarTrackId : similarTracks.results) EXPECT_TRUE(std::find_if(std::next(std::cbegin(tracks), 5), std::next(std::cend(tracks), -1), [&](const auto& track) { return similarTrackId == track.getId(); }) != std::cend(tracks)); } { - auto similarTracks{ Track::findSimilarTrackIds(session, {tracks.front().getId()}) }; + auto similarTracks{ Track::findSimilarTrackIds(session, { tracks.front().getId() }) }; EXPECT_EQ(similarTracks.results.size(), tracks.size() - 1); for (const TrackId similarTrackId : similarTracks.results) EXPECT_TRUE(std::find_if(std::next(std::cbegin(tracks), 1), std::cend(tracks), [&](const auto& track) { return similarTrackId == track.getId(); }) != std::cend(tracks)); @@ -610,11 +607,11 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto artists{ Artist::findIds(session, Artist::FindParameters {}.setClusters(std::initializer_list{cluster.getId()})) }; + auto artists{ Artist::findIds(session, Artist::FindParameters{}.setClusters(std::initializer_list{ cluster.getId() })) }; ASSERT_EQ(artists.results.size(), 1); EXPECT_EQ(artists.results.front(), artist.getId()); - auto releases{ Release::findIds(session, Release::FindParameters {}.setArtist(artist.getId())) }; + auto releases{ Release::findIds(session, Release::FindParameters{}.setArtist(artist.getId())) }; ASSERT_EQ(releases.results.size(), 1); EXPECT_EQ(releases.results.front(), release.getId()); @@ -645,7 +642,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto releases{ Release::findIds(session, Release::FindParameters {}.setArtist(artist.getId())) }; + auto releases{ Release::findIds(session, Release::FindParameters{}.setArtist(artist.getId())) }; ASSERT_EQ(releases.results.size(), 1); EXPECT_EQ(releases.results.front(), release.getId()); @@ -790,24 +787,24 @@ namespace lms::db::tests } { - auto artists{ artist1->findSimilarArtistIds({TrackArtistLinkType::Artist}) }; + auto artists{ artist1->findSimilarArtistIds({ TrackArtistLinkType::Artist }) }; ASSERT_EQ(artists.results.size(), 1); EXPECT_EQ(artists.results.front(), artist2.getId()); } { - auto artists{ artist1->findSimilarArtistIds({TrackArtistLinkType::ReleaseArtist}) }; + auto artists{ artist1->findSimilarArtistIds({ TrackArtistLinkType::ReleaseArtist }) }; EXPECT_EQ(artists.results.size(), 0); } { - auto artists{ artist1->findSimilarArtistIds({TrackArtistLinkType::Artist, TrackArtistLinkType::ReleaseArtist}) }; + auto artists{ artist1->findSimilarArtistIds({ TrackArtistLinkType::Artist, TrackArtistLinkType::ReleaseArtist }) }; ASSERT_EQ(artists.results.size(), 1); EXPECT_EQ(artists.results.front(), artist2.getId()); } { - auto artists{ artist1->findSimilarArtistIds({TrackArtistLinkType::Composer}) }; + auto artists{ artist1->findSimilarArtistIds({ TrackArtistLinkType::Composer }) }; EXPECT_EQ(artists.results.size(), 0); } @@ -878,4 +875,4 @@ namespace lms::db::tests } } } -} \ No newline at end of file +} // namespace lms::db::tests \ No newline at end of file diff --git a/src/libs/database/test/Common.cpp b/src/libs/database/test/Common.cpp index 4ffe33d2..b61399b7 100644 --- a/src/libs/database/test/Common.cpp +++ b/src/libs/database/test/Common.cpp @@ -109,13 +109,13 @@ namespace lms::db::tests results.moreResults = false; { - auto subRange{ results.getSubRange(Range {0, 0}) }; + auto subRange{ results.getSubRange(Range{ 0, 0 }) }; EXPECT_FALSE(subRange.moreResults); ASSERT_EQ(subRange.results.size(), 0); EXPECT_EQ(subRange.range, Range{}); } { - auto subRange{ results.getSubRange(Range {0, 1}) }; + auto subRange{ results.getSubRange(Range{ 0, 1 }) }; EXPECT_FALSE(subRange.moreResults); ASSERT_EQ(subRange.results.size(), 0); } @@ -130,28 +130,26 @@ namespace lms::db::tests std::vector expectedSubRanges; }; - TestCase testCases[] - { - {Range{0, 0}, 1, {}}, - {Range{1, 0}, 1, {}}, - {Range{1, 1}, 1, { Range{ 1,1 } }}, - {Range{1, 3}, 1, { Range{ 1,1 }, Range {2,1}, Range{3,1} }}, - {Range{0, 100}, 100, { Range{0,100} }}, - {Range{0, 50}, 100, { Range{0,50} }}, - {Range{100, 200}, 100, { Range{100,100}, Range{200,100} }}, - {Range{100, 101}, 100, { Range{100,100}, Range{200,1}}}, - {Range{1000, 10}, 100, { Range{1000,10} }}, - {Range{1, 100}, 50, { Range{1,50}, Range{51, 50} }}, + TestCase testCases[]{ + { Range{ 0, 0 }, 1, {} }, + { Range{ 1, 0 }, 1, {} }, + { Range{ 1, 1 }, 1, { Range{ 1, 1 } } }, + { Range{ 1, 3 }, 1, { Range{ 1, 1 }, Range{ 2, 1 }, Range{ 3, 1 } } }, + { Range{ 0, 100 }, 100, { Range{ 0, 100 } } }, + { Range{ 0, 50 }, 100, { Range{ 0, 50 } } }, + { Range{ 100, 200 }, 100, { Range{ 100, 100 }, Range{ 200, 100 } } }, + { Range{ 100, 101 }, 100, { Range{ 100, 100 }, Range{ 200, 1 } } }, + { Range{ 1000, 10 }, 100, { Range{ 1000, 10 } } }, + { Range{ 1, 100 }, 50, { Range{ 1, 50 }, Range{ 51, 50 } } }, }; for (const TestCase& test : testCases) { std::vector subRanges; - foreachSubRange(test.range, test.subRangeSize, [&](Range subRange) - { - subRanges.push_back(subRange); - return true; - }); + foreachSubRange(test.range, test.subRangeSize, [&](Range subRange) { + subRanges.push_back(subRange); + return true; + }); EXPECT_EQ(subRanges, test.expectedSubRanges) << ", test index = " << std::distance(std::cbegin(testCases), &test); } @@ -192,26 +190,26 @@ namespace lms::db::tests results.moreResults = false; { - auto subRange{ results.getSubRange(Range {0, 1}) }; + auto subRange{ results.getSubRange(Range{ 0, 1 }) }; EXPECT_TRUE(subRange.moreResults); ASSERT_EQ(subRange.results.size(), 1); EXPECT_EQ(subRange.results.front(), 5); } { - auto subRange{ results.getSubRange(Range {1, 1}) }; + auto subRange{ results.getSubRange(Range{ 1, 1 }) }; EXPECT_FALSE(subRange.moreResults); ASSERT_EQ(subRange.results.size(), 1); EXPECT_EQ(subRange.results.front(), 6); } { - auto subRange{ results.getSubRange(Range {0, 2}) }; + auto subRange{ results.getSubRange(Range{ 0, 2 }) }; EXPECT_FALSE(subRange.moreResults); ASSERT_EQ(subRange.results.size(), 2); EXPECT_EQ(subRange.results.front(), 5); EXPECT_EQ(subRange.results.back(), 6); } { - auto subRange{ results.getSubRange(Range {}) }; + auto subRange{ results.getSubRange(Range{}) }; EXPECT_FALSE(subRange.moreResults); ASSERT_EQ(subRange.results.size(), 2); EXPECT_EQ(subRange.results.front(), 5); @@ -220,7 +218,7 @@ namespace lms::db::tests } { - auto subRange{ results.getSubRange(Range {1, 0}) }; + auto subRange{ results.getSubRange(Range{ 1, 0 }) }; EXPECT_FALSE(subRange.moreResults); ASSERT_EQ(subRange.results.size(), 1); EXPECT_EQ(subRange.results.front(), 6); @@ -228,11 +226,11 @@ namespace lms::db::tests EXPECT_EQ(subRange.range, expectedRange); } { - auto subRange{ results.getSubRange(Range {3, 2}) }; + auto subRange{ results.getSubRange(Range{ 3, 2 }) }; EXPECT_FALSE(subRange.moreResults); ASSERT_EQ(subRange.results.size(), 0); const Range expectedRange{ 2, 0 }; EXPECT_EQ(subRange.range, expectedRange); } } -} \ No newline at end of file +} // namespace lms::db::tests \ No newline at end of file diff --git a/src/libs/database/test/Common.hpp b/src/libs/database/test/Common.hpp index 0b9268cd..45f53db5 100644 --- a/src/libs/database/test/Common.hpp +++ b/src/libs/database/test/Common.hpp @@ -42,14 +42,14 @@ namespace lms::db::tests { - template + template class [[nodiscard]] ScopedEntity { public: using IdType = typename T::IdType; - template - ScopedEntity(db::Session& session, Args&& ...args) + template + ScopedEntity(db::Session& session, Args&&... args) : _session{ session } { auto transaction{ _session.createWriteTransaction() }; @@ -113,7 +113,8 @@ namespace lms::db::tests class ScopedFileDeleter final { public: - ScopedFileDeleter(const std::filesystem::path& path) : _path{ path } {} + ScopedFileDeleter(const std::filesystem::path& path) + : _path{ path } {} ~ScopedFileDeleter() { std::filesystem::remove(_path); } private: @@ -155,4 +156,4 @@ namespace lms::db::tests public: db::Session session{ _tmpDb->getDb() }; }; -} \ No newline at end of file +} // namespace lms::db::tests \ No newline at end of file diff --git a/src/libs/database/test/DatabaseTest.cpp b/src/libs/database/test/DatabaseTest.cpp index 7d2c4840..5454f718 100644 --- a/src/libs/database/test/DatabaseTest.cpp +++ b/src/libs/database/test/DatabaseTest.cpp @@ -49,11 +49,11 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto releases{ Release::findIds(session, Release::FindParameters {}.setArtist(artist.getId())) }; + auto releases{ Release::findIds(session, Release::FindParameters{}.setArtist(artist.getId())) }; ASSERT_EQ(releases.results.size(), 1); EXPECT_EQ(releases.results.front(), release.getId()); - const auto releaseTracks{ Track::find(session, Track::FindParameters {}.setRelease(release.getId())) }; + const auto releaseTracks{ Track::find(session, Track::FindParameters{}.setRelease(release.getId())) }; EXPECT_EQ(releaseTracks.results.size(), nbTracks); } } @@ -74,7 +74,7 @@ namespace lms::db::tests { auto transaction{ session.createWriteTransaction() }; - auto releases{ Release::findIds(session, Release::FindParameters {}.setArtist(artist.getId())) }; + auto releases{ Release::findIds(session, Release::FindParameters{}.setArtist(artist.getId())) }; ASSERT_EQ(releases.results.size(), 1); EXPECT_EQ(releases.results.front(), release.getId()); @@ -101,7 +101,7 @@ namespace lms::db::tests EXPECT_EQ(User::getCount(session), 1); } } -} +} // namespace lms::db::tests int main(int argc, char** argv) { diff --git a/src/libs/database/test/Listen.cpp b/src/libs/database/test/Listen.cpp index f50246d6..7f299798 100644 --- a/src/libs/database/test/Listen.cpp +++ b/src/libs/database/test/Listen.cpp @@ -17,9 +17,10 @@ * along with LMS. If not, see . */ -#include "Common.hpp" #include "database/Listen.hpp" +#include "Common.hpp" + namespace lms::db::tests { using ScopedListen = ScopedEntity; @@ -35,7 +36,7 @@ namespace lms::db::tests EXPECT_EQ(Listen::getCount(session), 0); } - ScopedListen listen{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, Wt::WDateTime {Wt::WDate{2000, 1, 2}, Wt::WTime{12, 0, 1}} }; + ScopedListen listen{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, Wt::WDateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } } }; { auto transaction{ session.createReadTransaction() }; @@ -45,7 +46,7 @@ namespace lms::db::tests { auto transaction{ session.createWriteTransaction() }; - ScopedListen listen2{ session, user.get(), track.get(), ScrobblingBackend::Internal, Wt::WDateTime {Wt::WDate{2000, 1, 2}, Wt::WTime{13, 0, 1}} }; + ScopedListen listen2{ session, user.get(), track.get(), ScrobblingBackend::Internal, Wt::WDateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 13, 0, 1 } } }; EXPECT_EQ(Listen::getCount(session), 2); } @@ -61,7 +62,7 @@ namespace lms::db::tests { ScopedTrack track{ session }; ScopedUser user{ session, "MyUser" }; - ScopedListen listen{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, Wt::WDateTime {Wt::WDate{2000, 1, 2}, Wt::WTime{12, 0, 1}} }; + ScopedListen listen{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, Wt::WDateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } } }; { auto transaction{ session.createReadTransaction() }; @@ -95,9 +96,9 @@ namespace lms::db::tests { ScopedTrack track{ session }; ScopedUser user{ session, "MyUser" }; - ScopedListen listen3{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, Wt::WDateTime {Wt::WDate{2000, 1, 2}, Wt::WTime{12, 0, 3}} }; - ScopedListen listen1{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, Wt::WDateTime {Wt::WDate{2000, 1, 2}, Wt::WTime{12, 0, 1}} }; - ScopedListen listen2{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, Wt::WDateTime {Wt::WDate{2000, 1, 2}, Wt::WTime{12, 0, 2}} }; + ScopedListen listen3{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, Wt::WDateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 3 } } }; + ScopedListen listen1{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, Wt::WDateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } } }; + ScopedListen listen2{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, Wt::WDateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 2 } } }; { auto transaction{ session.createReadTransaction() }; @@ -114,8 +115,8 @@ namespace lms::db::tests { ScopedTrack track{ session }; ScopedUser user{ session, "MyUser" }; - const Wt::WDateTime dateTime1{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} }; - const Wt::WDateTime dateTime2{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 2} }; + const Wt::WDateTime dateTime1{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; + const Wt::WDateTime dateTime2{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 2 } }; ASSERT_GT(dateTime2, dateTime1); ScopedListen listen1{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime1 }; @@ -147,7 +148,7 @@ namespace lms::db::tests { ScopedTrack track1{ session }; ScopedUser user{ session, "MyUser" }; - const Wt::WDateTime dateTime1{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} }; + const Wt::WDateTime dateTime1{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedListen listen1{ session, user.lockAndGet(), track1.lockAndGet(), ScrobblingBackend::Internal, dateTime1 }; { @@ -230,7 +231,7 @@ namespace lms::db::tests ScopedArtist artist1{ session, "MyArtist1" }; ScopedTrack track2{ session }; ScopedArtist artist2{ session, "MyArtist2" }; - const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; { auto transaction{ session.createWriteTransaction() }; @@ -296,7 +297,7 @@ namespace lms::db::tests ScopedTrack track{ session }; ScopedUser user{ session, "MyUser" }; ScopedArtist artist{ session, "MyArtist" }; - const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedListen listen{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime }; ScopedClusterType clusterType{ session, "MyType" }; ScopedCluster cluster{ session, clusterType.lockAndGet(), "MyCluster" }; @@ -340,7 +341,7 @@ namespace lms::db::tests ScopedTrack track{ session }; ScopedArtist artist{ session, "MyArtist" }; ScopedUser user{ session, "MyUser" }; - const Wt::WDateTime dateTime1{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} }; + const Wt::WDateTime dateTime1{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedListen listen{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime1 }; ScopedMediaLibrary library{ session }; ScopedMediaLibrary otherLibrary{ session }; @@ -405,7 +406,7 @@ namespace lms::db::tests { ScopedTrack track{ session }; ScopedUser user{ session, "MyUser" }; - const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedRelease release{ session, "MyRelease" }; { auto transaction{ session.createWriteTransaction() }; @@ -456,7 +457,7 @@ namespace lms::db::tests ScopedTrack track1{ session }; ScopedTrack track2{ session }; ScopedUser user{ session, "MyUser" }; - const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedListen listen1{ session, user.lockAndGet(), track1.lockAndGet(), ScrobblingBackend::Internal, dateTime }; ScopedRelease release1{ session, "MyRelease1" }; ScopedRelease release2{ session, "MyRelease2" }; @@ -515,7 +516,7 @@ namespace lms::db::tests { ScopedTrack track{ session }; ScopedUser user{ session, "MyUser" }; - const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedListen listen{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime }; ScopedClusterType clusterType{ session, "MyType" }; ScopedCluster cluster{ session, clusterType.lockAndGet(), "MyCluster" }; @@ -560,7 +561,7 @@ namespace lms::db::tests { ScopedTrack track{ session }; ScopedUser user{ session, "MyUser" }; - const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedRelease release{ session, "MyRelease" }; ScopedMediaLibrary library{ session }; ScopedMediaLibrary otherLibrary{ session }; @@ -617,7 +618,7 @@ namespace lms::db::tests { ScopedTrack track{ session }; ScopedUser user{ session, "MyUser" }; - const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; { auto transaction{ session.createReadTransaction() }; @@ -663,7 +664,7 @@ namespace lms::db::tests ScopedTrack track{ session }; ScopedUser user{ session, "MyUser" }; ScopedArtist artist{ session, "MyArtist" }; - const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; { auto transaction{ session.createReadTransaction() }; @@ -717,7 +718,7 @@ namespace lms::db::tests ScopedTrack track1{ session }; ScopedTrack track2{ session }; ScopedUser user{ session, "MyUser" }; - const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedListen listen1{ session, user.lockAndGet(), track1.lockAndGet(), ScrobblingBackend::Internal, dateTime }; { @@ -768,7 +769,7 @@ namespace lms::db::tests { ScopedTrack track{ session }; ScopedUser user{ session, "MyUser" }; - const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedListen listen{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime }; ScopedClusterType clusterType{ session, "MyType" }; ScopedCluster cluster{ session, clusterType.lockAndGet(), "MyCluster" }; @@ -807,7 +808,7 @@ namespace lms::db::tests { ScopedTrack track{ session }; ScopedUser user{ session, "MyUser" }; - const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedMediaLibrary library{ session }; ScopedMediaLibrary otherLibrary{ session }; @@ -881,7 +882,7 @@ namespace lms::db::tests EXPECT_EQ(artists.moreResults, false); } - const Wt::WDateTime dateTime{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedListen listen1{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime }; { @@ -941,7 +942,7 @@ namespace lms::db::tests ScopedArtist artist1{ session, "MyArtist1" }; ScopedTrack track2{ session }; ScopedArtist artist2{ session, "MyArtist2" }; - const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; { auto transaction{ session.createWriteTransaction() }; @@ -1006,7 +1007,7 @@ namespace lms::db::tests ScopedTrack track{ session }; ScopedUser user{ session, "MyUser" }; ScopedArtist artist{ session, "MyArtist" }; - const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedListen listen{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime }; ScopedClusterType clusterType{ session, "MyType" }; ScopedCluster cluster{ session, clusterType.lockAndGet(), "MyCluster" }; @@ -1045,7 +1046,6 @@ namespace lms::db::tests } } - TEST_F(DatabaseFixture, Listen_getRecentArtists_mediaLibrary) { ScopedTrack track{ session }; @@ -1060,7 +1060,7 @@ namespace lms::db::tests track.get().modify()->setMediaLibrary(library.get()); } - const Wt::WDateTime dateTime{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedListen listen1{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime }; { @@ -1107,7 +1107,7 @@ namespace lms::db::tests ASSERT_EQ(releases.results.size(), 0); } - const Wt::WDateTime dateTime{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedListen listen1{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime }; { @@ -1153,7 +1153,7 @@ namespace lms::db::tests EXPECT_FALSE(listen); } - const Wt::WDateTime dateTime1{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} }; + const Wt::WDateTime dateTime1{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedListen listen1{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime1 }; { @@ -1164,7 +1164,7 @@ namespace lms::db::tests EXPECT_EQ(listen->getDateTime(), dateTime1); } - const Wt::WDateTime dateTime2{ Wt::WDate {1999, 1, 2}, Wt::WTime {12,0, 1} }; + const Wt::WDateTime dateTime2{ Wt::WDate{ 1999, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedListen listen2{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime2 }; { @@ -1175,7 +1175,7 @@ namespace lms::db::tests EXPECT_EQ(listen->getDateTime(), dateTime1); } - const Wt::WDateTime dateTime3{ Wt::WDate {2001, 1, 2}, Wt::WTime {12,0, 1} }; + const Wt::WDateTime dateTime3{ Wt::WDate{ 2001, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedListen listen3{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime3 }; { @@ -1201,7 +1201,7 @@ namespace lms::db::tests track2.get().modify()->setRelease(release2.get()); } - const Wt::WDateTime dateTime{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedListen listen1{ session, user.lockAndGet(), track2.lockAndGet(), ScrobblingBackend::Internal, dateTime }; { @@ -1287,7 +1287,7 @@ namespace lms::db::tests EXPECT_EQ(releases.results.size(), 0); } - const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedListen listen{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime }; { @@ -1334,7 +1334,7 @@ namespace lms::db::tests track.get().modify()->setMediaLibrary(library.get()); } - const Wt::WDateTime dateTime{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedListen listen1{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime }; { @@ -1377,7 +1377,7 @@ namespace lms::db::tests ASSERT_EQ(tracks.results.size(), 0); } - const Wt::WDateTime dateTime{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedListen listen1{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime }; { @@ -1406,7 +1406,6 @@ namespace lms::db::tests } } - TEST_F(DatabaseFixture, Listen_getRecentTracks_mediaLibrary) { ScopedTrack track{ session }; @@ -1414,7 +1413,7 @@ namespace lms::db::tests ScopedMediaLibrary library{ session }; ScopedMediaLibrary otherLibrary{ session }; - const Wt::WDateTime dateTime{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedListen listen1{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime }; { @@ -1458,7 +1457,7 @@ namespace lms::db::tests EXPECT_EQ(count, 0); } - const Wt::WDateTime dateTime1{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} }; + const Wt::WDateTime dateTime1{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedListen listen1{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime1 }; { @@ -1487,15 +1486,14 @@ namespace lms::db::tests ScopedUser user{ session, "MyUser" }; ScopedRelease release{ session, "MyRelease" }; - auto getReleaseListenCount{ [&] - { + auto getReleaseListenCount{ [&] { auto transaction{ session.createReadTransaction() }; return Listen::getCount(session, user->getId(), release.getId()); } }; EXPECT_EQ(getReleaseListenCount(), 0); - const Wt::WDateTime dateTime1{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} }; + const Wt::WDateTime dateTime1{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedListen listen1{ session, user.lockAndGet(), track1.lockAndGet(), ScrobblingBackend::Internal, dateTime1 }; EXPECT_EQ(getReleaseListenCount(), 0); @@ -1540,7 +1538,7 @@ namespace lms::db::tests EXPECT_FALSE(listen); } - const Wt::WDateTime dateTime1{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} }; + const Wt::WDateTime dateTime1{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedListen listen1{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime1 }; { @@ -1551,7 +1549,7 @@ namespace lms::db::tests EXPECT_EQ(listen->getDateTime(), dateTime1); } - const Wt::WDateTime dateTime2{ Wt::WDate {1999, 1, 2}, Wt::WTime {12,0, 1} }; + const Wt::WDateTime dateTime2{ Wt::WDate{ 1999, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedListen listen2{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime2 }; { @@ -1562,7 +1560,7 @@ namespace lms::db::tests EXPECT_EQ(listen->getDateTime(), dateTime1); } - const Wt::WDateTime dateTime3{ Wt::WDate {2001, 1, 2}, Wt::WTime {12,0, 1} }; + const Wt::WDateTime dateTime3{ Wt::WDate{ 2001, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedListen listen3{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime3 }; { @@ -1580,7 +1578,7 @@ namespace lms::db::tests ScopedTrack track2{ session }; ScopedUser user{ session, "MyUser" }; - const Wt::WDateTime dateTime{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedListen listen1{ session, user.lockAndGet(), track2.lockAndGet(), ScrobblingBackend::Internal, dateTime }; { @@ -1646,7 +1644,7 @@ namespace lms::db::tests { ScopedTrack track{ session }; ScopedUser user{ session, "MyUser" }; - const Wt::WDateTime dateTime{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } }; ScopedListen listen{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime }; ScopedClusterType clusterType{ session, "MyType" }; ScopedCluster cluster{ session, clusterType.lockAndGet(), "MyCluster" }; @@ -1680,4 +1678,4 @@ namespace lms::db::tests EXPECT_EQ(tracks.results[0], track.getId()); } } -} \ No newline at end of file +} // namespace lms::db::tests \ No newline at end of file diff --git a/src/libs/database/test/Migration.cpp b/src/libs/database/test/Migration.cpp index b7158bcc..e6d53fc4 100644 --- a/src/libs/database/test/Migration.cpp +++ b/src/libs/database/test/Migration.cpp @@ -34,7 +34,7 @@ namespace lms::db::tests session.execute(statement); } } - } + } // namespace TEST(Database, migration) { @@ -263,7 +263,7 @@ CREATE INDEX starred_artist_user_scrobbler_idx ON starred_artist(user_id,scrobbl CREATE INDEX starred_release_user_scrobbler_idx ON starred_release(user_id,scrobbler); CREATE INDEX starred_track_user_scrobbler_idx ON starred_track(user_id,scrobbler);)" }; - const std::string_view createDummyData{R"( + const std::string_view createDummyData{ R"( -- Inserting artists INSERT INTO artist (version, name, sort_name, mbid) VALUES (1, 'Artist A', 'Artist A', 'mbid_artist_a'), @@ -302,7 +302,7 @@ VALUES INSERT INTO track_artist_link (version, type, name, track_id, artist_id) VALUES (1, 1, 'Artist A', 5, 1), -(2, 1, 'Artist B', 6, 2);)"}; +(2, 1, 'Artist B', 6, 2);)" }; Session session{ db }; @@ -319,4 +319,4 @@ VALUES // Now perform full migration db.getTLSSession().migrateSchemaIfNeeded(); } -} \ No newline at end of file +} // namespace lms::db::tests \ No newline at end of file diff --git a/src/libs/database/test/Release.cpp b/src/libs/database/test/Release.cpp index 8f78a71d..c0b7cb48 100644 --- a/src/libs/database/test/Release.cpp +++ b/src/libs/database/test/Release.cpp @@ -50,25 +50,24 @@ namespace lms::db::tests } { - const auto releases{ Release::findIds(session, Release::FindParameters {}) }; + const auto releases{ Release::findIds(session, Release::FindParameters{}) }; ASSERT_EQ(releases.results.size(), 1); EXPECT_EQ(releases.results.front(), release.getId()); EXPECT_EQ(release->getDuration(), std::chrono::seconds{ 0 }); } { - const auto releases{ Release::find(session, Release::FindParameters {}) }; + const auto releases{ Release::find(session, Release::FindParameters{}) }; ASSERT_EQ(releases.results.size(), 1); EXPECT_EQ(releases.results.front()->getId(), release.getId()); } { bool visited{}; - Release::find(session, Release::FindParameters{}, [&](const Release::pointer& r) - { - visited = true; - EXPECT_EQ(r->getId(), release.getId()); - }); + Release::find(session, Release::FindParameters{}, [&](const Release::pointer& r) { + visited = true; + EXPECT_EQ(r->getId(), release.getId()); + }); EXPECT_TRUE(visited); } } @@ -101,10 +100,9 @@ namespace lms::db::tests ReleaseId lastRetrievedId; std::vector visitedReleases; - Release::find(session, lastRetrievedId, 10, [&](const Release::pointer& release) - { - visitedReleases.push_back(release); - }); + Release::find(session, lastRetrievedId, 10, [&](const Release::pointer& release) { + visitedReleases.push_back(release); + }); ASSERT_EQ(visitedReleases.size(), 3); EXPECT_EQ(visitedReleases[0]->getId(), release1.getId()); EXPECT_EQ(visitedReleases[1]->getId(), release2.getId()); @@ -117,10 +115,9 @@ namespace lms::db::tests ReleaseId lastRetrievedId{ release1.getId() }; std::vector visitedReleases; - Release::find(session, lastRetrievedId, 1, [&](const Release::pointer& release) - { - visitedReleases.push_back(release); - }); + Release::find(session, lastRetrievedId, 1, [&](const Release::pointer& release) { + visitedReleases.push_back(release); + }); ASSERT_EQ(visitedReleases.size(), 1); EXPECT_EQ(visitedReleases[0]->getId(), release2.getId()); EXPECT_EQ(lastRetrievedId, release2.getId()); @@ -131,10 +128,9 @@ namespace lms::db::tests ReleaseId lastRetrievedId{ release1.getId() }; std::vector visitedReleases; - Release::find(session, lastRetrievedId, 0, [&](const Release::pointer& release) - { - visitedReleases.push_back(release); - }); + Release::find(session, lastRetrievedId, 0, [&](const Release::pointer& release) { + visitedReleases.push_back(release); + }); ASSERT_EQ(visitedReleases.size(), 0); EXPECT_EQ(lastRetrievedId, release1.getId()); } @@ -144,10 +140,11 @@ namespace lms::db::tests ReleaseId lastRetrievedId; std::vector visitedReleases; - Release::find(session, lastRetrievedId, 10, [&](const Release::pointer& release) - { + Release::find( + session, lastRetrievedId, 10, [&](const Release::pointer& release) { visitedReleases.push_back(release); - }, otherLibrary.getId()); + }, + otherLibrary.getId()); ASSERT_EQ(visitedReleases.size(), 0); EXPECT_EQ(lastRetrievedId, ReleaseId{}); } @@ -157,10 +154,11 @@ namespace lms::db::tests ReleaseId lastRetrievedId; std::vector visitedReleases; - Release::find(session, lastRetrievedId, 10, [&](const Release::pointer& release) - { + Release::find( + session, lastRetrievedId, 10, [&](const Release::pointer& release) { visitedReleases.push_back(release); - }, library.getId()); + }, + library.getId()); ASSERT_EQ(visitedReleases.size(), 1); EXPECT_EQ(visitedReleases[0]->getId(), release2.getId()); EXPECT_EQ(lastRetrievedId, release2.getId()); @@ -185,7 +183,7 @@ namespace lms::db::tests auto transaction{ session.createReadTransaction() }; EXPECT_EQ(Release::findOrphanIds(session).results.size(), 0); - const auto tracks{ Track::findIds(session, Track::FindParameters {}.setRelease(release.getId())) }; + const auto tracks{ Track::findIds(session, Track::FindParameters{}.setRelease(release.getId())) }; ASSERT_EQ(tracks.results.size(), 1); EXPECT_EQ(tracks.results.front(), track.getId()); } @@ -218,7 +216,7 @@ namespace lms::db::tests { auto transaction{ session.createWriteTransaction() }; - const auto tracks{ Track::findIds(session, Track::FindParameters {}.setRelease(release.getId())) }; + const auto tracks{ Track::findIds(session, Track::FindParameters{}.setRelease(release.getId())) }; EXPECT_EQ(tracks.results.size(), 0); auto releases{ Release::findOrphanIds(session) }; @@ -318,34 +316,34 @@ namespace lms::db::tests auto transaction{ session.createReadTransaction() }; { - const auto releases{ Release::findIds(session, Release::FindParameters {}.setKeywords({"Release"})) }; + const auto releases{ Release::findIds(session, Release::FindParameters{}.setKeywords({ "Release" })) }; EXPECT_EQ(releases.results.size(), 6); } { - const auto releases{ Release::findIds(session, Release::FindParameters {}.setKeywords({"MyRelease"})) }; + const auto releases{ Release::findIds(session, Release::FindParameters{}.setKeywords({ "MyRelease" })) }; ASSERT_EQ(releases.results.size(), 5); EXPECT_TRUE(std::none_of(std::cbegin(releases.results), std::cend(releases.results), [&](const ReleaseId releaseId) { return releaseId == release6.getId(); })); } { - const auto releases{ Release::findIds(session, Release::FindParameters {}.setKeywords({"MyRelease%"})) }; + const auto releases{ Release::findIds(session, Release::FindParameters{}.setKeywords({ "MyRelease%" })) }; ASSERT_EQ(releases.results.size(), 2); EXPECT_EQ(releases.results[0], release2.getId()); EXPECT_EQ(releases.results[1], release4.getId()); } { - const auto releases{ Release::findIds(session, Release::FindParameters {}.setKeywords({"%MyRelease"})) }; + const auto releases{ Release::findIds(session, Release::FindParameters{}.setKeywords({ "%MyRelease" })) }; ASSERT_EQ(releases.results.size(), 2); EXPECT_EQ(releases.results[0], release3.getId()); EXPECT_EQ(releases.results[1], release5.getId()); } { - const auto releases{ Release::findIds(session, Release::FindParameters {}.setKeywords({"Foo%MyRelease"})) }; + const auto releases{ Release::findIds(session, Release::FindParameters{}.setKeywords({ "Foo%MyRelease" })) }; ASSERT_EQ(releases.results.size(), 1); EXPECT_EQ(releases.results[0], release5.getId()); } { - const auto releases{ Release::findIds(session, Release::FindParameters {}.setKeywords({"MyRelease%Foo"})) }; + const auto releases{ Release::findIds(session, Release::FindParameters{}.setKeywords({ "MyRelease%Foo" })) }; ASSERT_EQ(releases.results.size(), 1); EXPECT_EQ(releases.results[0], release4.getId()); } @@ -476,13 +474,13 @@ namespace lms::db::tests auto transaction{ session.createReadTransaction() }; { - const auto tracks{ Track::findIds(session, Track::FindParameters {}.setRelease(release1.getId()).setSortMethod(TrackSortMethod::Release)) }; + const auto tracks{ Track::findIds(session, Track::FindParameters{}.setRelease(release1.getId()).setSortMethod(TrackSortMethod::Release)) }; EXPECT_EQ(tracks.results.size(), 2); EXPECT_EQ(tracks.results.front(), track1A.getId()); } { - const auto tracks{ Track::findIds(session, Track::FindParameters {}.setRelease(release2.getId()).setSortMethod(TrackSortMethod::Release)) }; + const auto tracks{ Track::findIds(session, Track::FindParameters{}.setRelease(release2.getId()).setSortMethod(TrackSortMethod::Release)) }; EXPECT_EQ(tracks.results.size(), 2); EXPECT_EQ(tracks.results.front(), track2B.getId()); } @@ -493,8 +491,8 @@ namespace lms::db::tests { ScopedRelease release1{ session, "MyRelease1" }; ScopedRelease release2{ session, "MyRelease2" }; - const Wt::WDate release1Date{ Wt::WDate {1994, 2, 3} }; - const Wt::WDate release1OriginalDate{ Wt::WDate {1993, 4, 5} }; + const Wt::WDate release1Date{ Wt::WDate{ 1994, 2, 3 } }; + const Wt::WDate release1OriginalDate{ Wt::WDate{ 1993, 4, 5 } }; ScopedTrack track1A{ session }; ScopedTrack track1B{ session }; @@ -504,7 +502,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - const auto releases{ Release::findIds(session, Release::FindParameters {}.setDateRange(DateRange::fromYearRange(0, 3000))) }; + const auto releases{ Release::findIds(session, Release::FindParameters{}.setDateRange(DateRange::fromYearRange(0, 3000))) }; EXPECT_EQ(releases.results.size(), 0); } @@ -528,7 +526,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto releases{ Release::findIds(session, Release::FindParameters {}.setDateRange(DateRange::fromYearRange(1950, 2000))) }; + auto releases{ Release::findIds(session, Release::FindParameters{}.setDateRange(DateRange::fromYearRange(1950, 2000))) }; ASSERT_EQ(releases.results.size(), 1); EXPECT_EQ(releases.results.front(), release1.getId()); @@ -556,7 +554,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - const auto releases{ Release::findIds(session, Release::FindParameters {}.setDateRange(DateRange::fromYearRange(0, 3000))) }; + const auto releases{ Release::findIds(session, Release::FindParameters{}.setDateRange(DateRange::fromYearRange(0, 3000))) }; EXPECT_EQ(releases.results.size(), 0); } @@ -568,7 +566,6 @@ namespace lms::db::tests track2A.get().modify()->setRelease(release2.get()); track2B.get().modify()->setRelease(release2.get()); - track1A.get().modify()->setYear(release1Year); track1B.get().modify()->setYear(release1Year); track1A.get().modify()->setOriginalYear(release1OriginalYear); @@ -581,7 +578,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto releases{ Release::findIds(session, Release::FindParameters {}.setDateRange(DateRange::fromYearRange(1950, 2000))) }; + auto releases{ Release::findIds(session, Release::FindParameters{}.setDateRange(DateRange::fromYearRange(1950, 2000))) }; ASSERT_EQ(releases.results.size(), 1); EXPECT_EQ(releases.results.front(), release1.getId()); @@ -599,7 +596,7 @@ namespace lms::db::tests ScopedRelease release{ session, "MyRelease" }; ScopedTrack track{ session }; - const Wt::WDateTime dateTime{ Wt::WDate {1950, 1, 1}, Wt::WTime {12, 30, 20} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 1950, 1, 1 }, Wt::WTime{ 12, 30, 20 } }; { auto transaction{ session.createWriteTransaction() }; @@ -609,19 +606,19 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - const auto releases{ Release::findIds(session, Release::FindParameters {}) }; + const auto releases{ Release::findIds(session, Release::FindParameters{}) }; EXPECT_EQ(releases.results.size(), 1); } { auto transaction{ session.createReadTransaction() }; - const auto releases{ Release::findIds(session, Release::FindParameters {}.setWrittenAfter(dateTime.addSecs(-1))) }; + const auto releases{ Release::findIds(session, Release::FindParameters{}.setWrittenAfter(dateTime.addSecs(-1))) }; EXPECT_EQ(releases.results.size(), 1); } { auto transaction{ session.createReadTransaction() }; - const auto releases{ Release::findIds(session, Release::FindParameters {}.setWrittenAfter(dateTime.addSecs(+1))) }; + const auto releases{ Release::findIds(session, Release::FindParameters{}.setWrittenAfter(dateTime.addSecs(+1))) }; EXPECT_EQ(releases.results.size(), 0); } } @@ -640,7 +637,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto releases{ Release::findIds(session, Release::FindParameters {}.setArtist(artist.getId(), {TrackArtistLinkType::Artist})) }; + auto releases{ Release::findIds(session, Release::FindParameters{}.setArtist(artist.getId(), { TrackArtistLinkType::Artist })) }; EXPECT_EQ(releases.results.size(), 0); releases = Release::findIds(session, Release::FindParameters{}.setArtist(artist2.getId(), { TrackArtistLinkType::Artist })); @@ -651,7 +648,7 @@ namespace lms::db::tests auto transaction{ session.createWriteTransaction() }; TrackArtistLink::create(session, track.get(), artist.get(), TrackArtistLinkType::Artist); - auto releases{ Release::findIds(session, Release::FindParameters {}.setArtist(artist.getId(), {TrackArtistLinkType::Artist})) }; + auto releases{ Release::findIds(session, Release::FindParameters{}.setArtist(artist.getId(), { TrackArtistLinkType::Artist })) }; ASSERT_EQ(releases.results.size(), 1); EXPECT_EQ(releases.results.front(), release.getId()); @@ -810,11 +807,11 @@ namespace lms::db::tests TEST_F(DatabaseFixture, Release_sortMethod) { ScopedRelease release1{ session, "MyRelease1" }; - const Wt::WDate release1Date{ Wt::WDate {2000, 2, 3} }; - const Wt::WDate release1OriginalDate{ Wt::WDate {1993, 4, 5} }; + const Wt::WDate release1Date{ Wt::WDate{ 2000, 2, 3 } }; + const Wt::WDate release1OriginalDate{ Wt::WDate{ 1993, 4, 5 } }; ScopedRelease release2{ session, "MyRelease2" }; - const Wt::WDate release2Date{ Wt::WDate {1994, 2, 3} }; + const Wt::WDate release2Date{ Wt::WDate{ 1994, 2, 3 } }; ScopedTrack track1{ session }; ScopedTrack track2{ session }; @@ -836,7 +833,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - const auto releases{ Release::findIds(session, Release::FindParameters {}.setSortMethod(ReleaseSortMethod::Name)) }; + const auto releases{ Release::findIds(session, Release::FindParameters{}.setSortMethod(ReleaseSortMethod::Name)) }; ASSERT_EQ(releases.results.size(), 2); EXPECT_EQ(releases.results.front(), release1.getId()); EXPECT_EQ(releases.results.back(), release2.getId()); @@ -845,14 +842,14 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - const auto releases{ Release::findIds(session, Release::FindParameters {}.setSortMethod(ReleaseSortMethod::Random)) }; + const auto releases{ Release::findIds(session, Release::FindParameters{}.setSortMethod(ReleaseSortMethod::Random)) }; ASSERT_EQ(releases.results.size(), 2); } { auto transaction{ session.createReadTransaction() }; - const auto releases{ Release::findIds(session, Release::FindParameters {}.setSortMethod(ReleaseSortMethod::Date)) }; + const auto releases{ Release::findIds(session, Release::FindParameters{}.setSortMethod(ReleaseSortMethod::Date)) }; ASSERT_EQ(releases.results.size(), 2); EXPECT_EQ(releases.results.front(), release2.getId()); EXPECT_EQ(releases.results.back(), release1.getId()); @@ -861,7 +858,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - const auto releases{ Release::findIds(session, Release::FindParameters {}.setSortMethod(ReleaseSortMethod::OriginalDate)) }; + const auto releases{ Release::findIds(session, Release::FindParameters{}.setSortMethod(ReleaseSortMethod::OriginalDate)) }; ASSERT_EQ(releases.results.size(), 2); EXPECT_EQ(releases.results.front(), release1.getId()); EXPECT_EQ(releases.results.back(), release2.getId()); @@ -869,7 +866,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - const auto releases{ Release::findIds(session, Release::FindParameters {}.setSortMethod(ReleaseSortMethod::OriginalDateDesc)) }; + const auto releases{ Release::findIds(session, Release::FindParameters{}.setSortMethod(ReleaseSortMethod::OriginalDateDesc)) }; ASSERT_EQ(releases.results.size(), 2); EXPECT_EQ(releases.results.front(), release2.getId()); EXPECT_EQ(releases.results.back(), release1.getId()); @@ -883,11 +880,10 @@ namespace lms::db::tests ScopedTrack track2{ session }; ScopedTrack track3{ session }; - auto checkExpectedBitrate = [&](std::size_t bitrate) - { - auto transaction{ session.createReadTransaction() }; - EXPECT_EQ(release1->getMeanBitrate(), bitrate); - }; + auto checkExpectedBitrate = [&](std::size_t bitrate) { + auto transaction{ session.createReadTransaction() }; + EXPECT_EQ(release1->getMeanBitrate(), bitrate); + }; checkExpectedBitrate(0); @@ -938,4 +934,4 @@ namespace lms::db::tests EXPECT_EQ(release3->getTrackCount(), 0); } } -} \ No newline at end of file +} // namespace lms::db::tests \ No newline at end of file diff --git a/src/libs/database/test/StarredArtist.cpp b/src/libs/database/test/StarredArtist.cpp index ebd54357..dac89056 100644 --- a/src/libs/database/test/StarredArtist.cpp +++ b/src/libs/database/test/StarredArtist.cpp @@ -17,9 +17,10 @@ * along with LMS. If not, see . */ -#include "Common.hpp" #include "database/StarredArtist.hpp" +#include "Common.hpp" + namespace lms::db::tests { using ScopedStarredArtist = ScopedEntity; @@ -37,7 +38,7 @@ namespace lms::db::tests EXPECT_FALSE(starredArtist); EXPECT_EQ(StarredArtist::getCount(session), 0); - auto artists{ Artist::findIds(session, Artist::FindParameters {}) }; + auto artists{ Artist::findIds(session, Artist::FindParameters{}) }; EXPECT_EQ(artists.results.size(), 1); } @@ -53,7 +54,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto artists{ Artist::findIds(session, Artist::FindParameters {}) }; + auto artists{ Artist::findIds(session, Artist::FindParameters{}) }; EXPECT_EQ(artists.results.size(), 1); artists = Artist::findIds(session, Artist::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal)); @@ -96,7 +97,7 @@ namespace lms::db::tests { auto transaction{ session.createWriteTransaction() }; - auto artists{ Artist::findIds(session, Artist::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) }; + auto artists{ Artist::findIds(session, Artist::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal)) }; EXPECT_EQ(artists.results.size(), 1); starredArtist.get().modify()->setSyncState(SyncState::PendingRemove); @@ -114,12 +115,12 @@ namespace lms::db::tests ScopedStarredArtist starredArtist1{ session, artist1.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal }; ScopedStarredArtist starredArtist2{ session, artist2.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal }; - const Wt::WDateTime dateTime{ Wt::WDate {1950, 1, 2}, Wt::WTime {12, 30, 1} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 1950, 1, 2 }, Wt::WTime{ 12, 30, 1 } }; { auto transaction{ session.createReadTransaction() }; - auto artists{ Artist::find(session, Artist::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) }; + auto artists{ Artist::find(session, Artist::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal)) }; EXPECT_EQ(artists.results.size(), 2); } @@ -129,7 +130,7 @@ namespace lms::db::tests starredArtist1.get().modify()->setDateTime(dateTime); starredArtist2.get().modify()->setDateTime(dateTime.addSecs(-1)); - auto artists{ Artist::findIds(session, Artist::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(ArtistSortMethod::StarredDateDesc)) }; + auto artists{ Artist::findIds(session, Artist::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(ArtistSortMethod::StarredDateDesc)) }; ASSERT_EQ(artists.results.size(), 2); EXPECT_EQ(artists.results[0], starredArtist1->getArtist()->getId()); EXPECT_EQ(artists.results[1], starredArtist2->getArtist()->getId()); @@ -140,10 +141,10 @@ namespace lms::db::tests starredArtist1.get().modify()->setDateTime(dateTime); starredArtist2.get().modify()->setDateTime(dateTime.addSecs(1)); - auto artists{ Artist::findIds(session, Artist::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(ArtistSortMethod::StarredDateDesc)) }; + auto artists{ Artist::findIds(session, Artist::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(ArtistSortMethod::StarredDateDesc)) }; ASSERT_EQ(artists.results.size(), 2); EXPECT_EQ(artists.results[0], starredArtist2->getArtist()->getId()); EXPECT_EQ(artists.results[1], starredArtist1->getArtist()->getId()); } } -} \ No newline at end of file +} // namespace lms::db::tests \ No newline at end of file diff --git a/src/libs/database/test/StarredRelease.cpp b/src/libs/database/test/StarredRelease.cpp index bc88509a..6fc161a4 100644 --- a/src/libs/database/test/StarredRelease.cpp +++ b/src/libs/database/test/StarredRelease.cpp @@ -17,9 +17,10 @@ * along with LMS. If not, see . */ -#include "Common.hpp" #include "database/StarredRelease.hpp" +#include "Common.hpp" + namespace lms::db::tests { using ScopedStarredRelease = ScopedEntity; @@ -37,7 +38,7 @@ namespace lms::db::tests EXPECT_FALSE(starredRelease); EXPECT_EQ(StarredRelease::getCount(session), 0); - auto releases{ Release::find(session, Release::FindParameters {}) }; + auto releases{ Release::find(session, Release::FindParameters{}) }; EXPECT_EQ(releases.results.size(), 1); } @@ -53,7 +54,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto releases{ Release::find(session, Release::FindParameters {}) }; + auto releases{ Release::find(session, Release::FindParameters{}) }; EXPECT_EQ(releases.results.size(), 1); releases = Release::find(session, Release::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal)); @@ -85,7 +86,7 @@ namespace lms::db::tests { auto transaction{ session.createWriteTransaction() }; - auto releases{ Release::find(session, Release::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) }; + auto releases{ Release::find(session, Release::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal)) }; EXPECT_EQ(releases.results.size(), 1); starredRelease.get().modify()->setSyncState(SyncState::PendingRemove); @@ -103,12 +104,12 @@ namespace lms::db::tests ScopedStarredRelease starredRelease1{ session, release1.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal }; ScopedStarredRelease starredRelease2{ session, release2.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal }; - const Wt::WDateTime dateTime{ Wt::WDate {1950, 1, 2}, Wt::WTime {12, 30, 1} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 1950, 1, 2 }, Wt::WTime{ 12, 30, 1 } }; { auto transaction{ session.createReadTransaction() }; - auto releases{ Release::findIds(session, Release::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) }; + auto releases{ Release::findIds(session, Release::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal)) }; EXPECT_EQ(releases.results.size(), 2); } @@ -118,7 +119,7 @@ namespace lms::db::tests starredRelease1.get().modify()->setDateTime(dateTime); starredRelease2.get().modify()->setDateTime(dateTime.addSecs(-1)); - auto releases{ Release::findIds(session, Release::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(ReleaseSortMethod::StarredDateDesc)) }; + auto releases{ Release::findIds(session, Release::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(ReleaseSortMethod::StarredDateDesc)) }; ASSERT_EQ(releases.results.size(), 2); EXPECT_EQ(releases.results[0], starredRelease1->getRelease()->getId()); EXPECT_EQ(releases.results[1], starredRelease2->getRelease()->getId()); @@ -129,10 +130,10 @@ namespace lms::db::tests starredRelease1.get().modify()->setDateTime(dateTime); starredRelease2.get().modify()->setDateTime(dateTime.addSecs(1)); - auto releases{ Release::findIds(session, Release::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(ReleaseSortMethod::StarredDateDesc)) }; + auto releases{ Release::findIds(session, Release::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(ReleaseSortMethod::StarredDateDesc)) }; ASSERT_EQ(releases.results.size(), 2); EXPECT_EQ(releases.results[0], starredRelease2->getRelease()->getId()); EXPECT_EQ(releases.results[1], starredRelease1->getRelease()->getId()); } } -} \ No newline at end of file +} // namespace lms::db::tests \ No newline at end of file diff --git a/src/libs/database/test/StarredTrack.cpp b/src/libs/database/test/StarredTrack.cpp index 8ef77997..03e560c3 100644 --- a/src/libs/database/test/StarredTrack.cpp +++ b/src/libs/database/test/StarredTrack.cpp @@ -17,9 +17,10 @@ * along with LMS. If not, see . */ -#include "Common.hpp" #include "database/StarredTrack.hpp" +#include "Common.hpp" + namespace lms::db::tests { using ScopedStarredTrack = ScopedEntity; @@ -37,7 +38,7 @@ namespace lms::db::tests EXPECT_FALSE(starredTrack); EXPECT_EQ(StarredTrack::getCount(session), 0); - auto tracks{ Track::findIds(session, Track::FindParameters {}) }; + auto tracks{ Track::findIds(session, Track::FindParameters{}) }; EXPECT_EQ(tracks.results.size(), 1); } @@ -53,7 +54,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto tracks{ Track::findIds(session, Track::FindParameters {}) }; + auto tracks{ Track::findIds(session, Track::FindParameters{}) }; EXPECT_EQ(tracks.results.size(), 1); tracks = Track::findIds(session, Track::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal)); @@ -85,7 +86,7 @@ namespace lms::db::tests { auto transaction{ session.createWriteTransaction() }; - auto tracks{ Track::findIds(session, Track::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) }; + auto tracks{ Track::findIds(session, Track::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal)) }; EXPECT_EQ(tracks.results.size(), 1); starredTrack.get().modify()->setSyncState(SyncState::PendingRemove); @@ -103,12 +104,12 @@ namespace lms::db::tests ScopedStarredTrack starredTrack1{ session, track1.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal }; ScopedStarredTrack starredTrack2{ session, track2.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal }; - const Wt::WDateTime dateTime{ Wt::WDate {1950, 1, 2}, Wt::WTime {12, 30, 1} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 1950, 1, 2 }, Wt::WTime{ 12, 30, 1 } }; { auto transaction{ session.createReadTransaction() }; - auto tracks{ Track::findIds(session, Track::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) }; + auto tracks{ Track::findIds(session, Track::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal)) }; EXPECT_EQ(tracks.results.size(), 2); } @@ -118,7 +119,7 @@ namespace lms::db::tests starredTrack1.get().modify()->setDateTime(dateTime); starredTrack2.get().modify()->setDateTime(dateTime.addSecs(-1)); - auto tracks{ Track::findIds(session, Track::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(TrackSortMethod::StarredDateDesc)) }; + auto tracks{ Track::findIds(session, Track::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(TrackSortMethod::StarredDateDesc)) }; ASSERT_EQ(tracks.results.size(), 2); EXPECT_EQ(tracks.results[0], starredTrack1->getTrack()->getId()); EXPECT_EQ(tracks.results[1], starredTrack2->getTrack()->getId()); @@ -129,10 +130,10 @@ namespace lms::db::tests starredTrack1.get().modify()->setDateTime(dateTime); starredTrack2.get().modify()->setDateTime(dateTime.addSecs(1)); - auto tracks{ Track::findIds(session, Track::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(TrackSortMethod::StarredDateDesc)) }; + auto tracks{ Track::findIds(session, Track::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(TrackSortMethod::StarredDateDesc)) }; ASSERT_EQ(tracks.results.size(), 2); EXPECT_EQ(tracks.results[0], starredTrack2->getTrack()->getId()); EXPECT_EQ(tracks.results[1], starredTrack1->getTrack()->getId()); } } -} \ No newline at end of file +} // namespace lms::db::tests \ No newline at end of file diff --git a/src/libs/database/test/Track.cpp b/src/libs/database/test/Track.cpp index ec3a6b77..28bc730a 100644 --- a/src/libs/database/test/Track.cpp +++ b/src/libs/database/test/Track.cpp @@ -34,7 +34,7 @@ namespace lms::db::tests { bool visited{}; - Track::find(session, Track::FindParameters{}, [&](const Track::pointer&) {visited = true;}); + Track::find(session, Track::FindParameters{}, [&](const Track::pointer&) { visited = true; }); EXPECT_FALSE(visited); } } @@ -53,11 +53,10 @@ namespace lms::db::tests { bool visited{}; - Track::find(session, Track::FindParameters{}, [&](const Track::pointer& t) - { - visited = true; - EXPECT_EQ(t->getId(), track.getId()); - }); + Track::find(session, Track::FindParameters{}, [&](const Track::pointer& t) { + visited = true; + EXPECT_EQ(t->getId(), track.getId()); + }); EXPECT_TRUE(visited); } } @@ -81,10 +80,9 @@ namespace lms::db::tests TrackId lastRetrievedTrackId; std::vector visitedTracks; - Track::find(session, lastRetrievedTrackId, 10, [&](const Track::pointer& track) - { - visitedTracks.push_back(track); - }); + Track::find(session, lastRetrievedTrackId, 10, [&](const Track::pointer& track) { + visitedTracks.push_back(track); + }); ASSERT_EQ(visitedTracks.size(), 3); EXPECT_EQ(visitedTracks[0]->getId(), track1.getId()); EXPECT_EQ(visitedTracks[1]->getId(), track2.getId()); @@ -97,10 +95,9 @@ namespace lms::db::tests TrackId lastRetrievedTrackId{ track1.getId() }; std::vector visitedTracks; - Track::find(session, lastRetrievedTrackId, 1, [&](const Track::pointer& track) - { - visitedTracks.push_back(track); - }); + Track::find(session, lastRetrievedTrackId, 1, [&](const Track::pointer& track) { + visitedTracks.push_back(track); + }); ASSERT_EQ(visitedTracks.size(), 1); EXPECT_EQ(visitedTracks[0]->getId(), track2.getId()); EXPECT_EQ(lastRetrievedTrackId, track2.getId()); @@ -111,10 +108,9 @@ namespace lms::db::tests TrackId lastRetrievedTrackId{ track1.getId() }; std::vector visitedTracks; - Track::find(session, lastRetrievedTrackId, 0, [&](const Track::pointer& track) - { - visitedTracks.push_back(track); - }); + Track::find(session, lastRetrievedTrackId, 0, [&](const Track::pointer& track) { + visitedTracks.push_back(track); + }); ASSERT_EQ(visitedTracks.size(), 0); EXPECT_EQ(lastRetrievedTrackId, track1.getId()); } @@ -124,10 +120,11 @@ namespace lms::db::tests TrackId lastRetrievedTrackId{}; std::vector visitedTracks; - Track::find(session, lastRetrievedTrackId, 10, [&](const Track::pointer& track) - { + Track::find( + session, lastRetrievedTrackId, 10, [&](const Track::pointer& track) { visitedTracks.push_back(track); - }, otherLibrary.getId()); + }, + otherLibrary.getId()); ASSERT_EQ(visitedTracks.size(), 0); EXPECT_EQ(lastRetrievedTrackId, TrackId{}); } @@ -137,10 +134,11 @@ namespace lms::db::tests TrackId lastRetrievedTrackId{}; std::vector visitedTracks; - Track::find(session, lastRetrievedTrackId, 10, [&](const Track::pointer& track) - { + Track::find( + session, lastRetrievedTrackId, 10, [&](const Track::pointer& track) { visitedTracks.push_back(track); - }, library.getId()); + }, + library.getId()); ASSERT_EQ(visitedTracks.size(), 1); EXPECT_EQ(visitedTracks[0]->getId(), track2.getId()); EXPECT_EQ(lastRetrievedTrackId, track2.getId()); @@ -235,22 +233,22 @@ namespace lms::db::tests auto transaction{ session.createReadTransaction() }; { - const auto tracks{ Track::findIds(session, Track::FindParameters {}.setKeywords({"Track"})) }; + const auto tracks{ Track::findIds(session, Track::FindParameters{}.setKeywords({ "Track" })) }; EXPECT_EQ(tracks.results.size(), 6); } { - const auto tracks{ Track::findIds(session, Track::FindParameters {}.setKeywords({"MyTrack"})) }; + const auto tracks{ Track::findIds(session, Track::FindParameters{}.setKeywords({ "MyTrack" })) }; EXPECT_EQ(tracks.results.size(), 5); EXPECT_TRUE(std::none_of(std::cbegin(tracks.results), std::cend(tracks.results), [&](const TrackId trackId) { return trackId == track6.getId(); })); } { - const auto tracks{ Track::findIds(session, Track::FindParameters {}.setKeywords({"MyTrack%"})) }; + const auto tracks{ Track::findIds(session, Track::FindParameters{}.setKeywords({ "MyTrack%" })) }; ASSERT_EQ(tracks.results.size(), 2); EXPECT_EQ(tracks.results[0], track2.getId()); EXPECT_EQ(tracks.results[1], track3.getId()); } { - const auto tracks{ Track::findIds(session, Track::FindParameters {}.setKeywords({"%MyTrack"})) }; + const auto tracks{ Track::findIds(session, Track::FindParameters{}.setKeywords({ "%MyTrack" })) }; ASSERT_EQ(tracks.results.size(), 2); EXPECT_EQ(tracks.results[0], track4.getId()); EXPECT_EQ(tracks.results[1], track5.getId()); @@ -300,7 +298,7 @@ namespace lms::db::tests { ScopedTrack track{ session }; - const Wt::WDateTime dateTime{ Wt::WDate {1950, 1, 1}, Wt::WTime {12, 30, 20} }; + const Wt::WDateTime dateTime{ Wt::WDate{ 1950, 1, 1 }, Wt::WTime{ 12, 30, 20 } }; { auto transaction{ session.createWriteTransaction() }; @@ -309,19 +307,19 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - const auto tracks{ Track::findIds(session, Track::FindParameters {}) }; + const auto tracks{ Track::findIds(session, Track::FindParameters{}) }; EXPECT_EQ(tracks.results.size(), 1); } { auto transaction{ session.createReadTransaction() }; - const auto tracks{ Track::findIds(session, Track::FindParameters {}.setWrittenAfter(dateTime.addSecs(-1))) }; + const auto tracks{ Track::findIds(session, Track::FindParameters{}.setWrittenAfter(dateTime.addSecs(-1))) }; EXPECT_EQ(tracks.results.size(), 1); } { auto transaction{ session.createReadTransaction() }; - const auto tracks{ Track::findIds(session, Track::FindParameters {}.setWrittenAfter(dateTime.addSecs(+1))) }; + const auto tracks{ Track::findIds(session, Track::FindParameters{}.setWrittenAfter(dateTime.addSecs(+1))) }; EXPECT_EQ(tracks.results.size(), 0); } } @@ -343,7 +341,6 @@ namespace lms::db::tests } } - TEST_F(DatabaseFixture, Track_audioProperties) { ScopedTrack track{ session }; @@ -366,4 +363,4 @@ namespace lms::db::tests EXPECT_EQ(track->getSampleRate(), 44100); } } -} \ No newline at end of file +} // namespace lms::db::tests \ No newline at end of file diff --git a/src/libs/database/test/TrackBookmark.cpp b/src/libs/database/test/TrackBookmark.cpp index 91a533be..2b30eb07 100644 --- a/src/libs/database/test/TrackBookmark.cpp +++ b/src/libs/database/test/TrackBookmark.cpp @@ -64,4 +64,4 @@ namespace lms::db::tests EXPECT_EQ(userBookmark->getComment(), "MyComment"); } } -} \ No newline at end of file +} // namespace lms::db::tests \ No newline at end of file diff --git a/src/libs/database/test/TrackFeatures.cpp b/src/libs/database/test/TrackFeatures.cpp index ed42ee29..cb799684 100644 --- a/src/libs/database/test/TrackFeatures.cpp +++ b/src/libs/database/test/TrackFeatures.cpp @@ -46,4 +46,4 @@ namespace lms::db::tests EXPECT_EQ(allTrackFeatures.results.front(), trackFeatures.getId()); } } -} \ No newline at end of file +} // namespace lms::db::tests \ No newline at end of file diff --git a/src/libs/database/test/TrackList.cpp b/src/libs/database/test/TrackList.cpp index 091e4cc3..4fde7fa4 100644 --- a/src/libs/database/test/TrackList.cpp +++ b/src/libs/database/test/TrackList.cpp @@ -49,7 +49,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto tracks{ Track::findIds(session, Track::FindParameters {}.setTrackList(trackList1.getId())) }; + auto tracks{ Track::findIds(session, Track::FindParameters{}.setTrackList(trackList1.getId())) }; EXPECT_EQ(tracks.results.size(), 0); tracks = Track::findIds(session, Track::FindParameters{}.setTrackList(trackList2.getId())); @@ -65,7 +65,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto tracks{ Track::findIds(session, Track::FindParameters {}.setTrackList(trackList1.getId())) }; + auto tracks{ Track::findIds(session, Track::FindParameters{}.setTrackList(trackList1.getId())) }; ASSERT_EQ(tracks.results.size(), 1); EXPECT_EQ(tracks.results.front(), track.getId()); @@ -84,7 +84,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - const auto trackLists{ TrackList::find(session, TrackList::FindParameters {}.setSortMethod(TrackListSortMethod::Name)) }; + const auto trackLists{ TrackList::find(session, TrackList::FindParameters{}.setSortMethod(TrackListSortMethod::Name)) }; ASSERT_EQ(trackLists.results.size(), 2); EXPECT_EQ(trackLists.results[0], trackList1.getId()); EXPECT_EQ(trackLists.results[1], trackList2.getId()); @@ -93,14 +93,14 @@ namespace lms::db::tests { auto transaction{ session.createWriteTransaction() }; - trackList1.get().modify()->setLastModifiedDateTime(Wt::WDateTime{ Wt::WDate {1900,1,1} }); - trackList2.get().modify()->setLastModifiedDateTime(Wt::WDateTime{ Wt::WDate {1900,1,2} }); + trackList1.get().modify()->setLastModifiedDateTime(Wt::WDateTime{ Wt::WDate{ 1900, 1, 1 } }); + trackList2.get().modify()->setLastModifiedDateTime(Wt::WDateTime{ Wt::WDate{ 1900, 1, 2 } }); } { auto transaction{ session.createReadTransaction() }; - const auto trackLists{ TrackList::find(session, TrackList::FindParameters {}.setSortMethod(TrackListSortMethod::LastModifiedDesc)) }; + const auto trackLists{ TrackList::find(session, TrackList::FindParameters{}.setSortMethod(TrackListSortMethod::LastModifiedDesc)) }; ASSERT_EQ(trackLists.results.size(), 2); EXPECT_EQ(trackLists.results[0], trackList2.getId()); EXPECT_EQ(trackLists.results[1], trackList1.getId()); @@ -109,14 +109,14 @@ namespace lms::db::tests { auto transaction{ session.createWriteTransaction() }; - trackList1.get().modify()->setLastModifiedDateTime(Wt::WDateTime{ Wt::WDate {1900,1,2} }); - trackList2.get().modify()->setLastModifiedDateTime(Wt::WDateTime{ Wt::WDate {1900,1,1} }); + trackList1.get().modify()->setLastModifiedDateTime(Wt::WDateTime{ Wt::WDate{ 1900, 1, 2 } }); + trackList2.get().modify()->setLastModifiedDateTime(Wt::WDateTime{ Wt::WDate{ 1900, 1, 1 } }); } { auto transaction{ session.createReadTransaction() }; - const auto trackLists{ TrackList::find(session, TrackList::FindParameters {}.setSortMethod(TrackListSortMethod::LastModifiedDesc)) }; + const auto trackLists{ TrackList::find(session, TrackList::FindParameters{}.setSortMethod(TrackListSortMethod::LastModifiedDesc)) }; ASSERT_EQ(trackLists.results.size(), 2); EXPECT_EQ(trackLists.results[0], trackList1.getId()); EXPECT_EQ(trackLists.results[1], trackList2.getId()); @@ -170,10 +170,9 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; std::vector visitedTrackLists; - TrackList::find(session, TrackList::FindParameters{}, [&](const TrackList::pointer& trackList) - { - visitedTrackLists.push_back(trackList->getId()); - }); + TrackList::find(session, TrackList::FindParameters{}, [&](const TrackList::pointer& trackList) { + visitedTrackLists.push_back(trackList->getId()); + }); ASSERT_EQ(visitedTrackLists.size(), 2); EXPECT_EQ(visitedTrackLists[0], trackList1->getId()); EXPECT_EQ(visitedTrackLists[1], trackList2->getId()); @@ -182,10 +181,9 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; std::vector visitedTrackLists; - TrackList::find(session, TrackList::FindParameters{}.setMediaLibrary(library->getId()), [&](const TrackList::pointer& trackList) - { - visitedTrackLists.push_back(trackList->getId()); - }); + TrackList::find(session, TrackList::FindParameters{}.setMediaLibrary(library->getId()), [&](const TrackList::pointer& trackList) { + visitedTrackLists.push_back(trackList->getId()); + }); ASSERT_EQ(visitedTrackLists.size(), 1); EXPECT_EQ(visitedTrackLists[0], trackList2->getId()); } @@ -203,7 +201,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto trackLists{ TrackList::find(session, TrackList::FindParameters {}.setClusters(std::initializer_list{cluster.getId()})) }; + auto trackLists{ TrackList::find(session, TrackList::FindParameters{}.setClusters(std::initializer_list{ cluster.getId() })) }; EXPECT_EQ(trackLists.results.size(), 0); } @@ -217,7 +215,7 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto trackLists{ TrackList::find(session, TrackList::FindParameters {}.setClusters(std::initializer_list{cluster.getId()})) }; + auto trackLists{ TrackList::find(session, TrackList::FindParameters{}.setClusters(std::initializer_list{ cluster.getId() })) }; ASSERT_EQ(trackLists.results.size(), 1); EXPECT_EQ(trackLists.results.front(), trackList1.getId()); } @@ -257,9 +255,9 @@ namespace lms::db::tests { auto transaction{ session.createReadTransaction() }; - auto entries{ trackList.get()->getEntries(Range {1, 1}) }; + auto entries{ trackList.get()->getEntries(Range{ 1, 1 }) }; ASSERT_EQ(entries.results.size(), 1); EXPECT_EQ(entries.results[0]->getTrack()->getId(), track2.getId()); } } -} \ No newline at end of file +} // namespace lms::db::tests \ No newline at end of file diff --git a/src/libs/database/test/User.cpp b/src/libs/database/test/User.cpp index 039e485c..233c6379 100644 --- a/src/libs/database/test/User.cpp +++ b/src/libs/database/test/User.cpp @@ -27,10 +27,9 @@ namespace lms::db::tests auto transaction{ session.createReadTransaction() }; bool visited{}; - User::find(session, User::FindParameters{}, [&](const User::pointer&) - { - visited = true; - }); + User::find(session, User::FindParameters{}, [&](const User::pointer&) { + visited = true; + }); EXPECT_FALSE(visited); } @@ -41,13 +40,12 @@ namespace lms::db::tests auto transaction{ session.createReadTransaction() }; std::vector visitedUsers; - User::find(session, User::FindParameters{}, [&](const User::pointer& user) - { - visitedUsers.push_back(user->getId()); - }); + User::find(session, User::FindParameters{}, [&](const User::pointer& user) { + visitedUsers.push_back(user->getId()); + }); EXPECT_EQ(visitedUsers.size(), 2); EXPECT_EQ(visitedUsers[0], user1->getId()); EXPECT_EQ(visitedUsers[1], user2->getId()); } } -} \ No newline at end of file +} // namespace lms::db::tests \ No newline at end of file diff --git a/src/libs/image/impl/SvgImage.cpp b/src/libs/image/impl/SvgImage.cpp index 87636937..85eb62df 100644 --- a/src/libs/image/impl/SvgImage.cpp +++ b/src/libs/image/impl/SvgImage.cpp @@ -20,6 +20,7 @@ #include "SvgImage.hpp" #include + #include "core/ITraceLogger.hpp" #include "image/Exception.hpp" @@ -50,4 +51,4 @@ namespace lms::image return std::make_unique(std::move(data)); } -} \ No newline at end of file +} // namespace lms::image \ No newline at end of file diff --git a/src/libs/image/impl/SvgImage.hpp b/src/libs/image/impl/SvgImage.hpp index ce54cb30..5ae53aa3 100644 --- a/src/libs/image/impl/SvgImage.hpp +++ b/src/libs/image/impl/SvgImage.hpp @@ -30,7 +30,8 @@ namespace lms::image class SvgImage : public IEncodedImage { public: - SvgImage(std::vector&& data) : _data{ std::move(data) } {} + SvgImage(std::vector&& data) + : _data{ std::move(data) } {} const std::byte* getData() const { return &_data.front(); } std::size_t getDataSize() const { return _data.size(); } @@ -39,4 +40,4 @@ namespace lms::image private: const std::vector _data; }; -} \ No newline at end of file +} // namespace lms::image \ No newline at end of file diff --git a/src/libs/image/impl/graphicsmagick/JPEGImage.cpp b/src/libs/image/impl/graphicsmagick/JPEGImage.cpp index 8465a0c2..36b00d2c 100644 --- a/src/libs/image/impl/graphicsmagick/JPEGImage.cpp +++ b/src/libs/image/impl/graphicsmagick/JPEGImage.cpp @@ -19,37 +19,36 @@ #include "JPEGImage.hpp" -#include "RawImage.hpp" -#include "image/Exception.hpp" #include "core/ILogger.hpp" +#include "image/Exception.hpp" + +#include "RawImage.hpp" namespace lms::image::GraphicsMagick { - JPEGImage::JPEGImage(const RawImage& rawImage, unsigned quality) - { - try - { - Magick::Image image {rawImage.getMagickImage()}; - image.magick("JPEG"); - image.quality(quality); - image.write(&_blob); - } - catch (Magick::Exception& e) - { - LMS_LOG(COVER, ERROR, "Caught Magick exception: " << e.what()); - throw Exception {std::string {"Magick read error: "} + e.what()}; - } - } + JPEGImage::JPEGImage(const RawImage& rawImage, unsigned quality) + { + try + { + Magick::Image image{ rawImage.getMagickImage() }; + image.magick("JPEG"); + image.quality(quality); + image.write(&_blob); + } + catch (Magick::Exception& e) + { + LMS_LOG(COVER, ERROR, "Caught Magick exception: " << e.what()); + throw Exception{ std::string{ "Magick read error: " } + e.what() }; + } + } - const std::byte* - JPEGImage::getData() const - { - return reinterpret_cast(_blob.data()); - } + const std::byte* JPEGImage::getData() const + { + return reinterpret_cast(_blob.data()); + } - std::size_t - JPEGImage::getDataSize() const - { - return _blob.length(); - } -} + std::size_t JPEGImage::getDataSize() const + { + return _blob.length(); + } +} // namespace lms::image::GraphicsMagick diff --git a/src/libs/image/impl/graphicsmagick/JPEGImage.hpp b/src/libs/image/impl/graphicsmagick/JPEGImage.hpp index 934d2ed5..4d9386c0 100644 --- a/src/libs/image/impl/graphicsmagick/JPEGImage.hpp +++ b/src/libs/image/impl/graphicsmagick/JPEGImage.hpp @@ -25,17 +25,17 @@ namespace lms::image::GraphicsMagick { - class RawImage; - class JPEGImage : public IEncodedImage - { - public: - JPEGImage(const RawImage& rawImage, unsigned quality); + class RawImage; + class JPEGImage : public IEncodedImage + { + public: + JPEGImage(const RawImage& rawImage, unsigned quality); - private: - const std::byte* getData() const override; - std::size_t getDataSize() const override; - std::string_view getMimeType() const override { return "image/jpeg"; } + private: + const std::byte* getData() const override; + std::size_t getDataSize() const override; + std::string_view getMimeType() const override { return "image/jpeg"; } - Magick::Blob _blob; - }; -} + Magick::Blob _blob; + }; +} // namespace lms::image::GraphicsMagick diff --git a/src/libs/image/impl/graphicsmagick/RawImage.cpp b/src/libs/image/impl/graphicsmagick/RawImage.cpp index e0f74ebd..408c8e90 100644 --- a/src/libs/image/impl/graphicsmagick/RawImage.cpp +++ b/src/libs/image/impl/graphicsmagick/RawImage.cpp @@ -21,114 +21,110 @@ #include -#include "JPEGImage.hpp" -#include "image/Exception.hpp" #include "core/ILogger.hpp" +#include "image/Exception.hpp" + +#include "JPEGImage.hpp" namespace lms::image { - std::unique_ptr decodeImage(const std::byte* encodedData, std::size_t encodedDataSize) - { - return std::make_unique(encodedData, encodedDataSize); - } + std::unique_ptr decodeImage(const std::byte* encodedData, std::size_t encodedDataSize) + { + return std::make_unique(encodedData, encodedDataSize); + } - std::unique_ptr decodeImage(const std::filesystem::path& path) - { - return std::make_unique(path); - } + std::unique_ptr decodeImage(const std::filesystem::path& path) + { + return std::make_unique(path); + } - void - init(const std::filesystem::path& path) - { - Magick::InitializeMagick(path.string().c_str()); + void init(const std::filesystem::path& path) + { + Magick::InitializeMagick(path.string().c_str()); - if (auto nbThreads {MagickLib::GetMagickResourceLimit(MagickLib::ThreadsResource)}; nbThreads != 1) - LMS_LOG(COVER, WARNING, "Consider setting env var OMP_NUM_THREADS=1 to save resources"); + if (auto nbThreads{ MagickLib::GetMagickResourceLimit(MagickLib::ThreadsResource) }; nbThreads != 1) + LMS_LOG(COVER, WARNING, "Consider setting env var OMP_NUM_THREADS=1 to save resources"); - if (!MagickLib::SetMagickResourceLimit(MagickLib::ThreadsResource, 1)) - LMS_LOG(COVER, ERROR, "Cannot set Magick thread resource limit to 1!"); + if (!MagickLib::SetMagickResourceLimit(MagickLib::ThreadsResource, 1)) + LMS_LOG(COVER, ERROR, "Cannot set Magick thread resource limit to 1!"); - if (!MagickLib::SetMagickResourceLimit(MagickLib::DiskResource, 0)) - LMS_LOG(COVER, ERROR, "Cannot set Magick disk resource limit to 0!"); + if (!MagickLib::SetMagickResourceLimit(MagickLib::DiskResource, 0)) + LMS_LOG(COVER, ERROR, "Cannot set Magick disk resource limit to 0!"); - LMS_LOG(COVER, INFO, "Magick threads resource limit = " << GetMagickResourceLimit(MagickLib::ThreadsResource)); - LMS_LOG(COVER, INFO, "Magick Disk resource limit = " << GetMagickResourceLimit(MagickLib::DiskResource)); - } -} + LMS_LOG(COVER, INFO, "Magick threads resource limit = " << GetMagickResourceLimit(MagickLib::ThreadsResource)); + LMS_LOG(COVER, INFO, "Magick Disk resource limit = " << GetMagickResourceLimit(MagickLib::DiskResource)); + } +} // namespace lms::image namespace lms::image::GraphicsMagick { -RawImage::RawImage(const std::byte* encodedData, std::size_t encodedDataSize) -{ - try - { - Magick::Blob blob {encodedData, encodedDataSize}; - _image.read(blob); - } - catch (Magick::WarningCoder& e) - { - LMS_LOG(COVER, WARNING, "Caught Magick WarningCoder: " << e.what()); - } - catch (Magick::Warning& e) - { - LMS_LOG(COVER, WARNING, "Caught Magick warning: " << e.what()); - throw Exception {std::string {"Magick read warning: "} + e.what()}; - } - catch (Magick::Exception& e) - { - LMS_LOG(COVER, ERROR, "Caught Magick exception: " << e.what()); - throw Exception {std::string {"Magick read error: "} + e.what()}; - } -} + RawImage::RawImage(const std::byte* encodedData, std::size_t encodedDataSize) + { + try + { + Magick::Blob blob{ encodedData, encodedDataSize }; + _image.read(blob); + } + catch (Magick::WarningCoder& e) + { + LMS_LOG(COVER, WARNING, "Caught Magick WarningCoder: " << e.what()); + } + catch (Magick::Warning& e) + { + LMS_LOG(COVER, WARNING, "Caught Magick warning: " << e.what()); + throw Exception{ std::string{ "Magick read warning: " } + e.what() }; + } + catch (Magick::Exception& e) + { + LMS_LOG(COVER, ERROR, "Caught Magick exception: " << e.what()); + throw Exception{ std::string{ "Magick read error: " } + e.what() }; + } + } -RawImage::RawImage(const std::filesystem::path& p) -{ - try - { - _image.read(p.string().c_str()); - } - catch (Magick::WarningCoder& e) - { - LMS_LOG(COVER, WARNING, "Caught Magick WarningCoder: " << e.what()); - } - catch (Magick::Warning& e) - { - LMS_LOG(COVER, WARNING, "Caught Magick warning: " << e.what()); - throw Exception {std::string {"Magick read warning: "} + e.what()}; - } - catch (Magick::Exception& e) - { - LMS_LOG(COVER, ERROR, "Caught Magick exception: " << e.what()); - throw Exception {std::string {"Magick read error: "} + e.what()}; - } -} + RawImage::RawImage(const std::filesystem::path& p) + { + try + { + _image.read(p.string().c_str()); + } + catch (Magick::WarningCoder& e) + { + LMS_LOG(COVER, WARNING, "Caught Magick WarningCoder: " << e.what()); + } + catch (Magick::Warning& e) + { + LMS_LOG(COVER, WARNING, "Caught Magick warning: " << e.what()); + throw Exception{ std::string{ "Magick read warning: " } + e.what() }; + } + catch (Magick::Exception& e) + { + LMS_LOG(COVER, ERROR, "Caught Magick exception: " << e.what()); + throw Exception{ std::string{ "Magick read error: " } + e.what() }; + } + } -void -RawImage::resize(ImageSize width) -{ - try - { - _image.resize(Magick::Geometry {static_cast(width), static_cast(width)}); - } - catch (Magick::Exception& e) - { - LMS_LOG(COVER, ERROR, "Caught Magick exception while resizing: " << e.what()); - throw Exception {std::string {"Magick resize error: "} + e.what()}; - } -} + void RawImage::resize(ImageSize width) + { + try + { + _image.resize(Magick::Geometry{ static_cast(width), static_cast(width) }); + } + catch (Magick::Exception& e) + { + LMS_LOG(COVER, ERROR, "Caught Magick exception while resizing: " << e.what()); + throw Exception{ std::string{ "Magick resize error: " } + e.what() }; + } + } -std::unique_ptr -RawImage::encodeToJPEG(unsigned quality) const -{ - return std::make_unique(*this, quality); -} + std::unique_ptr RawImage::encodeToJPEG(unsigned quality) const + { + return std::make_unique(*this, quality); + } -Magick::Image -RawImage::getMagickImage() const -{ - return _image; -} + Magick::Image RawImage::getMagickImage() const + { + return _image; + } } // namespace lms::image::GraphicsMagick - diff --git a/src/libs/image/impl/graphicsmagick/RawImage.hpp b/src/libs/image/impl/graphicsmagick/RawImage.hpp index d65813e1..b217f9d2 100644 --- a/src/libs/image/impl/graphicsmagick/RawImage.hpp +++ b/src/libs/image/impl/graphicsmagick/RawImage.hpp @@ -19,30 +19,29 @@ #pragma once -#include - #include #include +#include + #include "image/IEncodedImage.hpp" #include "image/IRawImage.hpp" namespace lms::image::GraphicsMagick { - class RawImage : public IRawImage - { - public: - RawImage(const std::byte* encodedData, std::size_t encodedDataSize); - RawImage(const std::filesystem::path& path); + class RawImage : public IRawImage + { + public: + RawImage(const std::byte* encodedData, std::size_t encodedDataSize); + RawImage(const std::filesystem::path& path); - void resize(ImageSize width) override; - std::unique_ptr encodeToJPEG(unsigned quality) const override; + void resize(ImageSize width) override; + std::unique_ptr encodeToJPEG(unsigned quality) const override; - private: - friend class JPEGImage; - Magick::Image getMagickImage() const; - - Magick::Image _image; - }; -} + private: + friend class JPEGImage; + Magick::Image getMagickImage() const; + Magick::Image _image; + }; +} // namespace lms::image::GraphicsMagick diff --git a/src/libs/image/impl/stb/JPEGImage.cpp b/src/libs/image/impl/stb/JPEGImage.cpp index 681d93ea..f64f831a 100644 --- a/src/libs/image/impl/stb/JPEGImage.cpp +++ b/src/libs/image/impl/stb/JPEGImage.cpp @@ -24,41 +24,41 @@ #include "core/ITraceLogger.hpp" #include "image/Exception.hpp" + #include "RawImage.hpp" namespace lms::image::STB { - JPEGImage::JPEGImage(const RawImage& rawImage, unsigned quality) - { + JPEGImage::JPEGImage(const RawImage& rawImage, unsigned quality) + { LMS_SCOPED_TRACE_DETAILED("Image", "WriteJPEG"); - auto writeCb {[](void* ctx, void* writeData, int writeSize) - { - auto& output {*reinterpret_cast*>(ctx)}; - const std::size_t currentOutputSize {output.size()}; - output.resize(currentOutputSize + writeSize); - std::copy(reinterpret_cast(writeData), reinterpret_cast(writeData) + writeSize, output.data() + currentOutputSize); - }}; + auto writeCb{ [](void* ctx, void* writeData, int writeSize) { + auto& output{ *reinterpret_cast*>(ctx) }; + const std::size_t currentOutputSize{ output.size() }; + output.resize(currentOutputSize + writeSize); + std::copy(reinterpret_cast(writeData), reinterpret_cast(writeData) + writeSize, output.data() + currentOutputSize); + } }; - if (stbi_write_jpg_to_func(writeCb, &_data, rawImage.getWidth(), rawImage.getHeight(), 3, rawImage.getData(), quality) == 0) - { - _data.clear(); - throw Exception {"Failed to export in jpeg format!"}; - } - } + if (stbi_write_jpg_to_func(writeCb, &_data, rawImage.getWidth(), rawImage.getHeight(), 3, rawImage.getData(), quality) == 0) + { + _data.clear(); + throw Exception{ "Failed to export in jpeg format!" }; + } + } - const std::byte* - JPEGImage::getData() const - { - if (_data.empty()) - return nullptr; + const std::byte* + JPEGImage::getData() const + { + if (_data.empty()) + return nullptr; - return &_data.front(); - } + return &_data.front(); + } - std::size_t - JPEGImage::getDataSize() const - { - return _data.size(); - } -} + std::size_t + JPEGImage::getDataSize() const + { + return _data.size(); + } +} // namespace lms::image::STB diff --git a/src/libs/image/impl/stb/JPEGImage.hpp b/src/libs/image/impl/stb/JPEGImage.hpp index 34394d17..3b4ad706 100644 --- a/src/libs/image/impl/stb/JPEGImage.hpp +++ b/src/libs/image/impl/stb/JPEGImage.hpp @@ -25,17 +25,17 @@ namespace lms::image::STB { - class RawImage; - class JPEGImage : public IEncodedImage - { - public: - JPEGImage(const RawImage& rawImage, unsigned quality); + class RawImage; + class JPEGImage : public IEncodedImage + { + public: + JPEGImage(const RawImage& rawImage, unsigned quality); - private: - const std::byte* getData() const override; - std::size_t getDataSize() const override; - std::string_view getMimeType() const override { return "image/jpeg"; } + private: + const std::byte* getData() const override; + std::size_t getDataSize() const override; + std::string_view getMimeType() const override { return "image/jpeg"; } - std::vector _data; - }; -} + std::vector _data; + }; +} // namespace lms::image::STB diff --git a/src/libs/image/impl/stb/RawImage.cpp b/src/libs/image/impl/stb/RawImage.cpp index 28608217..569158f4 100644 --- a/src/libs/image/impl/stb/RawImage.cpp +++ b/src/libs/image/impl/stb/RawImage.cpp @@ -22,22 +22,23 @@ #define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_RESIZE_IMPLEMENTATION -#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL -#define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM +#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL +#define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM #define STBI_FAILURE_USERMSG #include #if STB_IMAGE_RESIZE_VERSION == 1 -#include + #include #elif STB_IMAGE_RESIZE_VERSION == 2 -#include + #include #else -#error "Unhandled STB image resize version"! + #error "Unhandled STB image resize version"! #endif #include "core/ITraceLogger.hpp" #include "image/Exception.hpp" + #include "JPEGImage.hpp" namespace lms::image @@ -57,7 +58,7 @@ namespace lms::image void init(const std::filesystem::path&) { } -} +} // namespace lms::image namespace lms::image::STB { @@ -102,12 +103,14 @@ namespace lms::image::STB #if STB_IMAGE_RESIZE_VERSION == 1 if (::stbir_resize_uint8_srgb(reinterpret_cast(_data.get()), _width, _height, 0, - reinterpret_cast(resizedData.get()), width, height, 0, - 3, STBIR_ALPHA_CHANNEL_NONE, 0) == 0) + reinterpret_cast(resizedData.get()), width, height, 0, + 3, STBIR_ALPHA_CHANNEL_NONE, 0) + == 0) #elif STB_IMAGE_RESIZE_VERSION == 2 if (::stbir_resize_uint8_srgb(reinterpret_cast(_data.get()), _width, _height, 0, - reinterpret_cast(resizedData.get()), width, height, 0, - STBIR_RGB) == 0) + reinterpret_cast(resizedData.get()), width, height, 0, + STBIR_RGB) + == 0) #else #error "Unhandled STB image resize version"! #endif @@ -142,4 +145,4 @@ namespace lms::image::STB return reinterpret_cast(_data.get()); } -} \ No newline at end of file +} // namespace lms::image::STB \ No newline at end of file diff --git a/src/libs/image/impl/stb/RawImage.hpp b/src/libs/image/impl/stb/RawImage.hpp index d4788d4d..65fd822c 100644 --- a/src/libs/image/impl/stb/RawImage.hpp +++ b/src/libs/image/impl/stb/RawImage.hpp @@ -46,5 +46,4 @@ namespace lms::image::STB using UniquePtrFree = std::unique_ptr; UniquePtrFree _data{ nullptr, std::free }; }; -} - +} // namespace lms::image::STB diff --git a/src/libs/image/include/image/Exception.hpp b/src/libs/image/include/image/Exception.hpp index 7e0d83ba..65d416ae 100644 --- a/src/libs/image/include/image/Exception.hpp +++ b/src/libs/image/include/image/Exception.hpp @@ -25,7 +25,7 @@ namespace lms::image { class Exception : public core::LmsException { - public: - using LmsException::LmsException; + public: + using LmsException::LmsException; }; -} // namespace lms::cover +} // namespace lms::image diff --git a/src/libs/image/include/image/IEncodedImage.hpp b/src/libs/image/include/image/IEncodedImage.hpp index 89685143..9bed88c0 100644 --- a/src/libs/image/include/image/IEncodedImage.hpp +++ b/src/libs/image/include/image/IEncodedImage.hpp @@ -35,4 +35,4 @@ namespace lms::image virtual std::size_t getDataSize() const = 0; virtual std::string_view getMimeType() const = 0; }; -} \ No newline at end of file +} // namespace lms::image \ No newline at end of file diff --git a/src/libs/image/include/image/IRawImage.hpp b/src/libs/image/include/image/IRawImage.hpp index 178da958..19b074a8 100644 --- a/src/libs/image/include/image/IRawImage.hpp +++ b/src/libs/image/include/image/IRawImage.hpp @@ -30,5 +30,4 @@ namespace lms::image virtual void resize(ImageSize width) = 0; virtual std::unique_ptr encodeToJPEG(unsigned quality) const = 0; }; -} - +} // namespace lms::image diff --git a/src/libs/image/include/image/Image.hpp b/src/libs/image/include/image/Image.hpp index a0ee4182..36184663 100644 --- a/src/libs/image/include/image/Image.hpp +++ b/src/libs/image/include/image/Image.hpp @@ -31,4 +31,4 @@ namespace lms::image std::unique_ptr decodeImage(const std::byte* encodedData, std::size_t encodedDataSize); std::unique_ptr decodeImage(const std::filesystem::path& path); std::unique_ptr readSvgFile(const std::filesystem::path& path); -} \ No newline at end of file +} // namespace lms::image \ No newline at end of file diff --git a/src/libs/metadata/impl/AvFormatTagReader.cpp b/src/libs/metadata/impl/AvFormatTagReader.cpp index 1f4852e7..f9ba4655 100644 --- a/src/libs/metadata/impl/AvFormatTagReader.cpp +++ b/src/libs/metadata/impl/AvFormatTagReader.cpp @@ -23,9 +23,10 @@ #include #include "av/IAudioFile.hpp" -#include "metadata/Exception.hpp" #include "core/ILogger.hpp" #include "core/String.hpp" +#include "metadata/Exception.hpp" + #include "Utils.hpp" namespace lms::metadata @@ -33,8 +34,7 @@ namespace lms::metadata namespace { // Mapping to internal avformat names and/or common alternative custom names - static const std::unordered_map> tagMapping - { + static const std::unordered_map> tagMapping{ { TagType::AcoustID, { "ACOUSTID_ID", "ACOUSTID ID" } }, { TagType::Album, { "ALBUM", "TALB", "WM/ALBUMTITLE" } }, { TagType::AlbumArtist, { "ALBUMARTIST", "ALBUM_ARTIST" } }, @@ -64,7 +64,7 @@ namespace lms::metadata { TagType::CopyrightURL, { "COPYRIGHTURL" } }, { TagType::Date, { "DATE", "YEAR", "WM/YEAR" } }, { TagType::Director, { "DIRECTOR" } }, - { TagType::DiscNumber, { "TPOS", "DISC", "DISK", "DISCNUMBER", "WM/PARTOFSET" } }, + { TagType::DiscNumber, { "TPOS", "DISC", "DISK", "DISCNUMBER", "WM/PARTOFSET" } }, { TagType::DiscSubtitle, { "TSST", "DISCSUBTITLE", "SETSUBTITLE" } }, { TagType::EncodedBy, { "ENCODEDBY" } }, { TagType::Engineer, { "ENGINEER" } }, @@ -129,7 +129,7 @@ namespace lms::metadata { TagType::Script, { "SCRIPT", "WM/SCRIPT" } }, { TagType::ShowWorkAndMovement, { "SHOWWORKMOVEMENT", "SHOWMOVEMENT" } }, { TagType::Subtitle, { "SUBTITLE" } }, - { TagType::TotalDiscs, { "DISCTOTAL", "TOTALDISCS"} }, + { TagType::TotalDiscs, { "DISCTOTAL", "TOTALDISCS" } }, { TagType::TotalTracks, { "TRACKTOTAL", "TOTALTRACKS" } }, { TagType::TrackNumber, { "TRCK", "TRACK", "TRACKNUMBER", "TRKN", "WM/TRACKNUMBER" } }, { TagType::TrackTitle, { "TITLE" } }, @@ -137,14 +137,14 @@ namespace lms::metadata { TagType::WorkTitle, { "WORK" } }, { TagType::Writer, { "WRITER" } }, }; - } + } // namespace AvFormatTagReader::AvFormatTagReader(const std::filesystem::path& p, bool debug) { try { const auto audioFile{ av::parseAudioFile(p) }; - + _audioProperties.duration = audioFile->getContainerInfo().duration; const auto bestAudioStream{ audioFile->getBestStreamInfo() }; @@ -182,11 +182,10 @@ namespace lms::metadata { bool visited{}; - visitTagValues(tagName, [&](std::string_view value) - { - visited = true; - visitor(value); - }); + visitTagValues(tagName, [&](std::string_view value) { + visited = true; + visitor(value); + }); if (visited) break; @@ -204,8 +203,7 @@ namespace lms::metadata void AvFormatTagReader::visitPerformerTags(PerformerVisitor visitor) const { - visitTagValues("PERFORMER", [&](std::string_view value) - { + visitTagValues("PERFORMER", [&](std::string_view value) { visitor("", value); }); } diff --git a/src/libs/metadata/impl/AvFormatTagReader.hpp b/src/libs/metadata/impl/AvFormatTagReader.hpp index 857de190..15b806b0 100644 --- a/src/libs/metadata/impl/AvFormatTagReader.hpp +++ b/src/libs/metadata/impl/AvFormatTagReader.hpp @@ -23,13 +23,14 @@ #include "av/IAudioFile.hpp" #include "metadata/IParser.hpp" + #include "ITagReader.hpp" namespace lms::metadata { class AvFormatTagReader : public ITagReader { - public: + public: AvFormatTagReader(const std::filesystem::path& path, bool debug); private: @@ -48,4 +49,3 @@ namespace lms::metadata bool _hasEmbeddedCover{}; }; } // namespace lms::metadata - diff --git a/src/libs/metadata/impl/Parser.cpp b/src/libs/metadata/impl/Parser.cpp index bfdb38e4..7d7e3b89 100644 --- a/src/libs/metadata/impl/Parser.cpp +++ b/src/libs/metadata/impl/Parser.cpp @@ -21,9 +21,9 @@ #include -#include "metadata/Exception.hpp" #include "core/ILogger.hpp" #include "core/String.hpp" +#include "metadata/Exception.hpp" #include "AvFormatTagReader.hpp" #include "TagLibTagReader.hpp" @@ -35,29 +35,27 @@ namespace lms::metadata { void visitTagValues(const ITagReader& tagReader, std::string_view tagType, std::span tagDelimiters, ITagReader::TagValueVisitor visitor) { - tagReader.visitTagValues(tagType, [&](std::string_view value) + tagReader.visitTagValues(tagType, [&](std::string_view value) { + auto visitTagIfNonEmpty{ [&](std::string_view tag) { + tag = core::stringUtils::stringTrim(tag); + if (!tag.empty()) + visitor(tag); + } }; + + for (std::string_view tagDelimiter : tagDelimiters) { - auto visitTagIfNonEmpty{ [&](std::string_view tag) + if (value.find(tagDelimiter) != std::string_view::npos) { - tag = core::stringUtils::stringTrim(tag); - if (!tag.empty()) - visitor(tag); - } }; + for (std::string_view splitTag : core::stringUtils::splitString(value, tagDelimiter)) + visitTagIfNonEmpty(splitTag); - for (std::string_view tagDelimiter : tagDelimiters) - { - if (value.find(tagDelimiter) != std::string_view::npos) - { - for (std::string_view splitTag : core::stringUtils::splitString(value, tagDelimiter)) - visitTagIfNonEmpty(splitTag); - - return; - } + return; } + } - // no delimiter found, or no delimiter to be used - visitTagIfNonEmpty(value); - }); + // no delimiter found, or no delimiter to be used + visitTagIfNonEmpty(value); + }); } template @@ -67,8 +65,7 @@ namespace lms::metadata for (const TagType tagType : tagTypes) { - auto addTagIfNonEmpty{ [&res](std::string_view tag) - { + auto addTagIfNonEmpty{ [&res](std::string_view tag) { tag = core::stringUtils::stringTrim(tag); if (!tag.empty()) { @@ -78,22 +75,21 @@ namespace lms::metadata } } }; - tagReader.visitTagValues(tagType, [&](std::string_view value) + tagReader.visitTagValues(tagType, [&](std::string_view value) { + for (std::string_view tagDelimiter : tagDelimiters) { - for (std::string_view tagDelimiter : tagDelimiters) + if (value.find(tagDelimiter) != std::string_view::npos) { - if (value.find(tagDelimiter) != std::string_view::npos) - { - for (std::string_view splitTag : core::stringUtils::splitString(value, tagDelimiter)) - addTagIfNonEmpty(splitTag); + for (std::string_view splitTag : core::stringUtils::splitString(value, tagDelimiter)) + addTagIfNonEmpty(splitTag); - return; - } + return; } + } - // no delimiter found, or no delimiter to be used - addTagIfNonEmpty(value); - }); + // no delimiter found, or no delimiter to be used + addTagIfNonEmpty(value); + }); if (!res.empty()) break; @@ -102,7 +98,7 @@ namespace lms::metadata return res; } - template + template std::optional getTagValueFirstMatchAs(const ITagReader& tagReader, std::initializer_list tagTypes) { std::optional res; @@ -113,13 +109,13 @@ namespace lms::metadata return res; } - template + template std::vector getTagValuesAs(const ITagReader& tagReader, TagType tagType, std::span tagDelimiters) { return getTagValuesFirstMatchAs(tagReader, { tagType }, tagDelimiters); } - template + template std::optional getTagValueAs(const ITagReader& tagReader, TagType tagType) { return getTagValueFirstMatchAs(tagReader, { tagType }); @@ -129,8 +125,7 @@ namespace lms::metadata std::initializer_list artistTagNames, std::initializer_list artistSortTagNames, std::initializer_list artistMBIDTagNames, - std::span artistTagDelimiters - ) + std::span artistTagDelimiters) { std::vector artistNames{ getTagValuesFirstMatchAs(tagReader, artistTagNames, artistTagDelimiters) }; if (artistNames.empty()) @@ -159,29 +154,28 @@ namespace lms::metadata { PerformerContainer performers; - tagReader.visitPerformerTags([&](std::string_view role, std::string_view name) + tagReader.visitPerformerTags([&](std::string_view role, std::string_view name) { + // picard stores like this: (see https://picard-docs.musicbrainz.org/en/appendices/tag_mapping.html#performer) + // We consider we may hit both styles for the same track + if (role.empty()) { - // picard stores like this: (see https://picard-docs.musicbrainz.org/en/appendices/tag_mapping.html#performer) - // We consider we may hit both styles for the same track - if (role.empty()) - { - // "PERFORMER" "artist (role)" - utils::PerformerArtist performer{ utils::extractPerformerAndRole(name) }; - core::stringUtils::capitalize(performer.role); - performers[performer.role].push_back(std::move(performer.artist)); - } - else - { - // "PERFORMER:role", "artist" (MP3) - std::string roleCapitalized{ core::stringUtils::stringToLower(role) }; - core::stringUtils::capitalize(roleCapitalized); - performers[roleCapitalized].push_back(Artist{ name }); - } - }); + // "PERFORMER" "artist (role)" + utils::PerformerArtist performer{ utils::extractPerformerAndRole(name) }; + core::stringUtils::capitalize(performer.role); + performers[performer.role].push_back(std::move(performer.artist)); + } + else + { + // "PERFORMER:role", "artist" (MP3) + std::string roleCapitalized{ core::stringUtils::stringToLower(role) }; + core::stringUtils::capitalize(roleCapitalized); + performers[roleCapitalized].push_back(Artist{ name }); + } + }); return performers; } - } + } // namespace std::unique_ptr createParser(ParserBackend parserBackend, ParserReadStyle parserReadStyle) { @@ -286,12 +280,11 @@ namespace lms::metadata for (const std::string& userExtraTag : _userExtraTags) { - visitTagValues(tagReader, userExtraTag, _defaultTagDelimiters, [&](std::string_view value) - { - value = core::stringUtils::stringTrim(value); - if (!value.empty()) - track.userExtraTags[userExtraTag].push_back(std::string{ value }); - }); + visitTagValues(tagReader, userExtraTag, _defaultTagDelimiters, [&](std::string_view value) { + value = core::stringUtils::stringTrim(value); + if (!value.empty()) + track.userExtraTags[userExtraTag].push_back(std::string{ value }); + }); } track.genres = getTagValuesAs(tagReader, TagType::Genre, _defaultTagDelimiters); @@ -321,7 +314,6 @@ namespace lms::metadata track.originalYear = track.originalDate.year(); } - std::optional Parser::getMedium(const ITagReader& tagReader) { std::optional medium; diff --git a/src/libs/metadata/impl/Parser.hpp b/src/libs/metadata/impl/Parser.hpp index 87bd8f21..fe2d2517 100644 --- a/src/libs/metadata/impl/Parser.hpp +++ b/src/libs/metadata/impl/Parser.hpp @@ -20,6 +20,7 @@ #pragma once #include "metadata/IParser.hpp" + #include "ITagReader.hpp" namespace lms::metadata @@ -50,4 +51,3 @@ namespace lms::metadata std::vector _defaultTagDelimiters; }; } // namespace lms::metadata - diff --git a/src/libs/metadata/impl/TagLibTagReader.cpp b/src/libs/metadata/impl/TagLibTagReader.cpp index fe3735b7..cdf176fc 100644 --- a/src/libs/metadata/impl/TagLibTagReader.cpp +++ b/src/libs/metadata/impl/TagLibTagReader.cpp @@ -25,11 +25,11 @@ #include #include #if TAGLIB_MAJOR_VERSION >= 2 -#include + #include #endif -#include #include #include +#include #include #include #include @@ -39,20 +39,21 @@ #include #include -#include "metadata/Exception.hpp" #include "core/ILogger.hpp" #include "core/ITraceLogger.hpp" #include "core/String.hpp" +#include "metadata/Exception.hpp" namespace lms::metadata { namespace { - class ParsingFailedException : public Exception {}; + class ParsingFailedException : public Exception + { + }; // Mapping to internal taglib names and/or common alternative custom names - static const std::unordered_map> tagMapping - { + static const std::unordered_map> tagMapping{ { TagType::AcoustID, { "ACOUSTID_ID", "ACOUSTID ID" } }, { TagType::Album, { "ALBUM" } }, { TagType::AlbumArtist, { "ALBUMARTIST" } }, @@ -147,7 +148,7 @@ namespace lms::metadata { TagType::Script, { "SCRIPT" } }, { TagType::ShowWorkAndMovement, { "SHOWWORKMOVEMENT", "SHOWMOVEMENT" } }, { TagType::Subtitle, { "SUBTITLE" } }, - { TagType::TotalDiscs, { "DISCTOTAL", "TOTALDISCS"} }, + { TagType::TotalDiscs, { "DISCTOTAL", "TOTALDISCS" } }, { TagType::TotalTracks, { "TRACKTOTAL", "TOTALTRACKS" } }, { TagType::TrackNumber, { "TRACKNUMBER" } }, { TagType::TrackTitle, { "TITLE" } }, @@ -160,9 +161,12 @@ namespace lms::metadata { switch (readStyle) { - case ParserReadStyle::Fast: return TagLib::AudioProperties::ReadStyle::Fast; - case ParserReadStyle::Average: return TagLib::AudioProperties::ReadStyle::Average; - case ParserReadStyle::Accurate: return TagLib::AudioProperties::ReadStyle::Accurate; + case ParserReadStyle::Fast: + return TagLib::AudioProperties::ReadStyle::Fast; + case ParserReadStyle::Average: + return TagLib::AudioProperties::ReadStyle::Average; + case ParserReadStyle::Accurate: + return TagLib::AudioProperties::ReadStyle::Accurate; } throw core::LmsException{ "Cannot convert read style" }; @@ -181,11 +185,11 @@ namespace lms::metadata { LMS_SCOPED_TRACE_DETAILED("MetaData", "TagLibParseFile"); - return TagLib::FileRef{ p.string().c_str() - , true // read audio properties - , readStyleToTagLibReadStyle(parserReadStyle) }; + return TagLib::FileRef{ p.string().c_str(), true // read audio properties + , + readStyleToTagLibReadStyle(parserReadStyle) }; } - } + } // namespace TagLibTagReader::TagLibTagReader(const std::filesystem::path& p, ParserReadStyle parserReadStyle, bool debug) : _file{ parseFile(p, parserReadStyle) } @@ -207,13 +211,12 @@ namespace lms::metadata _propertyMap = _file.file()->properties(); // Some tags may not be known by TagLib - auto getAPETags = [&](const TagLib::APE::Tag* apeTag) - { - if (!apeTag) - return; + auto getAPETags = [&](const TagLib::APE::Tag* apeTag) { + if (!apeTag) + return; - mergeTagMaps(_propertyMap, apeTag->properties()); - }; + mergeTagMaps(_propertyMap, apeTag->properties()); + }; // Not that good embedded pictures handling // + get some extra tags that may not be known by taglib @@ -263,7 +266,7 @@ namespace lms::metadata getAPETags(mp3File->APETag()); } - //MP4 + // MP4 else if (TagLib::MP4::File * mp4File{ dynamic_cast(_file.file()) }) { TagLib::MP4::Item coverItem{ mp4File->tag()->item("covr") }; @@ -321,18 +324,18 @@ namespace lms::metadata _audioProperties.duration = std::chrono::milliseconds{ properties->lengthInMilliseconds() }; _audioProperties.sampleRate = static_cast(properties->sampleRate()); - if (const auto * apeProperties{ dynamic_cast(properties) }) + if (const auto* apeProperties{ dynamic_cast(properties) }) _audioProperties.bitsPerSample = apeProperties->bitsPerSample(); - if (const auto * asfProperties{ dynamic_cast(properties) }) + if (const auto* asfProperties{ dynamic_cast(properties) }) _audioProperties.bitsPerSample = asfProperties->bitsPerSample(); - else if (const auto * flacProperties{ dynamic_cast(properties) }) + else if (const auto* flacProperties{ dynamic_cast(properties) }) _audioProperties.bitsPerSample = flacProperties->bitsPerSample(); - else if (const auto * mp4Properties{ dynamic_cast(properties) }) + else if (const auto* mp4Properties{ dynamic_cast(properties) }) _audioProperties.bitsPerSample = mp4Properties->bitsPerSample(); - else if (const auto * wavePackProperties{ dynamic_cast(properties) }) + else if (const auto* wavePackProperties{ dynamic_cast(properties) }) _audioProperties.bitsPerSample = wavePackProperties->bitsPerSample(); #if TAGLIB_MAJOR_VERSION >= 2 - else if (const auto * dsfProperties{ dynamic_cast(properties) }) + else if (const auto* dsfProperties{ dynamic_cast(properties) }) _audioProperties.bitsPerSample = dsfProperties->bitsPerSample(); #endif } @@ -347,11 +350,10 @@ namespace lms::metadata { bool visited{}; - visitTagValues(tagName, [&](std::string_view value) - { - visited = true; - visitor(value); - }); + visitTagValues(tagName, [&](std::string_view value) { + visited = true; + visitor(value); + }); if (visited) break; @@ -372,10 +374,9 @@ namespace lms::metadata void TagLibTagReader::visitPerformerTags(PerformerVisitor visitor) const { - visitTagValues("PERFORMER", [&](std::string_view value) - { - visitor("", value); - }); + visitTagValues("PERFORMER", [&](std::string_view value) { + visitor("", value); + }); for (const auto& [key, values] : _propertyMap) { diff --git a/src/libs/metadata/impl/TagLibTagReader.hpp b/src/libs/metadata/impl/TagLibTagReader.hpp index 3ada79af..0b13853d 100644 --- a/src/libs/metadata/impl/TagLibTagReader.hpp +++ b/src/libs/metadata/impl/TagLibTagReader.hpp @@ -25,6 +25,7 @@ #include #include "metadata/IParser.hpp" + #include "ITagReader.hpp" namespace lms::metadata diff --git a/src/libs/metadata/impl/Utils.cpp b/src/libs/metadata/impl/Utils.cpp index 1d9c5c70..6f87545f 100644 --- a/src/libs/metadata/impl/Utils.cpp +++ b/src/libs/metadata/impl/Utils.cpp @@ -19,9 +19,9 @@ #include "Utils.hpp" #include -#include #include #include +#include #include "core/Exception.hpp" @@ -29,8 +29,7 @@ namespace lms::metadata::utils { Wt::WDate parseDate(std::string_view dateStr) { - static constexpr const char* formats[] - { + static constexpr const char* formats[]{ "%Y-%m-%d", "%Y/%m/%d", }; @@ -41,7 +40,7 @@ namespace lms::metadata::utils tm.tm_mon = -1; tm.tm_mday = -1; - std::istringstream ss{ std::string {dateStr} }; // TODO, remove extra copy here + std::istringstream ss{ std::string{ dateStr } }; // TODO, remove extra copy here ss >> std::get_time(&tm, format); if (ss.fail()) continue; @@ -49,11 +48,10 @@ namespace lms::metadata::utils if (tm.tm_mday <= 0 || tm.tm_mon < 0) continue; - const Wt::WDate res - { - tm.tm_year + 1900, // tm.tm_year: years since 1900 - tm.tm_mon + 1, // tm.tm_mon: months since January – [00, 11] - tm.tm_mday // tm.tm_mday: day of the month – [1, 31] + const Wt::WDate res{ + tm.tm_year + 1900, // tm.tm_year: years since 1900 + tm.tm_mon + 1, // tm.tm_mon: months since January – [00, 11] + tm.tm_mday // tm.tm_mday: day of the month – [1, 31] }; if (!res.isValid()) continue; @@ -87,7 +85,8 @@ namespace lms::metadata::utils int result{}; for (std::size_t i{}; i < yearStr.size() && i < 4; ++i) { - if (!std::isdigit(yearStr[i])) { + if (!std::isdigit(yearStr[i])) + { break; } result = result * 10 + (yearStr[i] - '0'); @@ -100,9 +99,12 @@ namespace lms::metadata::utils { switch (readStyle) { - case ParserReadStyle::Fast: return "fast"; - case ParserReadStyle::Average: return "average"; - case ParserReadStyle::Accurate: return "accurate"; + case ParserReadStyle::Fast: + return "fast"; + case ParserReadStyle::Average: + return "average"; + case ParserReadStyle::Accurate: + return "accurate"; } throw core::LmsException{ "Unknown read style" }; @@ -150,6 +152,6 @@ namespace lms::metadata::utils if (!roleEnd || !roleBegin) artistName = core::stringUtils::stringTrim(entry); - return PerformerArtist{ Artist {artistName}, std::string {role} }; + return PerformerArtist{ Artist{ artistName }, std::string{ role } }; } -} \ No newline at end of file +} // namespace lms::metadata::utils \ No newline at end of file diff --git a/src/libs/metadata/impl/Utils.hpp b/src/libs/metadata/impl/Utils.hpp index 3e844da2..dc7671e8 100644 --- a/src/libs/metadata/impl/Utils.hpp +++ b/src/libs/metadata/impl/Utils.hpp @@ -22,22 +22,23 @@ #include #include + #include #include "metadata/IParser.hpp" namespace lms::metadata::utils { - Wt::WDate parseDate(std::string_view dateStr); - std::optional parseYear(std::string_view yearStr); - std::string_view readStyleToString(ParserReadStyle readStyle); + Wt::WDate parseDate(std::string_view dateStr); + std::optional parseYear(std::string_view yearStr); + std::string_view readStyleToString(ParserReadStyle readStyle); - struct PerformerArtist - { - Artist artist; - std::string role; - }; + struct PerformerArtist + { + Artist artist; + std::string role; + }; - // format is "artist name (role)" - PerformerArtist extractPerformerAndRole(std::string_view entry); -} + // format is "artist name (role)" + PerformerArtist extractPerformerAndRole(std::string_view entry); +} // namespace lms::metadata::utils diff --git a/src/libs/metadata/include/metadata/Exception.hpp b/src/libs/metadata/include/metadata/Exception.hpp index 7f0c6ac0..7a878420 100644 --- a/src/libs/metadata/include/metadata/Exception.hpp +++ b/src/libs/metadata/include/metadata/Exception.hpp @@ -34,4 +34,4 @@ namespace lms::metadata public: using Exception::Exception; }; -} \ No newline at end of file +} // namespace lms::metadata \ No newline at end of file diff --git a/src/libs/metadata/include/metadata/IParser.hpp b/src/libs/metadata/include/metadata/IParser.hpp index 47b6c908..f1553c5d 100644 --- a/src/libs/metadata/include/metadata/IParser.hpp +++ b/src/libs/metadata/include/metadata/IParser.hpp @@ -52,4 +52,4 @@ namespace lms::metadata Accurate, }; std::unique_ptr createParser(ParserBackend parserBackend, ParserReadStyle parserReadStyle); -} +} // namespace lms::metadata diff --git a/src/libs/metadata/test/Metadata.cpp b/src/libs/metadata/test/Metadata.cpp index 88325e8b..dc673372 100644 --- a/src/libs/metadata/test/Metadata.cpp +++ b/src/libs/metadata/test/Metadata.cpp @@ -19,9 +19,8 @@ #include -int main(int argc, char **argv) +int main(int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } - diff --git a/src/libs/metadata/test/Parser.cpp b/src/libs/metadata/test/Parser.cpp index 3c6bf9db..b5b6731b 100644 --- a/src/libs/metadata/test/Parser.cpp +++ b/src/libs/metadata/test/Parser.cpp @@ -19,10 +19,11 @@ #include #include + #include -#include "TestTagReader.hpp" #include "Parser.hpp" +#include "TestTagReader.hpp" namespace lms::metadata { @@ -65,23 +66,18 @@ namespace lms::metadata { TagType::Language, { "Language1", "Language2" } }, { TagType::Lyricist, { "MyLyricist1", "MyLyricist2" } }, { TagType::OriginalReleaseDate, { "2019/02/03" } }, - { TagType::ReleaseType, {"Album", "Compilation"} }, - { TagType::ReplayGainTrackGain, {"-0.33"} }, - { TagType::ReplayGainAlbumGain, {"-0.5"} }, - { TagType::TrackTitle, {"MyTitle"} }, + { TagType::ReleaseType, { "Album", "Compilation" } }, + { TagType::ReplayGainTrackGain, { "-0.33" } }, + { TagType::ReplayGainAlbumGain, { "-0.5" } }, + { TagType::TrackTitle, { "MyTitle" } }, { TagType::TrackNumber, { "7" } }, { TagType::TotalTracks, { "12" } }, { TagType::TotalDiscs, { "3" } }, - } - , - { - { "RoleA", { "MyPerformer1ForRoleA", "MyPerformer2ForRoleA" } }, - { "RoleB", { "MyPerformer1ForRoleB", "MyPerformer2ForRoleB" } } }, - { - { "MY_AWESOME_TAG_A", { "MyTagValue1ForTagA", "MyTagValue2ForTagA" } }, - { "MY_AWESOME_TAG_B", { "MyTagValue1ForTagB", "MyTagValue2ForTagB" } } - } + { { "RoleA", { "MyPerformer1ForRoleA", "MyPerformer2ForRoleA" } }, + { "RoleB", { "MyPerformer1ForRoleB", "MyPerformer2ForRoleB" } } }, + { { "MY_AWESOME_TAG_A", { "MyTagValue1ForTagA", "MyTagValue2ForTagA" } }, + { "MY_AWESOME_TAG_B", { "MyTagValue1ForTagB", "MyTagValue2ForTagB" } } } }; static_cast(parser).setUserExtraTags(std::vector{ "MY_AWESOME_TAG_A", "MY_AWESOME_TAG_B", "MY_AWESOME_MISSING_TAG" }); @@ -254,4 +250,4 @@ namespace lms::metadata EXPECT_EQ(track->artists[1].name, "Other Artist"); EXPECT_EQ(track->artistDisplayName, "This / is ; One Artist \\ Other Artist"); } -} +} // namespace lms::metadata diff --git a/src/libs/metadata/test/TestTagReader.hpp b/src/libs/metadata/test/TestTagReader.hpp index e7f968f4..d27acfaf 100644 --- a/src/libs/metadata/test/TestTagReader.hpp +++ b/src/libs/metadata/test/TestTagReader.hpp @@ -19,6 +19,7 @@ #include #include + #include #include "Parser.hpp" @@ -28,12 +29,11 @@ namespace lms::metadata class TestTagReader : public ITagReader { public: - static constexpr AudioProperties audioProperties - { + static constexpr AudioProperties audioProperties{ .bitrate = 128000, .bitsPerSample = 16, .channelCount = 2, - .duration = std::chrono::seconds{180}, + .duration = std::chrono::seconds{ 180 }, .sampleRate = 44000, }; @@ -84,4 +84,4 @@ namespace lms::metadata const Performers _performers; const ExtraUserTags _extraUserTags; }; -} \ No newline at end of file +} // namespace lms::metadata \ No newline at end of file diff --git a/src/libs/metadata/test/Utils.cpp b/src/libs/metadata/test/Utils.cpp index 4d766c70..925675ea 100644 --- a/src/libs/metadata/test/Utils.cpp +++ b/src/libs/metadata/test/Utils.cpp @@ -28,42 +28,41 @@ namespace lms::metadata::utils::tests { struct TestCase { - std::string str; - Wt::WDate result; - } testCases[] - { - { "1995-05-09", Wt::WDate {1995, 5, 9} }, - { "1995-01-01", Wt::WDate {1995, 1, 1} }, - { "1900-01-01", Wt::WDate {1900, 1, 1} }, - { "1899-01-01", Wt::WDate {1899, 1, 1} }, - { "1899-12-31", Wt::WDate {1899, 12, 31} }, - { "1899-11-30", Wt::WDate {1899, 11, 30} }, - { "1500-11-30", Wt::WDate {1500, 11, 30} }, - { "1000-11-30", Wt::WDate {1000, 11, 30} }, - { "1899-11-31", Wt::WDate {} }, // invalid day - { "1899-11-00", Wt::WDate {} }, // invalid day - { "1899-13-01", Wt::WDate {} }, // invalid month - { "1899-00-01", Wt::WDate {} }, // invalid month - { "1899-11", Wt::WDate {} }, // missing day - { "1899", Wt::WDate {} }, // missing month and days - { "1600", Wt::WDate {} }, // missing month and days - { "1995/05/09", Wt::WDate {1995, 5, 9} }, - { "1995/01/01", Wt::WDate {1995, 1, 1} }, - { "1900/01/01", Wt::WDate {1900, 1, 1} }, - { "1899/01/01", Wt::WDate {1899, 1, 1} }, - { "1899/12/31", Wt::WDate {1899, 12, 31} }, - { "1899/11/30", Wt::WDate {1899, 11, 30} }, - { "1500/11/30", Wt::WDate {1500, 11, 30} }, - { "1000/11/30", Wt::WDate {1000, 11, 30} }, - { "1899/11/31", Wt::WDate {} }, // invalid day - { "1899/11/00", Wt::WDate {} }, // invalid day - { "1899/13/01", Wt::WDate {} }, // invalid month - { "1899/00/01", Wt::WDate {} }, // invalid month - { "1899/11", Wt::WDate {} }, // missing day - { "1899", Wt::WDate {} }, // missing month and days - { "1600", Wt::WDate {} }, // missing month and days - { "1995/05-09", Wt::WDate {} }, // invalid mixup separators - { "1995-05/09", Wt::WDate {} }, // invalid mixup separators + std::string str; + Wt::WDate result; + } testCases[]{ + { "1995-05-09", Wt::WDate{ 1995, 5, 9 } }, + { "1995-01-01", Wt::WDate{ 1995, 1, 1 } }, + { "1900-01-01", Wt::WDate{ 1900, 1, 1 } }, + { "1899-01-01", Wt::WDate{ 1899, 1, 1 } }, + { "1899-12-31", Wt::WDate{ 1899, 12, 31 } }, + { "1899-11-30", Wt::WDate{ 1899, 11, 30 } }, + { "1500-11-30", Wt::WDate{ 1500, 11, 30 } }, + { "1000-11-30", Wt::WDate{ 1000, 11, 30 } }, + { "1899-11-31", Wt::WDate{} }, // invalid day + { "1899-11-00", Wt::WDate{} }, // invalid day + { "1899-13-01", Wt::WDate{} }, // invalid month + { "1899-00-01", Wt::WDate{} }, // invalid month + { "1899-11", Wt::WDate{} }, // missing day + { "1899", Wt::WDate{} }, // missing month and days + { "1600", Wt::WDate{} }, // missing month and days + { "1995/05/09", Wt::WDate{ 1995, 5, 9 } }, + { "1995/01/01", Wt::WDate{ 1995, 1, 1 } }, + { "1900/01/01", Wt::WDate{ 1900, 1, 1 } }, + { "1899/01/01", Wt::WDate{ 1899, 1, 1 } }, + { "1899/12/31", Wt::WDate{ 1899, 12, 31 } }, + { "1899/11/30", Wt::WDate{ 1899, 11, 30 } }, + { "1500/11/30", Wt::WDate{ 1500, 11, 30 } }, + { "1000/11/30", Wt::WDate{ 1000, 11, 30 } }, + { "1899/11/31", Wt::WDate{} }, // invalid day + { "1899/11/00", Wt::WDate{} }, // invalid day + { "1899/13/01", Wt::WDate{} }, // invalid month + { "1899/00/01", Wt::WDate{} }, // invalid month + { "1899/11", Wt::WDate{} }, // missing day + { "1899", Wt::WDate{} }, // missing month and days + { "1600", Wt::WDate{} }, // missing month and days + { "1995/05-09", Wt::WDate{} }, // invalid mixup separators + { "1995-05/09", Wt::WDate{} }, // invalid mixup separators }; for (const TestCase& testCase : testCases) @@ -80,10 +79,9 @@ namespace lms::metadata::utils::tests { struct TestCase { - std::string str; - std::optional result; - } testCases[] - { + std::string str; + std::optional result; + } testCases[]{ { "1995-05-09", 1995 }, { "1995", 1995 }, { "-0", 0 }, @@ -115,11 +113,10 @@ namespace lms::metadata::utils::tests { struct TestCase { - std::string str; + std::string str; std::string expectedArtistName; std::string expectedRole; - } testCases[] - { + } testCases[]{ { "", "", "" }, { "(myrole)", "", "myrole" }, { "(my role)", "", "my role" }, @@ -152,4 +149,4 @@ namespace lms::metadata::utils::tests EXPECT_EQ(performer.role, testCase.expectedRole) << " str was '" << testCase.str << "'"; } } -} \ No newline at end of file +} // namespace lms::metadata::utils::tests \ No newline at end of file diff --git a/src/libs/services/auth/impl/AuthServiceBase.cpp b/src/libs/services/auth/impl/AuthServiceBase.cpp index 9d72e2dd..3dfed8d2 100644 --- a/src/libs/services/auth/impl/AuthServiceBase.cpp +++ b/src/libs/services/auth/impl/AuthServiceBase.cpp @@ -19,11 +19,10 @@ #include "AuthServiceBase.hpp" -#include +#include "core/ILogger.hpp" #include "database/Db.hpp" #include "database/Session.hpp" #include "database/User.hpp" -#include "core/ILogger.hpp" namespace lms::auth { @@ -31,7 +30,8 @@ namespace lms::auth AuthServiceBase::AuthServiceBase(Db& db) : _db{ db } - {} + { + } UserId AuthServiceBase::getOrCreateUser(std::string_view loginName) { @@ -91,4 +91,4 @@ namespace lms::auth { return _db.getTLSSession(); } -} +} // namespace lms::auth diff --git a/src/libs/services/auth/impl/AuthServiceBase.hpp b/src/libs/services/auth/impl/AuthServiceBase.hpp index 918b4317..bba5f54e 100644 --- a/src/libs/services/auth/impl/AuthServiceBase.hpp +++ b/src/libs/services/auth/impl/AuthServiceBase.hpp @@ -20,13 +20,14 @@ #pragma once #include + #include "database/UserId.hpp" namespace lms::db { class Db; class Session; -} +} // namespace lms::db namespace lms::auth { @@ -35,12 +36,12 @@ namespace lms::auth protected: AuthServiceBase(db::Db& db); - db::UserId getOrCreateUser(std::string_view loginName); - void onUserAuthenticated(db::UserId userId); + db::UserId getOrCreateUser(std::string_view loginName); + void onUserAuthenticated(db::UserId userId); - db::Session& getDbSession(); + db::Session& getDbSession(); private: db::Db& _db; }; -} +} // namespace lms::auth diff --git a/src/libs/services/auth/impl/AuthTokenService.cpp b/src/libs/services/auth/impl/AuthTokenService.cpp index 38c5fce0..85196f72 100644 --- a/src/libs/services/auth/impl/AuthTokenService.cpp +++ b/src/libs/services/auth/impl/AuthTokenService.cpp @@ -23,121 +23,121 @@ #include #include -#include "services/auth/Types.hpp" +#include "core/Exception.hpp" +#include "core/ILogger.hpp" #include "database/AuthToken.hpp" #include "database/Session.hpp" #include "database/User.hpp" -#include "core/Exception.hpp" -#include "core/ILogger.hpp" +#include "services/auth/Types.hpp" namespace lms::auth { - std::unique_ptr createAuthTokenService(db::Db& db, std::size_t maxThrottlerEntries) - { - return std::make_unique(db, maxThrottlerEntries); - } + std::unique_ptr createAuthTokenService(db::Db& db, std::size_t maxThrottlerEntries) + { + return std::make_unique(db, maxThrottlerEntries); + } - static const Wt::Auth::SHA1HashFunction sha1Function; + static const Wt::Auth::SHA1HashFunction sha1Function; - AuthTokenService::AuthTokenService(db::Db& db, std::size_t maxThrottlerEntries) - : AuthServiceBase {db} - , _loginThrottler {maxThrottlerEntries} - { - } + AuthTokenService::AuthTokenService(db::Db& db, std::size_t maxThrottlerEntries) + : AuthServiceBase{ db } + , _loginThrottler{ maxThrottlerEntries } + { + } - std::string - AuthTokenService::createAuthToken(db::UserId userId, const Wt::WDateTime& expiry) - { - const std::string secret {Wt::WRandom::generateId(32)}; - const std::string secretHash {sha1Function.compute(secret, {})}; + std::string + AuthTokenService::createAuthToken(db::UserId userId, const Wt::WDateTime& expiry) + { + const std::string secret{ Wt::WRandom::generateId(32) }; + const std::string secretHash{ sha1Function.compute(secret, {}) }; - db::Session& session {getDbSession()}; + db::Session& session{ getDbSession() }; - auto transaction {session.createWriteTransaction()}; + auto transaction{ session.createWriteTransaction() }; - db::User::pointer user {db::User::find(session, userId)}; - if (!user) - throw Exception {"User deleted"}; + db::User::pointer user{ db::User::find(session, userId) }; + if (!user) + throw Exception{ "User deleted" }; - db::AuthToken::pointer authToken {session.create(secretHash, expiry, user)}; + db::AuthToken::pointer authToken{ session.create(secretHash, expiry, user) }; - LMS_LOG(UI, DEBUG, "Created auth token for user '" << user->getLoginName() << "', expiry = " << expiry.toString()); + LMS_LOG(UI, DEBUG, "Created auth token for user '" << user->getLoginName() << "', expiry = " << expiry.toString()); - if (user->getAuthTokensCount() >= 50) - db::AuthToken::removeExpiredTokens(session, Wt::WDateTime::currentDateTime()); + if (user->getAuthTokensCount() >= 50) + db::AuthToken::removeExpiredTokens(session, Wt::WDateTime::currentDateTime()); - return secret; - } + return secret; + } - std::optional - AuthTokenService::processAuthToken(std::string_view secret) - { - const std::string secretHash {sha1Function.compute(std::string {secret}, {})}; + std::optional + AuthTokenService::processAuthToken(std::string_view secret) + { + const std::string secretHash{ sha1Function.compute(std::string{ secret }, {}) }; - db::Session& session {getDbSession()}; - auto transaction {session.createWriteTransaction()}; + db::Session& session{ getDbSession() }; + auto transaction{ session.createWriteTransaction() }; - db::AuthToken::pointer authToken {db::AuthToken::find(session, secretHash)}; - if (!authToken) - return std::nullopt; + db::AuthToken::pointer authToken{ db::AuthToken::find(session, secretHash) }; + if (!authToken) + return std::nullopt; - if (authToken->getExpiry() < Wt::WDateTime::currentDateTime()) - { - authToken.remove(); - return std::nullopt; - } + if (authToken->getExpiry() < Wt::WDateTime::currentDateTime()) + { + authToken.remove(); + return std::nullopt; + } - LMS_LOG(UI, DEBUG, "Found auth token for user '" << authToken->getUser()->getLoginName() << "'!"); + LMS_LOG(UI, DEBUG, "Found auth token for user '" << authToken->getUser()->getLoginName() << "'!"); - AuthTokenService::AuthTokenProcessResult::AuthTokenInfo res {authToken->getUser()->getId(), authToken->getExpiry()}; - authToken.remove(); + AuthTokenService::AuthTokenProcessResult::AuthTokenInfo res{ authToken->getUser()->getId(), authToken->getExpiry() }; + authToken.remove(); - return res; - } + return res; + } - AuthTokenService::AuthTokenProcessResult - AuthTokenService::processAuthToken(const boost::asio::ip::address& clientAddress, std::string_view tokenValue) - { - // Do not waste too much resource on brute force attacks (optim) - { - std::shared_lock lock {_mutex}; + AuthTokenService::AuthTokenProcessResult + AuthTokenService::processAuthToken(const boost::asio::ip::address& clientAddress, std::string_view tokenValue) + { + // Do not waste too much resource on brute force attacks (optim) + { + std::shared_lock lock{ _mutex }; - if (_loginThrottler.isClientThrottled(clientAddress)) - return AuthTokenProcessResult {AuthTokenProcessResult::State::Throttled}; - } + if (_loginThrottler.isClientThrottled(clientAddress)) + return AuthTokenProcessResult{ AuthTokenProcessResult::State::Throttled }; + } - auto res {processAuthToken(tokenValue)}; - { - std::unique_lock lock {_mutex}; + auto res{ processAuthToken(tokenValue) }; + { + std::unique_lock lock{ _mutex }; - if (_loginThrottler.isClientThrottled(clientAddress)) - return AuthTokenProcessResult {AuthTokenProcessResult::State::Throttled}; + if (_loginThrottler.isClientThrottled(clientAddress)) + return AuthTokenProcessResult{ AuthTokenProcessResult::State::Throttled }; - if (!res) - { - _loginThrottler.onBadClientAttempt(clientAddress); - return AuthTokenProcessResult {AuthTokenProcessResult::State::Denied}; - } + if (!res) + { + _loginThrottler.onBadClientAttempt(clientAddress); + return AuthTokenProcessResult{ AuthTokenProcessResult::State::Denied }; + } - _loginThrottler.onGoodClientAttempt(clientAddress); - onUserAuthenticated(res->userId); - return AuthTokenProcessResult {AuthTokenProcessResult::State::Granted, std::move(*res)}; - } - } + _loginThrottler.onGoodClientAttempt(clientAddress); + onUserAuthenticated(res->userId); + return AuthTokenProcessResult{ AuthTokenProcessResult::State::Granted, std::move(*res) }; + } + } - void - AuthTokenService::clearAuthTokens(db::UserId userId) - { - db::Session& session {getDbSession()}; + void + AuthTokenService::clearAuthTokens(db::UserId userId) + { + db::Session& session{ getDbSession() }; - auto transaction {session.createWriteTransaction()}; + auto transaction{ session.createWriteTransaction() }; - db::User::pointer user {db::User::find(session, userId)}; - if (!user) - throw Exception {"User deleted"}; + db::User::pointer user{ db::User::find(session, userId) }; + if (!user) + throw Exception{ "User deleted" }; - user.modify()->clearAuthTokens(); - } + user.modify()->clearAuthTokens(); + } } // namespace lms::auth diff --git a/src/libs/services/auth/impl/AuthTokenService.hpp b/src/libs/services/auth/impl/AuthTokenService.hpp index 18234c24..f3160aba 100644 --- a/src/libs/services/auth/impl/AuthTokenService.hpp +++ b/src/libs/services/auth/impl/AuthTokenService.hpp @@ -22,34 +22,35 @@ #include #include "services/auth/IAuthTokenService.hpp" + #include "AuthServiceBase.hpp" #include "LoginThrottler.hpp" namespace lms::db { - class Session; + class Session; } namespace lms::auth { - class AuthTokenService : public IAuthTokenService, public AuthServiceBase - { - public: - AuthTokenService(db::Db& db, std::size_t maxThrottlerEntries); + class AuthTokenService : public IAuthTokenService, public AuthServiceBase + { + public: + AuthTokenService(db::Db& db, std::size_t maxThrottlerEntries); - AuthTokenService(const AuthTokenService&) = delete; - AuthTokenService& operator=(const AuthTokenService&) = delete; - AuthTokenService(AuthTokenService&&) = delete; - AuthTokenService& operator=(AuthTokenService&&) = delete; + AuthTokenService(const AuthTokenService&) = delete; + AuthTokenService& operator=(const AuthTokenService&) = delete; + AuthTokenService(AuthTokenService&&) = delete; + AuthTokenService& operator=(AuthTokenService&&) = delete; - private: - AuthTokenProcessResult processAuthToken(const boost::asio::ip::address& clientAddress, std::string_view tokenValue) override; - std::string createAuthToken(db::UserId userId, const Wt::WDateTime& expiry) override; - void clearAuthTokens(db::UserId userId) override; + private: + AuthTokenProcessResult processAuthToken(const boost::asio::ip::address& clientAddress, std::string_view tokenValue) override; + std::string createAuthToken(db::UserId userId, const Wt::WDateTime& expiry) override; + void clearAuthTokens(db::UserId userId) override; - std::optional processAuthToken(std::string_view secret); + std::optional processAuthToken(std::string_view secret); - std::shared_mutex _mutex; - LoginThrottler _loginThrottler; - }; -} + std::shared_mutex _mutex; + LoginThrottler _loginThrottler; + }; +} // namespace lms::auth diff --git a/src/libs/services/auth/impl/EnvService.cpp b/src/libs/services/auth/impl/EnvService.cpp index f0b32c60..113303c7 100644 --- a/src/libs/services/auth/impl/EnvService.cpp +++ b/src/libs/services/auth/impl/EnvService.cpp @@ -20,16 +20,17 @@ #include "services/auth/IEnvService.hpp" #include "services/auth/Types.hpp" + #include "http-headers/HttpHeadersEnvService.hpp" namespace lms::auth { - std::unique_ptr - createEnvService(std::string_view backendName, db::Db& db) - { - if (backendName == "http-headers") - return std::make_unique(db); + std::unique_ptr + createEnvService(std::string_view backendName, db::Db& db) + { + if (backendName == "http-headers") + return std::make_unique(db); - throw Exception {"Authentication backend '" + std::string {backendName} + "' is not supported!"}; - } -} + throw Exception{ "Authentication backend '" + std::string{ backendName } + "' is not supported!" }; + } +} // namespace lms::auth diff --git a/src/libs/services/auth/impl/LoginThrottler.cpp b/src/libs/services/auth/impl/LoginThrottler.cpp index be3e5be8..c04364fd 100644 --- a/src/libs/services/auth/impl/LoginThrottler.cpp +++ b/src/libs/services/auth/impl/LoginThrottler.cpp @@ -17,8 +17,6 @@ * along with LMS. If not, see . */ - /* This file contains some classes in order to get info from file using the libavconv */ - #include "LoginThrottler.hpp" #include "core/ILogger.hpp" @@ -44,13 +42,13 @@ namespace lms::auth { return address.is_v6() ? getAddressWithMask(address.to_v6(), 64) : address; } - } + } // namespace void LoginThrottler::removeOutdatedEntries() { const Wt::WDateTime now{ Wt::WDateTime::currentDateTime() }; - for (auto it{ std::begin(_attemptsInfo) }; it != std::end(_attemptsInfo); ) + for (auto it{ std::begin(_attemptsInfo) }; it != std::end(_attemptsInfo);) { if (it->second.nextAttempt <= now) it = _attemptsInfo.erase(it); @@ -110,4 +108,4 @@ namespace lms::auth return it->second.nextAttempt > Wt::WDateTime::currentDateTime(); } -} \ No newline at end of file +} // namespace lms::auth \ No newline at end of file diff --git a/src/libs/services/auth/impl/LoginThrottler.hpp b/src/libs/services/auth/impl/LoginThrottler.hpp index 035d092d..42a20fb8 100644 --- a/src/libs/services/auth/impl/LoginThrottler.hpp +++ b/src/libs/services/auth/impl/LoginThrottler.hpp @@ -24,34 +24,34 @@ #include -#include "core/NetAddress.hpp" #include "core/Exception.hpp" +#include "core/NetAddress.hpp" namespace lms::auth { - class LoginThrottler - { - public: - LoginThrottler(std::size_t maxEntries) : _maxEntries {maxEntries} {} + class LoginThrottler + { + public: + LoginThrottler(std::size_t maxEntries) + : _maxEntries{ maxEntries } {} - // user must lock these calls to avoid races - bool isClientThrottled(const boost::asio::ip::address& address) const; - void onBadClientAttempt(const boost::asio::ip::address& address); - void onGoodClientAttempt(const boost::asio::ip::address& address); + // user must lock these calls to avoid races + bool isClientThrottled(const boost::asio::ip::address& address) const; + void onBadClientAttempt(const boost::asio::ip::address& address); + void onGoodClientAttempt(const boost::asio::ip::address& address); - private: - void removeOutdatedEntries(); + private: + void removeOutdatedEntries(); - const std::size_t _maxEntries; - static constexpr std::size_t _maxBadConsecutiveAttemptCount {5}; - static constexpr std::chrono::seconds _throttlingDuration {3}; - - struct AttemptInfo - { - Wt::WDateTime nextAttempt; - std::size_t badConsecutiveAttemptCount{}; - }; - std::unordered_map _attemptsInfo; - }; -} // Auth + const std::size_t _maxEntries; + static constexpr std::size_t _maxBadConsecutiveAttemptCount{ 5 }; + static constexpr std::chrono::seconds _throttlingDuration{ 3 }; + struct AttemptInfo + { + Wt::WDateTime nextAttempt; + std::size_t badConsecutiveAttemptCount{}; + }; + std::unordered_map _attemptsInfo; + }; +} // namespace lms::auth diff --git a/src/libs/services/auth/impl/PasswordServiceBase.cpp b/src/libs/services/auth/impl/PasswordServiceBase.cpp index 5290b78f..4628e845 100644 --- a/src/libs/services/auth/impl/PasswordServiceBase.cpp +++ b/src/libs/services/auth/impl/PasswordServiceBase.cpp @@ -24,73 +24,72 @@ #include "internal/InternalPasswordService.hpp" #ifdef LMS_SUPPORT_PAM -#include "pam/PAMPasswordService.hpp" + #include "pam/PAMPasswordService.hpp" #endif // LMS_SUPPORT_PAM -#include "services/auth/Types.hpp" -#include "database/Session.hpp" -#include "database/User.hpp" #include "core/Exception.hpp" #include "core/ILogger.hpp" +#include "database/Session.hpp" +#include "database/User.hpp" +#include "services/auth/Types.hpp" namespace lms::auth { - static const Wt::Auth::SHA1HashFunction sha1Function; + static const Wt::Auth::SHA1HashFunction sha1Function; - std::unique_ptr - createPasswordService(std::string_view passwordAuthenticationBackend, db::Db& db, std::size_t maxThrottlerEntries, IAuthTokenService& authTokenService) - { - if (passwordAuthenticationBackend == "internal") - return std::make_unique(db, maxThrottlerEntries, authTokenService); + std::unique_ptr + createPasswordService(std::string_view passwordAuthenticationBackend, db::Db& db, std::size_t maxThrottlerEntries, IAuthTokenService& authTokenService) + { + if (passwordAuthenticationBackend == "internal") + return std::make_unique(db, maxThrottlerEntries, authTokenService); #ifdef LMS_SUPPORT_PAM - else if (passwordAuthenticationBackend == "pam") - return std::make_unique(db, maxThrottlerEntries, authTokenService); + else if (passwordAuthenticationBackend == "pam") + return std::make_unique(db, maxThrottlerEntries, authTokenService); #endif // LMS_SUPPORT_PAM - throw Exception {"Authentication backend '" + std::string {passwordAuthenticationBackend} + "' is not supported!"}; - } + throw Exception{ "Authentication backend '" + std::string{ passwordAuthenticationBackend } + "' is not supported!" }; + } - PasswordServiceBase::PasswordServiceBase(db::Db& db, std::size_t maxThrottlerEntries, IAuthTokenService& authTokenService) - : AuthServiceBase {db} - , _loginThrottler {maxThrottlerEntries} - , _authTokenService {authTokenService} - { - } + PasswordServiceBase::PasswordServiceBase(db::Db& db, std::size_t maxThrottlerEntries, IAuthTokenService& authTokenService) + : AuthServiceBase{ db } + , _loginThrottler{ maxThrottlerEntries } + , _authTokenService{ authTokenService } + { + } - PasswordServiceBase::CheckResult - PasswordServiceBase::checkUserPassword(const boost::asio::ip::address& clientAddress, std::string_view loginName, std::string_view password) - { - LMS_LOG(AUTH, DEBUG, "Checking password for user '" << loginName << "'"); + PasswordServiceBase::CheckResult + PasswordServiceBase::checkUserPassword(const boost::asio::ip::address& clientAddress, std::string_view loginName, std::string_view password) + { + LMS_LOG(AUTH, DEBUG, "Checking password for user '" << loginName << "'"); - // Do not waste too much resource on brute force attacks (optim) - { - std::shared_lock lock {_mutex}; + // Do not waste too much resource on brute force attacks (optim) + { + std::shared_lock lock{ _mutex }; - if (_loginThrottler.isClientThrottled(clientAddress)) - return {CheckResult::State::Throttled}; - } + if (_loginThrottler.isClientThrottled(clientAddress)) + return { CheckResult::State::Throttled }; + } - const bool match {checkUserPassword(loginName, password)}; - { - std::unique_lock lock {_mutex}; + const bool match{ checkUserPassword(loginName, password) }; + { + std::unique_lock lock{ _mutex }; - if (_loginThrottler.isClientThrottled(clientAddress)) - return {CheckResult::State::Throttled}; + if (_loginThrottler.isClientThrottled(clientAddress)) + return { CheckResult::State::Throttled }; - if (match) - { - _loginThrottler.onGoodClientAttempt(clientAddress); + if (match) + { + _loginThrottler.onGoodClientAttempt(clientAddress); - const db::UserId userId {getOrCreateUser(loginName)}; - onUserAuthenticated(userId); - return {CheckResult::State::Granted, userId}; - } - else - { - _loginThrottler.onBadClientAttempt(clientAddress); - return {CheckResult::State::Denied}; - } - } - } + const db::UserId userId{ getOrCreateUser(loginName) }; + onUserAuthenticated(userId); + return { CheckResult::State::Granted, userId }; + } + else + { + _loginThrottler.onBadClientAttempt(clientAddress); + return { CheckResult::State::Denied }; + } + } + } } // namespace lms::auth - diff --git a/src/libs/services/auth/impl/PasswordServiceBase.hpp b/src/libs/services/auth/impl/PasswordServiceBase.hpp index da431e84..1c32f5b9 100644 --- a/src/libs/services/auth/impl/PasswordServiceBase.hpp +++ b/src/libs/services/auth/impl/PasswordServiceBase.hpp @@ -21,40 +21,40 @@ #include -#include "services/auth/IPasswordService.hpp" #include "AuthServiceBase.hpp" #include "LoginThrottler.hpp" +#include "services/auth/IPasswordService.hpp" namespace lms::db { - class Db; - class Session; -} + class Db; + class Session; +} // namespace lms::db namespace lms::auth { - class PasswordServiceBase : public IPasswordService, public AuthServiceBase - { - public: - PasswordServiceBase(db::Db& db, std::size_t maxThrottlerEntries, IAuthTokenService& authTokenService); + class PasswordServiceBase : public IPasswordService, public AuthServiceBase + { + public: + PasswordServiceBase(db::Db& db, std::size_t maxThrottlerEntries, IAuthTokenService& authTokenService); - PasswordServiceBase(const PasswordServiceBase&) = delete; - PasswordServiceBase& operator=(const PasswordServiceBase&) = delete; - PasswordServiceBase(PasswordServiceBase&&) = delete; - PasswordServiceBase& operator=(PasswordServiceBase&&) = delete; + PasswordServiceBase(const PasswordServiceBase&) = delete; + PasswordServiceBase& operator=(const PasswordServiceBase&) = delete; + PasswordServiceBase(PasswordServiceBase&&) = delete; + PasswordServiceBase& operator=(PasswordServiceBase&&) = delete; - protected: - IAuthTokenService& getAuthTokenService() { return _authTokenService; } + protected: + IAuthTokenService& getAuthTokenService() { return _authTokenService; } - private: - virtual bool checkUserPassword(std::string_view loginName, std::string_view password) = 0; + private: + virtual bool checkUserPassword(std::string_view loginName, std::string_view password) = 0; - CheckResult checkUserPassword(const boost::asio::ip::address& clientAddress, - std::string_view loginName, - std::string_view password) override; + CheckResult checkUserPassword(const boost::asio::ip::address& clientAddress, + std::string_view loginName, + std::string_view password) override; - std::shared_mutex _mutex; - LoginThrottler _loginThrottler; - IAuthTokenService& _authTokenService; - }; -} + std::shared_mutex _mutex; + LoginThrottler _loginThrottler; + IAuthTokenService& _authTokenService; + }; +} // namespace lms::auth diff --git a/src/libs/services/auth/impl/http-headers/HttpHeadersEnvService.hpp b/src/libs/services/auth/impl/http-headers/HttpHeadersEnvService.hpp index 86cf48d0..0e3f9ffe 100644 --- a/src/libs/services/auth/impl/http-headers/HttpHeadersEnvService.hpp +++ b/src/libs/services/auth/impl/http-headers/HttpHeadersEnvService.hpp @@ -20,21 +20,21 @@ #pragma once #include "services/auth/IEnvService.hpp" + #include "AuthServiceBase.hpp" namespace lms::auth { - class HttpHeadersEnvService : public IEnvService, public AuthServiceBase - { - public: - HttpHeadersEnvService(db::Db& db); + class HttpHeadersEnvService : public IEnvService, public AuthServiceBase + { + public: + HttpHeadersEnvService(db::Db& db); - private: - CheckResult processEnv(const Wt::WEnvironment& env) override; - CheckResult processRequest(const Wt::Http::Request& request) override; + private: + CheckResult processEnv(const Wt::WEnvironment& env) override; + CheckResult processRequest(const Wt::Http::Request& request) override; - std::string _fieldName; - }; + std::string _fieldName; + }; } // namespace lms::auth - diff --git a/src/libs/services/auth/impl/internal/InternalPasswordService.cpp b/src/libs/services/auth/impl/internal/InternalPasswordService.cpp index 9aecde91..47b9fefe 100644 --- a/src/libs/services/auth/impl/internal/InternalPasswordService.cpp +++ b/src/libs/services/auth/impl/internal/InternalPasswordService.cpp @@ -18,14 +18,15 @@ */ #include "InternalPasswordService.hpp" + #include -#include "services/auth/IAuthTokenService.hpp" -#include "services/auth/Types.hpp" -#include "database/Session.hpp" -#include "database/User.hpp" #include "core/Exception.hpp" #include "core/ILogger.hpp" +#include "database/Session.hpp" +#include "database/User.hpp" +#include "services/auth/IAuthTokenService.hpp" +#include "services/auth/Types.hpp" namespace lms::auth { @@ -120,14 +121,13 @@ namespace lms::auth { const std::string salt{ Wt::WRandom::generateId(32) }; - return { salt, _hashFunc.compute(std::string {password}, salt) }; + return { salt, _hashFunc.compute(std::string{ password }, salt) }; } void - InternalPasswordService::hashRandomPassword() const + InternalPasswordService::hashRandomPassword() const { hashPassword(Wt::WRandom::generateId(32)); } } // namespace lms::auth - diff --git a/src/libs/services/auth/impl/internal/InternalPasswordService.hpp b/src/libs/services/auth/impl/internal/InternalPasswordService.hpp index c913d756..9c3e07d4 100644 --- a/src/libs/services/auth/impl/internal/InternalPasswordService.hpp +++ b/src/libs/services/auth/impl/internal/InternalPasswordService.hpp @@ -23,8 +23,9 @@ #include #include "database/User.hpp" -#include "PasswordServiceBase.hpp" + #include "LoginThrottler.hpp" +#include "PasswordServiceBase.hpp" namespace lms::auth { @@ -36,17 +37,17 @@ namespace lms::auth InternalPasswordService(db::Db& db, std::size_t maxThrottlerEntries, IAuthTokenService& authTokenService); private: - bool checkUserPassword(std::string_view loginName, std::string_view password) override; + bool checkUserPassword(std::string_view loginName, std::string_view password) override; - bool canSetPasswords() const override; - PasswordAcceptabilityResult checkPasswordAcceptability(std::string_view loginName, const PasswordValidationContext& context) const override; - void setPassword(db::UserId userId, std::string_view newPassword) override; + bool canSetPasswords() const override; + PasswordAcceptabilityResult checkPasswordAcceptability(std::string_view loginName, const PasswordValidationContext& context) const override; + void setPassword(db::UserId userId, std::string_view newPassword) override; - db::User::PasswordHash hashPassword(std::string_view password) const; - void hashRandomPassword() const; + db::User::PasswordHash hashPassword(std::string_view password) const; + void hashRandomPassword() const; - const Wt::Auth::BCryptHashFunction _hashFunc{ 7 }; // TODO parametrize this - Wt::Auth::PasswordStrengthValidator _validator; + const Wt::Auth::BCryptHashFunction _hashFunc{ 7 }; // TODO parametrize this + Wt::Auth::PasswordStrengthValidator _validator; }; -} +} // namespace lms::auth diff --git a/src/libs/services/auth/impl/pam/PAMPasswordService.cpp b/src/libs/services/auth/impl/pam/PAMPasswordService.cpp index 3d7d6be4..12cfe99c 100644 --- a/src/libs/services/auth/impl/pam/PAMPasswordService.cpp +++ b/src/libs/services/auth/impl/pam/PAMPasswordService.cpp @@ -20,15 +20,15 @@ #include "PAMPasswordService.hpp" #ifndef LMS_SUPPORT_PAM -#error "Should not compile this" + #error "Should not compile this" #endif #include #include -#include "services/auth/Types.hpp" -#include "database/Session.hpp" #include "core/ILogger.hpp" +#include "database/Session.hpp" +#include "services/auth/Types.hpp" namespace lms::auth { @@ -53,7 +53,7 @@ namespace lms::auth public: PAMContext(std::string_view loginName) { - int err{ pam_start("lms", std::string {loginName}.c_str(), &_conv, &_pamh) }; + int err{ pam_start("lms", std::string{ loginName }.c_str(), &_conv, &_pamh) }; if (err != PAM_SUCCESS) throw PAMError{ "start failed", _pamh, err }; } @@ -92,7 +92,8 @@ namespace lms::auth class AuthenticateConvContext final : public ConvContext { public: - AuthenticateConvContext(std::string_view password) : _password{ password } {} + AuthenticateConvContext(std::string_view password) + : _password{ password } {} std::string_view getPassword() const { return _password; } @@ -160,7 +161,7 @@ namespace lms::auth pam_conv _conv{ &PAMContext::conv, this }; pam_handle_t* _pamh{}; }; - } + } // namespace bool PAMPasswordService::checkUserPassword(std::string_view loginName, std::string_view password) { @@ -197,4 +198,3 @@ namespace lms::auth } } // namespace lms::auth - diff --git a/src/libs/services/auth/impl/pam/PAMPasswordService.hpp b/src/libs/services/auth/impl/pam/PAMPasswordService.hpp index b2c2b80e..38bb6d53 100644 --- a/src/libs/services/auth/impl/pam/PAMPasswordService.hpp +++ b/src/libs/services/auth/impl/pam/PAMPasswordService.hpp @@ -25,15 +25,15 @@ namespace lms::auth { - class PAMPasswordService: public PasswordServiceBase - { - public: - using PasswordServiceBase::PasswordServiceBase; + class PAMPasswordService : public PasswordServiceBase + { + public: + using PasswordServiceBase::PasswordServiceBase; - private: - bool checkUserPassword(std::string_view loginName,std::string_view password) override; - bool canSetPasswords() const override; - PasswordAcceptabilityResult checkPasswordAcceptability(std::string_view loginName, const PasswordValidationContext& context) const override; - void setPassword(db::UserId userId, std::string_view newPassword) override; - }; -} + private: + bool checkUserPassword(std::string_view loginName, std::string_view password) override; + bool canSetPasswords() const override; + PasswordAcceptabilityResult checkPasswordAcceptability(std::string_view loginName, const PasswordValidationContext& context) const override; + void setPassword(db::UserId userId, std::string_view newPassword) override; + }; +} // namespace lms::auth diff --git a/src/libs/services/auth/include/services/auth/IAuthTokenService.hpp b/src/libs/services/auth/include/services/auth/IAuthTokenService.hpp index 65941cde..f18d5244 100644 --- a/src/libs/services/auth/include/services/auth/IAuthTokenService.hpp +++ b/src/libs/services/auth/include/services/auth/IAuthTokenService.hpp @@ -17,58 +17,56 @@ * along with LMS. If not, see . */ -/* This file contains some classes in order to get info from file using the libavconv */ - #pragma once +#include +#include #include #include #include -#include -#include #include "database/UserId.hpp" namespace lms::db { - class Db; - class User; -} + class Db; + class User; +} // namespace lms::db namespace lms::auth { - class IAuthTokenService - { - public: - virtual ~IAuthTokenService() = default; + class IAuthTokenService + { + public: + virtual ~IAuthTokenService() = default; - // Auth Token services - struct AuthTokenProcessResult - { - enum class State - { - Granted, - Throttled, - Denied, - }; + // Auth Token services + struct AuthTokenProcessResult + { + enum class State + { + Granted, + Throttled, + Denied, + }; - struct AuthTokenInfo - { - db::UserId userId; - Wt::WDateTime expiry; - }; + struct AuthTokenInfo + { + db::UserId userId; + Wt::WDateTime expiry; + }; - State state {State::Denied}; - std::optional authTokenInfo {}; - }; + State state{ State::Denied }; + std::optional authTokenInfo{}; + }; - // Provided token is only accepted once - virtual AuthTokenProcessResult processAuthToken(const boost::asio::ip::address& clientAddress, std::string_view tokenValue) = 0; + // Provided token is only accepted once + virtual AuthTokenProcessResult processAuthToken(const boost::asio::ip::address& clientAddress, std::string_view tokenValue) = 0; - // Returns a one time token - virtual std::string createAuthToken(db::UserId userid, const Wt::WDateTime& expiry) = 0; - virtual void clearAuthTokens(db::UserId userid) = 0; - }; + // Returns a one time token + virtual std::string createAuthToken(db::UserId userid, const Wt::WDateTime& expiry) = 0; + virtual void clearAuthTokens(db::UserId userid) = 0; + }; - std::unique_ptr createAuthTokenService(db::Db& db, std::size_t maxThrottlerEntryCount); -} + std::unique_ptr createAuthTokenService(db::Db& db, std::size_t maxThrottlerEntryCount); +} // namespace lms::auth diff --git a/src/libs/services/auth/include/services/auth/IEnvService.hpp b/src/libs/services/auth/include/services/auth/IEnvService.hpp index d35b6cef..6dd5d85b 100644 --- a/src/libs/services/auth/include/services/auth/IEnvService.hpp +++ b/src/libs/services/auth/include/services/auth/IEnvService.hpp @@ -26,44 +26,44 @@ namespace lms::db { - class Db; - class Session; -} + class Db; + class Session; +} // namespace lms::db namespace Wt { - class WEnvironment; + class WEnvironment; } namespace Wt::Http { - class Request; + class Request; } namespace lms::auth { - class IEnvService - { - public: - virtual ~IEnvService() = default; + class IEnvService + { + public: + virtual ~IEnvService() = default; - // Auth Token services - struct CheckResult - { - enum class State - { - Granted, - Denied, - Throttled, - }; + // Auth Token services + struct CheckResult + { + enum class State + { + Granted, + Denied, + Throttled, + }; - State state {State::Denied}; - std::optional userId {}; - }; + State state{ State::Denied }; + std::optional userId{}; + }; - virtual CheckResult processEnv(const Wt::WEnvironment& env) = 0; - virtual CheckResult processRequest(const Wt::Http::Request& request) = 0; - }; + virtual CheckResult processEnv(const Wt::WEnvironment& env) = 0; + virtual CheckResult processRequest(const Wt::Http::Request& request) = 0; + }; - std::unique_ptr createEnvService(std::string_view backendName, db::Db& db); + std::unique_ptr createEnvService(std::string_view backendName, db::Db& db); } // namespace lms::auth diff --git a/src/libs/services/auth/include/services/auth/IPasswordService.hpp b/src/libs/services/auth/include/services/auth/IPasswordService.hpp index 9138e62c..21b12fab 100644 --- a/src/libs/services/auth/include/services/auth/IPasswordService.hpp +++ b/src/libs/services/auth/include/services/auth/IPasswordService.hpp @@ -19,59 +19,59 @@ #pragma once -#include #include +#include -#include -#include #include +#include +#include -#include "services/auth/Types.hpp" #include "database/UserId.hpp" +#include "services/auth/Types.hpp" namespace lms::db { - class Db; - class User; -} + class Db; + class User; +} // namespace lms::db namespace lms::auth { - class IAuthTokenService; + class IAuthTokenService; - class IPasswordService - { - public: - virtual ~IPasswordService() = default; + class IPasswordService + { + public: + virtual ~IPasswordService() = default; - struct CheckResult - { - enum class State - { - Granted, - Denied, - Throttled, - }; - State state {State::Denied}; - std::optional userId {}; - std::optional expiry {}; - }; - virtual CheckResult checkUserPassword(const boost::asio::ip::address& clientAddress, - std::string_view loginName, - std::string_view password) = 0; + struct CheckResult + { + enum class State + { + Granted, + Denied, + Throttled, + }; + State state{ State::Denied }; + std::optional userId{}; + std::optional expiry{}; + }; + virtual CheckResult checkUserPassword(const boost::asio::ip::address& clientAddress, + std::string_view loginName, + std::string_view password) + = 0; - virtual bool canSetPasswords() const = 0; + virtual bool canSetPasswords() const = 0; - enum class PasswordAcceptabilityResult - { - OK, - TooWeak, - MustMatchLoginName, - }; - virtual PasswordAcceptabilityResult checkPasswordAcceptability(std::string_view password, const PasswordValidationContext& context) const = 0; - virtual void setPassword(db::UserId userId, std::string_view newPassword) = 0; - }; - - std::unique_ptr createPasswordService(std::string_view authPasswordBackend, db::Db& db, std::size_t maxThrottlerEntryCount, IAuthTokenService& authTokenService); -} + enum class PasswordAcceptabilityResult + { + OK, + TooWeak, + MustMatchLoginName, + }; + virtual PasswordAcceptabilityResult checkPasswordAcceptability(std::string_view password, const PasswordValidationContext& context) const = 0; + virtual void setPassword(db::UserId userId, std::string_view newPassword) = 0; + }; + std::unique_ptr createPasswordService(std::string_view authPasswordBackend, db::Db& db, std::size_t maxThrottlerEntryCount, IAuthTokenService& authTokenService); +} // namespace lms::auth diff --git a/src/libs/services/auth/include/services/auth/Types.hpp b/src/libs/services/auth/include/services/auth/Types.hpp index 7d4b67aa..4122b2d2 100644 --- a/src/libs/services/auth/include/services/auth/Types.hpp +++ b/src/libs/services/auth/include/services/auth/Types.hpp @@ -20,50 +20,54 @@ #pragma once #include -#include "database/Types.hpp" + #include "core/Exception.hpp" +#include "database/Types.hpp" namespace lms::auth { - class Exception : public core::LmsException - { - using core::LmsException::LmsException; - }; + class Exception : public core::LmsException + { + using core::LmsException::LmsException; + }; - class NotImplementedException : public Exception - { - public: - NotImplementedException() : Exception {"Not implemented"} {} - }; + class NotImplementedException : public Exception + { + public: + NotImplementedException() + : Exception{ "Not implemented" } {} + }; - class UserNotFoundException : public Exception - { - public: - UserNotFoundException() : Exception {"User not found"} {} - }; + class UserNotFoundException : public Exception + { + public: + UserNotFoundException() + : Exception{ "User not found" } {} + }; - struct PasswordValidationContext - { - std::string loginName; - db::UserType userType; - }; + struct PasswordValidationContext + { + std::string loginName; + db::UserType userType; + }; - class PasswordException : public Exception - { - public: - using Exception::Exception; - }; + class PasswordException : public Exception + { + public: + using Exception::Exception; + }; - class PasswordTooWeakException : public PasswordException - { - public: - PasswordTooWeakException() : PasswordException {"Password too weak"} {} - }; - - class PasswordMustMatchLoginNameException : public PasswordException - { - public: - PasswordMustMatchLoginNameException() : PasswordException {"Password must match login name"} {} - }; -} + class PasswordTooWeakException : public PasswordException + { + public: + PasswordTooWeakException() + : PasswordException{ "Password too weak" } {} + }; + class PasswordMustMatchLoginNameException : public PasswordException + { + public: + PasswordMustMatchLoginNameException() + : PasswordException{ "Password must match login name" } {} + }; +} // namespace lms::auth diff --git a/src/libs/services/cover/impl/CoverService.cpp b/src/libs/services/cover/impl/CoverService.cpp index c3a04176..afb3cc29 100644 --- a/src/libs/services/cover/impl/CoverService.cpp +++ b/src/libs/services/cover/impl/CoverService.cpp @@ -22,21 +22,19 @@ #include #include "av/IAudioFile.hpp" - -#include "database/Db.hpp" -#include "database/Artist.hpp" -#include "database/Release.hpp" -#include "database/Session.hpp" -#include "database/Track.hpp" - -#include "image/Exception.hpp" -#include "image/Image.hpp" #include "core/IConfig.hpp" #include "core/ILogger.hpp" #include "core/Path.hpp" #include "core/Random.hpp" #include "core/String.hpp" #include "core/Utils.hpp" +#include "database/Artist.hpp" +#include "database/Db.hpp" +#include "database/Release.hpp" +#include "database/Session.hpp" +#include "database/Track.hpp" +#include "image/Exception.hpp" +#include "image/Image.hpp" namespace lms::cover { @@ -80,10 +78,10 @@ namespace lms::cover std::vector res; core::Service::get()->visitStrings("cover-preferred-file-names", - [&res](std::string_view fileName) - { + [&res](std::string_view fileName) { res.emplace_back(fileName); - }, { "cover", "front" }); + }, + { "cover", "front" }); return res; } @@ -93,10 +91,10 @@ namespace lms::cover std::vector res; core::Service::get()->visitStrings("artist-image-file-names", - [&res](std::string_view fileName) - { + [&res](std::string_view fileName) { res.emplace_back(fileName); - }, { "artist" }); + }, + { "artist" }); return res; } @@ -105,7 +103,7 @@ namespace lms::cover { return (std::find(std::cbegin(extensions), std::cend(extensions), file.extension()) != std::cend(extensions)); } - } + } // namespace std::unique_ptr createCoverService(db::Db& db, const std::filesystem::path& defaultSvgCoverPath) { @@ -136,22 +134,21 @@ namespace lms::cover { std::unique_ptr image; - input.visitAttachedPictures([&](const av::Picture& picture) - { - if (image) - return; + input.visitAttachedPictures([&](const av::Picture& picture) { + if (image) + return; - try - { - std::unique_ptr rawImage{ decodeImage(picture.data, picture.dataSize) }; - rawImage->resize(width); - image = rawImage->encodeToJPEG(_jpegQuality); - } - catch (const image::Exception& e) - { - LMS_LOG(COVER, ERROR, "Cannot read embedded cover: " << e.what()); - } - }); + try + { + std::unique_ptr rawImage{ decodeImage(picture.data, picture.dataSize) }; + rawImage->resize(width); + image = rawImage->encodeToJPEG(_jpegQuality); + } + catch (const image::Exception& e) + { + LMS_LOG(COVER, ERROR, "Cannot read embedded cover: " << e.what()); + } + }); return image; } @@ -183,19 +180,18 @@ namespace lms::cover { const std::multimap coverPaths{ getCoverPaths(directory) }; - auto tryLoadImageFromFilename = [&](std::string_view fileName) - { - std::unique_ptr image; + auto tryLoadImageFromFilename = [&](std::string_view fileName) { + std::unique_ptr image; - auto range{ coverPaths.equal_range(std::string {fileName}) }; - for (auto it{ range.first }; it != range.second; ++it) - { - image = getFromCoverFile(it->second, width); - if (image) - break; - } - return image; - }; + auto range{ coverPaths.equal_range(std::string{ fileName }) }; + for (auto it{ range.first }; it != range.second; ++it) + { + image = getFromCoverFile(it->second, width); + if (image) + break; + } + return image; + }; std::unique_ptr image; @@ -353,14 +349,13 @@ namespace lms::cover Session& session{ _db.getTLSSession() }; - auto getReleaseInfo{ [&] - { + auto getReleaseInfo{ [&] { std::optional res; auto transaction{ session.createReadTransaction() }; // get a track in this release, consider the release is in a single directory - const auto tracks{ Track::find(session, Track::FindParameters {}.setRelease(releaseId).setRange(Range{ 0, 1 }).setSortMethod(TrackSortMethod::Release)) }; + const auto tracks{ Track::find(session, Track::FindParameters{}.setRelease(releaseId).setRange(Range{ 0, 1 }).setSortMethod(TrackSortMethod::Release)) }; if (!tracks.results.empty()) { const Track::pointer& track{ tracks.results.front() }; @@ -416,18 +411,17 @@ namespace lms::cover Track::FindParameters params; params.setArtist(artistId, { TrackArtistLinkType::ReleaseArtist }); - Track::find(session, params, [&](const Track::pointer& track) - { - Artist::FindParameters artistFindParams; - artistFindParams.setTrack(track->getId()); - artistFindParams.setLinkType(TrackArtistLinkType::ReleaseArtist); + Track::find(session, params, [&](const Track::pointer& track) { + Artist::FindParameters artistFindParams; + artistFindParams.setTrack(track->getId()); + artistFindParams.setLinkType(TrackArtistLinkType::ReleaseArtist); - const auto releaseArtists{ Artist::findIds(session, artistFindParams) }; - if (releaseArtists.results.size() == 1) - releasePaths.insert(track->getAbsoluteFilePath().parent_path()); - else - multiArtistReleasePaths.insert(track->getAbsoluteFilePath().parent_path()); - }); + const auto releaseArtists{ Artist::findIds(session, artistFindParams) }; + if (releaseArtists.results.size() == 1) + releasePaths.insert(track->getAbsoluteFilePath().parent_path()); + else + multiArtistReleasePaths.insert(track->getAbsoluteFilePath().parent_path()); + }); } std::vector artistFileNames; @@ -497,4 +491,3 @@ namespace lms::cover } } // namespace lms::cover - diff --git a/src/libs/services/cover/impl/CoverService.hpp b/src/libs/services/cover/impl/CoverService.hpp index 946d3845..0eb0bf94 100644 --- a/src/libs/services/cover/impl/CoverService.hpp +++ b/src/libs/services/cover/impl/CoverService.hpp @@ -23,9 +23,10 @@ #include #include -#include "services/cover/ICoverService.hpp" -#include "image/IEncodedImage.hpp" #include "database/Types.hpp" +#include "image/IEncodedImage.hpp" +#include "services/cover/ICoverService.hpp" + #include "ImageCache.hpp" namespace lms::db @@ -49,23 +50,23 @@ namespace lms::cover CoverService(const CoverService&) = delete; CoverService& operator=(const CoverService&) = delete; - std::shared_ptr getFromTrack(db::TrackId trackId, image::ImageSize width) override; - std::shared_ptr getFromRelease(db::ReleaseId releaseId, image::ImageSize width) override; - std::shared_ptr getFromArtist(db::ArtistId artistId, image::ImageSize width) override; - std::shared_ptr getDefaultSvgCover() override; - void flushCache() override; - void setJpegQuality(unsigned quality) override; + std::shared_ptr getFromTrack(db::TrackId trackId, image::ImageSize width) override; + std::shared_ptr getFromRelease(db::ReleaseId releaseId, image::ImageSize width) override; + std::shared_ptr getFromArtist(db::ArtistId artistId, image::ImageSize width) override; + std::shared_ptr getDefaultSvgCover() override; + void flushCache() override; + void setJpegQuality(unsigned quality) override; - std::shared_ptr getFromTrack(db::Session& dbSession, db::TrackId trackId, image::ImageSize width, bool allowReleaseFallback); - std::unique_ptr getFromAvMediaFile(const av::IAudioFile& input, image::ImageSize width) const; - std::unique_ptr getFromCoverFile(const std::filesystem::path& p, image::ImageSize width) const; + std::shared_ptr getFromTrack(db::Session& dbSession, db::TrackId trackId, image::ImageSize width, bool allowReleaseFallback); + std::unique_ptr getFromAvMediaFile(const av::IAudioFile& input, image::ImageSize width) const; + std::unique_ptr getFromCoverFile(const std::filesystem::path& p, image::ImageSize width) const; - std::unique_ptr getFromTrack(const std::filesystem::path& path, image::ImageSize width) const; - std::multimap getCoverPaths(const std::filesystem::path& directoryPath) const; - std::unique_ptr getFromDirectory(const std::filesystem::path& directory, image::ImageSize width, const std::vector& preferredFileNames, bool allowPickRandom) const; - std::unique_ptr getFromSameNamedFile(const std::filesystem::path& filePath, image::ImageSize width) const; + std::unique_ptr getFromTrack(const std::filesystem::path& path, image::ImageSize width) const; + std::multimap getCoverPaths(const std::filesystem::path& directoryPath) const; + std::unique_ptr getFromDirectory(const std::filesystem::path& directory, image::ImageSize width, const std::vector& preferredFileNames, bool allowPickRandom) const; + std::unique_ptr getFromSameNamedFile(const std::filesystem::path& filePath, image::ImageSize width) const; - bool checkCoverFile(const std::filesystem::path& filePath) const; + bool checkCoverFile(const std::filesystem::path& filePath) const; db::Db& _db; @@ -80,4 +81,3 @@ namespace lms::cover }; } // namespace lms::cover - diff --git a/src/libs/services/cover/impl/ImageCache.cpp b/src/libs/services/cover/impl/ImageCache.cpp index 1409ab1a..13ffc31e 100644 --- a/src/libs/services/cover/impl/ImageCache.cpp +++ b/src/libs/services/cover/impl/ImageCache.cpp @@ -21,14 +21,15 @@ #include -#include "core/Random.hpp" #include "core/ILogger.hpp" +#include "core/Random.hpp" namespace lms::cover { ImageCache::ImageCache(std::size_t maxCacheSize) : _maxCacheSize{ maxCacheSize } - {} + { + } void ImageCache::addImage(const EntryDesc& entryDesc, std::shared_ptr image) { @@ -70,4 +71,4 @@ namespace lms::cover _cacheSize = 0; _cache.clear(); } -} \ No newline at end of file +} // namespace lms::cover \ No newline at end of file diff --git a/src/libs/services/cover/impl/ImageCache.hpp b/src/libs/services/cover/impl/ImageCache.hpp index a57553e8..41445296 100644 --- a/src/libs/services/cover/impl/ImageCache.hpp +++ b/src/libs/services/cover/impl/ImageCache.hpp @@ -65,8 +65,8 @@ namespace lms::cover }; std::unordered_map, EntryHasher> _cache; - std::size_t _cacheSize{}; - mutable std::atomic _cacheMisses{}; - mutable std::atomic _cacheHits{}; + std::size_t _cacheSize{}; + mutable std::atomic _cacheMisses{}; + mutable std::atomic _cacheHits{}; }; -} \ No newline at end of file +} // namespace lms::cover \ No newline at end of file diff --git a/src/libs/services/cover/include/services/cover/ICoverService.hpp b/src/libs/services/cover/include/services/cover/ICoverService.hpp index 6c740d23..cbed5e7f 100644 --- a/src/libs/services/cover/include/services/cover/ICoverService.hpp +++ b/src/libs/services/cover/include/services/cover/ICoverService.hpp @@ -52,5 +52,4 @@ namespace lms::cover std::unique_ptr createCoverService(db::Db& db, const std::filesystem::path& defaultSvgCoverPath); -} // namespace lms::coverArt - +} // namespace lms::cover diff --git a/src/libs/services/feedback/impl/FeedbackService.cpp b/src/libs/services/feedback/impl/FeedbackService.cpp index a9279156..f7c0bfe6 100644 --- a/src/libs/services/feedback/impl/FeedbackService.cpp +++ b/src/libs/services/feedback/impl/FeedbackService.cpp @@ -20,6 +20,7 @@ #include "FeedbackService.hpp" #include "FeedbackService.impl.hpp" +#include "core/ILogger.hpp" #include "database/Artist.hpp" #include "database/Db.hpp" #include "database/Release.hpp" @@ -29,7 +30,6 @@ #include "database/StarredTrack.hpp" #include "database/Track.hpp" #include "database/User.hpp" -#include "core/ILogger.hpp" #include "internal/InternalBackend.hpp" #include "listenbrainz/ListenBrainzBackend.hpp" @@ -187,5 +187,4 @@ namespace lms::feedback return Track::findIds(session, searchParams); } -} // ns Feedback - +} // namespace lms::feedback diff --git a/src/libs/services/feedback/impl/FeedbackService.hpp b/src/libs/services/feedback/impl/FeedbackService.hpp index 893d517d..33d6bf27 100644 --- a/src/libs/services/feedback/impl/FeedbackService.hpp +++ b/src/libs/services/feedback/impl/FeedbackService.hpp @@ -23,6 +23,7 @@ #include #include "services/feedback/IFeedbackService.hpp" + #include "IFeedbackBackend.hpp" namespace lms::db @@ -46,7 +47,7 @@ namespace lms::feedback void unstar(db::UserId userId, db::ArtistId artistId) override; bool isStarred(db::UserId userId, db::ArtistId artistId) override; Wt::WDateTime getStarredDateTime(db::UserId userId, db::ArtistId artistId) override; - ArtistContainer findStarredArtists(const ArtistFindParameters& params) override; + ArtistContainer findStarredArtists(const ArtistFindParameters& params) override; void star(db::UserId userId, db::ReleaseId releaseId) override; void unstar(db::UserId userId, db::ReleaseId releaseId) override; @@ -62,17 +63,17 @@ namespace lms::feedback std::optional getUserFeedbackBackend(db::UserId userId); - template + template void star(db::UserId userId, ObjIdType id); - template + template void unstar(db::UserId userId, ObjIdType id); - template + template bool isStarred(db::UserId userId, ObjIdType id); - template + template Wt::WDateTime getStarredDateTime(db::UserId userId, ObjIdType id); db::Db& _db; std::unordered_map> _backends; }; -} // ns Feedback +} // namespace lms::feedback diff --git a/src/libs/services/feedback/impl/FeedbackService.impl.hpp b/src/libs/services/feedback/impl/FeedbackService.impl.hpp index bf8f6537..d6d22e77 100644 --- a/src/libs/services/feedback/impl/FeedbackService.impl.hpp +++ b/src/libs/services/feedback/impl/FeedbackService.impl.hpp @@ -27,7 +27,7 @@ namespace lms::feedback { using namespace db; - template + template void FeedbackService::star(UserId userId, ObjIdType objId) { const auto backend{ getUserFeedbackBackend(userId) }; @@ -58,7 +58,7 @@ namespace lms::feedback _backends[*backend]->onStarred(starredObjId); } - template + template void FeedbackService::unstar(UserId userId, ObjIdType objId) { const auto backend{ getUserFeedbackBackend(userId) }; @@ -79,7 +79,7 @@ namespace lms::feedback _backends[*backend]->onUnstarred(starredObjId); } - template + template bool FeedbackService::isStarred(UserId userId, ObjIdType objId) { Session& session{ _db.getTLSSession() }; @@ -89,7 +89,7 @@ namespace lms::feedback return starredObj && (starredObj->getSyncState() != SyncState::PendingRemove); } - template + template Wt::WDateTime FeedbackService::getStarredDateTime(UserId userId, ObjIdType objId) { Session& session{ _db.getTLSSession() }; @@ -102,4 +102,4 @@ namespace lms::feedback return {}; } -} // ns Feedback \ No newline at end of file +} // namespace lms::feedback \ No newline at end of file diff --git a/src/libs/services/feedback/impl/IFeedbackBackend.hpp b/src/libs/services/feedback/impl/IFeedbackBackend.hpp index 0c0490db..1d6a6b79 100644 --- a/src/libs/services/feedback/impl/IFeedbackBackend.hpp +++ b/src/libs/services/feedback/impl/IFeedbackBackend.hpp @@ -40,4 +40,4 @@ namespace lms::feedback std::unique_ptr createFeedbackBackend(std::string_view backendName); -} // ns Feedback +} // namespace lms::feedback diff --git a/src/libs/services/feedback/impl/internal/InternalBackend.cpp b/src/libs/services/feedback/impl/internal/InternalBackend.cpp index c20521bd..1fa51022 100644 --- a/src/libs/services/feedback/impl/internal/InternalBackend.cpp +++ b/src/libs/services/feedback/impl/internal/InternalBackend.cpp @@ -29,7 +29,7 @@ namespace lms::feedback { namespace details { - template + template void onStarred(db::Session& session, typename StarredObjType::IdType id) { auto transaction{ session.createWriteTransaction() }; @@ -38,7 +38,7 @@ namespace lms::feedback starredObj.modify()->setSyncState(db::SyncState::Synchronized); } - template + template void onUnstarred(db::Session& session, typename StarredObjType::IdType id) { auto transaction{ session.createWriteTransaction() }; @@ -46,11 +46,12 @@ namespace lms::feedback if (auto starredObj{ StarredObjType::find(session, id) }) starredObj.remove(); } - } + } // namespace details InternalBackend::InternalBackend(db::Db& db) : _db{ db } - {} + { + } void InternalBackend::onStarred(db::StarredArtistId starredArtistId) { @@ -81,4 +82,4 @@ namespace lms::feedback { details::onUnstarred(_db.getTLSSession(), starredTrackId); } -} // Feedback +} // namespace lms::feedback diff --git a/src/libs/services/feedback/impl/internal/InternalBackend.hpp b/src/libs/services/feedback/impl/internal/InternalBackend.hpp index c74343a8..a7447d17 100644 --- a/src/libs/services/feedback/impl/internal/InternalBackend.hpp +++ b/src/libs/services/feedback/impl/internal/InternalBackend.hpp @@ -43,5 +43,4 @@ namespace lms::feedback db::Db& _db; }; -} // Feedback - +} // namespace lms::feedback diff --git a/src/libs/services/feedback/impl/listenbrainz/Exception.hpp b/src/libs/services/feedback/impl/listenbrainz/Exception.hpp index f040178c..7574c5c6 100644 --- a/src/libs/services/feedback/impl/listenbrainz/Exception.hpp +++ b/src/libs/services/feedback/impl/listenbrainz/Exception.hpp @@ -23,9 +23,9 @@ namespace lms::feedback::listenBrainz { - class Exception : public feedback::Exception - { - public: - using feedback::Exception::Exception; - }; -} + class Exception : public feedback::Exception + { + public: + using feedback::Exception::Exception; + }; +} // namespace lms::feedback::listenBrainz diff --git a/src/libs/services/feedback/impl/listenbrainz/FeedbackTypes.cpp b/src/libs/services/feedback/impl/listenbrainz/FeedbackTypes.cpp index d967aca4..328cf2a6 100644 --- a/src/libs/services/feedback/impl/listenbrainz/FeedbackTypes.cpp +++ b/src/libs/services/feedback/impl/listenbrainz/FeedbackTypes.cpp @@ -21,10 +21,9 @@ namespace lms::feedback::listenBrainz { - std::ostream& - operator<<(std::ostream& os, const Feedback& feedback) - { - os << "created = '" << feedback.created.toString() << "', recording MBID = '" << feedback.recordingMBID.getAsString() << "', score = " << static_cast(feedback.score); - return os; - } -} // feedback::ListenBrainz + std::ostream& operator<<(std::ostream& os, const Feedback& feedback) + { + os << "created = '" << feedback.created.toString() << "', recording MBID = '" << feedback.recordingMBID.getAsString() << "', score = " << static_cast(feedback.score); + return os; + } +} // namespace lms::feedback::listenBrainz diff --git a/src/libs/services/feedback/impl/listenbrainz/FeedbackTypes.hpp b/src/libs/services/feedback/impl/listenbrainz/FeedbackTypes.hpp index 6b8f7be5..354b1aa1 100644 --- a/src/libs/services/feedback/impl/listenbrainz/FeedbackTypes.hpp +++ b/src/libs/services/feedback/impl/listenbrainz/FeedbackTypes.hpp @@ -20,26 +20,28 @@ #pragma once #include + #include + #include "core/UUID.hpp" namespace lms::feedback::listenBrainz { - // See https://listenbrainz.readthedocs.io/en/production/dev/feedback-json/#feedback-json-doc - enum class FeedbackType - { - Love = 1, - Hate = -1, - Erase = 0, - }; + // See https://listenbrainz.readthedocs.io/en/production/dev/feedback-json/#feedback-json-doc + enum class FeedbackType + { + Love = 1, + Hate = -1, + Erase = 0, + }; - struct Feedback - { - Wt::WDateTime created; - core::UUID recordingMBID; - FeedbackType score; - }; + struct Feedback + { + Wt::WDateTime created; + core::UUID recordingMBID; + FeedbackType score; + }; - std::ostream& operator<<(std::ostream& os, const Feedback& feedback); + std::ostream& operator<<(std::ostream& os, const Feedback& feedback); -} // feedback::ListenBrainz +} // namespace lms::feedback::listenBrainz diff --git a/src/libs/services/feedback/impl/listenbrainz/FeedbacksParser.cpp b/src/libs/services/feedback/impl/listenbrainz/FeedbacksParser.cpp index 3ed62f51..fe6738b6 100644 --- a/src/libs/services/feedback/impl/listenbrainz/FeedbacksParser.cpp +++ b/src/libs/services/feedback/impl/listenbrainz/FeedbacksParser.cpp @@ -21,8 +21,8 @@ #include #include -#include #include +#include #include "Exception.hpp" #include "Utils.hpp" @@ -37,14 +37,13 @@ namespace lms::feedback::listenBrainz if (!recordingMBID) throw Exception{ "MBID not found!" }; - return Feedback - { + return Feedback{ Wt::WDateTime::fromTime_t(static_cast(feedbackObj.get("created"))), - *recordingMBID, - static_cast(static_cast(feedbackObj.get("score"))) + *recordingMBID, + static_cast(static_cast(feedbackObj.get("score"))) }; } - } + } // namespace FeedbacksParser::Result FeedbacksParser::parse(std::string_view msgBody) { @@ -87,4 +86,4 @@ namespace lms::feedback::listenBrainz return res; } -} // feedback::ListenBrainz +} // namespace lms::feedback::listenBrainz diff --git a/src/libs/services/feedback/impl/listenbrainz/FeedbacksParser.hpp b/src/libs/services/feedback/impl/listenbrainz/FeedbacksParser.hpp index 8f67a8c9..faa74b13 100644 --- a/src/libs/services/feedback/impl/listenbrainz/FeedbacksParser.hpp +++ b/src/libs/services/feedback/impl/listenbrainz/FeedbacksParser.hpp @@ -25,16 +25,16 @@ namespace lms::feedback::listenBrainz { - class FeedbacksParser - { - public: - struct Result - { - std::size_t feedbackCount {}; // >= feedbacks.size() - std::vector feedbacks; - }; + class FeedbacksParser + { + public: + struct Result + { + std::size_t feedbackCount{}; // >= feedbacks.size() + std::vector feedbacks; + }; - static Result parse(std::string_view msgBody); - }; + static Result parse(std::string_view msgBody); + }; -} // feedback::ListenBrainz +} // namespace lms::feedback::listenBrainz diff --git a/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.cpp b/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.cpp index 27b48d5a..2961858f 100644 --- a/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.cpp +++ b/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.cpp @@ -19,20 +19,20 @@ #include "FeedbacksSynchronizer.hpp" -#include #include #include -#include #include +#include +#include +#include "core/IConfig.hpp" +#include "core/Service.hpp" +#include "core/http/IClient.hpp" #include "database/Db.hpp" #include "database/Session.hpp" #include "database/StarredTrack.hpp" #include "database/Track.hpp" #include "database/User.hpp" -#include "core/IConfig.hpp" -#include "core/http/IClient.hpp" -#include "core/Service.hpp" #include "Exception.hpp" #include "FeedbacksParser.hpp" @@ -57,7 +57,7 @@ namespace lms::feedback::listenBrainz return std::nullopt; } } - } + } // namespace FeedbacksSynchronizer::FeedbacksSynchronizer(boost::asio::io_context& ioContext, db::Db& db, core::http::IClient& client) : _ioContext{ ioContext } @@ -125,19 +125,17 @@ namespace lms::feedback::listenBrainz request.message.addHeader("Authorization", "Token " + std::string{ listenBrainzToken->getAsString() }); Wt::Json::Object root; - root["recording_mbid"] = Wt::Json::Value{ std::string {recordingMBID->getAsString()} }; + root["recording_mbid"] = Wt::Json::Value{ std::string{ recordingMBID->getAsString() } }; root["score"] = Wt::Json::Value{ static_cast(type) }; request.message.addBodyText(Wt::Json::serialize(root)); request.message.addHeader("Content-Type", "application/json"); - request.onSuccessFunc = [this, type, starredTrackId](std::string_view /*msgBody*/) - { - _strand.dispatch([this, type, starredTrackId] - { - onFeedbackSent(type, starredTrackId); - }); - }; + request.onSuccessFunc = [this, type, starredTrackId](std::string_view /*msgBody*/) { + _strand.dispatch([this, type, starredTrackId] { + onFeedbackSent(type, starredTrackId); + }); + }; _client.sendPOSTRequest(std::move(request)); } catch (Exception& e) @@ -193,20 +191,19 @@ namespace lms::feedback::listenBrainz void FeedbacksSynchronizer::enquePendingFeedbacks() { - using namespace db; + using namespace db; - auto processPendingFeedbacks{ [this](SyncState scrobblingState, FeedbackType feedbackType) - { + auto processPendingFeedbacks{ [this](SyncState scrobblingState, FeedbackType feedbackType) { RangeResults pendingFeedbacks; { - db::Session& session {_db.getTLSSession()}; + db::Session& session{ _db.getTLSSession() }; - auto transaction {session.createReadTransaction()}; + auto transaction{ session.createReadTransaction() }; StarredTrack::FindParameters params; params.setFeedbackBackend(db::FeedbackBackend::ListenBrainz, scrobblingState) - .setRange(db::Range {0, 100}); // don't flood too much? + .setRange(db::Range{ 0, 100 }); // don't flood too much? pendingFeedbacks = StarredTrack::find(session, params); } @@ -236,10 +233,9 @@ namespace lms::feedback::listenBrainz bool FeedbacksSynchronizer::isSyncing() const { - return std::any_of(std::cbegin(_userContexts), std::cend(_userContexts), [](const auto& contextEntry) - { - return contextEntry.second.syncing; - }); + return std::any_of(std::cbegin(_userContexts), std::cend(_userContexts), [](const auto& contextEntry) { + return contextEntry.second.syncing; + }); } void FeedbacksSynchronizer::scheduleSync(std::chrono::seconds fromNow) @@ -249,20 +245,19 @@ namespace lms::feedback::listenBrainz LOG(DEBUG, "Scheduled sync in " << fromNow.count() << " seconds..."); _syncTimer.expires_after(fromNow); - _syncTimer.async_wait(boost::asio::bind_executor(_strand, [this](const boost::system::error_code& ec) + _syncTimer.async_wait(boost::asio::bind_executor(_strand, [this](const boost::system::error_code& ec) { + if (ec == boost::asio::error::operation_aborted) { - if (ec == boost::asio::error::operation_aborted) - { - LOG(DEBUG, "getFeedbacks aborted"); - return; - } - else if (ec) - { - throw Exception{ "GetFeedbacks timer failure: " + std::string {ec.message()} }; - } + LOG(DEBUG, "getFeedbacks aborted"); + return; + } + else if (ec) + { + throw Exception{ "GetFeedbacks timer failure: " + std::string{ ec.message() } }; + } - startSync(); - })); + startSync(); + })); } void FeedbacksSynchronizer::startSync() @@ -301,14 +296,13 @@ namespace lms::feedback::listenBrainz void FeedbacksSynchronizer::onSyncEnded(UserContext& context) { - _strand.dispatch([this, &context] - { - LOG(INFO, "Feedback sync done for user '" << context.listenBrainzUserName << "', fetched: " << context.fetchedFeedbackCount << ", matched: " << context.matchedFeedbackCount << ", imported: " << context.importedFeedbackCount); - context.syncing = false; + _strand.dispatch([this, &context] { + LOG(INFO, "Feedback sync done for user '" << context.listenBrainzUserName << "', fetched: " << context.fetchedFeedbackCount << ", matched: " << context.matchedFeedbackCount << ", imported: " << context.importedFeedbackCount); + context.syncing = false; - if (!isSyncing()) - scheduleSync(_syncFeedbacksPeriod); - }); + if (!isSyncing()) + scheduleSync(_syncFeedbacksPeriod); + }); } void FeedbacksSynchronizer::enqueValidateToken(UserContext& context) @@ -325,21 +319,19 @@ namespace lms::feedback::listenBrainz core::http::ClientGETRequestParameters request; request.priority = core::http::ClientRequestParameters::Priority::Low; request.relativeUrl = "/1/validate-token"; - request.headers = { {"Authorization", "Token " + std::string {listenBrainzToken->getAsString()}} }; - request.onSuccessFunc = [this, &context](std::string_view msgBody) - { - context.listenBrainzUserName = utils::parseValidateToken(msgBody); - if (context.listenBrainzUserName.empty()) - { - onSyncEnded(context); - return; - } - enqueGetFeedbackCount(context); - }; - request.onFailureFunc = [this, &context] + request.headers = { { "Authorization", "Token " + std::string{ listenBrainzToken->getAsString() } } }; + request.onSuccessFunc = [this, &context](std::string_view msgBody) { + context.listenBrainzUserName = utils::parseValidateToken(msgBody); + if (context.listenBrainzUserName.empty()) { onSyncEnded(context); - }; + return; + } + enqueGetFeedbackCount(context); + }; + request.onFailureFunc = [this, &context] { + onSyncEnded(context); + }; _client.sendGETRequest(std::move(request)); } @@ -351,30 +343,27 @@ namespace lms::feedback::listenBrainz core::http::ClientGETRequestParameters request; request.relativeUrl = "/1/feedback/user/" + std::string{ context.listenBrainzUserName } + "/get-feedback?score=1&count=0"; request.priority = core::http::ClientRequestParameters::Priority::Low; - request.onSuccessFunc = [this, &context](std::string_view msgBody) - { - std::string msgBodyCopy{ msgBody }; - _strand.dispatch([this, msgBodyCopy, &context] - { - LOG(DEBUG, "Current feedback count = " << (context.feedbackCount ? *context.feedbackCount : 0) << " for user '" << context.listenBrainzUserName << "'"); + request.onSuccessFunc = [this, &context](std::string_view msgBody) { + std::string msgBodyCopy{ msgBody }; + _strand.dispatch([this, msgBodyCopy, &context] { + LOG(DEBUG, "Current feedback count = " << (context.feedbackCount ? *context.feedbackCount : 0) << " for user '" << context.listenBrainzUserName << "'"); - const auto totalFeedbackCount = parseTotalFeedbackCount(msgBodyCopy); - if (totalFeedbackCount) - LOG(DEBUG, "Feedback count for listenbrainz user '" << context.listenBrainzUserName << "' = " << *totalFeedbackCount); + const auto totalFeedbackCount = parseTotalFeedbackCount(msgBodyCopy); + if (totalFeedbackCount) + LOG(DEBUG, "Feedback count for listenbrainz user '" << context.listenBrainzUserName << "' = " << *totalFeedbackCount); - bool needSync{ totalFeedbackCount && (!context.feedbackCount || *context.feedbackCount != *totalFeedbackCount) }; - context.feedbackCount = totalFeedbackCount; + bool needSync{ totalFeedbackCount && (!context.feedbackCount || *context.feedbackCount != *totalFeedbackCount) }; + context.feedbackCount = totalFeedbackCount; - if (needSync) - enqueGetFeedbacks(context); - else - onSyncEnded(context); - }); - }; - request.onFailureFunc = [this, &context] - { - onSyncEnded(context); - }; + if (needSync) + enqueGetFeedbacks(context); + else + onSyncEnded(context); + }); + }; + request.onFailureFunc = [this, &context] { + onSyncEnded(context); + }; _client.sendGETRequest(std::move(request)); } @@ -386,28 +375,25 @@ namespace lms::feedback::listenBrainz core::http::ClientGETRequestParameters request; request.relativeUrl = "/1/feedback/user/" + context.listenBrainzUserName + "/get-feedback?offset=" + std::to_string(context.fetchedFeedbackCount); request.priority = core::http::ClientRequestParameters::Priority::Low; - request.onSuccessFunc = [this, &context](std::string_view msgBody) - { - std::string msgBodyCopy{ msgBody }; - _strand.dispatch([this, msgBodyCopy, &context] - { - const std::size_t fetchedFeedbackCount{ processGetFeedbacks(msgBodyCopy, context) }; - if (fetchedFeedbackCount == 0 // no more thing available on server - || context.fetchedFeedbackCount >= context.feedbackCount // we may miss something, but we will get it next time - || context.fetchedFeedbackCount >= _maxSyncFeedbackCount) - { - onSyncEnded(context); - } - else - { - enqueGetFeedbacks(context); - } - }); - }; - request.onFailureFunc = [this, &context] - { - onSyncEnded(context); - }; + request.onSuccessFunc = [this, &context](std::string_view msgBody) { + std::string msgBodyCopy{ msgBody }; + _strand.dispatch([this, msgBodyCopy, &context] { + const std::size_t fetchedFeedbackCount{ processGetFeedbacks(msgBodyCopy, context) }; + if (fetchedFeedbackCount == 0 // no more thing available on server + || context.fetchedFeedbackCount >= context.feedbackCount // we may miss something, but we will get it next time + || context.fetchedFeedbackCount >= _maxSyncFeedbackCount) + { + onSyncEnded(context); + } + else + { + enqueGetFeedbacks(context); + } + }); + }; + request.onFailureFunc = [this, &context] { + onSyncEnded(context); + }; _client.sendGETRequest(std::move(request)); } diff --git a/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.hpp b/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.hpp index 8415f635..38c01030 100644 --- a/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.hpp +++ b/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.hpp @@ -21,12 +21,13 @@ #include #include + #include #include #include -#include "database/Types.hpp" #include "database/StarredTrackId.hpp" +#include "database/Types.hpp" #include "database/UserId.hpp" #include "FeedbackTypes.hpp" @@ -35,13 +36,13 @@ namespace lms { namespace core::http { - class IClient; + class IClient; } namespace db { class Db; } -} +} // namespace lms namespace lms::feedback::listenBrainz { @@ -59,22 +60,23 @@ namespace lms::feedback::listenBrainz struct UserContext { - UserContext(db::UserId id) : userId{ id } {} + UserContext(db::UserId id) + : userId{ id } {} UserContext(const UserContext&) = delete; UserContext& operator=(const UserContext&) = delete; - - const db::UserId userId; - bool syncing{}; - std::optional feedbackCount{}; + + const db::UserId userId; + bool syncing{}; + std::optional feedbackCount{}; // resetted at each sync - std::string listenBrainzUserName; // need to be resolved first + std::string listenBrainzUserName; // need to be resolved first - std::size_t currentOffset{}; - std::size_t fetchedFeedbackCount{}; - std::size_t matchedFeedbackCount{}; - std::size_t importedFeedbackCount{}; + std::size_t currentOffset{}; + std::size_t fetchedFeedbackCount{}; + std::size_t matchedFeedbackCount{}; + std::size_t importedFeedbackCount{}; }; UserContext& getUserContext(db::UserId userId); @@ -90,15 +92,14 @@ namespace lms::feedback::listenBrainz void tryImportFeedback(const Feedback& feedback, UserContext& context); boost::asio::io_context& _ioContext; - boost::asio::io_context::strand _strand{ _ioContext }; + boost::asio::io_context::strand _strand{ _ioContext }; db::Db& _db; - boost::asio::steady_timer _syncTimer{ _ioContext }; + boost::asio::steady_timer _syncTimer{ _ioContext }; core::http::IClient& _client; std::unordered_map _userContexts; - const std::size_t _maxSyncFeedbackCount; - const std::chrono::hours _syncFeedbacksPeriod; + const std::size_t _maxSyncFeedbackCount; + const std::chrono::hours _syncFeedbacksPeriod; }; -} // feedback::ListenBrainz - +} // namespace lms::feedback::listenBrainz diff --git a/src/libs/services/feedback/impl/listenbrainz/ListenBrainzBackend.cpp b/src/libs/services/feedback/impl/listenbrainz/ListenBrainzBackend.cpp index b8d02727..3789c332 100644 --- a/src/libs/services/feedback/impl/listenbrainz/ListenBrainzBackend.cpp +++ b/src/libs/services/feedback/impl/listenbrainz/ListenBrainzBackend.cpp @@ -19,22 +19,23 @@ #include "ListenBrainzBackend.hpp" +#include "core/IConfig.hpp" +#include "core/ILogger.hpp" +#include "core/Service.hpp" +#include "core/http/IClient.hpp" #include "database/Db.hpp" #include "database/Session.hpp" #include "database/StarredArtist.hpp" #include "database/StarredRelease.hpp" #include "database/Track.hpp" -#include "core/IConfig.hpp" -#include "core/http/IClient.hpp" -#include "core/ILogger.hpp" -#include "core/Service.hpp" + #include "Utils.hpp" namespace lms::feedback::listenBrainz { namespace details { - template + template void onStarred(db::Session& session, typename StarredObjType::IdType id) { auto transaction{ session.createWriteTransaction() }; @@ -46,7 +47,7 @@ namespace lms::feedback::listenBrainz } } - template + template void onUnstarred(db::Session& session, typename StarredObjType::IdType id) { auto transaction{ session.createWriteTransaction() }; @@ -54,7 +55,7 @@ namespace lms::feedback::listenBrainz if (auto starredObj{ StarredObjType::find(session, id) }) starredObj.remove(); } - } + } // namespace details ListenBrainzBackend::ListenBrainzBackend(boost::asio::io_context& ioContext, db::Db& db) : _ioContext{ ioContext } @@ -100,4 +101,4 @@ namespace lms::feedback::listenBrainz { _feedbacksSynchronizer.enqueFeedback(FeedbackType::Erase, starredtrackId); } -} // namespace lms::scrobbling::listenBrainz +} // namespace lms::feedback::listenBrainz diff --git a/src/libs/services/feedback/impl/listenbrainz/ListenBrainzBackend.hpp b/src/libs/services/feedback/impl/listenbrainz/ListenBrainzBackend.hpp index df69788f..f7359095 100644 --- a/src/libs/services/feedback/impl/listenbrainz/ListenBrainzBackend.hpp +++ b/src/libs/services/feedback/impl/listenbrainz/ListenBrainzBackend.hpp @@ -19,12 +19,12 @@ #pragma once +#include #include #include -#include -#include "IFeedbackBackend.hpp" #include "FeedbacksSynchronizer.hpp" +#include "IFeedbackBackend.hpp" namespace lms::db { @@ -52,8 +52,8 @@ namespace lms::feedback::listenBrainz boost::asio::io_context& _ioContext; db::Db& _db; - std::string _baseAPIUrl; - std::unique_ptr _client; - FeedbacksSynchronizer _feedbacksSynchronizer; + std::string _baseAPIUrl; + std::unique_ptr _client; + FeedbacksSynchronizer _feedbacksSynchronizer; }; -} \ No newline at end of file +} // namespace lms::feedback::listenBrainz \ No newline at end of file diff --git a/src/libs/services/feedback/impl/listenbrainz/Utils.cpp b/src/libs/services/feedback/impl/listenbrainz/Utils.cpp index ad545bf9..e240c8c6 100644 --- a/src/libs/services/feedback/impl/listenbrainz/Utils.cpp +++ b/src/libs/services/feedback/impl/listenbrainz/Utils.cpp @@ -59,4 +59,4 @@ namespace lms::feedback::listenBrainz::utils listenBrainzUserName = root.get("user_name").orIfNull(""); return listenBrainzUserName; } -} +} // namespace lms::feedback::listenBrainz::utils diff --git a/src/libs/services/feedback/impl/listenbrainz/Utils.hpp b/src/libs/services/feedback/impl/listenbrainz/Utils.hpp index 3ae8ce46..a55641ee 100644 --- a/src/libs/services/feedback/impl/listenbrainz/Utils.hpp +++ b/src/libs/services/feedback/impl/listenbrainz/Utils.hpp @@ -19,11 +19,11 @@ #pragma once -#include "database/UserId.hpp" #include "core/ILogger.hpp" #include "core/UUID.hpp" +#include "database/UserId.hpp" -#define LOG(sev, message) LMS_LOG(FEEDBACK, sev, "[listenbrainz] " << message) +#define LOG(sev, message) LMS_LOG(FEEDBACK, sev, "[listenbrainz] " << message) namespace lms::db { @@ -32,6 +32,6 @@ namespace lms::db namespace lms::feedback::listenBrainz::utils { - std::optional getListenBrainzToken(db::Session& session, db::UserId userId); + std::optional getListenBrainzToken(db::Session& session, db::UserId userId); std::string parseValidateToken(std::string_view msgBody); -} +} // namespace lms::feedback::listenBrainz::utils diff --git a/src/libs/services/feedback/include/services/feedback/Exception.hpp b/src/libs/services/feedback/include/services/feedback/Exception.hpp index 03a3d09e..b0e08547 100644 --- a/src/libs/services/feedback/include/services/feedback/Exception.hpp +++ b/src/libs/services/feedback/include/services/feedback/Exception.hpp @@ -28,4 +28,4 @@ namespace lms::feedback public: using LmsException::LmsException; }; -} +} // namespace lms::feedback diff --git a/src/libs/services/feedback/include/services/feedback/IFeedbackService.hpp b/src/libs/services/feedback/include/services/feedback/IFeedbackService.hpp index 208ba1d1..7bab297e 100644 --- a/src/libs/services/feedback/include/services/feedback/IFeedbackService.hpp +++ b/src/libs/services/feedback/include/services/feedback/IFeedbackService.hpp @@ -22,17 +22,17 @@ #include #include #include -#include -#include -#include "database/Types.hpp" +#include +#include + #include "database/ArtistId.hpp" #include "database/ClusterId.hpp" #include "database/MediaLibraryId.hpp" #include "database/ReleaseId.hpp" #include "database/TrackId.hpp" -#include "database/UserId.hpp" #include "database/Types.hpp" +#include "database/UserId.hpp" namespace lms::db { @@ -52,51 +52,78 @@ namespace lms::feedback struct FindParameters { - db::UserId user; - std::vector clusters; // if non empty, at least one artist that belongs to these clusters - std::vector keywords; // if non empty, name must match all of these keywords - std::optional range; - db::MediaLibraryId library; + db::UserId user; + std::vector clusters; // if non empty, at least one artist that belongs to these clusters + std::vector keywords; // if non empty, name must match all of these keywords + std::optional range; + db::MediaLibraryId library; - FindParameters& setUser(const db::UserId _user) { user = _user; return *this; } - FindParameters& setClusters(std::span _clusters) { clusters.assign(std::cbegin(_clusters), std::cend(_clusters)); return *this; } - FindParameters& setKeywords(const std::vector& _keywords) { keywords = _keywords; return *this; } - FindParameters& setRange(std::optional _range) { range = _range; return *this; } - FindParameters& setMediaLibrary(db::MediaLibraryId _library) { library = _library; return *this; } + FindParameters& setUser(const db::UserId _user) + { + user = _user; + return *this; + } + FindParameters& setClusters(std::span _clusters) + { + clusters.assign(std::cbegin(_clusters), std::cend(_clusters)); + return *this; + } + FindParameters& setKeywords(const std::vector& _keywords) + { + keywords = _keywords; + return *this; + } + FindParameters& setRange(std::optional _range) + { + range = _range; + return *this; + } + FindParameters& setMediaLibrary(db::MediaLibraryId _library) + { + library = _library; + return *this; + } }; // Artists struct ArtistFindParameters : public FindParameters { - std::optional linkType; // if set, only artists that have produced at least one track with this link type - db::ArtistSortMethod sortMethod{ db::ArtistSortMethod::None }; + std::optional linkType; // if set, only artists that have produced at least one track with this link type + db::ArtistSortMethod sortMethod{ db::ArtistSortMethod::None }; - ArtistFindParameters& setLinkType(std::optional _linkType) { linkType = _linkType; return *this; } - ArtistFindParameters& setSortMethod(db::ArtistSortMethod _sortMethod) { sortMethod = _sortMethod; return *this; } + ArtistFindParameters& setLinkType(std::optional _linkType) + { + linkType = _linkType; + return *this; + } + ArtistFindParameters& setSortMethod(db::ArtistSortMethod _sortMethod) + { + sortMethod = _sortMethod; + return *this; + } }; - virtual void star(db::UserId userId, db::ArtistId artistId) = 0; - virtual void unstar(db::UserId userId, db::ArtistId artistId) = 0; - virtual bool isStarred(db::UserId userId, db::ArtistId artistId) = 0; - virtual Wt::WDateTime getStarredDateTime(db::UserId userId, db::ArtistId artistId) = 0; - virtual ArtistContainer findStarredArtists(const ArtistFindParameters& params) = 0; + virtual void star(db::UserId userId, db::ArtistId artistId) = 0; + virtual void unstar(db::UserId userId, db::ArtistId artistId) = 0; + virtual bool isStarred(db::UserId userId, db::ArtistId artistId) = 0; + virtual Wt::WDateTime getStarredDateTime(db::UserId userId, db::ArtistId artistId) = 0; + virtual ArtistContainer findStarredArtists(const ArtistFindParameters& params) = 0; // Releases - virtual void star(db::UserId userId, db::ReleaseId releaseId) = 0; - virtual void unstar(db::UserId userId, db::ReleaseId releaseId) = 0; - virtual bool isStarred(db::UserId userId, db::ReleaseId artistId) = 0; - virtual Wt::WDateTime getStarredDateTime(db::UserId userId, db::ReleaseId artistId) = 0; - virtual ReleaseContainer findStarredReleases(const FindParameters& params) = 0; + virtual void star(db::UserId userId, db::ReleaseId releaseId) = 0; + virtual void unstar(db::UserId userId, db::ReleaseId releaseId) = 0; + virtual bool isStarred(db::UserId userId, db::ReleaseId artistId) = 0; + virtual Wt::WDateTime getStarredDateTime(db::UserId userId, db::ReleaseId artistId) = 0; + virtual ReleaseContainer findStarredReleases(const FindParameters& params) = 0; // Tracks - virtual void star(db::UserId userId, db::TrackId trackId) = 0; - virtual void unstar(db::UserId userId, db::TrackId trackId) = 0; - virtual bool isStarred(db::UserId userId, db::TrackId artistId) = 0; - virtual Wt::WDateTime getStarredDateTime(db::UserId userId, db::TrackId artistId) = 0; - virtual TrackContainer findStarredTracks(const FindParameters& params) = 0; + virtual void star(db::UserId userId, db::TrackId trackId) = 0; + virtual void unstar(db::UserId userId, db::TrackId trackId) = 0; + virtual bool isStarred(db::UserId userId, db::TrackId artistId) = 0; + virtual Wt::WDateTime getStarredDateTime(db::UserId userId, db::TrackId artistId) = 0; + virtual TrackContainer findStarredTracks(const FindParameters& params) = 0; }; std::unique_ptr createFeedbackService(boost::asio::io_service& ioService, db::Db& db); -} // ns Feedback - +} // namespace lms::feedback diff --git a/src/libs/services/recommendation/impl/ClustersEngineCreator.hpp b/src/libs/services/recommendation/impl/ClustersEngineCreator.hpp index eb3d36f0..d83328c8 100644 --- a/src/libs/services/recommendation/impl/ClustersEngineCreator.hpp +++ b/src/libs/services/recommendation/impl/ClustersEngineCreator.hpp @@ -23,12 +23,11 @@ namespace lms::db { - class Db; + class Db; } namespace lms::recommendation { - class IEngine; - std::unique_ptr createClustersEngine(db::Db& db); -} - + class IEngine; + std::unique_ptr createClustersEngine(db::Db& db); +} // namespace lms::recommendation diff --git a/src/libs/services/recommendation/impl/FeaturesEngineCreator.hpp b/src/libs/services/recommendation/impl/FeaturesEngineCreator.hpp index f1b335e1..107e250a 100644 --- a/src/libs/services/recommendation/impl/FeaturesEngineCreator.hpp +++ b/src/libs/services/recommendation/impl/FeaturesEngineCreator.hpp @@ -20,15 +20,15 @@ #pragma once #include + #include "IEngine.hpp" namespace lms::db { - class Db; + class Db; } namespace lms::recommendation { - std::unique_ptr createFeaturesEngine(db::Db& db); + std::unique_ptr createFeaturesEngine(db::Db& db); } - diff --git a/src/libs/services/recommendation/impl/IEngine.hpp b/src/libs/services/recommendation/impl/IEngine.hpp index aaf9b907..890631dc 100644 --- a/src/libs/services/recommendation/impl/IEngine.hpp +++ b/src/libs/services/recommendation/impl/IEngine.hpp @@ -20,33 +20,33 @@ #pragma once #include -#include "database/Types.hpp" -#include "database/TrackListId.hpp" -#include "services/recommendation/Types.hpp" + #include "core/EnumSet.hpp" +#include "database/TrackListId.hpp" +#include "database/Types.hpp" +#include "services/recommendation/Types.hpp" namespace lms::db { - class Db; + class Db; } namespace lms::recommendation { - class IEngine - { - public: - virtual ~IEngine() = default; + class IEngine + { + public: + virtual ~IEngine() = default; - virtual void load(bool forceReload, const ProgressCallback& progressCallback = {}) = 0; - virtual void requestCancelLoad() = 0; + virtual void load(bool forceReload, const ProgressCallback& progressCallback = {}) = 0; + virtual void requestCancelLoad() = 0; - virtual TrackContainer findSimilarTracksFromTrackList(db::TrackListId tracklistId, std::size_t maxCount) const = 0; - virtual TrackContainer findSimilarTracks(const std::vector& tracksId, std::size_t maxCount) const = 0; - virtual ReleaseContainer getSimilarReleases(db::ReleaseId releaseId, std::size_t maxCount) const = 0; - virtual ArtistContainer getSimilarArtists(db::ArtistId artistId, core::EnumSet linkTypes, std::size_t maxCount) const = 0; - }; + virtual TrackContainer findSimilarTracksFromTrackList(db::TrackListId tracklistId, std::size_t maxCount) const = 0; + virtual TrackContainer findSimilarTracks(const std::vector& tracksId, std::size_t maxCount) const = 0; + virtual ReleaseContainer getSimilarReleases(db::ReleaseId releaseId, std::size_t maxCount) const = 0; + virtual ArtistContainer getSimilarArtists(db::ArtistId artistId, core::EnumSet linkTypes, std::size_t maxCount) const = 0; + }; - std::unique_ptr createEngine(db::Db& db); - -} // ns Recommendation + std::unique_ptr createEngine(db::Db& db); +} // namespace lms::recommendation diff --git a/src/libs/services/recommendation/impl/PlaylistGeneratorService.cpp b/src/libs/services/recommendation/impl/PlaylistGeneratorService.cpp index 0d03a40b..2e25b1fc 100644 --- a/src/libs/services/recommendation/impl/PlaylistGeneratorService.cpp +++ b/src/libs/services/recommendation/impl/PlaylistGeneratorService.cpp @@ -19,14 +19,15 @@ #include "PlaylistGeneratorService.hpp" +#include "core/ILogger.hpp" #include "database/Db.hpp" #include "database/Session.hpp" #include "database/Track.hpp" #include "services/recommendation/IRecommendationService.hpp" + #include "playlist-constraints/ConsecutiveArtists.hpp" #include "playlist-constraints/ConsecutiveReleases.hpp" #include "playlist-constraints/DuplicateTracks.hpp" -#include "core/ILogger.hpp" namespace lms::recommendation { @@ -111,4 +112,4 @@ namespace lms::recommendation return tracks; } -} +} // namespace lms::recommendation diff --git a/src/libs/services/recommendation/impl/PlaylistGeneratorService.hpp b/src/libs/services/recommendation/impl/PlaylistGeneratorService.hpp index afdf0273..6287d778 100644 --- a/src/libs/services/recommendation/impl/PlaylistGeneratorService.hpp +++ b/src/libs/services/recommendation/impl/PlaylistGeneratorService.hpp @@ -21,22 +21,23 @@ #include "services/recommendation/IPlaylistGeneratorService.hpp" #include "services/recommendation/IRecommendationService.hpp" + #include "playlist-constraints/IConstraint.hpp" namespace lms::recommendation { - class PlaylistGeneratorService : public IPlaylistGeneratorService - { - public: - PlaylistGeneratorService(db::Db& db, IRecommendationService& recommendationService); + class PlaylistGeneratorService : public IPlaylistGeneratorService + { + public: + PlaylistGeneratorService(db::Db& db, IRecommendationService& recommendationService); - private: - TrackContainer extendPlaylist(db::TrackListId tracklistId, std::size_t maxCount) const override; + private: + TrackContainer extendPlaylist(db::TrackListId tracklistId, std::size_t maxCount) const override; - TrackContainer getTracksFromTrackList(db::TrackListId tracklistId) const; + TrackContainer getTracksFromTrackList(db::TrackListId tracklistId) const; - db::Db& _db; - IRecommendationService& _recommendationService; - std::vector> _constraints; - }; -} // namespace Radio + db::Db& _db; + IRecommendationService& _recommendationService; + std::vector> _constraints; + }; +} // namespace lms::recommendation diff --git a/src/libs/services/recommendation/impl/RecommendationService.cpp b/src/libs/services/recommendation/impl/RecommendationService.cpp index d1f95b9a..333bfdd2 100644 --- a/src/libs/services/recommendation/impl/RecommendationService.cpp +++ b/src/libs/services/recommendation/impl/RecommendationService.cpp @@ -22,14 +22,14 @@ #include #include -#include "ClustersEngineCreator.hpp" -#include "FeaturesEngineCreator.hpp" - -#include "database/Db.hpp" -#include "database/Session.hpp" -#include "database/ScanSettings.hpp" #include "core/Exception.hpp" #include "core/ILogger.hpp" +#include "database/Db.hpp" +#include "database/ScanSettings.hpp" +#include "database/Session.hpp" + +#include "ClustersEngineCreator.hpp" +#include "FeaturesEngineCreator.hpp" namespace lms::recommendation { @@ -41,7 +41,7 @@ namespace lms::recommendation return db::ScanSettings::get(session)->getSimilarityEngineType(); } - } + } // namespace std::unique_ptr createRecommendationService(db::Db& db) { @@ -81,7 +81,8 @@ namespace lms::recommendation if (!_engine) return res; - return _engine->getSimilarReleases(releaseId, maxCount);; + return _engine->getSimilarReleases(releaseId, maxCount); + ; } ArtistContainer RecommendationService::getSimilarArtists(db::ArtistId artistId, core::EnumSet linkTypes, std::size_t maxCount) const @@ -120,4 +121,4 @@ namespace lms::recommendation if (_engine) _engine->load(false); } -} // ns Similarity +} // namespace lms::recommendation diff --git a/src/libs/services/recommendation/impl/RecommendationService.hpp b/src/libs/services/recommendation/impl/RecommendationService.hpp index 4389aad0..721acc1a 100644 --- a/src/libs/services/recommendation/impl/RecommendationService.hpp +++ b/src/libs/services/recommendation/impl/RecommendationService.hpp @@ -22,6 +22,7 @@ #include #include "services/recommendation/IRecommendationService.hpp" + #include "IEngine.hpp" namespace lms::db @@ -63,5 +64,4 @@ namespace lms::recommendation std::unique_ptr _engine; }; -} // ns Recommendation - +} // namespace lms::recommendation diff --git a/src/libs/services/recommendation/impl/clusters/ClustersEngine.cpp b/src/libs/services/recommendation/impl/clusters/ClustersEngine.cpp index d8a8df8f..b1e43fad 100644 --- a/src/libs/services/recommendation/impl/clusters/ClustersEngine.cpp +++ b/src/libs/services/recommendation/impl/clusters/ClustersEngine.cpp @@ -27,7 +27,8 @@ #include "database/Track.hpp" #include "database/TrackList.hpp" -namespace lms::recommendation { +namespace lms::recommendation +{ using namespace db; @@ -44,7 +45,7 @@ namespace lms::recommendation { Session& dbSession{ _db.getTLSSession() }; auto transaction{ dbSession.createReadTransaction() }; - const auto similarTrackIds{ Track::findSimilarTrackIds(dbSession, trackIds, Range {0, maxCount}) }; + const auto similarTrackIds{ Track::findSimilarTrackIds(dbSession, trackIds, Range{ 0, maxCount }) }; return std::move(similarTrackIds.results); } @@ -104,7 +105,7 @@ namespace lms::recommendation { if (!artist) return {}; - const auto similarArtistIds{ artist->findSimilarArtistIds(artistLinkTypes, Range {0, maxCount}) }; + const auto similarArtistIds{ artist->findSimilarArtistIds(artistLinkTypes, Range{ 0, maxCount }) }; return std::move(similarArtistIds.results); } diff --git a/src/libs/services/recommendation/impl/clusters/ClustersEngine.hpp b/src/libs/services/recommendation/impl/clusters/ClustersEngine.hpp index da600bde..4d019ccd 100644 --- a/src/libs/services/recommendation/impl/clusters/ClustersEngine.hpp +++ b/src/libs/services/recommendation/impl/clusters/ClustersEngine.hpp @@ -24,27 +24,27 @@ namespace lms::recommendation { - class ClusterEngine : public IEngine - { - public: - ClusterEngine(db::Db& db) : _db {db} {} + class ClusterEngine : public IEngine + { + public: + ClusterEngine(db::Db& db) + : _db{ db } {} - ClusterEngine(const ClusterEngine&) = delete; - ClusterEngine(ClusterEngine&&) = delete; - ClusterEngine& operator=(const ClusterEngine&) = delete; - ClusterEngine& operator=(ClusterEngine&&) = delete; + ClusterEngine(const ClusterEngine&) = delete; + ClusterEngine(ClusterEngine&&) = delete; + ClusterEngine& operator=(const ClusterEngine&) = delete; + ClusterEngine& operator=(ClusterEngine&&) = delete; - private: - void load(bool, const ProgressCallback&) override {} - void requestCancelLoad() override {} + private: + void load(bool, const ProgressCallback&) override {} + void requestCancelLoad() override {} - TrackContainer findSimilarTracksFromTrackList(db::TrackListId tracklistId, std::size_t maxCount) const override; - TrackContainer findSimilarTracks(const std::vector& tracksId, std::size_t maxCount) const override; - ReleaseContainer getSimilarReleases(db::ReleaseId releaseId, std::size_t maxCount) const override; - ArtistContainer getSimilarArtists(db::ArtistId artistId, core::EnumSet linkTypes, std::size_t maxCount) const override; + TrackContainer findSimilarTracksFromTrackList(db::TrackListId tracklistId, std::size_t maxCount) const override; + TrackContainer findSimilarTracks(const std::vector& tracksId, std::size_t maxCount) const override; + ReleaseContainer getSimilarReleases(db::ReleaseId releaseId, std::size_t maxCount) const override; + ArtistContainer getSimilarArtists(db::ArtistId artistId, core::EnumSet linkTypes, std::size_t maxCount) const override; - db::Db& _db; - }; + db::Db& _db; + }; } // namespace lms::recommendation - diff --git a/src/libs/services/recommendation/impl/features/FeaturesDefs.cpp b/src/libs/services/recommendation/impl/features/FeaturesDefs.cpp index 418ef863..5a9e6b8e 100644 --- a/src/libs/services/recommendation/impl/features/FeaturesDefs.cpp +++ b/src/libs/services/recommendation/impl/features/FeaturesDefs.cpp @@ -24,370 +24,367 @@ #include "core/Exception.hpp" -namespace lms::recommendation { - -static const std::unordered_map featureDefinitions +namespace lms::recommendation { - { "lowlevel.average_loudness", {1}}, - { "lowlevel.barkbands.dmean", {27}}, - { "lowlevel.barkbands.dmean2", {27}}, - { "lowlevel.barkbands.dvar", {27}}, - { "lowlevel.barkbands.dvar2", {27}}, - { "lowlevel.barkbands.max", {27}}, - { "lowlevel.barkbands.mean", {27}}, - { "lowlevel.barkbands.median", {27}}, - { "lowlevel.barkbands.min", {27}}, - { "lowlevel.barkbands.var", {27}}, - { "lowlevel.barkbands_crest.dmean", {1}}, - { "lowlevel.barkbands_crest.dmean2", {1}}, - { "lowlevel.barkbands_crest.dvar", {1}}, - { "lowlevel.barkbands_crest.dvar2", {1}}, - { "lowlevel.barkbands_crest.max", {1}}, - { "lowlevel.barkbands_crest.mean", {1}}, - { "lowlevel.barkbands_crest.median", {1}}, - { "lowlevel.barkbands_crest.min", {1}}, - { "lowlevel.barkbands_crest.var", {1}}, - { "lowlevel.barkbands_flatness_db.dmean", {1}}, - { "lowlevel.barkbands_flatness_db.dmean2", {1}}, - { "lowlevel.barkbands_flatness_db.dvar", {1}}, - { "lowlevel.barkbands_flatness_db.dvar2", {1}}, - { "lowlevel.barkbands_flatness_db.max", {1}}, - { "lowlevel.barkbands_flatness_db.mean", {1}}, - { "lowlevel.barkbands_flatness_db.median", {1}}, - { "lowlevel.barkbands_flatness_db.min", {1}}, - { "lowlevel.barkbands_flatness_db.var", {1}}, - { "lowlevel.barkbands_kurtosis.dmean", {1}}, - { "lowlevel.barkbands_kurtosis.dmean2", {1}}, - { "lowlevel.barkbands_kurtosis.dvar", {1}}, - { "lowlevel.barkbands_kurtosis.dvar2", {1}}, - { "lowlevel.barkbands_kurtosis.max", {1}}, - { "lowlevel.barkbands_kurtosis.mean", {1}}, - { "lowlevel.barkbands_kurtosis.median", {1}}, - { "lowlevel.barkbands_kurtosis.min", {1}}, - { "lowlevel.barkbands_kurtosis.var", {1}}, - { "lowlevel.barkbands_skewness.dmean", {1}}, - { "lowlevel.barkbands_skewness.dmean2", {1}}, - { "lowlevel.barkbands_skewness.dvar", {1}}, - { "lowlevel.barkbands_skewness.dvar2", {1}}, - { "lowlevel.barkbands_skewness.max", {1}}, - { "lowlevel.barkbands_skewness.mean", {1}}, - { "lowlevel.barkbands_skewness.median", {1}}, - { "lowlevel.barkbands_skewness.min", {1}}, - { "lowlevel.barkbands_skewness.var", {1}}, - { "lowlevel.barkbands_spread.dmean", {1}}, - { "lowlevel.barkbands_spread.dmean2", {1}}, - { "lowlevel.barkbands_spread.dvar", {1}}, - { "lowlevel.barkbands_spread.dvar2", {1}}, - { "lowlevel.barkbands_spread.max", {1}}, - { "lowlevel.barkbands_spread.mean", {1}}, - { "lowlevel.barkbands_spread.median", {1}}, - { "lowlevel.barkbands_spread.min", {1}}, - { "lowlevel.barkbands_spread.var", {1}}, - { "lowlevel.dissonance.dmean", {1}}, - { "lowlevel.dissonance.dmean2", {1}}, - { "lowlevel.dissonance.dvar", {1}}, - { "lowlevel.dissonance.dvar2", {1}}, - { "lowlevel.dissonance.max", {1}}, - { "lowlevel.dissonance.mean", {1}}, - { "lowlevel.dissonance.median", {1}}, - { "lowlevel.dissonance.min", {1}}, - { "lowlevel.dissonance.var", {1}}, - { "lowlevel.dynamic_complexity", {1}}, - { "lowlevel.erbbands.dmean", {40}}, - { "lowlevel.erbbands.dmean2", {40}}, - { "lowlevel.erbbands.dvar", {40}}, - { "lowlevel.erbbands.dvar2", {40}}, - { "lowlevel.erbbands.max", {40}}, - { "lowlevel.erbbands.mean", {40}}, - { "lowlevel.erbbands.median", {40}}, - { "lowlevel.erbbands.min", {40}}, - { "lowlevel.erbbands.var", {40}}, - { "lowlevel.gfcc.mean", {13}}, - { "lowlevel.hfc.dmean", {1}}, - { "lowlevel.hfc.dmean2", {1}}, - { "lowlevel.hfc.dvar", {1}}, - { "lowlevel.hfc.dvar2", {1}}, - { "lowlevel.hfc.max", {1}}, - { "lowlevel.hfc.mean", {1}}, - { "lowlevel.hfc.median", {1}}, - { "lowlevel.hfc.min", {1}}, - { "lowlevel.hfc.var", {1}}, - { "tonal.hpcp.median", {36}}, - { "lowlevel.melbands.dmean", {40}}, - { "lowlevel.melbands.dmean2", {40}}, - { "lowlevel.melbands.dvar", {40}}, - { "lowlevel.melbands.dvar2", {40}}, - { "lowlevel.melbands.max", {40}}, - { "lowlevel.melbands.mean", {40}}, - { "lowlevel.melbands.median", {40}}, - { "lowlevel.melbands.min", {40}}, - { "lowlevel.melbands.var", {40}}, - { "lowlevel.melbands_crest.dmean", {1}}, - { "lowlevel.melbands_crest.dmean2", {1}}, - { "lowlevel.melbands_crest.dvar", {1}}, - { "lowlevel.melbands_crest.dvar2", {1}}, - { "lowlevel.melbands_crest.max", {1}}, - { "lowlevel.melbands_crest.mean", {1}}, - { "lowlevel.melbands_crest.median", {1}}, - { "lowlevel.melbands_crest.min", {1}}, - { "lowlevel.melbands_crest.var", {1}}, - { "lowlevel.melbands_flatness_db.dmean", {1}}, - { "lowlevel.melbands_flatness_db.dmean2", {1}}, - { "lowlevel.melbands_flatness_db.dvar", {1}}, - { "lowlevel.melbands_flatness_db.dvar2", {1}}, - { "lowlevel.melbands_flatness_db.max", {1}}, - { "lowlevel.melbands_flatness_db.mean", {1}}, - { "lowlevel.melbands_flatness_db.median", {1}}, - { "lowlevel.melbands_flatness_db.min", {1}}, - { "lowlevel.melbands_flatness_db.var", {1}}, - { "lowlevel.melbands_kurtosis.dmean", {1}}, - { "lowlevel.melbands_kurtosis.dmean2", {1}}, - { "lowlevel.melbands_kurtosis.dvar", {1}}, - { "lowlevel.melbands_kurtosis.dvar2", {1}}, - { "lowlevel.melbands_kurtosis.max", {1}}, - { "lowlevel.melbands_kurtosis.mean", {1}}, - { "lowlevel.melbands_kurtosis.median", {1}}, - { "lowlevel.melbands_kurtosis.min", {1}}, - { "lowlevel.melbands_kurtosis.var", {1}}, - { "lowlevel.melbands_skewness.dmean", {1}}, - { "lowlevel.melbands_skewness.dmean2", {1}}, - { "lowlevel.melbands_skewness.dvar", {1}}, - { "lowlevel.melbands_skewness.dvar2", {1}}, - { "lowlevel.melbands_skewness.max", {1}}, - { "lowlevel.melbands_skewness.mean", {1}}, - { "lowlevel.melbands_skewness.median", {1}}, - { "lowlevel.melbands_skewness.min", {1}}, - { "lowlevel.melbands_skewness.var", {1}}, - { "lowlevel.melbands_spread.dmean", {1}}, - { "lowlevel.melbands_spread.dmean2", {1}}, - { "lowlevel.melbands_spread.dvar", {1}}, - { "lowlevel.melbands_spread.dvar2", {1}}, - { "lowlevel.melbands_spread.max", {1}}, - { "lowlevel.melbands_spread.mean", {1}}, - { "lowlevel.melbands_spread.median", {1}}, - { "lowlevel.melbands_spread.min", {1}}, - { "lowlevel.melbands_spread.var", {1}}, - { "lowlevel.mfcc.mean", {13}}, - { "lowlevel.pitch_salience.dmean", {1}}, - { "lowlevel.pitch_salience.dmean2", {1}}, - { "lowlevel.pitch_salience.dvar", {1}}, - { "lowlevel.pitch_salience.dvar2", {1}}, - { "lowlevel.pitch_salience.max", {1}}, - { "lowlevel.pitch_salience.mean", {1}}, - { "lowlevel.pitch_salience.median", {1}}, - { "lowlevel.pitch_salience.min", {1}}, - { "lowlevel.pitch_salience.var", {1}}, - { "lowlevel.silence_rate_30dB.dmean", {1}}, - { "lowlevel.silence_rate_30dB.dmean2", {1}}, - { "lowlevel.silence_rate_30dB.dvar", {1}}, - { "lowlevel.silence_rate_30dB.dvar2", {1}}, - { "lowlevel.silence_rate_30dB.max", {1}}, - { "lowlevel.silence_rate_30dB.mean", {1}}, - { "lowlevel.silence_rate_30dB.median", {1}}, - { "lowlevel.silence_rate_30dB.min", {1}}, - { "lowlevel.silence_rate_30dB.var", {1}}, - { "lowlevel.silence_rate_60dB.dmean", {1}}, - { "lowlevel.silence_rate_60dB.dmean2", {1}}, - { "lowlevel.silence_rate_60dB.dvar", {1}}, - { "lowlevel.silence_rate_60dB.dvar2", {1}}, - { "lowlevel.silence_rate_60dB.max", {1}}, - { "lowlevel.silence_rate_60dB.mean", {1}}, - { "lowlevel.silence_rate_60dB.median", {1}}, - { "lowlevel.silence_rate_60dB.min", {1}}, - { "lowlevel.silence_rate_60dB.var", {1}}, - { "lowlevel.spectral_centroid.dmean", {1}}, - { "lowlevel.spectral_centroid.dmean2", {1}}, - { "lowlevel.spectral_centroid.dvar", {1}}, - { "lowlevel.spectral_centroid.dvar2", {1}}, - { "lowlevel.spectral_centroid.max", {1}}, - { "lowlevel.spectral_centroid.mean", {1}}, - { "lowlevel.spectral_centroid.median", {1}}, - { "lowlevel.spectral_centroid.min", {1}}, - { "lowlevel.spectral_centroid.var", {1}}, - { "lowlevel.spectral_complexity.dmean", {1}}, - { "lowlevel.spectral_complexity.dmean2", {1}}, - { "lowlevel.spectral_complexity.dvar", {1}}, - { "lowlevel.spectral_complexity.dvar2", {1}}, - { "lowlevel.spectral_complexity.max", {1}}, - { "lowlevel.spectral_complexity.mean", {1}}, - { "lowlevel.spectral_complexity.median", {1}}, - { "lowlevel.spectral_complexity.min", {1}}, - { "lowlevel.spectral_complexity.var", {1}}, - { "lowlevel.spectral_contrast_coeffs.dmean", {6}}, - { "lowlevel.spectral_contrast_coeffs.dmean2", {6}}, - { "lowlevel.spectral_contrast_coeffs.dvar", {6}}, - { "lowlevel.spectral_contrast_coeffs.dvar2", {6}}, - { "lowlevel.spectral_contrast_coeffs.max", {6}}, - { "lowlevel.spectral_contrast_coeffs.mean", {6}}, - { "lowlevel.spectral_contrast_coeffs.median", {6}}, - { "lowlevel.spectral_contrast_coeffs.min", {6}}, - { "lowlevel.spectral_contrast_coeffs.var", {6}}, - { "lowlevel.spectral_contrast_valleys.dmean", {6}}, - { "lowlevel.spectral_contrast_valleys.dmean2", {6}}, - { "lowlevel.spectral_contrast_valleys.dvar", {6}}, - { "lowlevel.spectral_contrast_valleys.dvar2", {6}}, - { "lowlevel.spectral_contrast_valleys.max", {6}}, - { "lowlevel.spectral_contrast_valleys.mean", {6}}, - { "lowlevel.spectral_contrast_valleys.median", {6}}, - { "lowlevel.spectral_contrast_valleys.min", {6}}, - { "lowlevel.spectral_contrast_valleys.var", {6}}, - { "lowlevel.spectral_decrease.dmean", {1}}, - { "lowlevel.spectral_decrease.dmean2", {1}}, - { "lowlevel.spectral_decrease.dvar", {1}}, - { "lowlevel.spectral_decrease.dvar2", {1}}, - { "lowlevel.spectral_decrease.max", {1}}, - { "lowlevel.spectral_decrease.mean", {1}}, - { "lowlevel.spectral_decrease.median", {1}}, - { "lowlevel.spectral_decrease.min", {1}}, - { "lowlevel.spectral_decrease.var", {1}}, - { "lowlevel.spectral_energy.dmean", {1}}, - { "lowlevel.spectral_energy.dmean2", {1}}, - { "lowlevel.spectral_energy.dvar", {1}}, - { "lowlevel.spectral_energy.dvar2", {1}}, - { "lowlevel.spectral_energy.max", {1}}, - { "lowlevel.spectral_energy.mean", {1}}, - { "lowlevel.spectral_energy.median", {1}}, - { "lowlevel.spectral_energy.min", {1}}, - { "lowlevel.spectral_energy.var", {1}}, - { "lowlevel.spectral_energyband_high.dmean", {1}}, - { "lowlevel.spectral_energyband_high.dmean2", {1}}, - { "lowlevel.spectral_energyband_high.dvar", {1}}, - { "lowlevel.spectral_energyband_high.dvar2", {1}}, - { "lowlevel.spectral_energyband_high.max", {1}}, - { "lowlevel.spectral_energyband_high.mean", {1}}, - { "lowlevel.spectral_energyband_high.median", {1}}, - { "lowlevel.spectral_energyband_high.min", {1}}, - { "lowlevel.spectral_energyband_high.var", {1}}, - { "lowlevel.spectral_energyband_low.dmean", {1}}, - { "lowlevel.spectral_energyband_low.dmean2", {1}}, - { "lowlevel.spectral_energyband_low.dvar", {1}}, - { "lowlevel.spectral_energyband_low.dvar2", {1}}, - { "lowlevel.spectral_energyband_low.max", {1}}, - { "lowlevel.spectral_energyband_low.mean", {1}}, - { "lowlevel.spectral_energyband_low.median", {1}}, - { "lowlevel.spectral_energyband_low.min", {1}}, - { "lowlevel.spectral_energyband_low.var", {1}}, - { "lowlevel.spectral_energyband_middle_high.dmean", {1}}, - { "lowlevel.spectral_energyband_middle_high.dmean2", {1}}, - { "lowlevel.spectral_energyband_middle_high.dvar", {1}}, - { "lowlevel.spectral_energyband_middle_high.dvar2", {1}}, - { "lowlevel.spectral_energyband_middle_high.max", {1}}, - { "lowlevel.spectral_energyband_middle_high.mean", {1}}, - { "lowlevel.spectral_energyband_middle_high.median", {1}}, - { "lowlevel.spectral_energyband_middle_high.min", {1}}, - { "lowlevel.spectral_energyband_middle_high.var", {1}}, - { "lowlevel.spectral_energyband_middle_low.dmean", {1}}, - { "lowlevel.spectral_energyband_middle_low.dmean2", {1}}, - { "lowlevel.spectral_energyband_middle_low.dvar", {1}}, - { "lowlevel.spectral_energyband_middle_low.dvar2", {1}}, - { "lowlevel.spectral_energyband_middle_low.max", {1}}, - { "lowlevel.spectral_energyband_middle_low.mean", {1}}, - { "lowlevel.spectral_energyband_middle_low.median", {1}}, - { "lowlevel.spectral_energyband_middle_low.min", {1}}, - { "lowlevel.spectral_energyband_middle_low.var", {1}}, - { "lowlevel.spectral_entropy.dmean", {1}}, - { "lowlevel.spectral_entropy.dmean2", {1}}, - { "lowlevel.spectral_entropy.dvar", {1}}, - { "lowlevel.spectral_entropy.dvar2", {1}}, - { "lowlevel.spectral_entropy.max", {1}}, - { "lowlevel.spectral_entropy.mean", {1}}, - { "lowlevel.spectral_entropy.median", {1}}, - { "lowlevel.spectral_entropy.min", {1}}, - { "lowlevel.spectral_entropy.var", {1}}, - { "lowlevel.spectral_flux.dmean", {1}}, - { "lowlevel.spectral_flux.dmean2", {1}}, - { "lowlevel.spectral_flux.dvar", {1}}, - { "lowlevel.spectral_flux.dvar2", {1}}, - { "lowlevel.spectral_flux.max", {1}}, - { "lowlevel.spectral_flux.mean", {1}}, - { "lowlevel.spectral_flux.median", {1}}, - { "lowlevel.spectral_flux.min", {1}}, - { "lowlevel.spectral_flux.var", {1}}, - { "lowlevel.spectral_kurtosis.dmean", {1}}, - { "lowlevel.spectral_kurtosis.dmean2", {1}}, - { "lowlevel.spectral_kurtosis.dvar", {1}}, - { "lowlevel.spectral_kurtosis.dvar2", {1}}, - { "lowlevel.spectral_kurtosis.max", {1}}, - { "lowlevel.spectral_kurtosis.mean", {1}}, - { "lowlevel.spectral_kurtosis.median", {1}}, - { "lowlevel.spectral_kurtosis.min", {1}}, - { "lowlevel.spectral_kurtosis.var", {1}}, - { "lowlevel.spectral_rms.dmean", {1}}, - { "lowlevel.spectral_rms.dmean2", {1}}, - { "lowlevel.spectral_rms.dvar", {1}}, - { "lowlevel.spectral_rms.dvar2", {1}}, - { "lowlevel.spectral_rms.max", {1}}, - { "lowlevel.spectral_rms.mean", {1}}, - { "lowlevel.spectral_rms.median", {1}}, - { "lowlevel.spectral_rms.min", {1}}, - { "lowlevel.spectral_rms.var", {1}}, - { "lowlevel.spectral_rolloff.dmean", {1}}, - { "lowlevel.spectral_rolloff.dmean2", {1}}, - { "lowlevel.spectral_rolloff.dvar", {1}}, - { "lowlevel.spectral_rolloff.dvar2", {1}}, - { "lowlevel.spectral_rolloff.max", {1}}, - { "lowlevel.spectral_rolloff.mean", {1}}, - { "lowlevel.spectral_rolloff.median", {1}}, - { "lowlevel.spectral_rolloff.min", {1}}, - { "lowlevel.spectral_rolloff.var", {1}}, - { "lowlevel.spectral_skewness.dmean", {1}}, - { "lowlevel.spectral_skewness.dmean2", {1}}, - { "lowlevel.spectral_skewness.dvar", {1}}, - { "lowlevel.spectral_skewness.dvar2", {1}}, - { "lowlevel.spectral_skewness.max", {1}}, - { "lowlevel.spectral_skewness.mean", {1}}, - { "lowlevel.spectral_skewness.median", {1}}, - { "lowlevel.spectral_skewness.min", {1}}, - { "lowlevel.spectral_skewness.var", {1}}, - { "lowlevel.spectral_spread.dmean", {1}}, - { "lowlevel.spectral_spread.dmean2", {1}}, - { "lowlevel.spectral_spread.dvar", {1}}, - { "lowlevel.spectral_spread.dvar2", {1}}, - { "lowlevel.spectral_spread.max", {1}}, - { "lowlevel.spectral_spread.mean", {1}}, - { "lowlevel.spectral_spread.median", {1}}, - { "lowlevel.spectral_spread.min", {1}}, - { "lowlevel.spectral_spread.var", {1}}, - { "lowlevel.spectral_strongpeak.dmean", {1}}, - { "lowlevel.spectral_strongpeak.dmean2", {1}}, - { "lowlevel.spectral_strongpeak.dvar", {1}}, - { "lowlevel.spectral_strongpeak.dvar2", {1}}, - { "lowlevel.spectral_strongpeak.max", {1}}, - { "lowlevel.spectral_strongpeak.mean", {1}}, - { "lowlevel.spectral_strongpeak.median", {1}}, - { "lowlevel.spectral_strongpeak.min", {1}}, - { "lowlevel.spectral_strongpeak.var", {1}}, - { "lowlevel.zerocrossingrate.dmean", {1}}, - { "lowlevel.zerocrossingrate.dmean2", {1}}, - { "lowlevel.zerocrossingrate.dvar", {1}}, - { "lowlevel.zerocrossingrate.dvar2", {1}}, - { "lowlevel.zerocrossingrate.max", {1}}, - { "lowlevel.zerocrossingrate.mean", {1}}, - { "lowlevel.zerocrossingrate.median", {1}}, - { "lowlevel.zerocrossingrate.min", {1}}, - { "lowlevel.zerocrossingrate.var", {1}}, -}; -FeatureDef -getFeatureDef(const FeatureName& featureName) -{ - auto it {featureDefinitions.find(featureName)}; - if (it == std::cend(featureDefinitions)) - throw core::LmsException {"Unhandled requested feature '" + featureName + "'"}; + static const std::unordered_map featureDefinitions{ + { "lowlevel.average_loudness", { 1 } }, + { "lowlevel.barkbands.dmean", { 27 } }, + { "lowlevel.barkbands.dmean2", { 27 } }, + { "lowlevel.barkbands.dvar", { 27 } }, + { "lowlevel.barkbands.dvar2", { 27 } }, + { "lowlevel.barkbands.max", { 27 } }, + { "lowlevel.barkbands.mean", { 27 } }, + { "lowlevel.barkbands.median", { 27 } }, + { "lowlevel.barkbands.min", { 27 } }, + { "lowlevel.barkbands.var", { 27 } }, + { "lowlevel.barkbands_crest.dmean", { 1 } }, + { "lowlevel.barkbands_crest.dmean2", { 1 } }, + { "lowlevel.barkbands_crest.dvar", { 1 } }, + { "lowlevel.barkbands_crest.dvar2", { 1 } }, + { "lowlevel.barkbands_crest.max", { 1 } }, + { "lowlevel.barkbands_crest.mean", { 1 } }, + { "lowlevel.barkbands_crest.median", { 1 } }, + { "lowlevel.barkbands_crest.min", { 1 } }, + { "lowlevel.barkbands_crest.var", { 1 } }, + { "lowlevel.barkbands_flatness_db.dmean", { 1 } }, + { "lowlevel.barkbands_flatness_db.dmean2", { 1 } }, + { "lowlevel.barkbands_flatness_db.dvar", { 1 } }, + { "lowlevel.barkbands_flatness_db.dvar2", { 1 } }, + { "lowlevel.barkbands_flatness_db.max", { 1 } }, + { "lowlevel.barkbands_flatness_db.mean", { 1 } }, + { "lowlevel.barkbands_flatness_db.median", { 1 } }, + { "lowlevel.barkbands_flatness_db.min", { 1 } }, + { "lowlevel.barkbands_flatness_db.var", { 1 } }, + { "lowlevel.barkbands_kurtosis.dmean", { 1 } }, + { "lowlevel.barkbands_kurtosis.dmean2", { 1 } }, + { "lowlevel.barkbands_kurtosis.dvar", { 1 } }, + { "lowlevel.barkbands_kurtosis.dvar2", { 1 } }, + { "lowlevel.barkbands_kurtosis.max", { 1 } }, + { "lowlevel.barkbands_kurtosis.mean", { 1 } }, + { "lowlevel.barkbands_kurtosis.median", { 1 } }, + { "lowlevel.barkbands_kurtosis.min", { 1 } }, + { "lowlevel.barkbands_kurtosis.var", { 1 } }, + { "lowlevel.barkbands_skewness.dmean", { 1 } }, + { "lowlevel.barkbands_skewness.dmean2", { 1 } }, + { "lowlevel.barkbands_skewness.dvar", { 1 } }, + { "lowlevel.barkbands_skewness.dvar2", { 1 } }, + { "lowlevel.barkbands_skewness.max", { 1 } }, + { "lowlevel.barkbands_skewness.mean", { 1 } }, + { "lowlevel.barkbands_skewness.median", { 1 } }, + { "lowlevel.barkbands_skewness.min", { 1 } }, + { "lowlevel.barkbands_skewness.var", { 1 } }, + { "lowlevel.barkbands_spread.dmean", { 1 } }, + { "lowlevel.barkbands_spread.dmean2", { 1 } }, + { "lowlevel.barkbands_spread.dvar", { 1 } }, + { "lowlevel.barkbands_spread.dvar2", { 1 } }, + { "lowlevel.barkbands_spread.max", { 1 } }, + { "lowlevel.barkbands_spread.mean", { 1 } }, + { "lowlevel.barkbands_spread.median", { 1 } }, + { "lowlevel.barkbands_spread.min", { 1 } }, + { "lowlevel.barkbands_spread.var", { 1 } }, + { "lowlevel.dissonance.dmean", { 1 } }, + { "lowlevel.dissonance.dmean2", { 1 } }, + { "lowlevel.dissonance.dvar", { 1 } }, + { "lowlevel.dissonance.dvar2", { 1 } }, + { "lowlevel.dissonance.max", { 1 } }, + { "lowlevel.dissonance.mean", { 1 } }, + { "lowlevel.dissonance.median", { 1 } }, + { "lowlevel.dissonance.min", { 1 } }, + { "lowlevel.dissonance.var", { 1 } }, + { "lowlevel.dynamic_complexity", { 1 } }, + { "lowlevel.erbbands.dmean", { 40 } }, + { "lowlevel.erbbands.dmean2", { 40 } }, + { "lowlevel.erbbands.dvar", { 40 } }, + { "lowlevel.erbbands.dvar2", { 40 } }, + { "lowlevel.erbbands.max", { 40 } }, + { "lowlevel.erbbands.mean", { 40 } }, + { "lowlevel.erbbands.median", { 40 } }, + { "lowlevel.erbbands.min", { 40 } }, + { "lowlevel.erbbands.var", { 40 } }, + { "lowlevel.gfcc.mean", { 13 } }, + { "lowlevel.hfc.dmean", { 1 } }, + { "lowlevel.hfc.dmean2", { 1 } }, + { "lowlevel.hfc.dvar", { 1 } }, + { "lowlevel.hfc.dvar2", { 1 } }, + { "lowlevel.hfc.max", { 1 } }, + { "lowlevel.hfc.mean", { 1 } }, + { "lowlevel.hfc.median", { 1 } }, + { "lowlevel.hfc.min", { 1 } }, + { "lowlevel.hfc.var", { 1 } }, + { "tonal.hpcp.median", { 36 } }, + { "lowlevel.melbands.dmean", { 40 } }, + { "lowlevel.melbands.dmean2", { 40 } }, + { "lowlevel.melbands.dvar", { 40 } }, + { "lowlevel.melbands.dvar2", { 40 } }, + { "lowlevel.melbands.max", { 40 } }, + { "lowlevel.melbands.mean", { 40 } }, + { "lowlevel.melbands.median", { 40 } }, + { "lowlevel.melbands.min", { 40 } }, + { "lowlevel.melbands.var", { 40 } }, + { "lowlevel.melbands_crest.dmean", { 1 } }, + { "lowlevel.melbands_crest.dmean2", { 1 } }, + { "lowlevel.melbands_crest.dvar", { 1 } }, + { "lowlevel.melbands_crest.dvar2", { 1 } }, + { "lowlevel.melbands_crest.max", { 1 } }, + { "lowlevel.melbands_crest.mean", { 1 } }, + { "lowlevel.melbands_crest.median", { 1 } }, + { "lowlevel.melbands_crest.min", { 1 } }, + { "lowlevel.melbands_crest.var", { 1 } }, + { "lowlevel.melbands_flatness_db.dmean", { 1 } }, + { "lowlevel.melbands_flatness_db.dmean2", { 1 } }, + { "lowlevel.melbands_flatness_db.dvar", { 1 } }, + { "lowlevel.melbands_flatness_db.dvar2", { 1 } }, + { "lowlevel.melbands_flatness_db.max", { 1 } }, + { "lowlevel.melbands_flatness_db.mean", { 1 } }, + { "lowlevel.melbands_flatness_db.median", { 1 } }, + { "lowlevel.melbands_flatness_db.min", { 1 } }, + { "lowlevel.melbands_flatness_db.var", { 1 } }, + { "lowlevel.melbands_kurtosis.dmean", { 1 } }, + { "lowlevel.melbands_kurtosis.dmean2", { 1 } }, + { "lowlevel.melbands_kurtosis.dvar", { 1 } }, + { "lowlevel.melbands_kurtosis.dvar2", { 1 } }, + { "lowlevel.melbands_kurtosis.max", { 1 } }, + { "lowlevel.melbands_kurtosis.mean", { 1 } }, + { "lowlevel.melbands_kurtosis.median", { 1 } }, + { "lowlevel.melbands_kurtosis.min", { 1 } }, + { "lowlevel.melbands_kurtosis.var", { 1 } }, + { "lowlevel.melbands_skewness.dmean", { 1 } }, + { "lowlevel.melbands_skewness.dmean2", { 1 } }, + { "lowlevel.melbands_skewness.dvar", { 1 } }, + { "lowlevel.melbands_skewness.dvar2", { 1 } }, + { "lowlevel.melbands_skewness.max", { 1 } }, + { "lowlevel.melbands_skewness.mean", { 1 } }, + { "lowlevel.melbands_skewness.median", { 1 } }, + { "lowlevel.melbands_skewness.min", { 1 } }, + { "lowlevel.melbands_skewness.var", { 1 } }, + { "lowlevel.melbands_spread.dmean", { 1 } }, + { "lowlevel.melbands_spread.dmean2", { 1 } }, + { "lowlevel.melbands_spread.dvar", { 1 } }, + { "lowlevel.melbands_spread.dvar2", { 1 } }, + { "lowlevel.melbands_spread.max", { 1 } }, + { "lowlevel.melbands_spread.mean", { 1 } }, + { "lowlevel.melbands_spread.median", { 1 } }, + { "lowlevel.melbands_spread.min", { 1 } }, + { "lowlevel.melbands_spread.var", { 1 } }, + { "lowlevel.mfcc.mean", { 13 } }, + { "lowlevel.pitch_salience.dmean", { 1 } }, + { "lowlevel.pitch_salience.dmean2", { 1 } }, + { "lowlevel.pitch_salience.dvar", { 1 } }, + { "lowlevel.pitch_salience.dvar2", { 1 } }, + { "lowlevel.pitch_salience.max", { 1 } }, + { "lowlevel.pitch_salience.mean", { 1 } }, + { "lowlevel.pitch_salience.median", { 1 } }, + { "lowlevel.pitch_salience.min", { 1 } }, + { "lowlevel.pitch_salience.var", { 1 } }, + { "lowlevel.silence_rate_30dB.dmean", { 1 } }, + { "lowlevel.silence_rate_30dB.dmean2", { 1 } }, + { "lowlevel.silence_rate_30dB.dvar", { 1 } }, + { "lowlevel.silence_rate_30dB.dvar2", { 1 } }, + { "lowlevel.silence_rate_30dB.max", { 1 } }, + { "lowlevel.silence_rate_30dB.mean", { 1 } }, + { "lowlevel.silence_rate_30dB.median", { 1 } }, + { "lowlevel.silence_rate_30dB.min", { 1 } }, + { "lowlevel.silence_rate_30dB.var", { 1 } }, + { "lowlevel.silence_rate_60dB.dmean", { 1 } }, + { "lowlevel.silence_rate_60dB.dmean2", { 1 } }, + { "lowlevel.silence_rate_60dB.dvar", { 1 } }, + { "lowlevel.silence_rate_60dB.dvar2", { 1 } }, + { "lowlevel.silence_rate_60dB.max", { 1 } }, + { "lowlevel.silence_rate_60dB.mean", { 1 } }, + { "lowlevel.silence_rate_60dB.median", { 1 } }, + { "lowlevel.silence_rate_60dB.min", { 1 } }, + { "lowlevel.silence_rate_60dB.var", { 1 } }, + { "lowlevel.spectral_centroid.dmean", { 1 } }, + { "lowlevel.spectral_centroid.dmean2", { 1 } }, + { "lowlevel.spectral_centroid.dvar", { 1 } }, + { "lowlevel.spectral_centroid.dvar2", { 1 } }, + { "lowlevel.spectral_centroid.max", { 1 } }, + { "lowlevel.spectral_centroid.mean", { 1 } }, + { "lowlevel.spectral_centroid.median", { 1 } }, + { "lowlevel.spectral_centroid.min", { 1 } }, + { "lowlevel.spectral_centroid.var", { 1 } }, + { "lowlevel.spectral_complexity.dmean", { 1 } }, + { "lowlevel.spectral_complexity.dmean2", { 1 } }, + { "lowlevel.spectral_complexity.dvar", { 1 } }, + { "lowlevel.spectral_complexity.dvar2", { 1 } }, + { "lowlevel.spectral_complexity.max", { 1 } }, + { "lowlevel.spectral_complexity.mean", { 1 } }, + { "lowlevel.spectral_complexity.median", { 1 } }, + { "lowlevel.spectral_complexity.min", { 1 } }, + { "lowlevel.spectral_complexity.var", { 1 } }, + { "lowlevel.spectral_contrast_coeffs.dmean", { 6 } }, + { "lowlevel.spectral_contrast_coeffs.dmean2", { 6 } }, + { "lowlevel.spectral_contrast_coeffs.dvar", { 6 } }, + { "lowlevel.spectral_contrast_coeffs.dvar2", { 6 } }, + { "lowlevel.spectral_contrast_coeffs.max", { 6 } }, + { "lowlevel.spectral_contrast_coeffs.mean", { 6 } }, + { "lowlevel.spectral_contrast_coeffs.median", { 6 } }, + { "lowlevel.spectral_contrast_coeffs.min", { 6 } }, + { "lowlevel.spectral_contrast_coeffs.var", { 6 } }, + { "lowlevel.spectral_contrast_valleys.dmean", { 6 } }, + { "lowlevel.spectral_contrast_valleys.dmean2", { 6 } }, + { "lowlevel.spectral_contrast_valleys.dvar", { 6 } }, + { "lowlevel.spectral_contrast_valleys.dvar2", { 6 } }, + { "lowlevel.spectral_contrast_valleys.max", { 6 } }, + { "lowlevel.spectral_contrast_valleys.mean", { 6 } }, + { "lowlevel.spectral_contrast_valleys.median", { 6 } }, + { "lowlevel.spectral_contrast_valleys.min", { 6 } }, + { "lowlevel.spectral_contrast_valleys.var", { 6 } }, + { "lowlevel.spectral_decrease.dmean", { 1 } }, + { "lowlevel.spectral_decrease.dmean2", { 1 } }, + { "lowlevel.spectral_decrease.dvar", { 1 } }, + { "lowlevel.spectral_decrease.dvar2", { 1 } }, + { "lowlevel.spectral_decrease.max", { 1 } }, + { "lowlevel.spectral_decrease.mean", { 1 } }, + { "lowlevel.spectral_decrease.median", { 1 } }, + { "lowlevel.spectral_decrease.min", { 1 } }, + { "lowlevel.spectral_decrease.var", { 1 } }, + { "lowlevel.spectral_energy.dmean", { 1 } }, + { "lowlevel.spectral_energy.dmean2", { 1 } }, + { "lowlevel.spectral_energy.dvar", { 1 } }, + { "lowlevel.spectral_energy.dvar2", { 1 } }, + { "lowlevel.spectral_energy.max", { 1 } }, + { "lowlevel.spectral_energy.mean", { 1 } }, + { "lowlevel.spectral_energy.median", { 1 } }, + { "lowlevel.spectral_energy.min", { 1 } }, + { "lowlevel.spectral_energy.var", { 1 } }, + { "lowlevel.spectral_energyband_high.dmean", { 1 } }, + { "lowlevel.spectral_energyband_high.dmean2", { 1 } }, + { "lowlevel.spectral_energyband_high.dvar", { 1 } }, + { "lowlevel.spectral_energyband_high.dvar2", { 1 } }, + { "lowlevel.spectral_energyband_high.max", { 1 } }, + { "lowlevel.spectral_energyband_high.mean", { 1 } }, + { "lowlevel.spectral_energyband_high.median", { 1 } }, + { "lowlevel.spectral_energyband_high.min", { 1 } }, + { "lowlevel.spectral_energyband_high.var", { 1 } }, + { "lowlevel.spectral_energyband_low.dmean", { 1 } }, + { "lowlevel.spectral_energyband_low.dmean2", { 1 } }, + { "lowlevel.spectral_energyband_low.dvar", { 1 } }, + { "lowlevel.spectral_energyband_low.dvar2", { 1 } }, + { "lowlevel.spectral_energyband_low.max", { 1 } }, + { "lowlevel.spectral_energyband_low.mean", { 1 } }, + { "lowlevel.spectral_energyband_low.median", { 1 } }, + { "lowlevel.spectral_energyband_low.min", { 1 } }, + { "lowlevel.spectral_energyband_low.var", { 1 } }, + { "lowlevel.spectral_energyband_middle_high.dmean", { 1 } }, + { "lowlevel.spectral_energyband_middle_high.dmean2", { 1 } }, + { "lowlevel.spectral_energyband_middle_high.dvar", { 1 } }, + { "lowlevel.spectral_energyband_middle_high.dvar2", { 1 } }, + { "lowlevel.spectral_energyband_middle_high.max", { 1 } }, + { "lowlevel.spectral_energyband_middle_high.mean", { 1 } }, + { "lowlevel.spectral_energyband_middle_high.median", { 1 } }, + { "lowlevel.spectral_energyband_middle_high.min", { 1 } }, + { "lowlevel.spectral_energyband_middle_high.var", { 1 } }, + { "lowlevel.spectral_energyband_middle_low.dmean", { 1 } }, + { "lowlevel.spectral_energyband_middle_low.dmean2", { 1 } }, + { "lowlevel.spectral_energyband_middle_low.dvar", { 1 } }, + { "lowlevel.spectral_energyband_middle_low.dvar2", { 1 } }, + { "lowlevel.spectral_energyband_middle_low.max", { 1 } }, + { "lowlevel.spectral_energyband_middle_low.mean", { 1 } }, + { "lowlevel.spectral_energyband_middle_low.median", { 1 } }, + { "lowlevel.spectral_energyband_middle_low.min", { 1 } }, + { "lowlevel.spectral_energyband_middle_low.var", { 1 } }, + { "lowlevel.spectral_entropy.dmean", { 1 } }, + { "lowlevel.spectral_entropy.dmean2", { 1 } }, + { "lowlevel.spectral_entropy.dvar", { 1 } }, + { "lowlevel.spectral_entropy.dvar2", { 1 } }, + { "lowlevel.spectral_entropy.max", { 1 } }, + { "lowlevel.spectral_entropy.mean", { 1 } }, + { "lowlevel.spectral_entropy.median", { 1 } }, + { "lowlevel.spectral_entropy.min", { 1 } }, + { "lowlevel.spectral_entropy.var", { 1 } }, + { "lowlevel.spectral_flux.dmean", { 1 } }, + { "lowlevel.spectral_flux.dmean2", { 1 } }, + { "lowlevel.spectral_flux.dvar", { 1 } }, + { "lowlevel.spectral_flux.dvar2", { 1 } }, + { "lowlevel.spectral_flux.max", { 1 } }, + { "lowlevel.spectral_flux.mean", { 1 } }, + { "lowlevel.spectral_flux.median", { 1 } }, + { "lowlevel.spectral_flux.min", { 1 } }, + { "lowlevel.spectral_flux.var", { 1 } }, + { "lowlevel.spectral_kurtosis.dmean", { 1 } }, + { "lowlevel.spectral_kurtosis.dmean2", { 1 } }, + { "lowlevel.spectral_kurtosis.dvar", { 1 } }, + { "lowlevel.spectral_kurtosis.dvar2", { 1 } }, + { "lowlevel.spectral_kurtosis.max", { 1 } }, + { "lowlevel.spectral_kurtosis.mean", { 1 } }, + { "lowlevel.spectral_kurtosis.median", { 1 } }, + { "lowlevel.spectral_kurtosis.min", { 1 } }, + { "lowlevel.spectral_kurtosis.var", { 1 } }, + { "lowlevel.spectral_rms.dmean", { 1 } }, + { "lowlevel.spectral_rms.dmean2", { 1 } }, + { "lowlevel.spectral_rms.dvar", { 1 } }, + { "lowlevel.spectral_rms.dvar2", { 1 } }, + { "lowlevel.spectral_rms.max", { 1 } }, + { "lowlevel.spectral_rms.mean", { 1 } }, + { "lowlevel.spectral_rms.median", { 1 } }, + { "lowlevel.spectral_rms.min", { 1 } }, + { "lowlevel.spectral_rms.var", { 1 } }, + { "lowlevel.spectral_rolloff.dmean", { 1 } }, + { "lowlevel.spectral_rolloff.dmean2", { 1 } }, + { "lowlevel.spectral_rolloff.dvar", { 1 } }, + { "lowlevel.spectral_rolloff.dvar2", { 1 } }, + { "lowlevel.spectral_rolloff.max", { 1 } }, + { "lowlevel.spectral_rolloff.mean", { 1 } }, + { "lowlevel.spectral_rolloff.median", { 1 } }, + { "lowlevel.spectral_rolloff.min", { 1 } }, + { "lowlevel.spectral_rolloff.var", { 1 } }, + { "lowlevel.spectral_skewness.dmean", { 1 } }, + { "lowlevel.spectral_skewness.dmean2", { 1 } }, + { "lowlevel.spectral_skewness.dvar", { 1 } }, + { "lowlevel.spectral_skewness.dvar2", { 1 } }, + { "lowlevel.spectral_skewness.max", { 1 } }, + { "lowlevel.spectral_skewness.mean", { 1 } }, + { "lowlevel.spectral_skewness.median", { 1 } }, + { "lowlevel.spectral_skewness.min", { 1 } }, + { "lowlevel.spectral_skewness.var", { 1 } }, + { "lowlevel.spectral_spread.dmean", { 1 } }, + { "lowlevel.spectral_spread.dmean2", { 1 } }, + { "lowlevel.spectral_spread.dvar", { 1 } }, + { "lowlevel.spectral_spread.dvar2", { 1 } }, + { "lowlevel.spectral_spread.max", { 1 } }, + { "lowlevel.spectral_spread.mean", { 1 } }, + { "lowlevel.spectral_spread.median", { 1 } }, + { "lowlevel.spectral_spread.min", { 1 } }, + { "lowlevel.spectral_spread.var", { 1 } }, + { "lowlevel.spectral_strongpeak.dmean", { 1 } }, + { "lowlevel.spectral_strongpeak.dmean2", { 1 } }, + { "lowlevel.spectral_strongpeak.dvar", { 1 } }, + { "lowlevel.spectral_strongpeak.dvar2", { 1 } }, + { "lowlevel.spectral_strongpeak.max", { 1 } }, + { "lowlevel.spectral_strongpeak.mean", { 1 } }, + { "lowlevel.spectral_strongpeak.median", { 1 } }, + { "lowlevel.spectral_strongpeak.min", { 1 } }, + { "lowlevel.spectral_strongpeak.var", { 1 } }, + { "lowlevel.zerocrossingrate.dmean", { 1 } }, + { "lowlevel.zerocrossingrate.dmean2", { 1 } }, + { "lowlevel.zerocrossingrate.dvar", { 1 } }, + { "lowlevel.zerocrossingrate.dvar2", { 1 } }, + { "lowlevel.zerocrossingrate.max", { 1 } }, + { "lowlevel.zerocrossingrate.mean", { 1 } }, + { "lowlevel.zerocrossingrate.median", { 1 } }, + { "lowlevel.zerocrossingrate.min", { 1 } }, + { "lowlevel.zerocrossingrate.var", { 1 } }, + }; - return it->second; -} + FeatureDef getFeatureDef(const FeatureName& featureName) + { + auto it{ featureDefinitions.find(featureName) }; + if (it == std::cend(featureDefinitions)) + throw core::LmsException{ "Unhandled requested feature '" + featureName + "'" }; -FeatureNames -getFeatureNames() -{ - FeatureNames res; + return it->second; + } - std::transform(std::cbegin(featureDefinitions), std::cend(featureDefinitions), - std::inserter(res, std::begin(res)), [](auto itFeature) { return itFeature.first; }); + FeatureNames getFeatureNames() + { + FeatureNames res; - return res; -} + std::transform(std::cbegin(featureDefinitions), std::cend(featureDefinitions), + std::inserter(res, std::begin(res)), [](auto itFeature) { return itFeature.first; }); + + return res; + } } // namespace lms::recommendation - diff --git a/src/libs/services/recommendation/impl/features/FeaturesDefs.hpp b/src/libs/services/recommendation/impl/features/FeaturesDefs.hpp index 6a83b7fb..dbb0ddf6 100644 --- a/src/libs/services/recommendation/impl/features/FeaturesDefs.hpp +++ b/src/libs/services/recommendation/impl/features/FeaturesDefs.hpp @@ -24,26 +24,27 @@ #include #include -namespace lms::recommendation { - -using FeatureName = std::string; -using FeatureNames = std::unordered_set; -using FeatureValue = double; -using FeatureValues = std::vector; -using FeatureValuesMap = std::unordered_map; - -struct FeatureDef +namespace lms::recommendation { - std::size_t nbDimensions {}; -}; -FeatureDef getFeatureDef(const FeatureName& featureName); -FeatureNames getFeatureNames(); + using FeatureName = std::string; + using FeatureNames = std::unordered_set; + using FeatureValue = double; + using FeatureValues = std::vector; + using FeatureValuesMap = std::unordered_map; -struct FeatureSettings -{ - double weight {}; -}; -using FeatureSettingsMap = std::unordered_map; + struct FeatureDef + { + std::size_t nbDimensions{}; + }; + + FeatureDef getFeatureDef(const FeatureName& featureName); + FeatureNames getFeatureNames(); + + struct FeatureSettings + { + double weight{}; + }; + using FeatureSettingsMap = std::unordered_map; } // namespace lms::recommendation diff --git a/src/libs/services/recommendation/impl/features/FeaturesEngine.cpp b/src/libs/services/recommendation/impl/features/FeaturesEngine.cpp index 0cec15ba..cca183fc 100644 --- a/src/libs/services/recommendation/impl/features/FeaturesEngine.cpp +++ b/src/libs/services/recommendation/impl/features/FeaturesEngine.cpp @@ -21,6 +21,8 @@ #include +#include "core/ILogger.hpp" +#include "core/Random.hpp" #include "database/Artist.hpp" #include "database/Db.hpp" #include "database/Release.hpp" @@ -30,8 +32,6 @@ #include "database/TrackFeatures.hpp" #include "database/TrackList.hpp" #include "som/DataNormalizer.hpp" -#include "core/ILogger.hpp" -#include "core/Random.hpp" namespace lms::recommendation { @@ -47,7 +47,7 @@ namespace lms::recommendation std::optional convertFeatureValuesMapToInputVector(const FeatureValuesMap& featureValuesMap, std::size_t nbDimensions) { std::size_t i{}; - std::optional res{ som::InputVector {nbDimensions} }; + std::optional res{ som::InputVector{ nbDimensions } }; for (const auto& [featureName, values] : featureValuesMap) { if (values.size() != getFeatureDef(featureName).nbDimensions) @@ -80,17 +80,16 @@ namespace lms::recommendation return weights; } - } + } // namespace const FeatureSettingsMap& FeaturesEngine::getDefaultTrainFeatureSettings() { - static const FeatureSettingsMap defaultTrainFeatureSettings - { - { "lowlevel.spectral_energyband_high.mean", {1}}, - { "lowlevel.spectral_rolloff.median", {1}}, - { "lowlevel.spectral_contrast_valleys.var", {1}}, - { "lowlevel.erbbands.mean", {1}}, - { "lowlevel.gfcc.mean", {1}}, + static const FeatureSettingsMap defaultTrainFeatureSettings{ + { "lowlevel.spectral_energyband_high.mean", { 1 } }, + { "lowlevel.spectral_rolloff.median", { 1 } }, + { "lowlevel.spectral_contrast_valleys.var", { 1 } }, + { "lowlevel.erbbands.mean", { 1 } }, + { "lowlevel.gfcc.mean", { 1 } }, }; return defaultTrainFeatureSettings; @@ -104,12 +103,12 @@ namespace lms::recommendation std::transform(std::cbegin(trainSettings.featureSettingsMap), std::cend(trainSettings.featureSettingsMap), std::inserter(featureNames, std::begin(featureNames)), [](const auto& itFeatureSetting) { return itFeatureSetting.first; }); - const std::size_t nbDimensions{ std::accumulate(std::cbegin(featureNames), std::cend(featureNames), std::size_t {0}, - [](std::size_t sum, const FeatureName& featureName) { return sum + getFeatureDef(featureName).nbDimensions; }) }; + const std::size_t nbDimensions{ std::accumulate(std::cbegin(featureNames), std::cend(featureNames), std::size_t{ 0 }, + [](std::size_t sum, const FeatureName& featureName) { return sum + getFeatureDef(featureName).nbDimensions; }) }; LMS_LOG(RECOMMENDATION, DEBUG, "Features dimension = " << nbDimensions); - Session & session{ _db.getTLSSession() }; + Session& session{ _db.getTLSSession() }; RangeResults trackFeaturesIds; { @@ -178,10 +177,9 @@ namespace lms::recommendation som::InputVector weights{ getInputVectorWeights(trainSettings.featureSettingsMap, nbDimensions) }; network.setDataWeights(weights); - auto somProgressCallback{ [&](const som::Network::CurrentIteration& iter) - { + auto somProgressCallback{ [&](const som::Network::CurrentIteration& iter) { LMS_LOG(RECOMMENDATION, DEBUG, "Current pass = " << iter.idIteration << " / " << iter.iterationCount); - progressCallback(Progress {iter.idIteration, iter.iterationCount}); + progressCallback(Progress{ iter.idIteration, iter.iterationCount }); } }; LMS_LOG(RECOMMENDATION, DEBUG, "Training network..."); @@ -216,15 +214,14 @@ namespace lms::recommendation TrackContainer FeaturesEngine::findSimilarTracksFromTrackList(TrackListId trackListId, std::size_t maxCount) const { - const TrackContainer trackIds{ [&] - { + const TrackContainer trackIds{ [&] { TrackContainer res; - Session& session {_db.getTLSSession()}; + Session& session{ _db.getTLSSession() }; - auto transaction {session.createReadTransaction()}; + auto transaction{ session.createReadTransaction() }; - const TrackList::pointer trackList {TrackList::find(session, trackListId)}; + const TrackList::pointer trackList{ TrackList::find(session, trackListId) }; if (trackList) res = trackList->getTrackIds(); @@ -245,10 +242,10 @@ namespace lms::recommendation auto transaction{ session.createReadTransaction() }; similarTrackIds.erase(std::remove_if(std::begin(similarTrackIds), std::end(similarTrackIds), - [&](TrackId trackId) - { - return !Track::exists(session, trackId); - }), std::end(similarTrackIds)); + [&](TrackId trackId) { + return !Track::exists(session, trackId); + }), + std::end(similarTrackIds)); } return similarTrackIds; @@ -256,7 +253,7 @@ namespace lms::recommendation ReleaseContainer FeaturesEngine::getSimilarReleases(ReleaseId releaseId, std::size_t maxCount) const { - auto similarReleaseIds{ getSimilarObjects({releaseId}, _releaseMatrix, _releasePositions, maxCount) }; + auto similarReleaseIds{ getSimilarObjects({ releaseId }, _releaseMatrix, _releasePositions, maxCount) }; Session& session{ _db.getTLSSession() }; @@ -266,10 +263,10 @@ namespace lms::recommendation auto transaction{ session.createReadTransaction() }; similarReleaseIds.erase(std::remove_if(std::begin(similarReleaseIds), std::end(similarReleaseIds), - [&](ReleaseId releaseId) - { - return !Release::exists(session, releaseId); - }), std::end(similarReleaseIds)); + [&](ReleaseId releaseId) { + return !Release::exists(session, releaseId); + }), + std::end(similarReleaseIds)); } return similarReleaseIds; @@ -277,17 +274,16 @@ namespace lms::recommendation ArtistContainer FeaturesEngine::getSimilarArtists(ArtistId artistId, core::EnumSet linkTypes, std::size_t maxCount) const { - auto getSimilarArtistIdsForLinkType{ [&](TrackArtistLinkType linkType) - { + auto getSimilarArtistIdsForLinkType{ [&](TrackArtistLinkType linkType) { ArtistContainer similarArtistIds; - const auto itArtists {_artistMatrix.find(linkType)}; + const auto itArtists{ _artistMatrix.find(linkType) }; if (itArtists == std::cend(_artistMatrix)) { return similarArtistIds; } - return getSimilarObjects({artistId}, itArtists->second, _artistPositions, maxCount); + return getSimilarObjects({ artistId }, itArtists->second, _artistPositions, maxCount); } }; std::unordered_set similarArtistIds; @@ -306,10 +302,10 @@ namespace lms::recommendation auto transaction{ session.createReadTransaction() }; res.erase(std::remove_if(std::begin(res), std::end(res), - [&](ArtistId artistId) - { - return !Artist::exists(session, artistId); - }), std::end(res)); + [&](ArtistId artistId) { + return !Artist::exists(session, artistId); + }), + std::end(res)); } while (res.size() > maxCount) @@ -364,7 +360,7 @@ namespace lms::recommendation LMS_LOG(RECOMMENDATION, DEBUG, "Constructing maps..."); - Session & session{ _db.getTLSSession() }; + Session& session{ _db.getTLSSession() }; for (const auto& [trackId, positions] : trackPositions) { @@ -410,4 +406,4 @@ namespace lms::recommendation LMS_LOG(RECOMMENDATION, INFO, "Classifier successfully loaded!"); } -} // ns Recommendation +} // namespace lms::recommendation diff --git a/src/libs/services/recommendation/impl/features/FeaturesEngine.hpp b/src/libs/services/recommendation/impl/features/FeaturesEngine.hpp index 8506dee7..1e0c91fa 100644 --- a/src/libs/services/recommendation/impl/features/FeaturesEngine.hpp +++ b/src/libs/services/recommendation/impl/features/FeaturesEngine.hpp @@ -21,17 +21,18 @@ #include #include -#include #include #include +#include #include +#include "core/Utils.hpp" #include "som/DataNormalizer.hpp" #include "som/Network.hpp" -#include "core/Utils.hpp" -#include "IEngine.hpp" -#include "FeaturesEngineCache.hpp" + #include "FeaturesDefs.hpp" +#include "FeaturesEngineCache.hpp" +#include "IEngine.hpp" namespace lms::db { @@ -45,7 +46,8 @@ namespace lms::recommendation class FeaturesEngine : public IEngine { public: - FeaturesEngine(db::Db& db) : _db{ db } {} + FeaturesEngine(db::Db& db) + : _db{ db } {} FeaturesEngine(const FeaturesEngine&) = delete; FeaturesEngine(FeaturesEngine&&) = delete; @@ -74,14 +76,14 @@ namespace lms::recommendation }; void loadFromTraining(const TrainSettings& trainSettings, const ProgressCallback& progressCallback); - template + template using ObjectPositions = std::unordered_map>; using ArtistPositions = ObjectPositions; using ReleasePositions = ObjectPositions; using TrackPositions = ObjectPositions; - template + template using ObjectMatrix = som::Matrix>; using ArtistMatrix = ObjectMatrix; using ReleaseMatrix = ObjectMatrix; @@ -91,34 +93,34 @@ namespace lms::recommendation FeaturesEngineCache toCache() const; - template + template static std::vector getMatchingRefVectorsPosition(const std::vector& ids, const ObjectPositions& objectPositions); - template + template static std::vector getObjectsIds(const std::vector& positions, const ObjectMatrix& objectsMatrix); - template + template std::vector getSimilarObjects(const std::vector& ids, const ObjectMatrix& objectMatrix, const ObjectPositions& objectPositions, std::size_t maxCount) const; db::Db& _db; - bool _loadCancelled{}; - std::unique_ptr _network; - double _networkRefVectorsDistanceMedian{}; + bool _loadCancelled{}; + std::unique_ptr _network; + double _networkRefVectorsDistanceMedian{}; - ArtistPositions _artistPositions; + ArtistPositions _artistPositions; std::unordered_map _artistMatrix; - ReleasePositions _releasePositions; - ReleaseMatrix _releaseMatrix; + ReleasePositions _releasePositions; + ReleaseMatrix _releaseMatrix; - TrackPositions _trackPositions; - TrackMatrix _trackMatrix; + TrackPositions _trackPositions; + TrackMatrix _trackMatrix; }; - template + template std::vector FeaturesEngine::getMatchingRefVectorsPosition(const std::vector& ids, const ObjectPositions& objectPositions) { std::vector res; @@ -139,7 +141,7 @@ namespace lms::recommendation return res; } - template + template std::vector FeaturesEngine::getObjectsIds(const std::vector& positions, const ObjectMatrix& objectMatrix) { std::vector res; @@ -153,11 +155,11 @@ namespace lms::recommendation return res; } - template + template std::vector FeaturesEngine::getSimilarObjects(const std::vector& ids, - const ObjectMatrix& objectMatrix, - const ObjectPositions& objectPositions, - std::size_t maxCount) const + const ObjectMatrix& objectMatrix, + const ObjectPositions& objectPositions, + std::size_t maxCount) const { std::vector res; @@ -171,11 +173,10 @@ namespace lms::recommendation // Remove objects that are already in input or already reported closestObjectIds.erase(std::remove_if(std::begin(closestObjectIds), std::end(closestObjectIds), - [&](IdType id) - { - return std::find(std::cbegin(ids), std::cend(ids), id) != std::cend(ids); - }) - , std::end(closestObjectIds)); + [&](IdType id) { + return std::find(std::cbegin(ids), std::cend(ids), id) != std::cend(ids); + }), + std::end(closestObjectIds)); for (IdType id : closestObjectIds) { @@ -198,4 +199,4 @@ namespace lms::recommendation return res; } -} +} // namespace lms::recommendation diff --git a/src/libs/services/recommendation/impl/features/FeaturesEngineCache.cpp b/src/libs/services/recommendation/impl/features/FeaturesEngineCache.cpp index dd3279dd..3934e3a1 100644 --- a/src/libs/services/recommendation/impl/features/FeaturesEngineCache.cpp +++ b/src/libs/services/recommendation/impl/features/FeaturesEngineCache.cpp @@ -86,7 +86,7 @@ namespace lms::recommendation return false; } } - } + } // namespace std::optional FeaturesEngineCache::createNetworkFromCacheFile(const std::filesystem::path& path) { @@ -240,8 +240,8 @@ namespace lms::recommendation } FeaturesEngineCache::FeaturesEngineCache(som::Network network, TrackPositions trackPositions) - : _network{ std::move(network) }, - _trackPositions{ std::move(trackPositions) } + : _network{ std::move(network) } + , _trackPositions{ std::move(trackPositions) } { } diff --git a/src/libs/services/recommendation/impl/features/FeaturesEngineCache.hpp b/src/libs/services/recommendation/impl/features/FeaturesEngineCache.hpp index c83bbf50..84ca8697 100644 --- a/src/libs/services/recommendation/impl/features/FeaturesEngineCache.hpp +++ b/src/libs/services/recommendation/impl/features/FeaturesEngineCache.hpp @@ -47,8 +47,8 @@ namespace lms::recommendation friend class FeaturesEngine; - som::Network _network; - TrackPositions _trackPositions; + som::Network _network; + TrackPositions _trackPositions; }; } // namespace lms::recommendation diff --git a/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveArtists.cpp b/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveArtists.cpp index 831041c4..0174a972 100644 --- a/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveArtists.cpp +++ b/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveArtists.cpp @@ -21,77 +21,73 @@ #include +#include "core/ILogger.hpp" #include "database/Db.hpp" #include "database/Release.hpp" #include "database/Session.hpp" #include "database/Track.hpp" -#include "core/ILogger.hpp" namespace lms::recommendation::PlaylistGeneratorConstraint { - namespace - { - std::size_t - countCommonArtists(const ArtistContainer& artists1, const ArtistContainer& artists2) - { - ArtistContainer intersection; + namespace + { + std::size_t countCommonArtists(const ArtistContainer& artists1, const ArtistContainer& artists2) + { + ArtistContainer intersection; - std::set_intersection(std::cbegin(artists1), std::cend(artists1), - std::cbegin(artists2), std::cend(artists2), - std::back_inserter(intersection)); + std::set_intersection(std::cbegin(artists1), std::cend(artists1), + std::cbegin(artists2), std::cend(artists2), + std::back_inserter(intersection)); - return intersection.size(); - } - } + return intersection.size(); + } + } // namespace - ConsecutiveArtists::ConsecutiveArtists(db::Db& db) - : _db {db} - {} + ConsecutiveArtists::ConsecutiveArtists(db::Db& db) + : _db{ db } + { + } - float - ConsecutiveArtists::computeScore(const std::vector& trackIds, std::size_t trackIndex) - { - assert(!trackIds.empty()); - assert(trackIndex <= trackIds.size() - 1); + float ConsecutiveArtists::computeScore(const std::vector& trackIds, std::size_t trackIndex) + { + assert(!trackIds.empty()); + assert(trackIndex <= trackIds.size() - 1); - const ArtistContainer artists {getArtists(trackIds[trackIndex])}; + const ArtistContainer artists{ getArtists(trackIds[trackIndex]) }; - constexpr std::size_t rangeSize{ 3 }; // check up to rangeSize tracks before/after the target track - static_assert(rangeSize > 0); + constexpr std::size_t rangeSize{ 3 }; // check up to rangeSize tracks before/after the target track + static_assert(rangeSize > 0); - float score {}; - for (std::size_t i {1}; i < rangeSize; ++i) - { - if (trackIndex >= i) - score += countCommonArtists(artists, getArtists(trackIds[trackIndex - i])) / static_cast(i); + float score{}; + for (std::size_t i{ 1 }; i < rangeSize; ++i) + { + if (trackIndex >= i) + score += countCommonArtists(artists, getArtists(trackIds[trackIndex - i])) / static_cast(i); - if (trackIndex + i < trackIds.size()) - score += countCommonArtists(artists, getArtists(trackIds[trackIndex + i])) / static_cast(i); - } + if (trackIndex + i < trackIds.size()) + score += countCommonArtists(artists, getArtists(trackIds[trackIndex + i])) / static_cast(i); + } - return score; - } + return score; + } - ArtistContainer - ConsecutiveArtists::getArtists(db::TrackId trackId) - { - using namespace db; + ArtistContainer ConsecutiveArtists::getArtists(db::TrackId trackId) + { + using namespace db; - ArtistContainer res; + ArtistContainer res; - Session& dbSession {_db.getTLSSession()}; - auto transaction {dbSession.createReadTransaction()}; + Session& dbSession{ _db.getTLSSession() }; + auto transaction{ dbSession.createReadTransaction() }; - const Track::pointer track {Track::find(dbSession, trackId)}; - if (!track) - return res; + const Track::pointer track{ Track::find(dbSession, trackId) }; + if (!track) + return res; - res = track->getArtistIds({}); - std::sort(std::begin(res), std::end(res)); + res = track->getArtistIds({}); + std::sort(std::begin(res), std::end(res)); - return res; - } - - -} // namespace lms::recommendation + return res; + } +} // namespace lms::recommendation::PlaylistGeneratorConstraint diff --git a/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveArtists.hpp b/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveArtists.hpp index 36dc4e26..2ae75144 100644 --- a/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveArtists.hpp +++ b/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveArtists.hpp @@ -25,21 +25,20 @@ namespace lms::db { - class Db; + class Db; } namespace lms::recommendation::PlaylistGeneratorConstraint { - class ConsecutiveArtists : public IConstraint - { - public: - ConsecutiveArtists(db::Db& db); + class ConsecutiveArtists : public IConstraint + { + public: + ConsecutiveArtists(db::Db& db); - private: - float computeScore(const TrackContainer& trackIds, std::size_t trackIndex) override; - ArtistContainer getArtists(db::TrackId trackId); + private: + float computeScore(const TrackContainer& trackIds, std::size_t trackIndex) override; + ArtistContainer getArtists(db::TrackId trackId); - db::Db& _db; - }; + db::Db& _db; + }; } // namespace lms::recommendation::PlaylistGeneratorConstraint - diff --git a/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveReleases.cpp b/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveReleases.cpp index 9bd83231..ab14bbc4 100644 --- a/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveReleases.cpp +++ b/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveReleases.cpp @@ -19,59 +19,57 @@ #include "ConsecutiveReleases.hpp" +#include "core/ILogger.hpp" #include "database/Db.hpp" #include "database/Release.hpp" #include "database/Session.hpp" #include "database/Track.hpp" -#include "core/ILogger.hpp" namespace lms::recommendation::PlaylistGeneratorConstraint { - ConsecutiveReleases::ConsecutiveReleases(db::Db& db) - : _db {db} - {} + ConsecutiveReleases::ConsecutiveReleases(db::Db& db) + : _db{ db } + { + } - float - ConsecutiveReleases::computeScore(const std::vector& trackIds, std::size_t trackIndex) - { - assert(!trackIds.empty()); - assert(trackIndex <= trackIds.size() - 1); + float ConsecutiveReleases::computeScore(const std::vector& trackIds, std::size_t trackIndex) + { + assert(!trackIds.empty()); + assert(trackIndex <= trackIds.size() - 1); - const db::ReleaseId releaseId {getReleaseId(trackIds[trackIndex])}; + const db::ReleaseId releaseId{ getReleaseId(trackIds[trackIndex]) }; - constexpr std::size_t rangeSize{ 3 }; // check up to rangeSize tracks before/after the target track - static_assert(rangeSize > 0); + constexpr std::size_t rangeSize{ 3 }; // check up to rangeSize tracks before/after the target track + static_assert(rangeSize > 0); - float score {}; - for (std::size_t i {1}; i < rangeSize; ++i) - { - if ((trackIndex >= i) && getReleaseId(trackIds[trackIndex - i]) == releaseId) - score += (1.f / static_cast(i)); + float score{}; + for (std::size_t i{ 1 }; i < rangeSize; ++i) + { + if ((trackIndex >= i) && getReleaseId(trackIds[trackIndex - i]) == releaseId) + score += (1.f / static_cast(i)); - if ((trackIndex + i < trackIds.size()) && getReleaseId(trackIds[trackIndex + i]) == releaseId) - score += (1.f / static_cast(i)); - } + if ((trackIndex + i < trackIds.size()) && getReleaseId(trackIds[trackIndex + i]) == releaseId) + score += (1.f / static_cast(i)); + } - return score; - } + return score; + } - db::ReleaseId - ConsecutiveReleases::getReleaseId(db::TrackId trackId) - { - using namespace db; + db::ReleaseId ConsecutiveReleases::getReleaseId(db::TrackId trackId) + { + using namespace db; - Session& dbSession {_db.getTLSSession()}; - auto transaction {dbSession.createReadTransaction()}; + Session& dbSession{ _db.getTLSSession() }; + auto transaction{ dbSession.createReadTransaction() }; - const Track::pointer track {Track::find(dbSession, trackId)}; - if (!track) - return {}; + const Track::pointer track{ Track::find(dbSession, trackId) }; + if (!track) + return {}; - const Release::pointer release {track->getRelease()}; - if (!release) - return {}; - - return release->getId(); - } -} // namespace lms::recommendation + const Release::pointer release{ track->getRelease() }; + if (!release) + return {}; + return release->getId(); + } +} // namespace lms::recommendation::PlaylistGeneratorConstraint diff --git a/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveReleases.hpp b/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveReleases.hpp index 7c9ace33..fc997a72 100644 --- a/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveReleases.hpp +++ b/src/libs/services/recommendation/impl/playlist-constraints/ConsecutiveReleases.hpp @@ -25,22 +25,21 @@ namespace lms::db { - class Db; + class Db; } namespace lms::recommendation::PlaylistGeneratorConstraint { - class ConsecutiveReleases : public IConstraint - { - public: - ConsecutiveReleases(db::Db& db); + class ConsecutiveReleases : public IConstraint + { + public: + ConsecutiveReleases(db::Db& db); - private: - float computeScore(const std::vector& trackIds, std::size_t trackIndex) override; + private: + float computeScore(const std::vector& trackIds, std::size_t trackIndex) override; - db::ReleaseId getReleaseId(db::TrackId trackId); - - db::Db& _db; - }; -} // namespace lms::recommendation + db::ReleaseId getReleaseId(db::TrackId trackId); + db::Db& _db; + }; +} // namespace lms::recommendation::PlaylistGeneratorConstraint diff --git a/src/libs/services/recommendation/impl/playlist-constraints/DuplicateTracks.cpp b/src/libs/services/recommendation/impl/playlist-constraints/DuplicateTracks.cpp index aff6c47f..8c61f970 100644 --- a/src/libs/services/recommendation/impl/playlist-constraints/DuplicateTracks.cpp +++ b/src/libs/services/recommendation/impl/playlist-constraints/DuplicateTracks.cpp @@ -23,11 +23,9 @@ namespace lms::recommendation::PlaylistGeneratorConstraint { - float - DuplicateTracks::computeScore(const std::vector& trackIds, std::size_t trackIndex) - { - const auto count {std::count(std::cbegin(trackIds), std::cend(trackIds), trackIds[trackIndex])}; - return count == 1 ? 0 : 1000; - } -} // namespace lms::recommendation - + float DuplicateTracks::computeScore(const std::vector& trackIds, std::size_t trackIndex) + { + const auto count{ std::count(std::cbegin(trackIds), std::cend(trackIds), trackIds[trackIndex]) }; + return count == 1 ? 0 : 1000; + } +} // namespace lms::recommendation::PlaylistGeneratorConstraint diff --git a/src/libs/services/recommendation/impl/playlist-constraints/DuplicateTracks.hpp b/src/libs/services/recommendation/impl/playlist-constraints/DuplicateTracks.hpp index 5b76c3e5..86bc267a 100644 --- a/src/libs/services/recommendation/impl/playlist-constraints/DuplicateTracks.hpp +++ b/src/libs/services/recommendation/impl/playlist-constraints/DuplicateTracks.hpp @@ -23,10 +23,9 @@ namespace lms::recommendation::PlaylistGeneratorConstraint { - class DuplicateTracks : public IConstraint - { - private: - float computeScore(const std::vector& trackIds, std::size_t trackIndex) override; - }; -} // namespace lms::recommendation::PlaylistGeneratorConstraints - + class DuplicateTracks : public IConstraint + { + private: + float computeScore(const std::vector& trackIds, std::size_t trackIndex) override; + }; +} // namespace lms::recommendation::PlaylistGeneratorConstraint diff --git a/src/libs/services/recommendation/impl/playlist-constraints/IConstraint.hpp b/src/libs/services/recommendation/impl/playlist-constraints/IConstraint.hpp index e73c44f5..cf5119fb 100644 --- a/src/libs/services/recommendation/impl/playlist-constraints/IConstraint.hpp +++ b/src/libs/services/recommendation/impl/playlist-constraints/IConstraint.hpp @@ -25,15 +25,15 @@ namespace lms::recommendation::PlaylistGeneratorConstraint { - class IConstraint - { - public: - virtual ~IConstraint() = default; + class IConstraint + { + public: + virtual ~IConstraint() = default; - // compute the score of the track at index trackIndex - // 0: best - // 1: worst - // > 1 : violation - virtual float computeScore(const TrackContainer& trackIds, std::size_t trackIndex) = 0; - }; -} // namespace lms::recommendation + // compute the score of the track at index trackIndex + // 0: best + // 1: worst + // > 1 : violation + virtual float computeScore(const TrackContainer& trackIds, std::size_t trackIndex) = 0; + }; +} // namespace lms::recommendation::PlaylistGeneratorConstraint diff --git a/src/libs/services/recommendation/include/services/recommendation/IPlaylistGeneratorService.hpp b/src/libs/services/recommendation/include/services/recommendation/IPlaylistGeneratorService.hpp index 54d59ef4..0676f13f 100644 --- a/src/libs/services/recommendation/include/services/recommendation/IPlaylistGeneratorService.hpp +++ b/src/libs/services/recommendation/include/services/recommendation/IPlaylistGeneratorService.hpp @@ -20,27 +20,27 @@ #pragma once #include + #include "database/TrackListId.hpp" #include "database/Types.hpp" #include "services/recommendation/Types.hpp" namespace lms::db { - class Db; + class Db; } namespace lms::recommendation { - class IRecommendationService; - class IPlaylistGeneratorService - { - public: - virtual ~IPlaylistGeneratorService() = default; + class IRecommendationService; + class IPlaylistGeneratorService + { + public: + virtual ~IPlaylistGeneratorService() = default; - // extend an existing playlist with similar tracks (but use playlist contraints) - virtual TrackContainer extendPlaylist(db::TrackListId tracklistId, std::size_t maxCount) const = 0; - }; - - std::unique_ptr createPlaylistGeneratorService(db::Db& db, IRecommendationService& recommandationService); -} // ns Recommendation + // extend an existing playlist with similar tracks (but use playlist contraints) + virtual TrackContainer extendPlaylist(db::TrackListId tracklistId, std::size_t maxCount) const = 0; + }; + std::unique_ptr createPlaylistGeneratorService(db::Db& db, IRecommendationService& recommandationService); +} // namespace lms::recommendation diff --git a/src/libs/services/recommendation/include/services/recommendation/IRecommendationService.hpp b/src/libs/services/recommendation/include/services/recommendation/IRecommendationService.hpp index 31bb8dea..89ef69fc 100644 --- a/src/libs/services/recommendation/include/services/recommendation/IRecommendationService.hpp +++ b/src/libs/services/recommendation/include/services/recommendation/IRecommendationService.hpp @@ -21,6 +21,7 @@ #include #include + #include "core/EnumSet.hpp" #include "database/TrackListId.hpp" #include "database/Types.hpp" @@ -28,24 +29,23 @@ namespace lms::db { - class Db; + class Db; } namespace lms::recommendation { - class IRecommendationService - { - public: - virtual ~IRecommendationService() = default; + class IRecommendationService + { + public: + virtual ~IRecommendationService() = default; - virtual void load() = 0; + virtual void load() = 0; - virtual TrackContainer findSimilarTracks(db::TrackListId tracklistId, std::size_t maxCount) const = 0; - virtual TrackContainer findSimilarTracks(const std::vector& tracksId, std::size_t maxCount) const = 0; - virtual ReleaseContainer getSimilarReleases(db::ReleaseId releaseId, std::size_t maxCount) const = 0; - virtual ArtistContainer getSimilarArtists(db::ArtistId artistId, core::EnumSet linkTypes, std::size_t maxCount) const = 0; - }; - - std::unique_ptr createRecommendationService(db::Db& db); -} // ns Recommendation + virtual TrackContainer findSimilarTracks(db::TrackListId tracklistId, std::size_t maxCount) const = 0; + virtual TrackContainer findSimilarTracks(const std::vector& tracksId, std::size_t maxCount) const = 0; + virtual ReleaseContainer getSimilarReleases(db::ReleaseId releaseId, std::size_t maxCount) const = 0; + virtual ArtistContainer getSimilarArtists(db::ArtistId artistId, core::EnumSet linkTypes, std::size_t maxCount) const = 0; + }; + std::unique_ptr createRecommendationService(db::Db& db); +} // namespace lms::recommendation diff --git a/src/libs/services/recommendation/include/services/recommendation/Types.hpp b/src/libs/services/recommendation/include/services/recommendation/Types.hpp index 84fe3775..53a7c9b8 100644 --- a/src/libs/services/recommendation/include/services/recommendation/Types.hpp +++ b/src/libs/services/recommendation/include/services/recommendation/Types.hpp @@ -1,24 +1,25 @@ #pragma once #include + #include "database/ArtistId.hpp" #include "database/ReleaseId.hpp" #include "database/TrackId.hpp" namespace lms::recommendation { - struct Progress - { - std::size_t totalElems {}; - std::size_t processedElems {}; - }; - using ProgressCallback = std::function; + struct Progress + { + std::size_t totalElems{}; + std::size_t processedElems{}; + }; + using ProgressCallback = std::function; - template - using ResultContainer = std::vector; + template + using ResultContainer = std::vector; - using ArtistContainer = ResultContainer; - using ReleaseContainer = ResultContainer; - using TrackContainer = ResultContainer; + using ArtistContainer = ResultContainer; + using ReleaseContainer = ResultContainer; + using TrackContainer = ResultContainer; } // namespace lms::recommendation diff --git a/src/libs/services/scanner/impl/IScanStep.hpp b/src/libs/services/scanner/impl/IScanStep.hpp index 0d00af85..ee30062d 100644 --- a/src/libs/services/scanner/impl/IScanStep.hpp +++ b/src/libs/services/scanner/impl/IScanStep.hpp @@ -43,4 +43,4 @@ namespace lms::scanner }; virtual void process(ScanContext& context) = 0; }; -} +} // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/ScanStepBase.hpp b/src/libs/services/scanner/impl/ScanStepBase.hpp index 21bd8dd5..a530dc1d 100644 --- a/src/libs/services/scanner/impl/ScanStepBase.hpp +++ b/src/libs/services/scanner/impl/ScanStepBase.hpp @@ -22,40 +22,42 @@ #include #include "services/scanner/ScannerStats.hpp" + #include "IScanStep.hpp" #include "ScannerSettings.hpp" namespace lms::db { - class Db; + class Db; } namespace lms::scanner { - class ScanStepBase : public IScanStep - { - public: - static inline const std::filesystem::path excludeDirFileName {".lmsignore"}; - using ProgressCallback = std::function; + class ScanStepBase : public IScanStep + { + public: + static inline const std::filesystem::path excludeDirFileName{ ".lmsignore" }; + using ProgressCallback = std::function; - struct InitParams - { - const ScannerSettings& settings; - ProgressCallback progressCallback; - bool& abortScan; - db::Db& db; - }; - ScanStepBase(InitParams& initParams) - : _settings {initParams.settings} - , _progressCallback {initParams.progressCallback} - , _abortScan {initParams.abortScan} - , _db {initParams.db} - {} + struct InitParams + { + const ScannerSettings& settings; + ProgressCallback progressCallback; + bool& abortScan; + db::Db& db; + }; + ScanStepBase(InitParams& initParams) + : _settings{ initParams.settings } + , _progressCallback{ initParams.progressCallback } + , _abortScan{ initParams.abortScan } + , _db{ initParams.db } + { + } - protected: - const ScannerSettings& _settings; - ProgressCallback _progressCallback; - bool& _abortScan; - db::Db& _db; - }; -} + protected: + const ScannerSettings& _settings; + ProgressCallback _progressCallback; + bool& _abortScan; + db::Db& _db; + }; +} // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/ScanStepCheckDuplicatedDbFiles.cpp b/src/libs/services/scanner/impl/ScanStepCheckDuplicatedDbFiles.cpp index 10f30e14..224342d7 100644 --- a/src/libs/services/scanner/impl/ScanStepCheckDuplicatedDbFiles.cpp +++ b/src/libs/services/scanner/impl/ScanStepCheckDuplicatedDbFiles.cpp @@ -19,10 +19,10 @@ #include "ScanStepCheckDuplicatedDbFiles.hpp" +#include "core/ILogger.hpp" #include "database/Db.hpp" #include "database/Session.hpp" #include "database/Track.hpp" -#include "core/ILogger.hpp" namespace lms::scanner { @@ -33,8 +33,8 @@ namespace lms::scanner if (_abortScan) return; - Session& session {_db.getTLSSession()}; - auto transaction {session.createReadTransaction()}; + Session& session{ _db.getTLSSession() }; + auto transaction{ session.createReadTransaction() }; const RangeResults tracks = Track::findIdsTrackMBIDDuplicates(session); for (const TrackId trackId : tracks.results) @@ -54,4 +54,4 @@ namespace lms::scanner LMS_LOG(DBUPDATER, DEBUG, "Found " << context.currentStepStats.processedElems << " duplicated audio files"); } -} +} // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/ScanStepCheckDuplicatedDbFiles.hpp b/src/libs/services/scanner/impl/ScanStepCheckDuplicatedDbFiles.hpp index d6762599..e0910796 100644 --- a/src/libs/services/scanner/impl/ScanStepCheckDuplicatedDbFiles.hpp +++ b/src/libs/services/scanner/impl/ScanStepCheckDuplicatedDbFiles.hpp @@ -23,14 +23,14 @@ namespace lms::scanner { - class ScanStepCheckDuplicatedDbFiles : public ScanStepBase - { - public: - using ScanStepBase::ScanStepBase; + class ScanStepCheckDuplicatedDbFiles : public ScanStepBase + { + public: + using ScanStepBase::ScanStepBase; - private: - core::LiteralString getStepName() const override { return "Check for duplicated files"; } - ScanStep getStep() const override { return ScanStep::CheckForDuplicateFiles; } - void process(ScanContext& context) override; - }; -} + private: + core::LiteralString getStepName() const override { return "Check for duplicated files"; } + ScanStep getStep() const override { return ScanStep::CheckForDuplicateFiles; } + void process(ScanContext& context) override; + }; +} // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/ScanStepCompact.cpp b/src/libs/services/scanner/impl/ScanStepCompact.cpp index b6078055..9a4f469f 100644 --- a/src/libs/services/scanner/impl/ScanStepCompact.cpp +++ b/src/libs/services/scanner/impl/ScanStepCompact.cpp @@ -30,4 +30,4 @@ namespace lms::scanner if (context.scanOptions.compact) _db.getTLSSession().vacuum(); } -} +} // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/ScanStepCompact.hpp b/src/libs/services/scanner/impl/ScanStepCompact.hpp index f56b4f24..d1c4e195 100644 --- a/src/libs/services/scanner/impl/ScanStepCompact.hpp +++ b/src/libs/services/scanner/impl/ScanStepCompact.hpp @@ -23,14 +23,14 @@ namespace lms::scanner { - class ScanStepCompact : public ScanStepBase - { - public: - using ScanStepBase::ScanStepBase; + class ScanStepCompact : public ScanStepBase + { + public: + using ScanStepBase::ScanStepBase; - private: - ScanStep getStep() const override { return ScanStep::Compact; } - core::LiteralString getStepName() const override { return "Compact"; } - void process(ScanContext& context) override; - }; -} + private: + ScanStep getStep() const override { return ScanStep::Compact; } + core::LiteralString getStepName() const override { return "Compact"; } + void process(ScanContext& context) override; + }; +} // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/ScanStepComputeClusterStats.cpp b/src/libs/services/scanner/impl/ScanStepComputeClusterStats.cpp index 331973fc..bc2f99b1 100644 --- a/src/libs/services/scanner/impl/ScanStepComputeClusterStats.cpp +++ b/src/libs/services/scanner/impl/ScanStepComputeClusterStats.cpp @@ -18,11 +18,11 @@ */ #include "ScanStepComputeClusterStats.hpp" -#include "database/Db.hpp" -#include "database/Cluster.hpp" -#include "database/Session.hpp" #include "core/ILogger.hpp" #include "core/Path.hpp" +#include "database/Cluster.hpp" +#include "database/Db.hpp" +#include "database/Session.hpp" namespace lms::scanner { @@ -38,53 +38,51 @@ namespace lms::scanner const std::size_t clusterCount{ [&] { auto transaction{ dbSession.createReadTransaction() }; return Cluster::getCount(dbSession); - }() }; + }() }; context.currentStepStats.totalElems = clusterCount; - foreachSubRange(Range{ 0, clusterCount }, 100, [&](Range range) + foreachSubRange(Range{ 0, clusterCount }, 100, [&](Range range) { + const std::vector clusterIds{ [&] { + Cluster::FindParameters params; + params.setRange(range); + + { + auto transaction{ dbSession.createReadTransaction() }; + return std::move(Cluster::findIds(dbSession, params).results); + } + }() }; + + for (const ClusterId clusterId : clusterIds) { - const std::vector clusterIds{ [&] + if (_abortScan) + break; + + std::size_t trackCount; + std::size_t releaseCount; + { - Cluster::FindParameters params; - params.setRange(range); + auto transaction{ dbSession.createReadTransaction() }; - { - auto transaction{ dbSession.createReadTransaction() }; - return std::move(Cluster::findIds(dbSession, params).results); - } - }() }; - - for (const ClusterId clusterId : clusterIds) - { - if (_abortScan) - break; - - std::size_t trackCount; - std::size_t releaseCount; - - { - auto transaction{ dbSession.createReadTransaction() }; - - trackCount = Cluster::computeTrackCount(dbSession, clusterId); - releaseCount = Cluster::computeReleaseCount(dbSession, clusterId); - } - - { - auto transaction{ dbSession.createWriteTransaction() }; - - auto cluster{ Cluster::find(dbSession, clusterId) }; - cluster.modify()->setTrackCount(trackCount); - cluster.modify()->setReleaseCount(releaseCount); - } - - context.currentStepStats.processedElems++; - _progressCallback(context.currentStepStats); + trackCount = Cluster::computeTrackCount(dbSession, clusterId); + releaseCount = Cluster::computeReleaseCount(dbSession, clusterId); } - return true; - }); + { + auto transaction{ dbSession.createWriteTransaction() }; + + auto cluster{ Cluster::find(dbSession, clusterId) }; + cluster.modify()->setTrackCount(trackCount); + cluster.modify()->setReleaseCount(releaseCount); + } + + context.currentStepStats.processedElems++; + _progressCallback(context.currentStepStats); + } + + return true; + }); LMS_LOG(DBUPDATER, DEBUG, "Recomputed stats for " << context.currentStepStats.processedElems << " clusters!"); } -} +} // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/ScanStepComputeClusterStats.hpp b/src/libs/services/scanner/impl/ScanStepComputeClusterStats.hpp index 43aeaf36..1139c7fc 100644 --- a/src/libs/services/scanner/impl/ScanStepComputeClusterStats.hpp +++ b/src/libs/services/scanner/impl/ScanStepComputeClusterStats.hpp @@ -33,4 +33,4 @@ namespace lms::scanner core::LiteralString getStepName() const override { return "Compute cluster stats"; } void process(ScanContext& context) override; }; -} +} // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/ScanStepDiscoverFiles.cpp b/src/libs/services/scanner/impl/ScanStepDiscoverFiles.cpp index d582bf18..43d0ebb9 100644 --- a/src/libs/services/scanner/impl/ScanStepDiscoverFiles.cpp +++ b/src/libs/services/scanner/impl/ScanStepDiscoverFiles.cpp @@ -31,8 +31,8 @@ namespace lms::scanner for (const ScannerSettings::MediaLibraryInfo& mediaLibrary : _settings.mediaLibraries) { std::size_t currentDirectoryProcessElemsCount{}; - core::pathUtils::exploreFilesRecursive(mediaLibrary.rootDirectory, [&](std::error_code ec, const std::filesystem::path& path) - { + core::pathUtils::exploreFilesRecursive( + mediaLibrary.rootDirectory, [&](std::error_code ec, const std::filesystem::path& path) { if (_abortScan) return false; @@ -44,7 +44,8 @@ namespace lms::scanner } return true; - }, &excludeDirFileName); + }, + &excludeDirFileName); LMS_LOG(DBUPDATER, DEBUG, "Discovered " << currentDirectoryProcessElemsCount << " files in '" << mediaLibrary.rootDirectory << "'"); } @@ -53,4 +54,4 @@ namespace lms::scanner LMS_LOG(DBUPDATER, DEBUG, "Discovered " << context.stats.filesScanned << " files in all directories"); } -} +} // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/ScanStepDiscoverFiles.hpp b/src/libs/services/scanner/impl/ScanStepDiscoverFiles.hpp index 3a350e4f..29d6d3af 100644 --- a/src/libs/services/scanner/impl/ScanStepDiscoverFiles.hpp +++ b/src/libs/services/scanner/impl/ScanStepDiscoverFiles.hpp @@ -23,14 +23,14 @@ namespace lms::scanner { - class ScanStepDiscoverFiles : public ScanStepBase - { - public: - using ScanStepBase::ScanStepBase; + class ScanStepDiscoverFiles : public ScanStepBase + { + public: + using ScanStepBase::ScanStepBase; - private: - ScanStep getStep() const override { return ScanStep::DiscoverFiles; } - core::LiteralString getStepName() const override { return "Discover files"; } - void process(ScanContext& context) override; - }; -} + private: + ScanStep getStep() const override { return ScanStep::DiscoverFiles; } + core::LiteralString getStepName() const override { return "Discover files"; } + void process(ScanContext& context) override; + }; +} // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/ScanStepOptimize.cpp b/src/libs/services/scanner/impl/ScanStepOptimize.cpp index 0bcfc7df..7ab5f69b 100644 --- a/src/libs/services/scanner/impl/ScanStepOptimize.cpp +++ b/src/libs/services/scanner/impl/ScanStepOptimize.cpp @@ -53,4 +53,4 @@ namespace lms::scanner LMS_LOG(DBUPDATER, INFO, "Database analyze complete"); } } -} +} // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/ScanStepOptimize.hpp b/src/libs/services/scanner/impl/ScanStepOptimize.hpp index a0fac852..117cda3a 100644 --- a/src/libs/services/scanner/impl/ScanStepOptimize.hpp +++ b/src/libs/services/scanner/impl/ScanStepOptimize.hpp @@ -23,14 +23,14 @@ namespace lms::scanner { - class ScanStepOptimize : public ScanStepBase - { - public: - using ScanStepBase::ScanStepBase; + class ScanStepOptimize : public ScanStepBase + { + public: + using ScanStepBase::ScanStepBase; - private: - ScanStep getStep() const override { return ScanStep::Optimize; } - core::LiteralString getStepName() const override { return "Optimize"; } - void process(ScanContext& context) override; - }; -} + private: + ScanStep getStep() const override { return ScanStep::Optimize; } + core::LiteralString getStepName() const override { return "Optimize"; } + void process(ScanContext& context) override; + }; +} // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/ScanStepRemoveOrphanDbFiles.cpp b/src/libs/services/scanner/impl/ScanStepRemoveOrphanDbFiles.cpp index 64009ebe..b86f35ac 100644 --- a/src/libs/services/scanner/impl/ScanStepRemoveOrphanDbFiles.cpp +++ b/src/libs/services/scanner/impl/ScanStepRemoveOrphanDbFiles.cpp @@ -19,14 +19,14 @@ #include "ScanStepRemoveOrphanDbFiles.hpp" +#include "core/ILogger.hpp" +#include "core/Path.hpp" #include "database/Artist.hpp" #include "database/Cluster.hpp" #include "database/Db.hpp" #include "database/Release.hpp" #include "database/Session.hpp" #include "database/Track.hpp" -#include "core/ILogger.hpp" -#include "core/Path.hpp" namespace lms::scanner { @@ -36,7 +36,7 @@ namespace lms::scanner { constexpr std::size_t batchSize = 100; - template + template void removeOrphanEntries(Session& session, bool& abortScan) { using IdType = typename T::IdType; @@ -68,7 +68,7 @@ namespace lms::scanner break; } } - } + } // namespace void ScanStepRemoveOrphanDbFiles::process(ScanContext& context) { @@ -110,15 +110,14 @@ namespace lms::scanner auto transaction{ session.createReadTransaction() }; endReached = true; - Track::find(session, lastCheckedTrackID, batchSize, [&](const Track::pointer& track) - { - endReached = false; + Track::find(session, lastCheckedTrackID, batchSize, [&](const Track::pointer& track) { + endReached = false; - if (!checkFile(track->getAbsoluteFilePath())) - tracksToRemove.push_back(track); + if (!checkFile(track->getAbsoluteFilePath())) + tracksToRemove.push_back(track); - context.currentStepStats.processedElems++; - }); + context.currentStepStats.processedElems++; + }); } if (!tracksToRemove.empty()) @@ -175,10 +174,9 @@ namespace lms::scanner } if (std::none_of(std::cbegin(_settings.mediaLibraries), std::cend(_settings.mediaLibraries), - [&](const ScannerSettings::MediaLibraryInfo& libraryInfo) - { - return core::pathUtils::isPathInRootPath(p, libraryInfo.rootDirectory, &excludeDirFileName); - })) + [&](const ScannerSettings::MediaLibraryInfo& libraryInfo) { + return core::pathUtils::isPathInRootPath(p, libraryInfo.rootDirectory, &excludeDirFileName); + })) { LMS_LOG(DBUPDATER, INFO, "Removing '" << p.string() << "': out of media directory"); return false; @@ -198,4 +196,4 @@ namespace lms::scanner return false; } } -} +} // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/ScanStepRemoveOrphanDbFiles.hpp b/src/libs/services/scanner/impl/ScanStepRemoveOrphanDbFiles.hpp index fbc6391b..8b3750d4 100644 --- a/src/libs/services/scanner/impl/ScanStepRemoveOrphanDbFiles.hpp +++ b/src/libs/services/scanner/impl/ScanStepRemoveOrphanDbFiles.hpp @@ -25,21 +25,21 @@ namespace lms::scanner { - class ScanStepRemoveOrphanDbFiles : public ScanStepBase - { - public: - using ScanStepBase::ScanStepBase; + class ScanStepRemoveOrphanDbFiles : public ScanStepBase + { + public: + using ScanStepBase::ScanStepBase; - private: - core::LiteralString getStepName() const override { return "Check orphaned entries"; } - ScanStep getStep() const override { return ScanStep::CheckForMissingFiles; } - void process(ScanContext& context) override; + private: + core::LiteralString getStepName() const override { return "Check orphaned entries"; } + ScanStep getStep() const override { return ScanStep::CheckForMissingFiles; } + void process(ScanContext& context) override; - void removeOrphanTracks(ScanContext& context); - void removeOrphanClusters(); - void removeOrphanClusterTypes(); - void removeOrphanArtists(); - void removeOrphanReleases(); - bool checkFile(const std::filesystem::path& p); - }; -} + void removeOrphanTracks(ScanContext& context); + void removeOrphanClusters(); + void removeOrphanClusterTypes(); + void removeOrphanArtists(); + void removeOrphanReleases(); + bool checkFile(const std::filesystem::path& p); + }; +} // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/ScanStepScanFiles.cpp b/src/libs/services/scanner/impl/ScanStepScanFiles.cpp index a1b25f6b..e296b38b 100644 --- a/src/libs/services/scanner/impl/ScanStepScanFiles.cpp +++ b/src/libs/services/scanner/impl/ScanStepScanFiles.cpp @@ -19,6 +19,11 @@ #include "ScanStepScanFiles.hpp" +#include "core/Exception.hpp" +#include "core/IConfig.hpp" +#include "core/ILogger.hpp" +#include "core/ITraceLogger.hpp" +#include "core/Path.hpp" #include "database/Artist.hpp" #include "database/Cluster.hpp" #include "database/Db.hpp" @@ -26,15 +31,10 @@ #include "database/Release.hpp" #include "database/Session.hpp" #include "database/Track.hpp" -#include "database/TrackFeatures.hpp" #include "database/TrackArtistLink.hpp" +#include "database/TrackFeatures.hpp" #include "metadata/Exception.hpp" #include "metadata/IParser.hpp" -#include "core/Exception.hpp" -#include "core/IConfig.hpp" -#include "core/ILogger.hpp" -#include "core/Path.hpp" -#include "core/ITraceLogger.hpp" namespace lms::scanner { @@ -249,8 +249,7 @@ namespace lms::scanner { std::vector clusters; - auto getOrCreateClusters{ [&](std::string tag, std::span values) - { + auto getOrCreateClusters{ [&](std::string tag, std::span values) { auto clusterType = ClusterType::find(session, tag); if (!clusterType) clusterType = session.create(tag); @@ -306,7 +305,8 @@ namespace lms::scanner : _metadataParser{ parser } , _scanContextRunner{ _scanContext, threadCount, "ScannerMetadata" } , _abort{ abort } - {} + { + } void ScanStepScanFiles::MetadataScanQueue::pushScanRequest(const std::filesystem::path& path) { @@ -315,38 +315,37 @@ namespace lms::scanner _ongoingScanCount += 1; } - _scanContext.post([=, this] + _scanContext.post([=, this] { + LMS_SCOPED_TRACE_OVERVIEW("Scanner", "AudioFileParseJob"); + + std::unique_ptr track; + + if (_abort) { - LMS_SCOPED_TRACE_OVERVIEW("Scanner", "AudioFileParseJob"); + std::scoped_lock lock{ _mutex }; + _ongoingScanCount -= 1; + } + else + { + try + { + track = _metadataParser.parse(path); + } + catch (const metadata::Exception& e) + { + LMS_LOG(DBUPDATER, INFO, "Failed to parse '" << path.string() << "'"); + } - std::unique_ptr track; - - if (_abort) { std::scoped_lock lock{ _mutex }; + + _scanResults.emplace_back(MetaDataScanResult{ std::move(path), std::move(track) }); _ongoingScanCount -= 1; } - else - { - try - { - track = _metadataParser.parse(path); - } - catch (const metadata::Exception& e) - { - LMS_LOG(DBUPDATER, INFO, "Failed to parse '" << path.string() << "'"); - } + } - { - std::scoped_lock lock{ _mutex }; - - _scanResults.emplace_back(MetaDataScanResult{ std::move(path), std::move(track) }); - _ongoingScanCount -= 1; - } - } - - _condVar.notify_all(); - }); + _condVar.notify_all(); + }); } std::size_t ScanStepScanFiles::MetadataScanQueue::getResultsCount() const @@ -407,8 +406,8 @@ namespace lms::scanner for (const ScannerSettings::MediaLibraryInfo& mediaLibrary : _settings.mediaLibraries) { - core::pathUtils::exploreFilesRecursive(mediaLibrary.rootDirectory, [&](std::error_code ec, const std::filesystem::path& path) - { + core::pathUtils::exploreFilesRecursive( + mediaLibrary.rootDirectory, [&](std::error_code ec, const std::filesystem::path& path) { LMS_SCOPED_TRACE_DETAILED("Scanner", "OnExploreFile"); if (_abortScan) @@ -437,7 +436,8 @@ namespace lms::scanner _metadataScanQueue.wait(scanQueueMaxScanRequestCount); return true; - }, &excludeDirFileName); + }, + &excludeDirFileName); _metadataScanQueue.wait(); @@ -469,8 +469,7 @@ namespace lms::scanner if (track && track->getLastWriteTime().toTime_t() == lastWriteTime.toTime_t() - && track->getScanVersion() == _settings.scanVersion - ) + && track->getScanVersion() == _settings.scanVersion) { // this file may have been moved from one library to another, then we just need to update the media library id instead of a full rescan const auto trackMediaLibrary{ track->getMediaLibrary() }; @@ -568,10 +567,9 @@ namespace lms::scanner // Skip if duplicate files no longer in media root: as it will be removed later, we will end up with no file if (std::none_of(std::cbegin(_settings.mediaLibraries), std::cend(_settings.mediaLibraries), - [&](const ScannerSettings::MediaLibraryInfo& libraryInfo) - { - return core::pathUtils::isPathInRootPath(file, libraryInfo.rootDirectory, &excludeDirFileName); - })) + [&](const ScannerSettings::MediaLibraryInfo& libraryInfo) { + return core::pathUtils::isPathInRootPath(file, libraryInfo.rootDirectory, &excludeDirFileName); + })) { continue; } @@ -723,4 +721,4 @@ namespace lms::scanner stats.updates++; } } -} +} // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/ScanStepScanFiles.hpp b/src/libs/services/scanner/impl/ScanStepScanFiles.hpp index d176857e..7af546da 100644 --- a/src/libs/services/scanner/impl/ScanStepScanFiles.hpp +++ b/src/libs/services/scanner/impl/ScanStepScanFiles.hpp @@ -27,8 +27,9 @@ #include #include -#include "metadata/IParser.hpp" #include "core/IOContextRunner.hpp" +#include "metadata/IParser.hpp" + #include "ScanStepBase.hpp" namespace lms::scanner @@ -52,36 +53,36 @@ namespace lms::scanner void processMetaDataScanResults(ScanContext& context, std::span scanResults, const ScannerSettings::MediaLibraryInfo& libraryInfo); void processFileMetaData(ScanContext& context, const std::filesystem::path& file, const metadata::Track& trackMetadata, const ScannerSettings::MediaLibraryInfo& libraryInfo); - std::unique_ptr _metadataParser; - const std::vector _extraTagsToParse; + std::unique_ptr _metadataParser; + const std::vector _extraTagsToParse; class MetadataScanQueue { - public: - MetadataScanQueue(metadata::IParser& parser, std::size_t threadCount, bool& abort); + public: + MetadataScanQueue(metadata::IParser& parser, std::size_t threadCount, bool& abort); - std::size_t getThreadCount() const { return _scanContextRunner.getThreadCount(); } + std::size_t getThreadCount() const { return _scanContextRunner.getThreadCount(); } - void pushScanRequest(const std::filesystem::path& path); + void pushScanRequest(const std::filesystem::path& path); - std::size_t getResultsCount() const; - size_t popResults(std::vector& results, std::size_t maxCount); + std::size_t getResultsCount() const; + size_t popResults(std::vector& results, std::size_t maxCount); - void wait(std::size_t maxScanRequestCount = 0); // wait until ongoing scan request count <= maxScanRequestCount + void wait(std::size_t maxScanRequestCount = 0); // wait until ongoing scan request count <= maxScanRequestCount - private: - metadata::IParser& _metadataParser; - boost::asio::io_context _scanContext; - core::IOContextRunner _scanContextRunner; + private: + metadata::IParser& _metadataParser; + boost::asio::io_context _scanContext; + core::IOContextRunner _scanContextRunner; - mutable std::mutex _mutex ; - std::size_t _ongoingScanCount{}; - std::deque _scanResults; - std::condition_variable _condVar; - bool& _abort; + mutable std::mutex _mutex; + std::size_t _ongoingScanCount{}; + std::deque _scanResults; + std::condition_variable _condVar; + bool& _abort; }; MetadataScanQueue _metadataScanQueue; std::deque _metaDataScanResults; }; -} +} // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/ScannerService.cpp b/src/libs/services/scanner/impl/ScannerService.cpp index f29a9b52..852d28d2 100644 --- a/src/libs/services/scanner/impl/ScannerService.cpp +++ b/src/libs/services/scanner/impl/ScannerService.cpp @@ -21,14 +21,14 @@ #include -#include "database/MediaLibrary.hpp" -#include "database/TrackFeatures.hpp" -#include "database/ScanSettings.hpp" #include "core/Exception.hpp" -#include "core/Path.hpp" #include "core/IConfig.hpp" #include "core/ILogger.hpp" #include "core/ITraceLogger.hpp" +#include "core/Path.hpp" +#include "database/MediaLibrary.hpp" +#include "database/ScanSettings.hpp" +#include "database/TrackFeatures.hpp" #include "ScanStepCheckDuplicatedDbFiles.hpp" #include "ScanStepCompact.hpp" @@ -91,13 +91,12 @@ namespace lms::scanner { std::scoped_lock lock{ _controlMutex }; - _ioService.post([this] - { - if (_abortScan) - return; + _ioService.post([this] { + if (_abortScan) + return; - scheduleNextScan(); - }); + scheduleNextScan(); + }); _ioService.start(); } @@ -139,25 +138,23 @@ namespace lms::scanner void ScannerService::requestImmediateScan(const ScanOptions& scanOptions) { abortScan(); - _ioService.post([this, scanOptions] - { - if (_abortScan) - return; + _ioService.post([this, scanOptions] { + if (_abortScan) + return; - scheduleScan(scanOptions); - }); + scheduleScan(scanOptions); + }); } void ScannerService::requestReload() { abortScan(); - _ioService.post([this]() - { - if (_abortScan) - return; + _ioService.post([this]() { + if (_abortScan) + return; - scheduleNextScan(); - }); + scheduleNextScan(); + }); } ScannerService::Status ScannerService::getStatus() const @@ -229,8 +226,7 @@ namespace lms::scanner void ScannerService::scheduleScan(const ScanOptions& scanOptions, const Wt::WDateTime& dateTime) { - auto cb{ [this, scanOptions](boost::system::error_code ec) - { + auto cb{ [this, scanOptions](boost::system::error_code ec) { if (ec) return; @@ -270,7 +266,7 @@ namespace lms::scanner refreshScanSettings(); - IScanStep::ScanContext scanContext{ scanOptions, ScanStats {}, ScanStepStats {} }; + IScanStep::ScanContext scanContext{ scanOptions, ScanStats{}, ScanStepStats{} }; ScanStats& stats{ scanContext.stats }; stats.startTime = Wt::WDateTime::currentDateTime(); @@ -329,13 +325,11 @@ namespace lms::scanner _settings = std::move(newSettings); - auto cbFunc{ [this](const ScanStepStats& stats) - { - notifyInProgressIfNeeded(stats); - } }; + auto cbFunc{ [this](const ScanStepStats& stats) { + notifyInProgressIfNeeded(stats); + } }; - ScanStepBase::InitParams params - { + ScanStepBase::InitParams params{ _settings, cbFunc, _abortScan, @@ -373,14 +367,13 @@ namespace lms::scanner [](const std::filesystem::path& extension) { return std::filesystem::path{ core::stringUtils::stringToLower(extension.string()) }; }); } - MediaLibrary::find(_db.getTLSSession(), [&](const MediaLibrary::pointer& mediaLibrary) - { - newSettings.mediaLibraries.push_back(ScannerSettings::MediaLibraryInfo{ mediaLibrary->getId(), mediaLibrary->getPath().lexically_normal() }); - }); + MediaLibrary::find(_db.getTLSSession(), [&](const MediaLibrary::pointer& mediaLibrary) { + newSettings.mediaLibraries.push_back(ScannerSettings::MediaLibraryInfo{ mediaLibrary->getId(), mediaLibrary->getPath().lexically_normal() }); + }); { const auto& tags{ scanSettings->getExtraTagsToScan() }; - std::transform(std::cbegin(tags), std::cend(tags), std::back_inserter(newSettings.extraTags), [](std::string_view tag) { return std::string{ tag };}); + std::transform(std::cbegin(tags), std::cend(tags), std::back_inserter(newSettings.extraTags), [](std::string_view tag) { return std::string{ tag }; }); } newSettings.artistTagDelimiters = scanSettings->getArtistTagDelimiters(); diff --git a/src/libs/services/scanner/impl/ScannerService.hpp b/src/libs/services/scanner/impl/ScannerService.hpp index 5750c915..2a1bbd82 100644 --- a/src/libs/services/scanner/impl/ScannerService.hpp +++ b/src/libs/services/scanner/impl/ScannerService.hpp @@ -20,23 +20,22 @@ #pragma once #include -#include #include +#include #include #include #include #include - #include +#include "IScanStep.hpp" +#include "ScannerSettings.hpp" +#include "core/Path.hpp" #include "database/Db.hpp" #include "database/Session.hpp" #include "database/Types.hpp" #include "services/scanner/IScannerService.hpp" -#include "core/Path.hpp" -#include "IScanStep.hpp" -#include "ScannerSettings.hpp" namespace lms::scanner { @@ -53,7 +52,7 @@ namespace lms::scanner void requestReload() override; void requestImmediateScan(const ScanOptions& scanOptions) override; - Status getStatus() const override; + Status getStatus() const override; Events& getEvents() override { return _events; } private: @@ -78,23 +77,22 @@ namespace lms::scanner void notifyInProgressIfNeeded(const ScanStepStats& stats); void notifyInProgress(const ScanStepStats& stats); - std::vector> _scanSteps; + std::vector> _scanSteps; - std::mutex _controlMutex; - bool _abortScan{}; - Wt::WIOService _ioService; - boost::asio::system_timer _scheduleTimer{ _ioService }; - Events _events; - std::chrono::system_clock::time_point _lastScanInProgressEmit{}; + std::mutex _controlMutex; + bool _abortScan{}; + Wt::WIOService _ioService; + boost::asio::system_timer _scheduleTimer{ _ioService }; + Events _events; + std::chrono::system_clock::time_point _lastScanInProgressEmit{}; db::Db& _db; - mutable std::shared_mutex _statusMutex; - State _curState{ State::NotScheduled }; - std::optional _lastCompleteScanStats; - std::optional _currentScanStepStats; - Wt::WDateTime _nextScheduledScan; + mutable std::shared_mutex _statusMutex; + State _curState{ State::NotScheduled }; + std::optional _lastCompleteScanStats; + std::optional _currentScanStepStats; + Wt::WDateTime _nextScheduledScan; - ScannerSettings _settings; + ScannerSettings _settings; }; -} // Scanner - +} // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/ScannerSettings.hpp b/src/libs/services/scanner/impl/ScannerSettings.hpp index eca0f08e..48ba2971 100644 --- a/src/libs/services/scanner/impl/ScannerSettings.hpp +++ b/src/libs/services/scanner/impl/ScannerSettings.hpp @@ -22,7 +22,9 @@ #include #include #include + #include + #include "database/MediaLibraryId.hpp" #include "database/ScanSettings.hpp" @@ -30,14 +32,14 @@ namespace lms::scanner { struct ScannerSettings { - std::size_t scanVersion{}; - Wt::WTime startTime; - db::ScanSettings::UpdatePeriod updatePeriod{ db::ScanSettings::UpdatePeriod::Never }; - std::vector supportedExtensions; - bool skipDuplicateMBID{}; - std::vector extraTags; - std::vector artistTagDelimiters; - std::vector defaultTagDelimiters; + std::size_t scanVersion{}; + Wt::WTime startTime; + db::ScanSettings::UpdatePeriod updatePeriod{ db::ScanSettings::UpdatePeriod::Never }; + std::vector supportedExtensions; + bool skipDuplicateMBID{}; + std::vector extraTags; + std::vector artistTagDelimiters; + std::vector defaultTagDelimiters; struct MediaLibraryInfo { @@ -46,8 +48,8 @@ namespace lms::scanner auto operator<=>(const MediaLibraryInfo& other) const = default; }; - std::vector mediaLibraries; + std::vector mediaLibraries; bool operator==(const ScannerSettings& rhs) const = default; }; -} +} // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/ScannerStats.cpp b/src/libs/services/scanner/impl/ScannerStats.cpp index b2df60d6..be05106b 100644 --- a/src/libs/services/scanner/impl/ScannerStats.cpp +++ b/src/libs/services/scanner/impl/ScannerStats.cpp @@ -22,9 +22,9 @@ namespace lms::scanner { ScanError::ScanError(const std::filesystem::path& _file, ScanErrorType _error, const std::string& _systemError) - : file{ _file }, - error{ _error }, - systemError{ _systemError } + : file{ _file } + , error{ _error } + , systemError{ _systemError } { } @@ -43,4 +43,3 @@ namespace lms::scanner return (processedElems / static_cast(totalElems ? totalElems : 1)) * 100; } } // namespace lms::scanner - diff --git a/src/libs/services/scanner/include/services/scanner/IScannerService.hpp b/src/libs/services/scanner/include/services/scanner/IScannerService.hpp index 2c724449..b811ce29 100644 --- a/src/libs/services/scanner/include/services/scanner/IScannerService.hpp +++ b/src/libs/services/scanner/include/services/scanner/IScannerService.hpp @@ -50,10 +50,10 @@ namespace lms::scanner struct Status { - State currentState{ State::NotScheduled }; - Wt::WDateTime nextScheduledScan; - std::optional lastCompleteScanStats; - std::optional currentScanStepStats; + State currentState{ State::NotScheduled }; + Wt::WDateTime nextScheduledScan; + std::optional lastCompleteScanStats; + std::optional currentScanStepStats; }; virtual Status getStatus() const = 0; @@ -62,4 +62,4 @@ namespace lms::scanner }; std::unique_ptr createScannerService(db::Db& db); -} // Scanner +} // namespace lms::scanner diff --git a/src/libs/services/scanner/include/services/scanner/ScannerEvents.hpp b/src/libs/services/scanner/include/services/scanner/ScannerEvents.hpp index 19dfe89d..5084093e 100644 --- a/src/libs/services/scanner/include/services/scanner/ScannerEvents.hpp +++ b/src/libs/services/scanner/include/services/scanner/ScannerEvents.hpp @@ -30,20 +30,19 @@ namespace lms::scanner struct Events { // Called if scan was aborted - Wt::Signal<> scanAborted; + Wt::Signal<> scanAborted; // Called just after scan start - Wt::Signal<> scanStarted; + Wt::Signal<> scanStarted; // Called just after scan complete (true if changes have been made) - Wt::Signal scanComplete; + Wt::Signal scanComplete; // Called during scan in progress - Wt::Signal scanInProgress; + Wt::Signal scanInProgress; // Called after a schedule - Wt::Signal scanScheduled; + Wt::Signal scanScheduled; }; -} // ns Scanner - +} // namespace lms::scanner diff --git a/src/libs/services/scanner/include/services/scanner/ScannerOptions.hpp b/src/libs/services/scanner/include/services/scanner/ScannerOptions.hpp index 33ac40b2..4864d018 100644 --- a/src/libs/services/scanner/include/services/scanner/ScannerOptions.hpp +++ b/src/libs/services/scanner/include/services/scanner/ScannerOptions.hpp @@ -23,8 +23,8 @@ namespace lms::scanner { struct ScanOptions { - bool fullScan{}; // scan files even if not changed + bool fullScan{}; // scan files even if not changed bool forceOptimize{}; // force optimize database - bool compact{}; // compact the database + bool compact{}; // compact the database }; -} \ No newline at end of file +} // namespace lms::scanner \ No newline at end of file diff --git a/src/libs/services/scanner/include/services/scanner/ScannerStats.hpp b/src/libs/services/scanner/include/services/scanner/ScannerStats.hpp index 9c8d9621..b056faf8 100644 --- a/src/libs/services/scanner/include/services/scanner/ScannerStats.hpp +++ b/src/libs/services/scanner/include/services/scanner/ScannerStats.hpp @@ -30,10 +30,10 @@ namespace lms::scanner { enum class ScanErrorType { - CannotReadFile, // cannot read file - CannotParseFile, // cannot parse file - NoAudioTrack, // no audio track found - BadDuration, // bad duration + CannotReadFile, // cannot read file + CannotParseFile, // cannot parse file + NoAudioTrack, // no audio track found + BadDuration, // bad duration }; enum class DuplicateReason @@ -44,17 +44,17 @@ namespace lms::scanner struct ScanError { - std::filesystem::path file; - ScanErrorType error; - std::string systemError; + std::filesystem::path file; + ScanErrorType error; + std::string systemError; ScanError(const std::filesystem::path& file, ScanErrorType error, const std::string& systemError = ""); }; struct ScanDuplicate { - db::TrackId trackId; - DuplicateReason reason; + db::TrackId trackId; + DuplicateReason reason; }; enum class ScanStep @@ -74,38 +74,37 @@ namespace lms::scanner // reduced scan stats struct ScanStepStats { - Wt::WDateTime startTime; + Wt::WDateTime startTime; std::size_t stepIndex{}; ScanStep currentStep; - std::size_t totalElems{}; - std::size_t processedElems{}; + std::size_t totalElems{}; + std::size_t processedElems{}; - unsigned progress() const; + unsigned progress() const; }; struct ScanStats { - Wt::WDateTime startTime; - Wt::WDateTime stopTime; + Wt::WDateTime startTime; + Wt::WDateTime stopTime; - std::size_t filesScanned{}; // Total number of files scanned (estimated) + std::size_t filesScanned{}; // Total number of files scanned (estimated) - std::size_t skips{}; // no change since last scan - std::size_t scans{}; // actually scanned filed + std::size_t skips{}; // no change since last scan + std::size_t scans{}; // actually scanned filed - std::size_t additions{}; // added in DB - std::size_t deletions{}; // removed from DB - std::size_t updates{}; // updated file in DB + std::size_t additions{}; // added in DB + std::size_t deletions{}; // removed from DB + std::size_t updates{}; // updated file in DB - std::size_t featuresFetched{}; // features fetched in DB + std::size_t featuresFetched{}; // features fetched in DB - std::vector errors; - std::vector duplicates; + std::vector errors; + std::vector duplicates; - std::size_t nbFiles() const; - std::size_t nbChanges() const; + std::size_t nbFiles() const; + std::size_t nbChanges() const; }; } // namespace lms::scanner - diff --git a/src/libs/services/scrobbling/impl/IScrobblingBackend.hpp b/src/libs/services/scrobbling/impl/IScrobblingBackend.hpp index 99b1805e..60c6f128 100644 --- a/src/libs/services/scrobbling/impl/IScrobblingBackend.hpp +++ b/src/libs/services/scrobbling/impl/IScrobblingBackend.hpp @@ -30,7 +30,7 @@ namespace lms::db class Session; class TrackList; class User; -} +} // namespace lms::db namespace lms::scrobbling { @@ -44,5 +44,4 @@ namespace lms::scrobbling virtual void listenFinished(const Listen& listen, std::optional duration) = 0; virtual void addTimedListen(const TimedListen& listen) = 0; }; -} // ns Scrobbling - +} // namespace lms::scrobbling diff --git a/src/libs/services/scrobbling/impl/ScrobblingService.cpp b/src/libs/services/scrobbling/impl/ScrobblingService.cpp index 6b572efa..52e43074 100644 --- a/src/libs/services/scrobbling/impl/ScrobblingService.cpp +++ b/src/libs/services/scrobbling/impl/ScrobblingService.cpp @@ -19,6 +19,7 @@ #include "ScrobblingService.hpp" +#include "core/ILogger.hpp" #include "database/Artist.hpp" #include "database/Db.hpp" #include "database/Listen.hpp" @@ -26,7 +27,6 @@ #include "database/Session.hpp" #include "database/Track.hpp" #include "database/User.hpp" -#include "core/ILogger.hpp" #include "internal/InternalBackend.hpp" #include "listenbrainz/ListenBrainzBackend.hpp" @@ -54,7 +54,7 @@ namespace lms::scrobbling { return db::Listen::ArtistStatsFindParameters{ convertToListenFindParameters(static_cast(params)), params.linkType }; } - } + } // namespace std::unique_ptr createScrobblingService(boost::asio::io_context& ioContext, Db& db) { @@ -253,5 +253,4 @@ namespace lms::scrobbling res = db::Listen::getTopTracks(session, listenFindParams); return res; } -} // ns Scrobbling - +} // namespace lms::scrobbling diff --git a/src/libs/services/scrobbling/impl/ScrobblingService.hpp b/src/libs/services/scrobbling/impl/ScrobblingService.hpp index ce816f0c..1bde3e49 100644 --- a/src/libs/services/scrobbling/impl/ScrobblingService.hpp +++ b/src/libs/services/scrobbling/impl/ScrobblingService.hpp @@ -24,6 +24,7 @@ #include #include "services/scrobbling/IScrobblingService.hpp" + #include "IScrobblingBackend.hpp" namespace lms::scrobbling @@ -59,5 +60,4 @@ namespace lms::scrobbling std::unordered_map> _scrobblingBackends; }; -} // ns Scrobbling - +} // namespace lms::scrobbling diff --git a/src/libs/services/scrobbling/impl/internal/InternalBackend.cpp b/src/libs/services/scrobbling/impl/internal/InternalBackend.cpp index 5512acbe..b70ab4b7 100644 --- a/src/libs/services/scrobbling/impl/internal/InternalBackend.cpp +++ b/src/libs/services/scrobbling/impl/internal/InternalBackend.cpp @@ -29,7 +29,8 @@ namespace lms::scrobbling { InternalBackend::InternalBackend(db::Db& db) : _db{ db } - {} + { + } void InternalBackend::listenStarted(const Listen&) { @@ -64,5 +65,4 @@ namespace lms::scrobbling auto dbListen{ session.create(user, track, db::ScrobblingBackend::Internal, listen.listenedAt) }; dbListen.modify()->setSyncState(db::SyncState::Synchronized); } -} // Scrobbling - +} // namespace lms::scrobbling diff --git a/src/libs/services/scrobbling/impl/internal/InternalBackend.hpp b/src/libs/services/scrobbling/impl/internal/InternalBackend.hpp index 349addf9..a0fd45d7 100644 --- a/src/libs/services/scrobbling/impl/internal/InternalBackend.hpp +++ b/src/libs/services/scrobbling/impl/internal/InternalBackend.hpp @@ -40,5 +40,4 @@ namespace lms::scrobbling db::Db& _db; }; -} // Scrobbling - +} // namespace lms::scrobbling diff --git a/src/libs/services/scrobbling/impl/listenbrainz/Exception.hpp b/src/libs/services/scrobbling/impl/listenbrainz/Exception.hpp index 7bf30fff..517f8ef3 100644 --- a/src/libs/services/scrobbling/impl/listenbrainz/Exception.hpp +++ b/src/libs/services/scrobbling/impl/listenbrainz/Exception.hpp @@ -23,9 +23,9 @@ namespace lms::scrobbling::listenBrainz { - class Exception : public scrobbling::Exception - { - public: - using scrobbling::Exception::Exception; - }; -} + class Exception : public scrobbling::Exception + { + public: + using scrobbling::Exception::Exception; + }; +} // namespace lms::scrobbling::listenBrainz diff --git a/src/libs/services/scrobbling/impl/listenbrainz/ListenBrainzBackend.cpp b/src/libs/services/scrobbling/impl/listenbrainz/ListenBrainzBackend.cpp index 7bf6dccd..1d0ac7a5 100644 --- a/src/libs/services/scrobbling/impl/listenbrainz/ListenBrainzBackend.cpp +++ b/src/libs/services/scrobbling/impl/listenbrainz/ListenBrainzBackend.cpp @@ -19,13 +19,14 @@ #include "ListenBrainzBackend.hpp" +#include "core/IConfig.hpp" +#include "core/ILogger.hpp" +#include "core/Service.hpp" +#include "core/http/IClient.hpp" #include "database/Db.hpp" #include "database/Session.hpp" #include "database/Track.hpp" -#include "core/IConfig.hpp" -#include "core/http/IClient.hpp" -#include "core/ILogger.hpp" -#include "core/Service.hpp" + #include "Utils.hpp" namespace lms::scrobbling::listenBrainz @@ -48,7 +49,7 @@ namespace lms::scrobbling::listenBrainz return res; } - } + } // namespace ListenBrainzBackend::ListenBrainzBackend(boost::asio::io_context& ioContext, Db& db) : _ioContext{ ioContext } @@ -84,4 +85,3 @@ namespace lms::scrobbling::listenBrainz _listensSynchronizer.enqueListen(timedListen); } } // namespace lms::scrobbling::listenBrainz - diff --git a/src/libs/services/scrobbling/impl/listenbrainz/ListenBrainzBackend.hpp b/src/libs/services/scrobbling/impl/listenbrainz/ListenBrainzBackend.hpp index ba1bccbc..3ab08fd5 100644 --- a/src/libs/services/scrobbling/impl/listenbrainz/ListenBrainzBackend.hpp +++ b/src/libs/services/scrobbling/impl/listenbrainz/ListenBrainzBackend.hpp @@ -19,8 +19,9 @@ #pragma once -#include #include +#include + #include #include "IScrobblingBackend.hpp" @@ -50,11 +51,10 @@ namespace lms::scrobbling::listenBrainz // Submit listens void enqueListen(const Listen& listen, const Wt::WDateTime& timePoint); - boost::asio::io_context& _ioContext; - db::Db& _db; - std::string _baseAPIUrl; - std::unique_ptr _client; - ListensSynchronizer _listensSynchronizer; + boost::asio::io_context& _ioContext; + db::Db& _db; + std::string _baseAPIUrl; + std::unique_ptr _client; + ListensSynchronizer _listensSynchronizer; }; -} // scrobbling::ListenBrainz - +} // namespace lms::scrobbling::listenBrainz diff --git a/src/libs/services/scrobbling/impl/listenbrainz/ListenTypes.cpp b/src/libs/services/scrobbling/impl/listenbrainz/ListenTypes.cpp index 690c4186..322ae5f0 100644 --- a/src/libs/services/scrobbling/impl/listenbrainz/ListenTypes.cpp +++ b/src/libs/services/scrobbling/impl/listenbrainz/ListenTypes.cpp @@ -21,21 +21,20 @@ namespace lms::scrobbling::listenBrainz { - std::ostream& - operator<<(std::ostream& os, const Listen& listen) - { - os << "track name = '" << listen.trackName << "', artistName = '" << listen.artistName << "'"; - if (listen.listenedAt.isValid()) - os << ", listenedAt = " << listen.listenedAt.toString(); - if (!listen.releaseName.empty()) - os << ", releaseName = '" << listen.releaseName << "'"; - if (listen.trackNumber) - os << ", trackNumber = " << *listen.trackNumber; - if (listen.trackMBID) - os << ", trackMBID = '" << listen.trackMBID->getAsString() << "'"; - if (listen.recordingMBID) - os << ", recordingMBID = '" << listen.recordingMBID->getAsString() << "'"; + std::ostream& operator<<(std::ostream& os, const Listen& listen) + { + os << "track name = '" << listen.trackName << "', artistName = '" << listen.artistName << "'"; + if (listen.listenedAt.isValid()) + os << ", listenedAt = " << listen.listenedAt.toString(); + if (!listen.releaseName.empty()) + os << ", releaseName = '" << listen.releaseName << "'"; + if (listen.trackNumber) + os << ", trackNumber = " << *listen.trackNumber; + if (listen.trackMBID) + os << ", trackMBID = '" << listen.trackMBID->getAsString() << "'"; + if (listen.recordingMBID) + os << ", recordingMBID = '" << listen.recordingMBID->getAsString() << "'"; - return os; - } -} // scrobbling::ListenBrainz + return os; + } +} // namespace lms::scrobbling::listenBrainz diff --git a/src/libs/services/scrobbling/impl/listenbrainz/ListenTypes.hpp b/src/libs/services/scrobbling/impl/listenbrainz/ListenTypes.hpp index 37c64dc6..504f5280 100644 --- a/src/libs/services/scrobbling/impl/listenbrainz/ListenTypes.hpp +++ b/src/libs/services/scrobbling/impl/listenbrainz/ListenTypes.hpp @@ -19,25 +19,26 @@ #pragma once -#include #include +#include + #include #include "core/UUID.hpp" namespace lms::scrobbling::listenBrainz { - struct Listen - { - std::string trackName; - std::string releaseName; - std::string artistName; - std::optional recordingMBID; - std::optional trackMBID; - std::optional releaseMBID; - std::optional trackNumber; - Wt::WDateTime listenedAt; - }; + struct Listen + { + std::string trackName; + std::string releaseName; + std::string artistName; + std::optional recordingMBID; + std::optional trackMBID; + std::optional releaseMBID; + std::optional trackNumber; + Wt::WDateTime listenedAt; + }; - std::ostream& operator<<(std::ostream& os, const Listen& listen); -} + std::ostream& operator<<(std::ostream& os, const Listen& listen); +} // namespace lms::scrobbling::listenBrainz diff --git a/src/libs/services/scrobbling/impl/listenbrainz/ListensParser.cpp b/src/libs/services/scrobbling/impl/listenbrainz/ListensParser.cpp index b7bf7d45..7701a96d 100644 --- a/src/libs/services/scrobbling/impl/listenbrainz/ListensParser.cpp +++ b/src/libs/services/scrobbling/impl/listenbrainz/ListensParser.cpp @@ -21,10 +21,11 @@ #include #include -#include #include +#include #include "core/ILogger.hpp" + #include "Utils.hpp" namespace lms::scrobbling::listenBrainz @@ -102,4 +103,4 @@ namespace lms::scrobbling::listenBrainz return result; } -} // scrobbling::ListenBrainz +} // namespace lms::scrobbling::listenBrainz diff --git a/src/libs/services/scrobbling/impl/listenbrainz/ListensParser.hpp b/src/libs/services/scrobbling/impl/listenbrainz/ListensParser.hpp index c85a9814..17767b41 100644 --- a/src/libs/services/scrobbling/impl/listenbrainz/ListensParser.hpp +++ b/src/libs/services/scrobbling/impl/listenbrainz/ListensParser.hpp @@ -25,15 +25,15 @@ namespace lms::scrobbling::listenBrainz { - class ListensParser - { - public: - struct Result - { - std::size_t listenCount {}; // may be > than listens.size() - std::vector listens; // successfully parsed listens - }; + class ListensParser + { + public: + struct Result + { + std::size_t listenCount{}; // may be > than listens.size() + std::vector listens; // successfully parsed listens + }; - static Result parse(std::string_view msgBody); - }; -} // scrobbling::ListenBrainz + static Result parse(std::string_view msgBody); + }; +} // namespace lms::scrobbling::listenBrainz diff --git a/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.cpp b/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.cpp index c221c3ca..cf6d6a96 100644 --- a/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.cpp +++ b/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.cpp @@ -19,12 +19,16 @@ #include "ListensSynchronizer.hpp" -#include #include #include -#include #include +#include +#include +#include "ListensParser.hpp" +#include "core/IConfig.hpp" +#include "core/Service.hpp" +#include "core/http/IClient.hpp" #include "database/Artist.hpp" #include "database/Db.hpp" #include "database/Listen.hpp" @@ -33,10 +37,6 @@ #include "database/Track.hpp" #include "database/User.hpp" #include "services/scrobbling/Exception.hpp" -#include "core/IConfig.hpp" -#include "core/http/IClient.hpp" -#include "core/Service.hpp" -#include "ListensParser.hpp" #include "Utils.hpp" @@ -52,7 +52,7 @@ namespace lms::scrobbling::listenBrainz if (!track) return std::nullopt; - auto artists{ track->getArtists({db::TrackArtistLinkType::Artist}) }; + auto artists{ track->getArtists({ db::TrackArtistLinkType::Artist }) }; if (artists.empty()) artists = track->getArtists({ db::TrackArtistLinkType::ReleaseArtist }); @@ -65,12 +65,12 @@ namespace lms::scrobbling::listenBrainz Wt::Json::Object additionalInfo; additionalInfo["listening_from"] = "LMS"; additionalInfo["duration_ms"] = std::chrono::duration_cast(track->getDuration()).count(); - if (const auto release {track->getRelease()}) + if (const auto release{ track->getRelease() }) { if (auto MBID{ release->getMBID() }) - additionalInfo["release_mbid"] = Wt::Json::Value{ std::string {MBID->getAsString()} }; + additionalInfo["release_mbid"] = Wt::Json::Value{ std::string{ MBID->getAsString() } }; if (auto groupMBID{ release->getGroupMBID() }) - additionalInfo["release_group_mbid"] = Wt::Json::Value{ std::string {groupMBID->getAsString()} }; + additionalInfo["release_group_mbid"] = Wt::Json::Value{ std::string{ groupMBID->getAsString() } }; } { @@ -78,7 +78,7 @@ namespace lms::scrobbling::listenBrainz for (const db::Artist::pointer& artist : artists) { if (auto MBID{ artist->getMBID() }) - artistMBIDs.push_back(Wt::Json::Value{ std::string {MBID->getAsString()} }); + artistMBIDs.push_back(Wt::Json::Value{ std::string{ MBID->getAsString() } }); } if (!artistMBIDs.empty()) @@ -86,10 +86,10 @@ namespace lms::scrobbling::listenBrainz } if (auto MBID{ track->getTrackMBID() }) - additionalInfo["track_mbid"] = Wt::Json::Value{ std::string {MBID->getAsString()} }; + additionalInfo["track_mbid"] = Wt::Json::Value{ std::string{ MBID->getAsString() } }; if (auto MBID{ track->getRecordingMBID() }) - additionalInfo["recording_mbid"] = Wt::Json::Value{ std::string {MBID->getAsString()} }; + additionalInfo["recording_mbid"] = Wt::Json::Value{ std::string{ MBID->getAsString() } }; if (const std::optional trackNumber{ track->getTrackNumber() }) additionalInfo["tracknumber"] = Wt::Json::Value{ static_cast(*trackNumber) }; @@ -99,7 +99,7 @@ namespace lms::scrobbling::listenBrainz trackMetadata["artist_name"] = Wt::Json::Value{ std::string{ track->getArtistDisplayName() } }; trackMetadata["track_name"] = Wt::Json::Value{ track->getName() }; if (track->getRelease()) - trackMetadata["release_name"] = Wt::Json::Value{ std::string {track->getRelease()->getName()} }; + trackMetadata["release_name"] = Wt::Json::Value{ std::string{ track->getRelease()->getName() } }; Wt::Json::Object payload; payload["track_metadata"] = std::move(trackMetadata); @@ -118,7 +118,7 @@ namespace lms::scrobbling::listenBrainz return res; Wt::Json::Object root; - root["listen_type"] = Wt::Json::Value{ std::string {listenType} }; + root["listen_type"] = Wt::Json::Value{ std::string{ listenType } }; root["payload"] = Wt::Json::Array{ std::move(*payload) }; res = Wt::Json::serialize(root); @@ -207,7 +207,7 @@ namespace lms::scrobbling::listenBrainz LOG(DEBUG, "No match for listen '" << listen << "'"); return {}; } - } + } // namespace ListensSynchronizer::ListensSynchronizer(boost::asio::io_context& ioContext, db::Db& db, core::http::IClient& client) : _ioContext{ ioContext } @@ -244,18 +244,16 @@ namespace lms::scrobbling::listenBrainz saveListen(timedListen, db::SyncState::PendingAdd); request.priority = core::http::ClientRequestParameters::Priority::Normal; - request.onSuccessFunc = [this, timedListen](std::string_view) - { - _strand.dispatch([this, timedListen] - { - if (saveListen(timedListen, db::SyncState::Synchronized)) - { - UserContext& context{ getUserContext(timedListen.userId) }; - if (context.listenCount) - (*context.listenCount)++; - } - }); - }; + request.onSuccessFunc = [this, timedListen](std::string_view) { + _strand.dispatch([this, timedListen] { + if (saveListen(timedListen, db::SyncState::Synchronized)) + { + UserContext& context{ getUserContext(timedListen.userId) }; + if (context.listenCount) + (*context.listenCount)++; + } + }); + }; // on failure, this listen will be sent during the next sync } else @@ -369,10 +367,9 @@ namespace lms::scrobbling::listenBrainz bool ListensSynchronizer::isSyncing() const { - return std::any_of(std::cbegin(_userContexts), std::cend(_userContexts), [](const auto& contextEntry) - { - return contextEntry.second.syncing; - }); + return std::any_of(std::cbegin(_userContexts), std::cend(_userContexts), [](const auto& contextEntry) { + return contextEntry.second.syncing; + }); } void ListensSynchronizer::scheduleSync(std::chrono::seconds fromNow) @@ -382,20 +379,19 @@ namespace lms::scrobbling::listenBrainz LOG(DEBUG, "Scheduled sync in " << fromNow.count() << " seconds..."); _syncTimer.expires_after(fromNow); - _syncTimer.async_wait(boost::asio::bind_executor(_strand, [this](const boost::system::error_code& ec) + _syncTimer.async_wait(boost::asio::bind_executor(_strand, [this](const boost::system::error_code& ec) { + if (ec == boost::asio::error::operation_aborted) { - if (ec == boost::asio::error::operation_aborted) - { - LOG(DEBUG, "getListens aborted"); - return; - } - else if (ec) - { - throw Exception{ "GetListens timer failure: " + std::string {ec.message()} }; - } + LOG(DEBUG, "getListens aborted"); + return; + } + else if (ec) + { + throw Exception{ "GetListens timer failure: " + std::string{ ec.message() } }; + } - startSync(); - })); + startSync(); + })); } void ListensSynchronizer::startSync() @@ -434,14 +430,13 @@ namespace lms::scrobbling::listenBrainz void ListensSynchronizer::onSyncEnded(UserContext& context) { - _strand.dispatch([this, &context] - { - LOG(INFO, "Sync done for user '" << context.listenBrainzUserName << "', fetched: " << context.fetchedListenCount << ", matched: " << context.matchedListenCount << ", imported: " << context.importedListenCount); - context.syncing = false; + _strand.dispatch([this, &context] { + LOG(INFO, "Sync done for user '" << context.listenBrainzUserName << "', fetched: " << context.fetchedListenCount << ", matched: " << context.matchedListenCount << ", imported: " << context.importedListenCount); + context.syncing = false; - if (!isSyncing()) - scheduleSync(_syncListensPeriod); - }); + if (!isSyncing()) + scheduleSync(_syncListensPeriod); + }); } void ListensSynchronizer::enqueValidateToken(UserContext& context) @@ -458,21 +453,19 @@ namespace lms::scrobbling::listenBrainz core::http::ClientGETRequestParameters request; request.priority = core::http::ClientRequestParameters::Priority::Low; request.relativeUrl = "/1/validate-token"; - request.headers = { {"Authorization", "Token " + std::string {listenBrainzToken->getAsString()}} }; - request.onSuccessFunc = [this, &context](std::string_view msgBody) - { - context.listenBrainzUserName = utils::parseValidateToken(msgBody); - if (context.listenBrainzUserName.empty()) - { - onSyncEnded(context); - return; - } - enqueGetListenCount(context); - }; - request.onFailureFunc = [this, &context] + request.headers = { { "Authorization", "Token " + std::string{ listenBrainzToken->getAsString() } } }; + request.onSuccessFunc = [this, &context](std::string_view msgBody) { + context.listenBrainzUserName = utils::parseValidateToken(msgBody); + if (context.listenBrainzUserName.empty()) { onSyncEnded(context); - }; + return; + } + enqueGetListenCount(context); + }; + request.onFailureFunc = [this, &context] { + onSyncEnded(context); + }; _client.sendGETRequest(std::move(request)); } @@ -484,31 +477,28 @@ namespace lms::scrobbling::listenBrainz core::http::ClientGETRequestParameters request; request.relativeUrl = "/1/user/" + std::string{ context.listenBrainzUserName } + "/listen-count"; request.priority = core::http::ClientRequestParameters::Priority::Low; - request.onSuccessFunc = [this, &context](std::string_view msgBody) - { - const auto listenCount{ parseListenCount(msgBody) }; - _strand.dispatch([this, listenCount, &context] - { - if (listenCount) - LOG(DEBUG, "Listen count for listenbrainz user '" << context.listenBrainzUserName << "' = " << *listenCount); + request.onSuccessFunc = [this, &context](std::string_view msgBody) { + const auto listenCount{ parseListenCount(msgBody) }; + _strand.dispatch([this, listenCount, &context] { + if (listenCount) + LOG(DEBUG, "Listen count for listenbrainz user '" << context.listenBrainzUserName << "' = " << *listenCount); - bool needSync{ listenCount && (!context.listenCount || *context.listenCount != *listenCount) }; - context.listenCount = listenCount; + bool needSync{ listenCount && (!context.listenCount || *context.listenCount != *listenCount) }; + context.listenCount = listenCount; - if (!needSync) - { - onSyncEnded(context); - return; - } + if (!needSync) + { + onSyncEnded(context); + return; + } - context.maxDateTime = Wt::WDateTime::currentDateTime(); - enqueGetListens(context); - }); - }; - request.onFailureFunc = [this, &context] - { - onSyncEnded(context); - }; + context.maxDateTime = Wt::WDateTime::currentDateTime(); + enqueGetListens(context); + }); + }; + request.onFailureFunc = [this, &context] { + onSyncEnded(context); + }; _client.sendGETRequest(std::move(request)); } @@ -520,21 +510,19 @@ namespace lms::scrobbling::listenBrainz core::http::ClientGETRequestParameters request; request.relativeUrl = "/1/user/" + context.listenBrainzUserName + "/listens?max_ts=" + std::to_string(context.maxDateTime.toTime_t()); request.priority = core::http::ClientRequestParameters::Priority::Low; - request.onSuccessFunc = [this, &context](std::string_view msgBody) - { - processGetListensResponse(msgBody, context); - if (context.fetchedListenCount >= _maxSyncListenCount || !context.maxDateTime.isValid()) - { - onSyncEnded(context); - return; - } - - enqueGetListens(context); - }; - request.onFailureFunc = [this, &context] + request.onSuccessFunc = [this, &context](std::string_view msgBody) { + processGetListensResponse(msgBody, context); + if (context.fetchedListenCount >= _maxSyncListenCount || !context.maxDateTime.isValid()) { onSyncEnded(context); - }; + return; + } + + enqueGetListens(context); + }; + request.onFailureFunc = [this, &context] { + onSyncEnded(context); + }; _client.sendGETRequest(std::move(request)); } @@ -563,7 +551,7 @@ namespace lms::scrobbling::listenBrainz { context.matchedListenCount++; - const scrobbling::TimedListen listen{ {context.userId, trackId}, parsedListen.listenedAt }; + const scrobbling::TimedListen listen{ { context.userId, trackId }, parsedListen.listenedAt }; if (saveListen(listen, db::SyncState::Synchronized)) context.importedListenCount++; } diff --git a/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.hpp b/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.hpp index afdcdac6..dd851e45 100644 --- a/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.hpp +++ b/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.hpp @@ -21,6 +21,7 @@ #include #include + #include #include #include @@ -32,74 +33,74 @@ namespace lms { - namespace core::http - { - class IClient; - } - namespace db - { - class Db; - } -} + namespace core::http + { + class IClient; + } + namespace db + { + class Db; + } +} // namespace lms namespace lms::scrobbling::listenBrainz { - class ListensSynchronizer - { - public: - ListensSynchronizer(boost::asio::io_context& ioContext, db::Db& db, core::http::IClient& client); + class ListensSynchronizer + { + public: + ListensSynchronizer(boost::asio::io_context& ioContext, db::Db& db, core::http::IClient& client); - void enqueListen(const TimedListen& listen); - void enqueListenNow(const Listen& listen); + void enqueListen(const TimedListen& listen); + void enqueListenNow(const Listen& listen); - private: - void enqueListen(const Listen& listen, const Wt::WDateTime& timePoint); - bool saveListen(const TimedListen& listen, db::SyncState scrobblinState); + private: + void enqueListen(const Listen& listen, const Wt::WDateTime& timePoint); + bool saveListen(const TimedListen& listen, db::SyncState scrobblinState); - void enquePendingListens(); + void enquePendingListens(); - struct UserContext - { - UserContext(db::UserId id) : userId {id} {} + struct UserContext + { + UserContext(db::UserId id) + : userId{ id } {} - UserContext(const UserContext&) = delete; - UserContext(UserContext&&) = delete; - UserContext& operator=(const UserContext&) = delete; - UserContext& operator=(UserContext&&) = delete; + UserContext(const UserContext&) = delete; + UserContext(UserContext&&) = delete; + UserContext& operator=(const UserContext&) = delete; + UserContext& operator=(UserContext&&) = delete; - const db::UserId userId; - bool syncing {}; - std::optional listenCount {}; + const db::UserId userId; + bool syncing{}; + std::optional listenCount{}; - // resetted at each sync - std::string listenBrainzUserName; // need to be resolved first - Wt::WDateTime maxDateTime; - std::size_t fetchedListenCount{}; - std::size_t matchedListenCount{}; - std::size_t importedListenCount{}; - }; + // resetted at each sync + std::string listenBrainzUserName; // need to be resolved first + Wt::WDateTime maxDateTime; + std::size_t fetchedListenCount{}; + std::size_t matchedListenCount{}; + std::size_t importedListenCount{}; + }; - UserContext& getUserContext(db::UserId userId); - bool isSyncing() const; - void scheduleSync(std::chrono::seconds fromNow); - void startSync(); - void startSync(UserContext& context); - void onSyncEnded(UserContext& context); - void enqueValidateToken(UserContext& context); - void enqueGetListenCount(UserContext& context); - void enqueGetListens(UserContext& context); - void processGetListensResponse(std::string_view body, UserContext& context); + UserContext& getUserContext(db::UserId userId); + bool isSyncing() const; + void scheduleSync(std::chrono::seconds fromNow); + void startSync(); + void startSync(UserContext& context); + void onSyncEnded(UserContext& context); + void enqueValidateToken(UserContext& context); + void enqueGetListenCount(UserContext& context); + void enqueGetListens(UserContext& context); + void processGetListensResponse(std::string_view body, UserContext& context); - boost::asio::io_context& _ioContext; - boost::asio::io_context::strand _strand {_ioContext}; - db::Db& _db; - boost::asio::steady_timer _syncTimer {_ioContext}; - core::http::IClient& _client; + boost::asio::io_context& _ioContext; + boost::asio::io_context::strand _strand{ _ioContext }; + db::Db& _db; + boost::asio::steady_timer _syncTimer{ _ioContext }; + core::http::IClient& _client; - std::unordered_map _userContexts; - - const std::size_t _maxSyncListenCount; - const std::chrono::hours _syncListensPeriod; - }; -} // scrobbling::ListenBrainz + std::unordered_map _userContexts; + const std::size_t _maxSyncListenCount; + const std::chrono::hours _syncListensPeriod; + }; +} // namespace lms::scrobbling::listenBrainz diff --git a/src/libs/services/scrobbling/impl/listenbrainz/Utils.cpp b/src/libs/services/scrobbling/impl/listenbrainz/Utils.cpp index 118ce4fd..3c0d47bf 100644 --- a/src/libs/services/scrobbling/impl/listenbrainz/Utils.cpp +++ b/src/libs/services/scrobbling/impl/listenbrainz/Utils.cpp @@ -59,4 +59,4 @@ namespace lms::scrobbling::listenBrainz::utils listenBrainzUserName = root.get("user_name").orIfNull(""); return listenBrainzUserName; } -} +} // namespace lms::scrobbling::listenBrainz::utils diff --git a/src/libs/services/scrobbling/impl/listenbrainz/Utils.hpp b/src/libs/services/scrobbling/impl/listenbrainz/Utils.hpp index ab8204db..0e3801c8 100644 --- a/src/libs/services/scrobbling/impl/listenbrainz/Utils.hpp +++ b/src/libs/services/scrobbling/impl/listenbrainz/Utils.hpp @@ -19,11 +19,11 @@ #pragma once -#include "database/UserId.hpp" #include "core/ILogger.hpp" #include "core/UUID.hpp" +#include "database/UserId.hpp" -#define LOG(sev, message) LMS_LOG(SCROBBLING, sev, "[listenbrainz] " << message) +#define LOG(sev, message) LMS_LOG(SCROBBLING, sev, "[listenbrainz] " << message) namespace lms::db { @@ -32,6 +32,6 @@ namespace lms::db namespace lms::scrobbling::listenBrainz::utils { - std::optional getListenBrainzToken(db::Session& session, db::UserId userId); + std::optional getListenBrainzToken(db::Session& session, db::UserId userId); std::string parseValidateToken(std::string_view msgBody); -} +} // namespace lms::scrobbling::listenBrainz::utils diff --git a/src/libs/services/scrobbling/include/services/scrobbling/Exception.hpp b/src/libs/services/scrobbling/include/services/scrobbling/Exception.hpp index 85c72db3..944c0102 100644 --- a/src/libs/services/scrobbling/include/services/scrobbling/Exception.hpp +++ b/src/libs/services/scrobbling/include/services/scrobbling/Exception.hpp @@ -28,4 +28,4 @@ namespace lms::scrobbling public: using LmsException::LmsException; }; -} +} // namespace lms::scrobbling diff --git a/src/libs/services/scrobbling/include/services/scrobbling/IScrobblingService.hpp b/src/libs/services/scrobbling/include/services/scrobbling/IScrobblingService.hpp index 7f04ca3e..a0a26008 100644 --- a/src/libs/services/scrobbling/include/services/scrobbling/IScrobblingService.hpp +++ b/src/libs/services/scrobbling/include/services/scrobbling/IScrobblingService.hpp @@ -23,16 +23,17 @@ #include #include #include -#include -#include -#include "services/scrobbling/Listen.hpp" +#include +#include + #include "database/ArtistId.hpp" #include "database/ClusterId.hpp" #include "database/MediaLibraryId.hpp" #include "database/ReleaseId.hpp" #include "database/TrackId.hpp" #include "database/Types.hpp" +#include "services/scrobbling/Listen.hpp" namespace lms::db { @@ -59,29 +60,61 @@ namespace lms::scrobbling struct FindParameters { - db::UserId user; - std::vector clusters; // if non empty, at least one artist that belongs to these clusters - std::vector keywords; // if non empty, name must match all of these keywords - std::optional range; - db::MediaLibraryId library; // if set, match this library - db::ArtistId artist; // if set, match this artist + db::UserId user; + std::vector clusters; // if non empty, at least one artist that belongs to these clusters + std::vector keywords; // if non empty, name must match all of these keywords + std::optional range; + db::MediaLibraryId library; // if set, match this library + db::ArtistId artist; // if set, match this artist - FindParameters& setUser(const db::UserId _user) { user = _user; return *this; } - FindParameters& setClusters(std::span _clusters) { clusters.assign(std::cbegin(_clusters), std::cend(_clusters)); return *this; } - FindParameters& setKeywords(const std::vector& _keywords) { keywords = _keywords; return *this; } - FindParameters& setRange(std::optional _range) { range = _range; return *this; } - FindParameters& setMediaLibrary(db::MediaLibraryId _library) { library = _library; return *this; } - FindParameters& setArtist(db::ArtistId _artist) { artist = _artist; return *this; } + FindParameters& setUser(const db::UserId _user) + { + user = _user; + return *this; + } + FindParameters& setClusters(std::span _clusters) + { + clusters.assign(std::cbegin(_clusters), std::cend(_clusters)); + return *this; + } + FindParameters& setKeywords(const std::vector& _keywords) + { + keywords = _keywords; + return *this; + } + FindParameters& setRange(std::optional _range) + { + range = _range; + return *this; + } + FindParameters& setMediaLibrary(db::MediaLibraryId _library) + { + library = _library; + return *this; + } + FindParameters& setArtist(db::ArtistId _artist) + { + artist = _artist; + return *this; + } }; // Artists struct ArtistFindParameters : public FindParameters { - std::optional linkType; // if set, only artists that have produced at least one track with this link type - db::ArtistSortMethod sortMethod{ db::ArtistSortMethod::None }; + std::optional linkType; // if set, only artists that have produced at least one track with this link type + db::ArtistSortMethod sortMethod{ db::ArtistSortMethod::None }; - ArtistFindParameters& setLinkType(std::optional _linkType) { linkType = _linkType; return *this; } - ArtistFindParameters& setSortMethod(db::ArtistSortMethod _sortMethod) { sortMethod = _sortMethod; return *this; } + ArtistFindParameters& setLinkType(std::optional _linkType) + { + linkType = _linkType; + return *this; + } + ArtistFindParameters& setSortMethod(db::ArtistSortMethod _sortMethod) + { + sortMethod = _sortMethod; + return *this; + } }; // From most recent to oldest @@ -102,4 +135,4 @@ namespace lms::scrobbling }; std::unique_ptr createScrobblingService(boost::asio::io_service& ioService, db::Db& db); -} // ns Scrobbling +} // namespace lms::scrobbling diff --git a/src/libs/services/scrobbling/include/services/scrobbling/Listen.hpp b/src/libs/services/scrobbling/include/services/scrobbling/Listen.hpp index 499522ba..7491bd04 100644 --- a/src/libs/services/scrobbling/include/services/scrobbling/Listen.hpp +++ b/src/libs/services/scrobbling/include/services/scrobbling/Listen.hpp @@ -36,5 +36,4 @@ namespace lms::scrobbling { Wt::WDateTime listenedAt; }; -} // ns Scrobbling - +} // namespace lms::scrobbling diff --git a/src/libs/services/scrobbling/test/Listenbrainz.cpp b/src/libs/services/scrobbling/test/Listenbrainz.cpp index 86ea1840..3b585d0d 100644 --- a/src/libs/services/scrobbling/test/Listenbrainz.cpp +++ b/src/libs/services/scrobbling/test/Listenbrainz.cpp @@ -25,7 +25,7 @@ namespace lms::scrobbling::listenBrainz::tests { TEST(Listenbrainz, parseListens_empty) { - ListensParser::Result result {ListensParser::parse("")}; + ListensParser::Result result{ ListensParser::parse("") }; EXPECT_EQ(result.listenCount, 0); EXPECT_EQ(result.listens.size(), 0); @@ -36,7 +36,7 @@ namespace lms::scrobbling::listenBrainz::tests TEST(Listenbrainz, parseListens_single_missingMBID) { - ListensParser::Result result {ListensParser::parse(R"({"payload":{"count":1,"latest_listen_ts":1663159479,"listens":[{"inserted_at":1650541124,"listened_at":1650541124,"recording_msid":"0e1418e3-b485-413a-84af-6316312cb116","track_metadata":{"additional_info":{"artist_msid":"ab5b27ad-e579-441c-ac60-d5dd9975c044","listening_from":"LMS","recording_msid":"0e1418e3-b485-413a-84af-6316312cb116","release_msid":"3f22f274-a9ee-4cb2-8dd1-f3bd18407099","tracknumber":8},"artist_name":"Broke For Free","release_name":"YEKOMS","track_name":"U2B"},"user_name":"epoupon"}],"user_id":"epoupon"}})")}; + ListensParser::Result result{ ListensParser::parse(R"({"payload":{"count":1,"latest_listen_ts":1663159479,"listens":[{"inserted_at":1650541124,"listened_at":1650541124,"recording_msid":"0e1418e3-b485-413a-84af-6316312cb116","track_metadata":{"additional_info":{"artist_msid":"ab5b27ad-e579-441c-ac60-d5dd9975c044","listening_from":"LMS","recording_msid":"0e1418e3-b485-413a-84af-6316312cb116","release_msid":"3f22f274-a9ee-4cb2-8dd1-f3bd18407099","tracknumber":8},"artist_name":"Broke For Free","release_name":"YEKOMS","track_name":"U2B"},"user_name":"epoupon"}],"user_id":"epoupon"}})") }; EXPECT_EQ(result.listenCount, 1); ASSERT_EQ(result.listens.size(), 1); EXPECT_EQ(result.listens[0].trackName, "U2B"); @@ -53,7 +53,7 @@ namespace lms::scrobbling::listenBrainz::tests TEST(Listenbrainz, parseListens_tworesults) { - ListensParser::Result result {ListensParser::parse(R"({"payload":{"count":2,"latest_listen_ts":1664028167,"listens":[{"inserted_at":1664028167,"listened_at":1664028167,"recording_msid":"29c11137-e40b-4875-9ec0-9a20a4bdc2d3","track_metadata":{"additional_info":{"artist_mbids":["069a1c1f-14eb-4d36-b0a0-77dffbd67713"],"artist_msid":null,"listening_from":"LMS","recording_mbid":"46ae879f-2dbe-46d3-99ad-05c116f97a30","recording_msid":"29c11137-e40b-4875-9ec0-9a20a4bdc2d3","release_mbid":"44915500-fbb9-4060-98ce-59a57a429edc","release_msid":null,"track_mbid":"5427a943-a096-4d0b-8b9a-53aca9ed61ac","tracknumber":5},"artist_name":"Broke For Free","mbid_mapping":{"artist_mbids":["069a1c1f-14eb-4d36-b0a0-77dffbd67713"],"recording_mbid":"46ae879f-2dbe-46d3-99ad-05c116f97a30","release_mbid":"44915500-fbb9-4060-98ce-59a57a429edc"},"release_name":"Petal","track_name":"Juparo"},"user_name":"epoupon"},{"inserted_at":1664027919,"listened_at":1664027918,"recording_msid":"fe5abc47-89cd-4235-80b5-00f47cecbe01","track_metadata":{"additional_info":{"artist_mbids":["069a1c1f-14eb-4d36-b0a0-77dffbd67713"],"artist_msid":null,"listening_from":"LMS","recording_mbid":"d89d042c-8cc1-4526-9080-5bab728ee15f","recording_msid":"fe5abc47-89cd-4235-80b5-00f47cecbe01","release_mbid":"44915500-fbb9-4060-98ce-59a57a429edc","release_msid":null,"track_mbid":"9f33a17f-e33e-492f-85a4-7b2e9e09613e","tracknumber":4},"artist_name":"Broke For Free","mbid_mapping":{"artist_mbids":["069a1c1f-14eb-4d36-b0a0-77dffbd67713"],"recording_mbid":"d89d042c-8cc1-4526-9080-5bab728ee15f","release_mbid":"44915500-fbb9-4060-98ce-59a57a429edc"},"release_name":"Petal","track_name":"Melt"},"user_name":"epoupon"}],"user_id":"epoupon"}})")}; + ListensParser::Result result{ ListensParser::parse(R"({"payload":{"count":2,"latest_listen_ts":1664028167,"listens":[{"inserted_at":1664028167,"listened_at":1664028167,"recording_msid":"29c11137-e40b-4875-9ec0-9a20a4bdc2d3","track_metadata":{"additional_info":{"artist_mbids":["069a1c1f-14eb-4d36-b0a0-77dffbd67713"],"artist_msid":null,"listening_from":"LMS","recording_mbid":"46ae879f-2dbe-46d3-99ad-05c116f97a30","recording_msid":"29c11137-e40b-4875-9ec0-9a20a4bdc2d3","release_mbid":"44915500-fbb9-4060-98ce-59a57a429edc","release_msid":null,"track_mbid":"5427a943-a096-4d0b-8b9a-53aca9ed61ac","tracknumber":5},"artist_name":"Broke For Free","mbid_mapping":{"artist_mbids":["069a1c1f-14eb-4d36-b0a0-77dffbd67713"],"recording_mbid":"46ae879f-2dbe-46d3-99ad-05c116f97a30","release_mbid":"44915500-fbb9-4060-98ce-59a57a429edc"},"release_name":"Petal","track_name":"Juparo"},"user_name":"epoupon"},{"inserted_at":1664027919,"listened_at":1664027918,"recording_msid":"fe5abc47-89cd-4235-80b5-00f47cecbe01","track_metadata":{"additional_info":{"artist_mbids":["069a1c1f-14eb-4d36-b0a0-77dffbd67713"],"artist_msid":null,"listening_from":"LMS","recording_mbid":"d89d042c-8cc1-4526-9080-5bab728ee15f","recording_msid":"fe5abc47-89cd-4235-80b5-00f47cecbe01","release_mbid":"44915500-fbb9-4060-98ce-59a57a429edc","release_msid":null,"track_mbid":"9f33a17f-e33e-492f-85a4-7b2e9e09613e","tracknumber":4},"artist_name":"Broke For Free","mbid_mapping":{"artist_mbids":["069a1c1f-14eb-4d36-b0a0-77dffbd67713"],"recording_mbid":"d89d042c-8cc1-4526-9080-5bab728ee15f","release_mbid":"44915500-fbb9-4060-98ce-59a57a429edc"},"release_name":"Petal","track_name":"Melt"},"user_name":"epoupon"}],"user_id":"epoupon"}})") }; EXPECT_EQ(result.listenCount, 2); ASSERT_EQ(result.listens.size(), 2); EXPECT_EQ(result.listens[0].trackName, "Juparo"); @@ -77,7 +77,7 @@ namespace lms::scrobbling::listenBrainz::tests TEST(Listenbrainz, parseListens_tworesults_butinvalid) { - ListensParser::Result result {ListensParser::parse(R"({"payload":{"count":2,"latest_listen_ts":1664028167,"listens":[{"inserted_at":1664028167,"listened_at":1664028167,"recording_msid":"29c11137-e40b-4875-9ec0-9a20a4bdc2d3","track_metadata":{"additional_info":{"artist_mbids":["069a1c1f-14eb-4d36-b0a0-77dffbd67713"],"artist_msid":null,"listening_from":"LMS","recording_mbid":"46ae879f-2dbe-46d3-99ad-05c116f97a30","recording_msid":"29c11137-e40b-4875-9ec0-9a20a4bdc2d3","release_mbid":"44915500-fbb9-4060-98ce-59a57a429edc","release_msid":null,"track_mbid":"5427a943-a096-4d0b-8b9a-53aca9ed61ac","tracknumber":5},"artist_name":"Broke For Free","mbid_mapping":{"artist_mbids":["069a1c1f-14eb-4d36-b0a0-77dffbd67713"],"recording_mbid":"46ae879f-2dbe-46d3-99ad-05c116f97a30","release_mbid":"44915500-fbb9-4060-98ce-59a57a429edc"},"release_name":"Petal","track_name":"Juparo"},"user_name":"epoupon"},{"inserted_at":1664027919}],"user_id":"epoupon"}})")}; + ListensParser::Result result{ ListensParser::parse(R"({"payload":{"count":2,"latest_listen_ts":1664028167,"listens":[{"inserted_at":1664028167,"listened_at":1664028167,"recording_msid":"29c11137-e40b-4875-9ec0-9a20a4bdc2d3","track_metadata":{"additional_info":{"artist_mbids":["069a1c1f-14eb-4d36-b0a0-77dffbd67713"],"artist_msid":null,"listening_from":"LMS","recording_mbid":"46ae879f-2dbe-46d3-99ad-05c116f97a30","recording_msid":"29c11137-e40b-4875-9ec0-9a20a4bdc2d3","release_mbid":"44915500-fbb9-4060-98ce-59a57a429edc","release_msid":null,"track_mbid":"5427a943-a096-4d0b-8b9a-53aca9ed61ac","tracknumber":5},"artist_name":"Broke For Free","mbid_mapping":{"artist_mbids":["069a1c1f-14eb-4d36-b0a0-77dffbd67713"],"recording_mbid":"46ae879f-2dbe-46d3-99ad-05c116f97a30","release_mbid":"44915500-fbb9-4060-98ce-59a57a429edc"},"release_name":"Petal","track_name":"Juparo"},"user_name":"epoupon"},{"inserted_at":1664027919}],"user_id":"epoupon"}})") }; EXPECT_EQ(result.listenCount, 2); ASSERT_EQ(result.listens.size(), 1); EXPECT_EQ(result.listens[0].trackName, "Juparo"); @@ -92,7 +92,7 @@ namespace lms::scrobbling::listenBrainz::tests TEST(Listenbrainz, parseListens_entryNotFromLms) { - ListensParser::Result result {ListensParser::parse(R"({"payload":{"count":1,"latest_listen_ts":1664105730,"listens":[{"inserted_at":1664105730,"listened_at":1664105730,"recording_msid":"6a11ff4d-0623-4b2e-98e0-0e172f1f28d7","track_metadata":{"additional_info":{"artist_msid":null,"media_player":"BrainzPlayer","music_service":"youtube.com","music_service_name":"youtube","origin_url":"https://www.youtube.com/watch?v=EBP5vL3YWTI","recording_msid":"6a11ff4d-0623-4b2e-98e0-0e172f1f28d7","release_msid":null,"submission_client":"BrainzPlayer"},"artist_name":"Dio","brainzplayer_metadata":{"track_name":"Dio - Breathless"},"mbid_mapping":{"artist_mbids":["c55193fb-f5d2-4839-a263-4c044fca1456"],"recording_mbid":"92929526-21d7-4e75-b759-1072951664c4","release_mbid":"16cbf9ba-2e38-3893-9f23-f8567e26c18b"},"release_name":"The Last in Line","track_name":"Breathless"},"user_name":"epoupon"}],"user_id":"epoupon"}})")}; + ListensParser::Result result{ ListensParser::parse(R"({"payload":{"count":1,"latest_listen_ts":1664105730,"listens":[{"inserted_at":1664105730,"listened_at":1664105730,"recording_msid":"6a11ff4d-0623-4b2e-98e0-0e172f1f28d7","track_metadata":{"additional_info":{"artist_msid":null,"media_player":"BrainzPlayer","music_service":"youtube.com","music_service_name":"youtube","origin_url":"https://www.youtube.com/watch?v=EBP5vL3YWTI","recording_msid":"6a11ff4d-0623-4b2e-98e0-0e172f1f28d7","release_msid":null,"submission_client":"BrainzPlayer"},"artist_name":"Dio","brainzplayer_metadata":{"track_name":"Dio - Breathless"},"mbid_mapping":{"artist_mbids":["c55193fb-f5d2-4839-a263-4c044fca1456"],"recording_mbid":"92929526-21d7-4e75-b759-1072951664c4","release_mbid":"16cbf9ba-2e38-3893-9f23-f8567e26c18b"},"release_name":"The Last in Line","track_name":"Breathless"},"user_name":"epoupon"}],"user_id":"epoupon"}})") }; EXPECT_EQ(result.listenCount, 1); ASSERT_EQ(result.listens.size(), 1); EXPECT_EQ(result.listens[0].trackName, "Breathless"); @@ -104,7 +104,7 @@ namespace lms::scrobbling::listenBrainz::tests TEST(Listenbrainz, parseListens_multiArtists) { - ListensParser::Result result {ListensParser::parse(R"({"payload":{"count":1,"latest_listen_ts":1664106427,"listens":[{"inserted_at":1664106427,"listened_at":1664106427,"recording_msid":"b1dad0df-329b-443d-bacf-cdbebdddbfd0","track_metadata":{"additional_info":{"artist_mbids":["04ce0202-043d-4cbe-8f09-8abaf3b80c71","79311c51-9748-49df-baa1-d925fd29f4e8"],"artist_msid":null,"listening_from":"LMS","recording_mbid":"a5f380bc-0a85-4a9f-88db-d41bb9aa2a4b","recording_msid":"b1dad0df-329b-443d-bacf-cdbebdddbfd0","release_mbid":"147b4669-3d20-43f8-89c0-ba1da8b87dd3","release_msid":null,"track_mbid":"a20dd067-29b6-3d38-a0be-eeb86b4671c1","tracknumber":1},"artist_name":"Gloom","release_name":"Demovibes 9: Party, people going","track_name":"Stargazer of Disgrace"},"user_name":"epoupon"}],"user_id":"epoupon"}})")}; + ListensParser::Result result{ ListensParser::parse(R"({"payload":{"count":1,"latest_listen_ts":1664106427,"listens":[{"inserted_at":1664106427,"listened_at":1664106427,"recording_msid":"b1dad0df-329b-443d-bacf-cdbebdddbfd0","track_metadata":{"additional_info":{"artist_mbids":["04ce0202-043d-4cbe-8f09-8abaf3b80c71","79311c51-9748-49df-baa1-d925fd29f4e8"],"artist_msid":null,"listening_from":"LMS","recording_mbid":"a5f380bc-0a85-4a9f-88db-d41bb9aa2a4b","recording_msid":"b1dad0df-329b-443d-bacf-cdbebdddbfd0","release_mbid":"147b4669-3d20-43f8-89c0-ba1da8b87dd3","release_msid":null,"track_mbid":"a20dd067-29b6-3d38-a0be-eeb86b4671c1","tracknumber":1},"artist_name":"Gloom","release_name":"Demovibes 9: Party, people going","track_name":"Stargazer of Disgrace"},"user_name":"epoupon"}],"user_id":"epoupon"}})") }; EXPECT_EQ(result.listenCount, 1); ASSERT_EQ(result.listens.size(), 1); EXPECT_EQ(result.listens[0].trackNumber, 1); @@ -112,7 +112,7 @@ namespace lms::scrobbling::listenBrainz::tests TEST(Listenbrainz, parseListens_minPayload) { - ListensParser::Result result {ListensParser::parse(R"({"payload":{"count":1,"latest_listen_ts":1664106427,"listens":[{"track_metadata":{"artist_name":"Gloom","track_name":"Stargazer of Disgrace"},"user_name":"epoupon"}],"user_id":"epoupon"}})")}; + ListensParser::Result result{ ListensParser::parse(R"({"payload":{"count":1,"latest_listen_ts":1664106427,"listens":[{"track_metadata":{"artist_name":"Gloom","track_name":"Stargazer of Disgrace"},"user_name":"epoupon"}],"user_id":"epoupon"}})") }; EXPECT_EQ(result.listenCount, 1); ASSERT_EQ(result.listens.size(), 1); EXPECT_FALSE(result.listens[0].listenedAt.isValid()); @@ -126,10 +126,10 @@ namespace lms::scrobbling::listenBrainz::tests TEST(Listenbrainz, parseListens_stringInsteadOfInt) { - ListensParser::Result result {ListensParser::parse(R"({"payload":{"count":1,"latest_listen_ts":1683298766,"listens":[{"inserted_at":1683299849,"listened_at":1683298766,"recording_msid":"3841ad1c-f674-491c-b855-f10a82ea38fe","track_metadata":{"additional_info":{"albumartist":"Various Artists","artist_mbids":["80ccfede-c258-4575-a7ad-c982e9932e0f"],"date":"2002-06-10","discnumber":"1","duration":190,"isrc":"USAM10200204","media_player":"foobar2000","media_player_version":"1.6.16","recording_msid":"3841ad1c-f674-491c-b855-f10a82ea38fe","release_group_mbid":"25f44677-2ecd-33fb-8454-9a9776496e3c","release_mbid":"bddad4c6-e9e1-4218-b9d2-b02a5a778a7d","submission_client":"foobar2000","submission_client_version":"1.3.2","totaldiscs":"1","totaltracks":"18","track_mbid":"08b1a5c1-c845-3d3b-9aa4-560a1af7f28c","tracknumber":"4"},"artist_name":"Sheryl Crow","mbid_mapping":{"artist_mbids":["80ccfede-c258-4575-a7ad-c982e9932e0f"],"artists":[{"artist_credit_name":"Sheryl Crow","artist_mbid":"80ccfede-c258-4575-a7ad-c982e9932e0f","join_phrase":""}],"caa_id":22039936498,"caa_release_mbid":"f10b4b40-4db1-4b9a-a223-06915fa06b3c","recording_mbid":"7ca21c82-1345-44df-b7ac-035a6e05d4ed","recording_name":"Strong Enough","release_mbid":"f10b4b40-4db1-4b9a-a223-06915fa06b3c"},"release_name":"The Very Best of MTV Unplugged","track_name":"Strong Enough"},"user_name":"awesomeuser"}],"user_id":"awesomeuser"}})")}; + ListensParser::Result result{ ListensParser::parse(R"({"payload":{"count":1,"latest_listen_ts":1683298766,"listens":[{"inserted_at":1683299849,"listened_at":1683298766,"recording_msid":"3841ad1c-f674-491c-b855-f10a82ea38fe","track_metadata":{"additional_info":{"albumartist":"Various Artists","artist_mbids":["80ccfede-c258-4575-a7ad-c982e9932e0f"],"date":"2002-06-10","discnumber":"1","duration":190,"isrc":"USAM10200204","media_player":"foobar2000","media_player_version":"1.6.16","recording_msid":"3841ad1c-f674-491c-b855-f10a82ea38fe","release_group_mbid":"25f44677-2ecd-33fb-8454-9a9776496e3c","release_mbid":"bddad4c6-e9e1-4218-b9d2-b02a5a778a7d","submission_client":"foobar2000","submission_client_version":"1.3.2","totaldiscs":"1","totaltracks":"18","track_mbid":"08b1a5c1-c845-3d3b-9aa4-560a1af7f28c","tracknumber":"4"},"artist_name":"Sheryl Crow","mbid_mapping":{"artist_mbids":["80ccfede-c258-4575-a7ad-c982e9932e0f"],"artists":[{"artist_credit_name":"Sheryl Crow","artist_mbid":"80ccfede-c258-4575-a7ad-c982e9932e0f","join_phrase":""}],"caa_id":22039936498,"caa_release_mbid":"f10b4b40-4db1-4b9a-a223-06915fa06b3c","recording_mbid":"7ca21c82-1345-44df-b7ac-035a6e05d4ed","recording_name":"Strong Enough","release_mbid":"f10b4b40-4db1-4b9a-a223-06915fa06b3c"},"release_name":"The Very Best of MTV Unplugged","track_name":"Strong Enough"},"user_name":"awesomeuser"}],"user_id":"awesomeuser"}})") }; EXPECT_EQ(result.listenCount, 1); ASSERT_EQ(result.listens.size(), 1); EXPECT_EQ(result.listens[0].trackNumber, 4); } -} \ No newline at end of file +} // namespace lms::scrobbling::listenBrainz::tests \ No newline at end of file diff --git a/src/libs/services/scrobbling/test/Scrobbling.cpp b/src/libs/services/scrobbling/test/Scrobbling.cpp index 5a4f6499..b918b0d4 100644 --- a/src/libs/services/scrobbling/test/Scrobbling.cpp +++ b/src/libs/services/scrobbling/test/Scrobbling.cpp @@ -27,9 +27,8 @@ int main(int argc, char** argv) { using namespace lms; // log to stdout - core::Service logger{ std::make_unique(std::cout, core::EnumSet {core::logging::Severity::FATAL, core::logging::Severity::ERROR}) }; + core::Service logger{ std::make_unique(std::cout, core::EnumSet{ core::logging::Severity::FATAL, core::logging::Severity::ERROR }) }; ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } - diff --git a/src/libs/som/bench/SomBench.cpp b/src/libs/som/bench/SomBench.cpp index 23eb763f..57181e74 100644 --- a/src/libs/som/bench/SomBench.cpp +++ b/src/libs/som/bench/SomBench.cpp @@ -18,6 +18,7 @@ */ #include + #include #include "som/Network.hpp" @@ -50,6 +51,6 @@ namespace lms::som // Register the benchmark with custom range BENCHMARK(BM_Matrix)->Arg(3)->Arg(6)->Arg(12)->Arg(24); -} +} // namespace lms::som BENCHMARK_MAIN(); diff --git a/src/libs/som/impl/DataNormalizer.cpp b/src/libs/som/impl/DataNormalizer.cpp index 85cc32b3..df07ac1f 100644 --- a/src/libs/som/impl/DataNormalizer.cpp +++ b/src/libs/som/impl/DataNormalizer.cpp @@ -25,96 +25,85 @@ namespace lms::som { + template + static T variance(const std::vector& vec) + { + std::size_t size{ vec.size() }; -template -static -T -variance(const std::vector& vec) -{ - std::size_t size {vec.size()}; + if (size == 1) + return T{}; - if (size == 1) - return T {}; + const T mean{ std::accumulate(vec.begin(), vec.end(), T{}) / size }; - const T mean {std::accumulate(vec.begin(), vec.end(), T{}) / size}; + return std::accumulate(vec.begin(), vec.end(), T{}, + [mean, size](T accumulator, const T& val) { + return accumulator + ((val - mean) * (val - mean) / (size - 1)); + }); + } - return std::accumulate(vec.begin(), vec.end(), T {}, - [mean, size] (T accumulator, const T& val) - { - return accumulator + ((val - mean) * (val - mean) / (size - 1)); - }); -} + DataNormalizer::DataNormalizer(std::size_t inputDimCount) + : _inputDimCount{ inputDimCount } + { + } -DataNormalizer::DataNormalizer(std::size_t inputDimCount) -: _inputDimCount{inputDimCount} -{ -} + const DataNormalizer::MinMax& DataNormalizer::getValue(std::size_t index) const + { + return _minmax[index]; + } -const DataNormalizer::MinMax& -DataNormalizer::getValue(std::size_t index) const -{ - return _minmax[index]; -} + void DataNormalizer::setValue(std::size_t index, const MinMax& minMax) + { + _minmax[index] = minMax; + } -void -DataNormalizer::setValue(std::size_t index, const MinMax& minMax) -{ - _minmax[index] = minMax; -} + void DataNormalizer::computeNormalizationFactors(const std::vector& inputVectors) + { + if (inputVectors.empty()) + throw Exception("Empty input vectors"); -void -DataNormalizer::computeNormalizationFactors(const std::vector& inputVectors) -{ - if (inputVectors.empty()) - throw Exception("Empty input vectors"); + // For each dimension of the input, compute the min/max + _minmax.clear(); + _minmax.resize(_inputDimCount); - // For each dimension of the input, compute the min/max - _minmax.clear(); - _minmax.resize(_inputDimCount); + for (std::size_t dimId{}; dimId < _inputDimCount; ++dimId) + { + std::vector values; - for (std::size_t dimId {}; dimId < _inputDimCount; ++dimId) - { - std::vector values; + for (const auto& inputVector : inputVectors) + { + checkSameDimensions(inputVector, _inputDimCount); + values.push_back(inputVector[dimId]); + } - for (const auto& inputVector: inputVectors) - { - checkSameDimensions(inputVector, _inputDimCount); - values.push_back(inputVector[dimId]); - } + auto result{ std::minmax_element(values.begin(), values.end()) }; + _minmax[dimId] = { *result.first, *result.second }; + } + } - auto result {std::minmax_element(values.begin(), values.end())}; - _minmax[dimId] = {*result.first, *result.second}; - } -} + InputVector::value_type DataNormalizer::normalizeValue(InputVector::value_type value, std::size_t dimId) const + { + // clamp + if (value > _minmax[dimId].max) + value = _minmax[dimId].max; + else if (value < _minmax[dimId].min) + value = _minmax[dimId].min; -InputVector::value_type -DataNormalizer::normalizeValue(InputVector::value_type value, std::size_t dimId) const -{ - // clamp - if (value > _minmax[dimId].max) - value = _minmax[dimId].max; - else if (value < _minmax[dimId].min) - value = _minmax[dimId].min; + return (value - _minmax[dimId].min) / (_minmax[dimId].max - _minmax[dimId].min); + } - return (value - _minmax[dimId].min) / (_minmax[dimId].max - _minmax[dimId].min); -} + void DataNormalizer::normalizeData(InputVector& a) const + { + checkSameDimensions(a, _inputDimCount); -void -DataNormalizer::normalizeData(InputVector& a) const -{ - checkSameDimensions(a, _inputDimCount); - - for (std::size_t dimId {}; dimId < _inputDimCount; ++dimId) - { - a[dimId] = normalizeValue(a[dimId], dimId); - } -} - -void -DataNormalizer::dump(std::ostream& os) const -{ - for (std::size_t i {}; i < _inputDimCount; ++i) - os << "(" << _minmax[i].min << ", " << _minmax[i].max << ")"; -} + for (std::size_t dimId{}; dimId < _inputDimCount; ++dimId) + { + a[dimId] = normalizeValue(a[dimId], dimId); + } + } + void DataNormalizer::dump(std::ostream& os) const + { + for (std::size_t i{}; i < _inputDimCount; ++i) + os << "(" << _minmax[i].min << ", " << _minmax[i].max << ")"; + } } // namespace lms::som diff --git a/src/libs/som/impl/Network.cpp b/src/libs/som/impl/Network.cpp index 65226342..aa768108 100644 --- a/src/libs/som/impl/Network.cpp +++ b/src/libs/som/impl/Network.cpp @@ -31,300 +31,270 @@ namespace lms::som { + void checkSameDimensions(const InputVector& a, const InputVector& b) + { + if (!a.hasSameDimension(b)) + throw Exception("Bad data dimension count"); + } -void -checkSameDimensions(const InputVector& a, const InputVector& b) -{ - if (!a.hasSameDimension(b)) - throw Exception("Bad data dimension count"); -} + void checkSameDimensions(const InputVector& a, std::size_t inputDimCount) + { + if (a.getNbDimensions() != inputDimCount) + throw Exception("Bad data dimension count"); + } -void -checkSameDimensions(const InputVector& a, std::size_t inputDimCount) -{ - if (a.getNbDimensions() != inputDimCount) - throw Exception("Bad data dimension count"); -} + static LearningFactor defaultLearningFactor(Network::CurrentIteration iteration) + { + static const LearningFactor initialValue{ 1 }; -static LearningFactor -defaultLearningFactor(Network::CurrentIteration iteration) -{ - static const LearningFactor initialValue{1}; + return initialValue * exp(-((iteration.idIteration + 1) / static_cast(iteration.iterationCount))); + } - return initialValue * exp(-((iteration.idIteration + 1) / static_cast(iteration.iterationCount))); -} + static InputVector::Distance euclidianSquareDistance(const InputVector& a, const InputVector& b, const InputVector& weights) + { + return a.computeEuclidianSquareDistance(b, weights); + } -static InputVector::Distance -euclidianSquareDistance(const InputVector& a, const InputVector& b, const InputVector& weights) -{ - return a.computeEuclidianSquareDistance(b, weights); -} + static InputVector::value_type sigmaFunc(Network::CurrentIteration iteration) + { + constexpr InputVector::value_type sigma0{ 1 }; -static -InputVector::value_type -sigmaFunc(Network::CurrentIteration iteration) -{ - constexpr InputVector::value_type sigma0 {1}; + return sigma0 * std::exp(-((iteration.idIteration + 1) / static_cast(iteration.iterationCount))); + } - return sigma0 * std::exp(- ((iteration.idIteration + 1) / static_cast(iteration.iterationCount))); -} + static InputVector::value_type defaultNeighbourhoodFunc(Norm norm, const Network::CurrentIteration& iteration) + { + InputVector::value_type sigma{ sigmaFunc(iteration) }; -static -InputVector::value_type -defaultNeighbourhoodFunc(Norm norm, const Network::CurrentIteration& iteration) -{ - InputVector::value_type sigma {sigmaFunc(iteration)}; + return exp(-norm / (2 * sigma * sigma)); + } - return exp(-norm / (2 * sigma * sigma)); -} + Network::Network(Coordinate width, Coordinate height, std::size_t inputDimCount) + : _inputDimCount{ inputDimCount } + , _weights{ inputDimCount, static_cast(1) } + , _refVectors{ width, height, _inputDimCount } + , _distanceFunc{ euclidianSquareDistance } + , _learningFactorFunc{ defaultLearningFactor } + , _neighbourhoodFunc{ defaultNeighbourhoodFunc } + { + // init each vector with a random normalized value + for (Coordinate y{}; y < _refVectors.getHeight(); ++y) + { + for (Coordinate x{}; x < _refVectors.getWidth(); ++x) + { + for (InputVector::value_type& val : _refVectors.get({ x, y })) + val = core::random::getRealRandom(0, 1); + } + } + } -Network::Network(Coordinate width, Coordinate height, std::size_t inputDimCount) -: -_inputDimCount {inputDimCount}, -_weights {inputDimCount, static_cast(1)}, -_refVectors {width, height, _inputDimCount}, -_distanceFunc {euclidianSquareDistance}, -_learningFactorFunc {defaultLearningFactor}, -_neighbourhoodFunc {defaultNeighbourhoodFunc} -{ - // init each vector with a random normalized value - for (Coordinate y {}; y < _refVectors.getHeight(); ++y) - { - for (Coordinate x {}; x < _refVectors.getWidth(); ++x) - { - for (InputVector::value_type& val : _refVectors.get({x,y})) - val = core::random::getRealRandom(0, 1); - } - } -} + void Network::setDataWeights(const InputVector& weights) + { + checkSameDimensions(weights, _inputDimCount); -void -Network::setDataWeights(const InputVector& weights) -{ - checkSameDimensions(weights, _inputDimCount); + _weights = weights; + } - _weights = weights; -} + void Network::setRefVector(const Position& position, const InputVector& data) + { + checkSameDimensions(data, _inputDimCount); -void -Network::setRefVector(const Position& position, const InputVector& data) -{ - checkSameDimensions(data, _inputDimCount); + _refVectors[position] = data; + } - _refVectors[position] = data; -} + InputVector::Distance Network::getRefVectorsDistance(const Position& position1, const Position& position2) const + { + return _distanceFunc(_refVectors.get(position1), _refVectors.get(position2), _weights); + } -InputVector::Distance -Network::getRefVectorsDistance(const Position& position1, const Position& position2) const -{ - return _distanceFunc(_refVectors.get(position1), _refVectors.get(position2), _weights); -} + InputVector::Distance Network::computeRefVectorsDistanceMean() const + { + std::vector values; + values.reserve(2 * _refVectors.getHeight() * _refVectors.getWidth() - _refVectors.getWidth() - _refVectors.getHeight()); + for (Coordinate y{}; y < _refVectors.getHeight(); ++y) + { + for (Coordinate x{}; x < _refVectors.getWidth(); ++x) + { + if (x != _refVectors.getWidth() - 1) + values.emplace_back(getRefVectorsDistance({ x, y }, { x + 1, y })); + if (y != _refVectors.getHeight() - 1) + values.emplace_back(getRefVectorsDistance({ x, y }, { x, y + 1 })); + } + } -InputVector::Distance -Network::computeRefVectorsDistanceMean() const -{ - std::vector values; - values.reserve(2 * _refVectors.getHeight()*_refVectors.getWidth() - _refVectors.getWidth() - _refVectors.getHeight()); - for (Coordinate y {}; y < _refVectors.getHeight(); ++y) - { - for (Coordinate x {}; x < _refVectors.getWidth(); ++x) - { - if (x != _refVectors.getWidth() - 1) - values.emplace_back(getRefVectorsDistance( {x, y}, {x + 1, y})); - if (y != _refVectors.getHeight() - 1) - values.emplace_back(getRefVectorsDistance( {x, y}, {x, y + 1})); - } - } + return std::accumulate(values.begin(), values.end(), 0.) / values.size(); + } - return std::accumulate(values.begin(), values.end(), 0.) / values.size(); -} + double Network::computeRefVectorsDistanceMedian() const + { + std::vector values; + values.reserve(2 * _refVectors.getHeight() * _refVectors.getWidth() - _refVectors.getWidth() - _refVectors.getHeight()); + for (Coordinate y{}; y < _refVectors.getHeight(); ++y) + { + for (Coordinate x{}; x < _refVectors.getWidth(); ++x) + { + if (x != _refVectors.getWidth() - 1) + values.emplace_back(getRefVectorsDistance({ x, y }, { x + 1, y })); + if (y != _refVectors.getHeight() - 1) + values.emplace_back(getRefVectorsDistance({ x, y }, { x, y + 1 })); + } + } -double -Network::computeRefVectorsDistanceMedian() const -{ - std::vector values; - values.reserve(2*_refVectors.getHeight()*_refVectors.getWidth() - _refVectors.getWidth() - _refVectors.getHeight()); - for (Coordinate y {}; y < _refVectors.getHeight(); ++y) - { - for (Coordinate x {}; x < _refVectors.getWidth(); ++x) - { - if (x != _refVectors.getWidth() - 1) - values.emplace_back(getRefVectorsDistance( {x, y}, {x + 1, y})); - if (y != _refVectors.getHeight() - 1) - values.emplace_back(getRefVectorsDistance( {x, y}, {x, y + 1})); - } - } + std::sort(values.begin(), values.end()); - std::sort(values.begin(), values.end()); + return values[values.size() > 1 ? values.size() / 2 - 1 : 0]; + } - return values[values.size() > 1 ? values.size()/2 - 1 : 0]; -} + void Network::dump(std::ostream& os) const + { + os << "Width: " << _refVectors.getWidth() << ", Height: " << _refVectors.getHeight() << std::endl; + ; -void -Network::dump(std::ostream& os) const -{ - os << "Width: " << _refVectors.getWidth() << ", Height: " << _refVectors.getHeight() << std::endl;; + for (Coordinate y{}; y < _refVectors.getHeight(); ++y) + { + for (Coordinate x{}; x < _refVectors.getWidth(); ++x) + { + os << _refVectors.get({ x, y }) << " "; + } - for (Coordinate y {}; y < _refVectors.getHeight(); ++y) - { - for (Coordinate x {}; x < _refVectors.getWidth(); ++x) - { - os << _refVectors.get({x, y}) << " "; - } + os << std::endl; + } + os << std::endl; + } - os << std::endl; - } - os << std::endl; -} + Position Network::getClosestRefVectorPosition(const InputVector& data) const + { + return _refVectors.getPositionMinElement([&](const auto& a, const auto& b) { + return (_distanceFunc(a, data, _weights) < _distanceFunc(b, data, _weights)); + }); + } -Position -Network::getClosestRefVectorPosition(const InputVector& data) const -{ - return _refVectors.getPositionMinElement([&](const auto& a, const auto& b) - { - return (_distanceFunc(a, data, _weights) < _distanceFunc(b, data, _weights)); - }); -} + std::optional Network::getClosestRefVectorPosition(const InputVector& data, InputVector::Distance maxDistance) const + { + std::optional position{ getClosestRefVectorPosition(data) }; -std::optional -Network::getClosestRefVectorPosition(const InputVector& data, InputVector::Distance maxDistance) const -{ - std::optional position {getClosestRefVectorPosition(data)}; + if (_distanceFunc(data, _refVectors.get(*position), _weights) > maxDistance) + position.reset(); - if (_distanceFunc(data, _refVectors.get(*position), _weights) > maxDistance) - position.reset(); + return position; + } - return position; -} + std::optional Network::getClosestRefVectorPosition(const std::vector& refVectorsPosition, InputVector::Distance maxDistance) const + { + std::unordered_set neighboursPosition; + for (const Position& refVectorPosition : refVectorsPosition) + { + if (refVectorPosition.y > 0) + neighboursPosition.insert({ refVectorPosition.x, refVectorPosition.y - 1 }); + if (refVectorPosition.y < _refVectors.getHeight() - 1) + neighboursPosition.insert({ refVectorPosition.x, refVectorPosition.y + 1 }); + if (refVectorPosition.x > 0) + neighboursPosition.insert({ refVectorPosition.x - 1, refVectorPosition.y }); + if (refVectorPosition.x < _refVectors.getWidth() - 1) + neighboursPosition.insert({ refVectorPosition.x + 1, refVectorPosition.y }); + } -std::optional -Network::getClosestRefVectorPosition(const std::vector& refVectorsPosition, InputVector::Distance maxDistance) const -{ - std::unordered_set neighboursPosition; - for (const Position& refVectorPosition : refVectorsPosition) - { - if (refVectorPosition.y > 0) - neighboursPosition.insert({ refVectorPosition.x, refVectorPosition.y - 1 }); - if (refVectorPosition.y < _refVectors.getHeight() - 1) - neighboursPosition.insert({ refVectorPosition.x, refVectorPosition.y + 1 }); - if (refVectorPosition.x > 0) - neighboursPosition.insert({ refVectorPosition.x - 1, refVectorPosition.y }); - if (refVectorPosition.x < _refVectors.getWidth() - 1) - neighboursPosition.insert({ refVectorPosition.x + 1, refVectorPosition.y }); - } + // remove position that are in the input position + for (const auto& refVectorPosition : refVectorsPosition) + neighboursPosition.erase(refVectorPosition); - // remove position that are in the input position - for (const auto& refVectorPosition : refVectorsPosition) - neighboursPosition.erase(refVectorPosition); + if (neighboursPosition.empty()) + return std::nullopt; - if (neighboursPosition.empty()) - return std::nullopt; + // Now compute the distance for each neighbour + struct NeighbourInfo + { + Position position; + double distance; + }; - // Now compute the distance for each neighbour - struct NeighbourInfo - { - Position position; - double distance; - }; + std::vector neighboursInfo; + for (const Position& neighbourPosition : neighboursPosition) + { + auto min = std::min_element(refVectorsPosition.begin(), refVectorsPosition.end(), + [this, neighbourPosition](const auto& a, const auto& b) { + return (this->getRefVectorsDistance(a, neighbourPosition) < this->getRefVectorsDistance(b, neighbourPosition)); + }); - std::vector neighboursInfo; - for (const Position& neighbourPosition : neighboursPosition) - { - auto min = std::min_element(refVectorsPosition.begin(), refVectorsPosition.end(), - [this, neighbourPosition](const auto& a, const auto& b) - { - return (this->getRefVectorsDistance(a, neighbourPosition) < this->getRefVectorsDistance(b, neighbourPosition)); - }); + InputVector::Distance distance{ getRefVectorsDistance(neighbourPosition, *min) }; + if (distance > maxDistance) + continue; - InputVector::Distance distance {getRefVectorsDistance(neighbourPosition, *min)}; - if (distance > maxDistance) - continue; + neighboursInfo.emplace_back(NeighbourInfo{ neighbourPosition, distance }); + } - neighboursInfo.emplace_back(NeighbourInfo {neighbourPosition, distance}); - } + if (neighboursInfo.empty()) + return std::nullopt; - if (neighboursInfo.empty()) - return std::nullopt; + auto min{ std::min_element(std::cbegin(neighboursInfo), std::cend(neighboursInfo), + [&](const auto& a, const auto& b) { + return a.distance < b.distance; + }) }; - auto min {std::min_element(std::cbegin(neighboursInfo), std::cend(neighboursInfo), - [&](const auto& a, const auto& b) - { - return a.distance < b.distance; - })}; + return min->position; + } + static Norm computePositionNorm(const Position& c1, const Position& c2) + { + return std::sqrt((c1.x - c2.x) * (c1.x - c2.x) + (c1.y - c2.y) * (c1.y - c2.y)); + } - return min->position; -} + void Network::updateRefVectors(const Position& closestRefVectorPosition, const InputVector& input, LearningFactor learningFactor, const CurrentIteration& iteration) + { + for (Coordinate y{}; y < _refVectors.getHeight(); ++y) + { + for (Coordinate x{}; x < _refVectors.getWidth(); ++x) + { + InputVector& refVector{ _refVectors.get({ x, y }) }; -static Norm -computePositionNorm(const Position& c1, const Position& c2) -{ - return std::sqrt((c1.x - c2.x) * (c1.x - c2.x) + (c1.y - c2.y) * (c1.y - c2.y)); -} + const Norm norm{ computePositionNorm({ x, y }, closestRefVectorPosition) }; -void -Network::updateRefVectors(const Position& closestRefVectorPosition, const InputVector& input, LearningFactor learningFactor, const CurrentIteration& iteration) -{ - for (Coordinate y {}; y < _refVectors.getHeight(); ++y) - { - for (Coordinate x {}; x < _refVectors.getWidth(); ++x) - { - InputVector& refVector {_refVectors.get({x, y})}; + InputVector delta{ input - refVector }; + delta *= (learningFactor * _neighbourhoodFunc(norm, iteration)); - const Norm norm {computePositionNorm({x, y}, closestRefVectorPosition)}; + refVector += delta; + } + } + } - InputVector delta {input - refVector}; - delta *= (learningFactor * _neighbourhoodFunc(norm, iteration)); + void Network::train(const std::vector& inputData, std::size_t nbIterations, ProgressCallback progressCallback, RequestStopCallback requestStopCallback) + { + bool stopRequested{ false }; + std::vector inputDataShuffled; - refVector += delta; - } - } -} + inputDataShuffled.reserve(inputData.size()); + for (const auto& input : inputData) + inputDataShuffled.push_back(&input); -void -Network::train(const std::vector& inputData, std::size_t nbIterations, ProgressCallback progressCallback, RequestStopCallback requestStopCallback) -{ - bool stopRequested {false}; - std::vector inputDataShuffled; + for (std::size_t i{}; i < nbIterations; ++i) + { + CurrentIteration curIter{ i, nbIterations }; - inputDataShuffled.reserve(inputData.size()); - for (const auto& input : inputData) - inputDataShuffled.push_back(&input); + if (progressCallback) + progressCallback(curIter); - for (std::size_t i {}; i < nbIterations; ++i) - { - CurrentIteration curIter {i, nbIterations}; + core::random::shuffleContainer(inputDataShuffled); - if (progressCallback) - progressCallback(curIter); + const LearningFactor learningFactor{ _learningFactorFunc(curIter) }; - core::random::shuffleContainer(inputDataShuffled); + for (const InputVector* input : inputDataShuffled) + { + if (requestStopCallback) + stopRequested = requestStopCallback(); - const LearningFactor learningFactor {_learningFactorFunc(curIter)}; + if (stopRequested) + return; - for (const InputVector* input : inputDataShuffled) - { - if (requestStopCallback) - stopRequested = requestStopCallback(); - - if (stopRequested) - return; - - updateRefVectors(getClosestRefVectorPosition(*input), *input, learningFactor, curIter); - } - - if (stopRequested) - return; - } -} - -const InputVector& -Network::getRefVector(const Position& position) const -{ - return _refVectors[position]; -} + updateRefVectors(getClosestRefVectorPosition(*input), *input, learningFactor, curIter); + } + if (stopRequested) + return; + } + } + const InputVector& Network::getRefVector(const Position& position) const + { + return _refVectors[position]; + } } // namespace lms::som - - diff --git a/src/libs/som/include/som/DataNormalizer.hpp b/src/libs/som/include/som/DataNormalizer.hpp index 0ba14ace..29ee83c4 100644 --- a/src/libs/som/include/som/DataNormalizer.hpp +++ b/src/libs/som/include/som/DataNormalizer.hpp @@ -19,42 +19,40 @@ #pragma once -#include #include +#include #include "Network.hpp" namespace lms::som { + class DataNormalizer + { + public: + struct MinMax + { + InputVector::value_type min; + InputVector::value_type max; + }; -class DataNormalizer -{ - public: - struct MinMax - { - InputVector::value_type min; - InputVector::value_type max; - }; + DataNormalizer(std::size_t inputDimCount); - DataNormalizer(std::size_t inputDimCount); + std::size_t getInputDimCount() const { return _inputDimCount; } + const MinMax& getValue(std::size_t index) const; - std::size_t getInputDimCount() const { return _inputDimCount; } - const MinMax& getValue(std::size_t index) const; + void setValue(std::size_t index, const MinMax& minMax); - void setValue(std::size_t index, const MinMax& minMax); + void computeNormalizationFactors(const std::vector& dataSamples); - void computeNormalizationFactors(const std::vector& dataSamples); + void normalizeData(InputVector& data) const; - void normalizeData(InputVector& data) const; + void dump(std::ostream& os) const; - void dump(std::ostream& os) const; + private: + InputVector::value_type normalizeValue(InputVector::value_type value, std::size_t dimensionId) const; - private: - InputVector::value_type normalizeValue(InputVector::value_type value, std::size_t dimensionId) const; - - const std::size_t _inputDimCount; - - std::vector _minmax; // Indexed min/max used to normalize data -}; + const std::size_t _inputDimCount; + std::vector _minmax; // Indexed min/max used to normalize data + }; } // namespace lms::som diff --git a/src/libs/som/include/som/InputVector.hpp b/src/libs/som/include/som/InputVector.hpp index cc0f920a..ced4b2e4 100644 --- a/src/libs/som/include/som/InputVector.hpp +++ b/src/libs/som/include/som/InputVector.hpp @@ -20,176 +20,174 @@ #pragma once -#include #include +#include #include "core/Exception.hpp" namespace lms::som { + class Exception : public core::LmsException + { + public: + using LmsException::LmsException; + }; -class Exception : public core::LmsException -{ - public: - using LmsException::LmsException; -}; + class InputVector + { + public: + using value_type = double; + using Norm = double; + using Distance = double; -class InputVector -{ - public: - using value_type = double; - using Norm = double; - using Distance = double; + InputVector(std::size_t nbDimensions, value_type defaultValue = value_type{}) + : _values(nbDimensions, defaultValue) {} - InputVector(std::size_t nbDimensions, value_type defaultValue = value_type {}) : _values(nbDimensions, defaultValue) {} + bool hasSameDimension(const InputVector& other) const + { + return _values.size() == other._values.size(); + } - bool hasSameDimension(const InputVector& other) const - { - return _values.size() == other._values.size(); - } + std::size_t getNbDimensions() const + { + return _values.size(); + } - std::size_t getNbDimensions() const - { - return _values.size(); - } + value_type& operator[](std::size_t index) + { + if (index >= getNbDimensions()) + throw Exception("Bad range"); - value_type& operator[](std::size_t index) - { - if (index >= getNbDimensions()) - throw Exception("Bad range"); + return _values[index]; + } - return _values[index]; - } + value_type operator[](std::size_t index) const + { + if (index >= getNbDimensions()) + throw Exception("Bad range"); - value_type operator[](std::size_t index) const - { - if (index >= getNbDimensions()) - throw Exception("Bad range"); + return _values[index]; + } - return _values[index]; - } + InputVector& operator+=(const InputVector& other) + { + if (!hasSameDimension(other.getNbDimensions())) + throw Exception{ "Not the same dimension count" }; - InputVector& operator+=(const InputVector& other) - { - if (!hasSameDimension(other.getNbDimensions())) - throw Exception {"Not the same dimension count"}; + for (std::size_t i{}; i < _values.size(); ++i) + { + _values[i] += other[i]; + } - for (std::size_t i {}; i < _values.size(); ++i) - { - _values[i] += other[i]; - } + return *this; + } - return *this; - } + InputVector& operator-=(const InputVector& other) + { + if (!hasSameDimension(other.getNbDimensions())) + throw Exception{ "Not the same dimension count" }; - InputVector& operator-=(const InputVector& other) - { - if (!hasSameDimension(other.getNbDimensions())) - throw Exception {"Not the same dimension count"}; + for (std::size_t i{}; i < _values.size(); ++i) + { + _values[i] -= other[i]; + } - for (std::size_t i {}; i < _values.size(); ++i) - { - _values[i] -= other[i]; - } + return *this; + } - return *this; - } + InputVector& operator*=(value_type factor) + { + for (std::size_t i{}; i < _values.size(); ++i) + { + _values[i] *= factor; + } - InputVector& operator*=(value_type factor) - { - for (std::size_t i {}; i < _values.size(); ++i) - { - _values[i] *= factor; - } + return *this; + } - return *this; - } + Norm computeNorm() const + { + Norm res{}; + for (value_type val : _values) + res += val * val; + return std::sqrt(res); + } - Norm computeNorm() const - { - Norm res {}; - for (value_type val : _values) - res += val * val; - return std::sqrt(res); - } + Distance computeEuclidianSquareDistance(const InputVector& other, const InputVector& weights) const + { + if (!hasSameDimension(other.getNbDimensions()) + || !hasSameDimension(weights.getNbDimensions())) + { + throw Exception{ "Not the same dimension count" }; + } - Distance computeEuclidianSquareDistance(const InputVector& other, const InputVector& weights) const - { - if (!hasSameDimension(other.getNbDimensions()) - || !hasSameDimension(weights.getNbDimensions())) - { - throw Exception {"Not the same dimension count"}; - } + Distance res{}; - Distance res {}; + for (std::size_t i{}; i < getNbDimensions(); ++i) + { + const InputVector::value_type diff{ _values[i] - other._values[i] }; + res += diff * diff * weights._values[i]; + } - for (std::size_t i {}; i < getNbDimensions(); ++i) - { - const InputVector::value_type diff {_values[i] - other._values[i]}; - res += diff * diff * weights._values[i]; - } + return res; + } - return res; - } + std::vector::iterator begin() + { + return _values.begin(); + } - std::vector::iterator begin() - { - return _values.begin(); - } + std::vector::const_iterator begin() const + { + return _values.cbegin(); + } - std::vector::const_iterator begin() const - { - return _values.cbegin(); - } + std::vector::const_iterator cbegin() const + { + return _values.cbegin(); + } - std::vector::const_iterator cbegin() const - { - return _values.cbegin(); - } + std::vector::iterator end() + { + return _values.end(); + } - std::vector::iterator end() - { - return _values.end(); - } + std::vector::const_iterator end() const + { + return _values.cend(); + } - std::vector::const_iterator end() const - { - return _values.cend(); - } + std::vector::const_iterator cend() const + { + return _values.cend(); + } - std::vector::const_iterator cend() const - { - return _values.cend(); - } + private: + friend class InputVector operator-(const InputVector& a, const InputVector& b) + { + if (!a.hasSameDimension(b.getNbDimensions())) + throw Exception{ "Not the same dimension count" }; - private: - friend class InputVector operator-(const InputVector& a, const InputVector& b) - { - if (!a.hasSameDimension(b.getNbDimensions())) - throw Exception {"Not the same dimension count"}; + InputVector res{ a.getNbDimensions() }; - InputVector res {a.getNbDimensions()}; + for (std::size_t i{}; i < res._values.size(); ++i) + res._values[i] = a._values[i] - b._values[i]; - for (std::size_t i {}; i < res._values.size(); ++i) - res._values[i] = a._values[i] - b._values[i]; + return res; + } - return res; - } + friend std::ostream& operator<<(std::ostream& os, const InputVector& a) + { + os << "["; + for (value_type val : a._values) + { + os << val << " "; + } + os << "]"; - friend std::ostream& - operator<<(std::ostream& os, const InputVector& a) - { - os << "["; - for (value_type val : a._values) - { - os << val << " "; - } - os << "]"; + return os; + } - return os; - } - - std::vector _values; -}; - -} + std::vector _values; + }; +} // namespace lms::som diff --git a/src/libs/som/include/som/Matrix.hpp b/src/libs/som/include/som/Matrix.hpp index 9192a678..83d8c34e 100644 --- a/src/libs/som/include/som/Matrix.hpp +++ b/src/libs/som/include/som/Matrix.hpp @@ -47,7 +47,7 @@ namespace lms::som } }; - template + template class Matrix { public: @@ -61,7 +61,7 @@ namespace lms::som } template - Matrix(Coordinate width, Coordinate height, CtrArgs&& ... args) + Matrix(Coordinate width, Coordinate height, CtrArgs&&... args) : _width{ width } , _height{ height } { @@ -93,7 +93,7 @@ namespace lms::som T& operator[](const Position& position) { return get(position); } const T& operator[](const Position& position) const { return get(position); } - template + template Position getPositionMinElement(Func func) const { assert(!_values.empty()); @@ -105,12 +105,12 @@ namespace lms::som } private: - Coordinate _width{}; - Coordinate _height{}; - std::vector _values; + Coordinate _width{}; + Coordinate _height{}; + std::vector _values; }; -} // ns lms::som +} // namespace lms::som namespace std { @@ -125,5 +125,4 @@ namespace std return h1 ^ (h2 << 1); } }; -} // ns std - +} // namespace std diff --git a/src/libs/som/include/som/Network.hpp b/src/libs/som/include/som/Network.hpp index b951c9f8..2bb28901 100644 --- a/src/libs/som/include/som/Network.hpp +++ b/src/libs/som/include/som/Network.hpp @@ -19,17 +19,16 @@ #pragma once -#include +#include #include #include -#include +#include #include "InputVector.hpp" #include "Matrix.hpp" namespace lms::som { - using LearningFactor = InputVector::value_type; using Norm = InputVector::value_type; @@ -92,16 +91,14 @@ namespace lms::som void setNeighbourhoodFunc(NeighbourhoodFunc neighbourhoodFunc); private: - void updateRefVectors(const Position& closestRefVectorPosition, const InputVector& input, LearningFactor learningFactor, const CurrentIteration& iteration); std::size_t _inputDimCount{}; - InputVector _weights; // weight for each dimension + InputVector _weights; // weight for each dimension Matrix _refVectors; DistanceFunc _distanceFunc; LearningFactorFunc _learningFactorFunc; NeighbourhoodFunc _neighbourhoodFunc; }; - } // namespace lms::som diff --git a/src/libs/som/test/SomTest.cpp b/src/libs/som/test/SomTest.cpp index 38bee392..a6c98f76 100644 --- a/src/libs/som/test/SomTest.cpp +++ b/src/libs/som/test/SomTest.cpp @@ -18,117 +18,118 @@ */ #include + #include + #include "som/DataNormalizer.hpp" #include "som/Network.hpp" namespace lms::som { - static constexpr InputVector::value_type EPSILON = 0.01; + static constexpr InputVector::value_type EPSILON = 0.01; - TEST(som, Matrix) - { - { - Matrix testMatrix{ 2, 2, 123 }; - { - const Position pos{ 0, 0 }; - EXPECT_EQ(testMatrix[pos], 123); - } - { - const Position pos{ 0, 1 }; - EXPECT_EQ(testMatrix[pos], 123); - } - { - const Position pos{ 1, 0 }; - EXPECT_EQ(testMatrix[pos], 123); - } - { - const Position pos{ 1, 1 }; - EXPECT_EQ(testMatrix[pos], 123); - } - } - } + TEST(som, Matrix) + { + { + Matrix testMatrix{ 2, 2, 123 }; + { + const Position pos{ 0, 0 }; + EXPECT_EQ(testMatrix[pos], 123); + } + { + const Position pos{ 0, 1 }; + EXPECT_EQ(testMatrix[pos], 123); + } + { + const Position pos{ 1, 0 }; + EXPECT_EQ(testMatrix[pos], 123); + } + { + const Position pos{ 1, 1 }; + EXPECT_EQ(testMatrix[pos], 123); + } + } + } - TEST(som, InputVector) - { - { - InputVector test1{ 2 }; - test1[0] = 0; - test1[1] = 1; + TEST(som, InputVector) + { + { + InputVector test1{ 2 }; + test1[0] = 0; + test1[1] = 1; - InputVector test2{ 2 }; - test2[0] = 1; - test2[1] = 0; + InputVector test2{ 2 }; + test2[0] = 1; + test2[1] = 0; - InputVector test3{ test1 }; - test3 += test2; - EXPECT_LT(std::abs(test3[0] - 1), EPSILON); - EXPECT_LT(std::abs(test3[1] - 1), EPSILON); - } - } + InputVector test3{ test1 }; + test3 += test2; + EXPECT_LT(std::abs(test3[0] - 1), EPSILON); + EXPECT_LT(std::abs(test3[1] - 1), EPSILON); + } + } - TEST(som, Network) - { - Network network{ 2, 2, 1 }; + TEST(som, Network) + { + Network network{ 2, 2, 1 }; - const InputVector weights{ 1, 1 }; - std::vector trainData - { - { 1, 50 }, - { 1, 100 }, - { 1, 150 }, - { 1, 200 }, - }; + const InputVector weights{ 1, 1 }; + std::vector trainData{ + { 1, 50 }, + { 1, 100 }, + { 1, 150 }, + { 1, 200 }, + }; - DataNormalizer normalizer{ 1 }; - normalizer.computeNormalizationFactors(trainData); - for (auto& data : trainData) - normalizer.normalizeData(data); + DataNormalizer normalizer{ 1 }; + normalizer.computeNormalizationFactors(trainData); + for (auto& data : trainData) + normalizer.normalizeData(data); - network.dump(std::cout); - network.train(trainData, 20); - network.dump(std::cout); + network.dump(std::cout); + network.train(trainData, 20); + network.dump(std::cout); - auto distFunc{ network.getDistanceFunc() }; + auto distFunc{ network.getDistanceFunc() }; - EXPECT_LT((std::abs(distFunc({ 1, 0 }, { 1, 1 }, weights) - 1)), EPSILON); - EXPECT_LT((std::abs(distFunc({ 1, 0 }, { 1, 2 }, weights) - 4)), EPSILON); - EXPECT_LT(std::abs(distFunc({ 1, 0 }, { 1, 0.33 }, weights) - distFunc({ 1, 0.66 }, { 1, 1. }, weights)), EPSILON); + EXPECT_LT((std::abs(distFunc({ 1, 0 }, { 1, 1 }, weights) - 1)), EPSILON); + EXPECT_LT((std::abs(distFunc({ 1, 0 }, { 1, 2 }, weights) - 4)), EPSILON); + EXPECT_LT(std::abs(distFunc({ 1, 0 }, { 1, 0.33 }, weights) - distFunc({ 1, 0.66 }, { 1, 1. }, weights)), EPSILON); - { - std::unordered_set positions; - for (const InputVector& data : trainData) - positions.insert(network.getClosestRefVectorPosition(data)); + { + std::unordered_set positions; + for (const InputVector& data : trainData) + positions.insert(network.getClosestRefVectorPosition(data)); - EXPECT_EQ(positions.size(), 4); - } + EXPECT_EQ(positions.size(), 4); + } - { - Position pos{ network.getClosestRefVectorPosition(InputVector{1, 0.66}) }; - for (std::size_t i{}; i < 40; ++i) - { - InputVector input{ 1, 130 + static_cast(i) }; - normalizer.normalizeData(input); + { + Position pos{ network.getClosestRefVectorPosition(InputVector{ 1, 0.66 }) }; + for (std::size_t i{}; i < 40; ++i) + { + InputVector input{ 1, 130 + static_cast(i) }; + normalizer.normalizeData(input); - EXPECT_EQ(network.getClosestRefVectorPosition(input), pos); - } - } + EXPECT_EQ(network.getClosestRefVectorPosition(input), pos); + } + } - { - Position pos{ network.getClosestRefVectorPosition(InputVector{1, 1}) }; - for (std::size_t i{}; i < 40; ++i) - { - InputVector input{ 1, 180 + static_cast(i) }; - normalizer.normalizeData(input); + { + Position pos{ network.getClosestRefVectorPosition(InputVector{ 1, 1 }) }; + for (std::size_t i{}; i < 40; ++i) + { + InputVector input{ 1, 180 + static_cast(i) }; + normalizer.normalizeData(input); - EXPECT_EQ(network.getClosestRefVectorPosition(input), pos); - } - } - } -} + EXPECT_EQ(network.getClosestRefVectorPosition(input), pos); + } + } + } +} // namespace lms::som int main(int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } diff --git a/src/libs/subsonic/bench/SubsonicBench.cpp b/src/libs/subsonic/bench/SubsonicBench.cpp index 123bc39a..eee953fd 100644 --- a/src/libs/subsonic/bench/SubsonicBench.cpp +++ b/src/libs/subsonic/bench/SubsonicBench.cpp @@ -18,6 +18,7 @@ */ #include + #include #include "SubsonicResponse.hpp" @@ -47,7 +48,7 @@ namespace lms::api::subsonic::benchs return response; } - } + } // namespace static void BM_SubsonicResponse_generate(benchmark::State& state) { @@ -59,7 +60,7 @@ namespace lms::api::subsonic::benchs } } - template + template static void BM_SubsonicResponse_serialize(benchmark::State& state) { const Response response{ generateFakeResponse() }; @@ -74,6 +75,6 @@ namespace lms::api::subsonic::benchs BENCHMARK(BM_SubsonicResponse_generate)->Threads(1)->Threads(std::thread::hardware_concurrency()); BENCHMARK(BM_SubsonicResponse_serialize); BENCHMARK(BM_SubsonicResponse_serialize); -} +} // namespace lms::api::subsonic::benchs BENCHMARK_MAIN(); \ No newline at end of file diff --git a/src/libs/subsonic/impl/ClientInfo.hpp b/src/libs/subsonic/impl/ClientInfo.hpp index 045bafcf..1cca28bb 100644 --- a/src/libs/subsonic/impl/ClientInfo.hpp +++ b/src/libs/subsonic/impl/ClientInfo.hpp @@ -20,6 +20,7 @@ #pragma once #include + #include "ProtocolVersion.hpp" namespace lms::api::subsonic @@ -32,4 +33,4 @@ namespace lms::api::subsonic std::string password; ProtocolVersion version; }; -} +} // namespace lms::api::subsonic diff --git a/src/libs/subsonic/impl/ParameterParsing.cpp b/src/libs/subsonic/impl/ParameterParsing.cpp index 6811c690..5e5aaa62 100644 --- a/src/libs/subsonic/impl/ParameterParsing.cpp +++ b/src/libs/subsonic/impl/ParameterParsing.cpp @@ -39,4 +39,4 @@ namespace lms::api::subsonic return password; } -} \ No newline at end of file +} // namespace lms::api::subsonic \ No newline at end of file diff --git a/src/libs/subsonic/impl/ParameterParsing.hpp b/src/libs/subsonic/impl/ParameterParsing.hpp index 99b96e59..e3a650a0 100644 --- a/src/libs/subsonic/impl/ParameterParsing.hpp +++ b/src/libs/subsonic/impl/ParameterParsing.hpp @@ -22,11 +22,12 @@ #include #include -#include #include +#include -#include "database/Types.hpp" #include "core/String.hpp" +#include "database/Types.hpp" + #include "SubsonicResponse.hpp" namespace lms::api::subsonic @@ -84,5 +85,4 @@ namespace lms::api::subsonic bool hasParameter(const Wt::Http::ParameterMap& parameterMap, const std::string& param); std::string decodePasswordIfNeeded(const std::string& password); -} - +} // namespace lms::api::subsonic diff --git a/src/libs/subsonic/impl/ProtocolVersion.cpp b/src/libs/subsonic/impl/ProtocolVersion.cpp index 94b5027e..c3a6d3a7 100644 --- a/src/libs/subsonic/impl/ProtocolVersion.cpp +++ b/src/libs/subsonic/impl/ProtocolVersion.cpp @@ -51,5 +51,4 @@ namespace lms::core::stringUtils return version; } -} - +} // namespace lms::core::stringUtils diff --git a/src/libs/subsonic/impl/ProtocolVersion.hpp b/src/libs/subsonic/impl/ProtocolVersion.hpp index 7e54a304..28d63cfa 100644 --- a/src/libs/subsonic/impl/ProtocolVersion.hpp +++ b/src/libs/subsonic/impl/ProtocolVersion.hpp @@ -32,11 +32,10 @@ namespace lms::api::subsonic static inline constexpr ProtocolVersion defaultServerProtocolVersion{ 1, 16, 0 }; static inline constexpr std::string_view serverVersion{ "6" }; -} +} // namespace lms::api::subsonic namespace lms::core::stringUtils { template<> std::optional readAs(std::string_view str); } - diff --git a/src/libs/subsonic/impl/RequestContext.hpp b/src/libs/subsonic/impl/RequestContext.hpp index 03bf4ccc..f90b4940 100644 --- a/src/libs/subsonic/impl/RequestContext.hpp +++ b/src/libs/subsonic/impl/RequestContext.hpp @@ -24,6 +24,7 @@ #include #include "database/Object.hpp" + #include "ClientInfo.hpp" #include "ProtocolVersion.hpp" @@ -31,7 +32,7 @@ namespace lms::db { class Session; class User; -} +} // namespace lms::db namespace lms::api::subsonic { @@ -43,7 +44,6 @@ namespace lms::api::subsonic ClientInfo clientInfo; ProtocolVersion serverProtocolVersion; bool enableOpenSubsonic{ true }; - bool enableDefaultCover{ }; + bool enableDefaultCover{}; }; -} - +} // namespace lms::api::subsonic diff --git a/src/libs/subsonic/impl/SubsonicId.cpp b/src/libs/subsonic/impl/SubsonicId.cpp index 7d0f3ad4..9ec69508 100644 --- a/src/libs/subsonic/impl/SubsonicId.cpp +++ b/src/libs/subsonic/impl/SubsonicId.cpp @@ -141,4 +141,4 @@ namespace lms::core::stringUtils return std::nullopt; } -} +} // namespace lms::core::stringUtils diff --git a/src/libs/subsonic/impl/SubsonicId.hpp b/src/libs/subsonic/impl/SubsonicId.hpp index 770d3177..d7a88efa 100644 --- a/src/libs/subsonic/impl/SubsonicId.hpp +++ b/src/libs/subsonic/impl/SubsonicId.hpp @@ -19,16 +19,18 @@ #pragma once +#include "core/String.hpp" #include "database/ArtistId.hpp" #include "database/MediaLibraryId.hpp" #include "database/ReleaseId.hpp" #include "database/TrackId.hpp" #include "database/TrackListId.hpp" -#include "core/String.hpp" namespace lms::api::subsonic { - struct RootId {}; + struct RootId + { + }; std::string idToString(db::ArtistId id); std::string idToString(db::MediaLibraryId id); @@ -58,5 +60,4 @@ namespace lms::core::stringUtils template<> std::optional readAs(std::string_view str); -} - +} // namespace lms::core::stringUtils diff --git a/src/libs/subsonic/impl/SubsonicResource.cpp b/src/libs/subsonic/impl/SubsonicResource.cpp index 2e311628..311c420f 100644 --- a/src/libs/subsonic/impl/SubsonicResource.cpp +++ b/src/libs/subsonic/impl/SubsonicResource.cpp @@ -22,23 +22,29 @@ #include #include -#include "services/auth/IPasswordService.hpp" -#include "services/auth/IEnvService.hpp" -#include "database/Db.hpp" -#include "database/Session.hpp" -#include "database/User.hpp" #include "core/EnumSet.hpp" -#include "core/LiteralString.hpp" #include "core/IConfig.hpp" #include "core/ILogger.hpp" #include "core/ITraceLogger.hpp" +#include "core/LiteralString.hpp" #include "core/Service.hpp" #include "core/String.hpp" #include "core/Utils.hpp" +#include "database/Db.hpp" +#include "database/Session.hpp" +#include "database/User.hpp" +#include "services/auth/IEnvService.hpp" +#include "services/auth/IPasswordService.hpp" +#include "ParameterParsing.hpp" +#include "ProtocolVersion.hpp" +#include "RequestContext.hpp" +#include "SubsonicId.hpp" +#include "SubsonicResponse.hpp" +#include "Utils.hpp" #include "entrypoints/AlbumSongLists.hpp" -#include "entrypoints/Browsing.hpp" #include "entrypoints/Bookmarks.hpp" +#include "entrypoints/Browsing.hpp" #include "entrypoints/MediaAnnotation.hpp" #include "entrypoints/MediaLibraryScanning.hpp" #include "entrypoints/MediaRetrieval.hpp" @@ -46,12 +52,6 @@ #include "entrypoints/Searching.hpp" #include "entrypoints/System.hpp" #include "entrypoints/UserManagement.hpp" -#include "ParameterParsing.hpp" -#include "ProtocolVersion.hpp" -#include "RequestContext.hpp" -#include "SubsonicId.hpp" -#include "SubsonicResponse.hpp" -#include "Utils.hpp" namespace lms::api::subsonic { @@ -67,10 +67,10 @@ namespace lms::api::subsonic std::unordered_map res; core::Service::get()->visitStrings("api-subsonic-old-server-protocol-clients", - [&](std::string_view client) - { + [&](std::string_view client) { res.emplace(std::string{ client }, ProtocolVersion{ 1, 12, 0 }); - }, { "DSub" }); + }, + { "DSub" }); return res; } @@ -80,10 +80,10 @@ namespace lms::api::subsonic std::unordered_set res; core::Service::get()->visitStrings("api-open-subsonic-disabled-clients", - [&](std::string_view client) - { + [&](std::string_view client) { res.emplace(std::string{ client }); - }, { "DSub" }); + }, + { "DSub" }); return res; } @@ -93,23 +93,22 @@ namespace lms::api::subsonic std::unordered_set res; core::Service::get()->visitStrings("api-subsonic-default-cover-clients", - [&](std::string_view client) - { + [&](std::string_view client) { res.emplace(std::string{ client }); - }, { "DSub", "substreamer" }); + }, + { "DSub", "substreamer" }); return res; } std::string parameterMapToDebugString(const Wt::Http::ParameterMap& parameterMap) { - auto censorValue = [](const std::string& type, const std::string& value) -> std::string - { - if (type == "p" || type == "password") - return "*REDACTED*"; - else - return value; - }; + auto censorValue = [](const std::string& type, const std::string& value) -> std::string { + if (type == "p" || type == "password") + return "*REDACTED*"; + else + return value; + }; std::string res; @@ -148,124 +147,122 @@ namespace lms::api::subsonic using CheckImplementedFunc = std::function; struct RequestEntryPointInfo { - RequestHandlerFunc func; - core::EnumSet allowedUserTypes{ db::UserType::DEMO, db::UserType::REGULAR, db::UserType::ADMIN }; - CheckImplementedFunc checkFunc{}; + RequestHandlerFunc func; + core::EnumSet allowedUserTypes{ db::UserType::DEMO, db::UserType::REGULAR, db::UserType::ADMIN }; + CheckImplementedFunc checkFunc{}; }; - const std::unordered_map requestEntryPoints - { + const std::unordered_map requestEntryPoints{ // System - {"/ping", {handlePingRequest}}, - {"/getLicense", {handleGetLicenseRequest}}, - {"/getOpenSubsonicExtensions", {handleGetOpenSubsonicExtensions}}, + { "/ping", { handlePingRequest } }, + { "/getLicense", { handleGetLicenseRequest } }, + { "/getOpenSubsonicExtensions", { handleGetOpenSubsonicExtensions } }, // Browsing - {"/getMusicFolders", {handleGetMusicFoldersRequest}}, - {"/getIndexes", {handleGetIndexesRequest}}, - {"/getMusicDirectory", {handleGetMusicDirectoryRequest}}, - {"/getGenres", {handleGetGenresRequest}}, - {"/getArtists", {handleGetArtistsRequest}}, - {"/getArtist", {handleGetArtistRequest}}, - {"/getAlbum", {handleGetAlbumRequest}}, - {"/getSong", {handleGetSongRequest}}, - {"/getVideos", {handleNotImplemented}}, - {"/getArtistInfo", {handleGetArtistInfoRequest}}, - {"/getArtistInfo2", {handleGetArtistInfo2Request}}, - {"/getAlbumInfo", {handleNotImplemented}}, - {"/getAlbumInfo2", {handleNotImplemented}}, - {"/getSimilarSongs", {handleGetSimilarSongsRequest}}, - {"/getSimilarSongs2", {handleGetSimilarSongs2Request}}, - {"/getTopSongs", {handleGetTopSongs}}, + { "/getMusicFolders", { handleGetMusicFoldersRequest } }, + { "/getIndexes", { handleGetIndexesRequest } }, + { "/getMusicDirectory", { handleGetMusicDirectoryRequest } }, + { "/getGenres", { handleGetGenresRequest } }, + { "/getArtists", { handleGetArtistsRequest } }, + { "/getArtist", { handleGetArtistRequest } }, + { "/getAlbum", { handleGetAlbumRequest } }, + { "/getSong", { handleGetSongRequest } }, + { "/getVideos", { handleNotImplemented } }, + { "/getArtistInfo", { handleGetArtistInfoRequest } }, + { "/getArtistInfo2", { handleGetArtistInfo2Request } }, + { "/getAlbumInfo", { handleNotImplemented } }, + { "/getAlbumInfo2", { handleNotImplemented } }, + { "/getSimilarSongs", { handleGetSimilarSongsRequest } }, + { "/getSimilarSongs2", { handleGetSimilarSongs2Request } }, + { "/getTopSongs", { handleGetTopSongs } }, // Album/song lists - {"/getAlbumList", {handleGetAlbumListRequest}}, - {"/getAlbumList2", {handleGetAlbumList2Request}}, - {"/getRandomSongs", {handleGetRandomSongsRequest}}, - {"/getSongsByGenre", {handleGetSongsByGenreRequest}}, - {"/getNowPlaying", {handleNotImplemented}}, - {"/getStarred", {handleGetStarredRequest}}, - {"/getStarred2", {handleGetStarred2Request}}, + { "/getAlbumList", { handleGetAlbumListRequest } }, + { "/getAlbumList2", { handleGetAlbumList2Request } }, + { "/getRandomSongs", { handleGetRandomSongsRequest } }, + { "/getSongsByGenre", { handleGetSongsByGenreRequest } }, + { "/getNowPlaying", { handleNotImplemented } }, + { "/getStarred", { handleGetStarredRequest } }, + { "/getStarred2", { handleGetStarred2Request } }, // Searching - {"/search", {handleNotImplemented}}, - {"/search2", {handleSearch2Request}}, - {"/search3", {handleSearch3Request}}, + { "/search", { handleNotImplemented } }, + { "/search2", { handleSearch2Request } }, + { "/search3", { handleSearch3Request } }, // Playlists - {"/getPlaylists", {handleGetPlaylistsRequest}}, - {"/getPlaylist", {handleGetPlaylistRequest}}, - {"/createPlaylist", {handleCreatePlaylistRequest}}, - {"/updatePlaylist", {handleUpdatePlaylistRequest}}, - {"/deletePlaylist", {handleDeletePlaylistRequest}}, + { "/getPlaylists", { handleGetPlaylistsRequest } }, + { "/getPlaylist", { handleGetPlaylistRequest } }, + { "/createPlaylist", { handleCreatePlaylistRequest } }, + { "/updatePlaylist", { handleUpdatePlaylistRequest } }, + { "/deletePlaylist", { handleDeletePlaylistRequest } }, // Media retrieval - {"/hls", {handleNotImplemented}}, - {"/getCaptions", {handleNotImplemented}}, - {"/getLyrics", {handleNotImplemented}}, - {"/getAvatar", {handleNotImplemented}}, + { "/hls", { handleNotImplemented } }, + { "/getCaptions", { handleNotImplemented } }, + { "/getLyrics", { handleNotImplemented } }, + { "/getAvatar", { handleNotImplemented } }, // Media annotation - {"/star", {handleStarRequest}}, - {"/unstar", {handleUnstarRequest}}, - {"/setRating", {handleNotImplemented}}, - {"/scrobble", {handleScrobble}}, + { "/star", { handleStarRequest } }, + { "/unstar", { handleUnstarRequest } }, + { "/setRating", { handleNotImplemented } }, + { "/scrobble", { handleScrobble } }, // Sharing - {"/getShares", {handleNotImplemented}}, - {"/createShares", {handleNotImplemented}}, - {"/updateShare", {handleNotImplemented}}, - {"/deleteShare", {handleNotImplemented}}, + { "/getShares", { handleNotImplemented } }, + { "/createShares", { handleNotImplemented } }, + { "/updateShare", { handleNotImplemented } }, + { "/deleteShare", { handleNotImplemented } }, // Podcast - {"/getPodcasts", {handleNotImplemented}}, - {"/getNewestPodcasts", {handleNotImplemented}}, - {"/refreshPodcasts", {handleNotImplemented}}, - {"/createPodcastChannel", {handleNotImplemented}}, - {"/deletePodcastChannel", {handleNotImplemented}}, - {"/deletePodcastEpisode", {handleNotImplemented}}, - {"/downloadPodcastEpisode", {handleNotImplemented}}, + { "/getPodcasts", { handleNotImplemented } }, + { "/getNewestPodcasts", { handleNotImplemented } }, + { "/refreshPodcasts", { handleNotImplemented } }, + { "/createPodcastChannel", { handleNotImplemented } }, + { "/deletePodcastChannel", { handleNotImplemented } }, + { "/deletePodcastEpisode", { handleNotImplemented } }, + { "/downloadPodcastEpisode", { handleNotImplemented } }, // Jukebox - {"/jukeboxControl", {handleNotImplemented}}, + { "/jukeboxControl", { handleNotImplemented } }, // Internet radio - {"/getInternetRadioStations", {handleNotImplemented}}, - {"/createInternetRadioStation", {handleNotImplemented}}, - {"/updateInternetRadioStation", {handleNotImplemented}}, - {"/deleteInternetRadioStation", {handleNotImplemented}}, + { "/getInternetRadioStations", { handleNotImplemented } }, + { "/createInternetRadioStation", { handleNotImplemented } }, + { "/updateInternetRadioStation", { handleNotImplemented } }, + { "/deleteInternetRadioStation", { handleNotImplemented } }, // Chat - {"/getChatMessages", {handleNotImplemented}}, - {"/addChatMessages", {handleNotImplemented}}, + { "/getChatMessages", { handleNotImplemented } }, + { "/addChatMessages", { handleNotImplemented } }, // User management - {"/getUser", {handleGetUserRequest}}, - {"/getUsers", {handleGetUsersRequest, {db::UserType::ADMIN}}}, - {"/createUser", {handleCreateUserRequest, {db::UserType::ADMIN}, &utils::checkSetPasswordImplemented}}, - {"/updateUser", {handleUpdateUserRequest, {db::UserType::ADMIN}}}, - {"/deleteUser", {handleDeleteUserRequest, {db::UserType::ADMIN}}}, - {"/changePassword", {handleChangePassword, {db::UserType::REGULAR, db::UserType::ADMIN}, &utils::checkSetPasswordImplemented}}, + { "/getUser", { handleGetUserRequest } }, + { "/getUsers", { handleGetUsersRequest, { db::UserType::ADMIN } } }, + { "/createUser", { handleCreateUserRequest, { db::UserType::ADMIN }, &utils::checkSetPasswordImplemented } }, + { "/updateUser", { handleUpdateUserRequest, { db::UserType::ADMIN } } }, + { "/deleteUser", { handleDeleteUserRequest, { db::UserType::ADMIN } } }, + { "/changePassword", { handleChangePassword, { db::UserType::REGULAR, db::UserType::ADMIN }, &utils::checkSetPasswordImplemented } }, // Bookmarks - {"/getBookmarks", {handleGetBookmarks}}, - {"/createBookmark", {handleCreateBookmark}}, - {"/deleteBookmark", {handleDeleteBookmark}}, - {"/getPlayQueue", {handleNotImplemented}}, - {"/savePlayQueue", {handleNotImplemented}}, + { "/getBookmarks", { handleGetBookmarks } }, + { "/createBookmark", { handleCreateBookmark } }, + { "/deleteBookmark", { handleDeleteBookmark } }, + { "/getPlayQueue", { handleNotImplemented } }, + { "/savePlayQueue", { handleNotImplemented } }, // Media library scanning - {"/getScanStatus", {Scan::handleGetScanStatus, {db::UserType::ADMIN}}}, - {"/startScan", {Scan::handleStartScan, {db::UserType::ADMIN}}}, + { "/getScanStatus", { Scan::handleGetScanStatus, { db::UserType::ADMIN } } }, + { "/startScan", { Scan::handleStartScan, { db::UserType::ADMIN } } }, }; using MediaRetrievalHandlerFunc = std::function; - const std::unordered_map mediaRetrievalHandlers - { + const std::unordered_map mediaRetrievalHandlers{ // Media retrieval - {"/download", handleDownload}, - {"/stream", handleStream}, - {"/getCoverArt", handleGetCoverArt}, + { "/download", handleDownload }, + { "/stream", handleStream }, + { "/getCoverArt", handleGetCoverArt }, }; struct TLSMonotonicMemoryResourceCleaner @@ -280,7 +277,7 @@ namespace lms::api::subsonic TLSMonotonicMemoryResourceCleaner(const TLSMonotonicMemoryResourceCleaner&) = delete; TLSMonotonicMemoryResourceCleaner& operator=(const TLSMonotonicMemoryResourceCleaner&) = delete; }; - } + } // namespace SubsonicResource::SubsonicResource(db::Db& db) : _serverProtocolVersionsByClient{ readConfigProtocolVersions() } @@ -294,8 +291,8 @@ namespace lms::api::subsonic { static std::atomic curRequestId{}; - const std::size_t requestId{ curRequestId++ }; - TLSMonotonicMemoryResourceCleaner memoryResourceCleaner; + const std::size_t requestId{ curRequestId++ }; + TLSMonotonicMemoryResourceCleaner memoryResourceCleaner; LMS_LOG(API_SUBSONIC, DEBUG, "Handling request " << requestId << " '" << request.pathInfo() << "', continuation = " << (request.continuation() ? "true" : "false") << ", params = " << parameterMapToDebugString(request.getParameterMap())); @@ -327,7 +324,7 @@ namespace lms::api::subsonic const Response resp{ [&] { LMS_SCOPED_TRACE_DETAILED("Subsonic", "HandleRequest"); return itEntryPoint->second.func(requestContext); - }()}; + }() }; { LMS_SCOPED_TRACE_DETAILED("Subsonic", "WriteResponse"); @@ -356,8 +353,8 @@ namespace lms::api::subsonic catch (const Error& e) { LMS_LOG(API_SUBSONIC, ERROR, "Error while processing request '" << requestPath << "'" - << ", params = [" << parameterMapToDebugString(request.getParameterMap()) << "]" - << ", code = " << static_cast(e.getCode()) << ", msg = '" << e.getMessage() << "'"); + << ", params = [" << parameterMapToDebugString(request.getParameterMap()) << "]" + << ", code = " << static_cast(e.getCode()) << ", msg = '" << e.getMessage() << "'"); Response resp{ Response::createFailedResponse(protocolVersion, e) }; resp.write(response.out(), format); response.setMimeType(std::string{ ResponseFormatToMimeType(format) }); @@ -443,7 +440,7 @@ namespace lms::api::subsonic return user->getId(); } - if (auto * authEnvService{ core::Service::get() }) + if (auto* authEnvService{ core::Service::get() }) { const auto checkResult{ authEnvService->processRequest(request) }; if (checkResult.state != auth::IEnvService::CheckResult::State::Granted) @@ -451,7 +448,7 @@ namespace lms::api::subsonic return *checkResult.userId; } - else if (auto * authPasswordService{ core::Service::get() }) + else if (auto* authPasswordService{ core::Service::get() }) { const auto checkResult{ authPasswordService->checkUserPassword(boost::asio::ip::address::from_string(request.clientAddress()), clientInfo.user, clientInfo.password) }; @@ -471,4 +468,3 @@ namespace lms::api::subsonic } } // namespace lms::api::subsonic - diff --git a/src/libs/subsonic/impl/SubsonicResource.hpp b/src/libs/subsonic/impl/SubsonicResource.hpp index 33b99054..6303d580 100644 --- a/src/libs/subsonic/impl/SubsonicResource.hpp +++ b/src/libs/subsonic/impl/SubsonicResource.hpp @@ -19,14 +19,15 @@ #pragma once #include -#include #include +#include -#include #include +#include #include "database/Types.hpp" #include "database/UserId.hpp" + #include "ClientInfo.hpp" #include "RequestContext.hpp" @@ -37,26 +38,24 @@ namespace lms::db namespace lms::api::subsonic { - class SubsonicResource final : public Wt::WResource { - public: - SubsonicResource(db::Db& db); + public: + SubsonicResource(db::Db& db); - private: - void handleRequest(const Wt::Http::Request &request, Wt::Http::Response &response) override; - ProtocolVersion getServerProtocolVersion(const std::string& clientName) const; + private: + void handleRequest(const Wt::Http::Request& request, Wt::Http::Response& response) override; + ProtocolVersion getServerProtocolVersion(const std::string& clientName) const; - static void checkProtocolVersion(ProtocolVersion client, ProtocolVersion server); - ClientInfo getClientInfo(const Wt::Http::Request& request); - RequestContext buildRequestContext(const Wt::Http::Request& request); - db::UserId authenticateUser(const Wt::Http::Request& request, const ClientInfo& clientInfo); + static void checkProtocolVersion(ProtocolVersion client, ProtocolVersion server); + ClientInfo getClientInfo(const Wt::Http::Request& request); + RequestContext buildRequestContext(const Wt::Http::Request& request); + db::UserId authenticateUser(const Wt::Http::Request& request, const ClientInfo& clientInfo); - const std::unordered_map _serverProtocolVersionsByClient; - const std::unordered_set _openSubsonicDisabledClients; - const std::unordered_set _defaultCoverClients; + const std::unordered_map _serverProtocolVersionsByClient; + const std::unordered_set _openSubsonicDisabledClients; + const std::unordered_set _defaultCoverClients; - db::Db& _db; + db::Db& _db; }; - -} // namespace +} // namespace lms::api::subsonic diff --git a/src/libs/subsonic/impl/SubsonicResponse.cpp b/src/libs/subsonic/impl/SubsonicResponse.cpp index f82f7305..993e2dfc 100644 --- a/src/libs/subsonic/impl/SubsonicResponse.cpp +++ b/src/libs/subsonic/impl/SubsonicResponse.cpp @@ -20,12 +20,14 @@ #include "SubsonicResponse.hpp" #include -#include #include +#include + #include #include "core/Exception.hpp" #include "core/String.hpp" + #include "ProtocolVersion.hpp" namespace lms::api::subsonic @@ -34,8 +36,10 @@ namespace lms::api::subsonic { switch (format) { - case ResponseFormat::xml: return "text/xml"; - case ResponseFormat::json: return "application/json"; + case ResponseFormat::xml: + return "text/xml"; + case ResponseFormat::json: + return "application/json"; } return ""; @@ -92,7 +96,7 @@ namespace lms::api::subsonic assert(!_children.contains(key)); auto& values{ _childrenValues[key] }; values.emplace_back(string{ value }); - assert(std::all_of(std::cbegin(values) + 1, std::cend(values), [&](const ValueType& value) {return value.index() == values.front().index();})); + assert(std::all_of(std::cbegin(values) + 1, std::cend(values), [&](const ValueType& value) { return value.index() == values.front().index(); })); } void Response::Node::addArrayValue(Key key, long long value) @@ -100,7 +104,7 @@ namespace lms::api::subsonic assert(!_value); auto& values{ _childrenValues[key] }; values.emplace_back(value); - assert(std::all_of(std::cbegin(values) + 1, std::cend(values), [&](const ValueType& value) {return value.index() == values.front().index();})); + assert(std::all_of(std::cbegin(values) + 1, std::cend(values), [&](const ValueType& value) { return value.index() == values.front().index(); })); } Response::Node& Response::Node::createChild(Key key) @@ -186,60 +190,58 @@ namespace lms::api::subsonic void Response::writeXML(std::ostream& os) const { - std::function nodeToPropertyTree = [&](const Node& node) + std::function nodeToPropertyTree = [&](const Node& node) { + boost::property_tree::ptree res; + + for (const auto& [key, value] : node._attributes) { + if (std::holds_alternative(value)) + res.put("." + std::string{ key.str() }, std::get(value)); + else if (std::holds_alternative(value)) + res.put("." + std::string{ key.str() }, std::get(value)); + else if (std::holds_alternative(value)) + res.put("." + std::string{ key.str() }, std::get(value)); + else if (std::holds_alternative(value)) + res.put("." + std::string{ key.str() }, std::get(value)); + } + + auto valueToPropertyTree = [](const Node::ValueType& value) { boost::property_tree::ptree res; - - for (const auto& [key, value] : node._attributes) - { - if (std::holds_alternative(value)) - res.put("." + std::string{ key.str() }, std::get(value)); - else if (std::holds_alternative(value)) - res.put("." + std::string{ key.str() }, std::get(value)); - else if (std::holds_alternative(value)) - res.put("." + std::string{ key.str() }, std::get(value)); - else if (std::holds_alternative(value)) - res.put("." + std::string{ key.str() }, std::get(value)); - } - - auto valueToPropertyTree = [](const Node::ValueType& value) - { - boost::property_tree::ptree res; - std::visit([&](const auto& rawValue) - { - res.put_value(rawValue); - }, value); - - return res; - }; - - if (node._value) - { - res = valueToPropertyTree(*node._value); - } - else - { - for (const auto& [key, childNode] : node._children) - { - res.add_child(std::string{ key.str() }, nodeToPropertyTree(childNode)); - } - - for (const auto& [key, childArrayNodes] : node._childrenArrays) - { - for (const Node& childNode : childArrayNodes) - res.add_child(std::string{ key.str() }, nodeToPropertyTree(childNode)); - } - - for (const auto& [key, childArrayValues] : node._childrenValues) - { - for (const Response::Node::ValueType& value : childArrayValues) - res.add_child(std::string{ key.str() }, valueToPropertyTree(value)); - } - } + std::visit([&](const auto& rawValue) { + res.put_value(rawValue); + }, + value); return res; }; + if (node._value) + { + res = valueToPropertyTree(*node._value); + } + else + { + for (const auto& [key, childNode] : node._children) + { + res.add_child(std::string{ key.str() }, nodeToPropertyTree(childNode)); + } + + for (const auto& [key, childArrayNodes] : node._childrenArrays) + { + for (const Node& childNode : childArrayNodes) + res.add_child(std::string{ key.str() }, nodeToPropertyTree(childNode)); + } + + for (const auto& [key, childArrayValues] : node._childrenValues) + { + for (const Response::Node::ValueType& value : childArrayValues) + res.add_child(std::string{ key.str() }, valueToPropertyTree(value)); + } + } + + return res; + }; + const boost::property_tree::ptree root{ nodeToPropertyTree(_root) }; boost::property_tree::write_xml(os, root); } @@ -376,4 +378,4 @@ namespace lms::api::subsonic serializer.serializeNode(os, _root); } -} // namespace +} // namespace lms::api::subsonic diff --git a/src/libs/subsonic/impl/SubsonicResponse.hpp b/src/libs/subsonic/impl/SubsonicResponse.hpp index c1ecc59a..4c273ab5 100644 --- a/src/libs/subsonic/impl/SubsonicResponse.hpp +++ b/src/libs/subsonic/impl/SubsonicResponse.hpp @@ -26,6 +26,7 @@ #include #include "core/LiteralString.hpp" + #include "RequestContext.hpp" #include "SubsonicResponseAllocator.hpp" @@ -57,7 +58,8 @@ namespace lms::api::subsonic RequestedDataNotFound = 70, }; - Error(Code code) : _code{ code } {} + Error(Code code) + : _code{ code } {} virtual std::string getMessage() const = 0; @@ -70,7 +72,8 @@ namespace lms::api::subsonic class GenericError : public Error { public: - GenericError() : Error{ Code::Generic } {} + GenericError() + : Error{ Code::Generic } {} }; class RequiredParameterMissingError : public Error @@ -79,7 +82,8 @@ namespace lms::api::subsonic RequiredParameterMissingError(std::string_view param) : Error{ Code::RequiredParameterMissing } , _param{ param } - {} + { + } private: std::string getMessage() const override { return "Required parameter '" + _param + "' is missing."; } @@ -89,7 +93,9 @@ namespace lms::api::subsonic class ClientMustUpgradeError : public Error { public: - ClientMustUpgradeError() : Error{ Code::ClientMustUpgrade } {} + ClientMustUpgradeError() + : Error{ Code::ClientMustUpgrade } {} + private: std::string getMessage() const override { return "Incompatible Subsonic REST protocol version. Client must upgrade."; } }; @@ -97,7 +103,9 @@ namespace lms::api::subsonic class ServerMustUpgradeError : public Error { public: - ServerMustUpgradeError() : Error{ Code::ServerMustUpgrade } {} + ServerMustUpgradeError() + : Error{ Code::ServerMustUpgrade } {} + private: std::string getMessage() const override { return "Incompatible Subsonic REST protocol version. Server must upgrade."; } }; @@ -105,7 +113,9 @@ namespace lms::api::subsonic class WrongUsernameOrPasswordError : public Error { public: - WrongUsernameOrPasswordError() : Error{ Code::WrongUsernameOrPassword } {} + WrongUsernameOrPasswordError() + : Error{ Code::WrongUsernameOrPassword } {} + private: std::string getMessage() const override { return "Wrong username or password."; } }; @@ -113,7 +123,9 @@ namespace lms::api::subsonic class TokenAuthenticationNotSupportedForLDAPUsersError : public Error { public: - TokenAuthenticationNotSupportedForLDAPUsersError() : Error{ Code::TokenAuthenticationNotSupportedForLDAPUsers } {} + TokenAuthenticationNotSupportedForLDAPUsersError() + : Error{ Code::TokenAuthenticationNotSupportedForLDAPUsers } {} + private: std::string getMessage() const override { return "Token authentication not supported for LDAP users."; } }; @@ -121,7 +133,9 @@ namespace lms::api::subsonic class UserNotAuthorizedError : public Error { public: - UserNotAuthorizedError() : Error{ Code::UserNotAuthorized } {} + UserNotAuthorizedError() + : Error{ Code::UserNotAuthorized } {} + private: std::string getMessage() const override { return "User is not authorized for the given operation."; } }; @@ -129,7 +143,9 @@ namespace lms::api::subsonic class RequestedDataNotFoundError : public Error { public: - RequestedDataNotFoundError() : Error{ Code::RequestedDataNotFound } {} + RequestedDataNotFoundError() + : Error{ Code::RequestedDataNotFound } {} + private: std::string getMessage() const override { return "The requested data was not found."; } }; @@ -137,7 +153,9 @@ namespace lms::api::subsonic class InternalErrorGenericError : public GenericError { public: - InternalErrorGenericError(const std::string& message) : _message{ message } {} + InternalErrorGenericError(const std::string& message) + : _message{ message } {} + private: std::string getMessage() const override { return "Internal error: " + _message; } const std::string _message; @@ -181,7 +199,8 @@ namespace lms::api::subsonic class BadParameterGenericError : public GenericError { public: - BadParameterGenericError(const std::string& parameterName) : _parameterName{ parameterName } {} + BadParameterGenericError(const std::string& parameterName) + : _parameterName{ parameterName } {} private: std::string getMessage() const override { return "Parameter '" + _parameterName + "': bad value"; } @@ -192,7 +211,9 @@ namespace lms::api::subsonic class ParameterValueTooHighGenericError : public GenericError { public: - ParameterValueTooHighGenericError(std::string_view parameterName, std::size_t max) : _parameterName{ parameterName }, _max{ max } {} + ParameterValueTooHighGenericError(std::string_view parameterName, std::size_t max) + : _parameterName{ parameterName } + , _max{ max } {} private: std::string getMessage() const override { return "Parameter '" + _parameterName + "': bad value (max is " + std::to_string(_max) + ")"; } @@ -211,7 +232,7 @@ namespace lms::api::subsonic void setAttribute(Key key, std::string_view value); - template ::value>* = nullptr> + template::value>* = nullptr> void setAttribute(Key key, T value) { if constexpr (std::is_same::value) @@ -242,10 +263,10 @@ namespace lms::api::subsonic friend class Response; - template - using map = std::map< Key, Value, std::less, ResponseAllocator>>; + template + using map = std::map, ResponseAllocator>>; - template + template using vector = std::vector>; using string = std::basic_string, ResponseAllocator>; @@ -280,7 +301,7 @@ namespace lms::api::subsonic class JsonSerializer { - public: + public: void serializeNode(std::ostream& os, const Node& node); void serializeValue(std::ostream& os, const Node::ValueType& value); void serializeEscapedString(std::ostream&, std::string_view str); @@ -293,5 +314,4 @@ namespace lms::api::subsonic Node _root; }; -} // namespace - +} // namespace lms::api::subsonic diff --git a/src/libs/subsonic/impl/SubsonicResponseAllocator.hpp b/src/libs/subsonic/impl/SubsonicResponseAllocator.hpp index b8195a08..b0335a79 100644 --- a/src/libs/subsonic/impl/SubsonicResponseAllocator.hpp +++ b/src/libs/subsonic/impl/SubsonicResponseAllocator.hpp @@ -23,7 +23,7 @@ namespace lms::api::subsonic { // Stateless allocator that uses a shared MemoryResource - template + template class Allocator { public: @@ -37,10 +37,12 @@ namespace lms::api::subsonic constexpr Allocator() noexcept = default; - template - constexpr Allocator(const Allocator&) noexcept {} + template + constexpr Allocator(const Allocator&) noexcept + { + } - template + template struct rebind { using other = Allocator; @@ -59,17 +61,17 @@ namespace lms::api::subsonic }; template - bool operator==(const Allocator &, const Allocator &) + bool operator==(const Allocator&, const Allocator&) { return true; } template - bool operator!=(const Allocator &, const Allocator &) + bool operator!=(const Allocator&, const Allocator&) { return false; } - - template + + template using ResponseAllocator = Allocator; -} \ No newline at end of file +} // namespace lms::api::subsonic \ No newline at end of file diff --git a/src/libs/subsonic/impl/TLSMonotonicMemoryResource.hpp b/src/libs/subsonic/impl/TLSMonotonicMemoryResource.hpp index 07e03639..9ff50e79 100644 --- a/src/libs/subsonic/impl/TLSMonotonicMemoryResource.hpp +++ b/src/libs/subsonic/impl/TLSMonotonicMemoryResource.hpp @@ -18,10 +18,10 @@ */ #pragma once +#include #include #include #include -#include #include namespace lms::api::subsonic @@ -55,7 +55,7 @@ namespace lms::api::subsonic throw std::bad_alloc{}; assert(currentAddrAligned >= &_currentBlock->front()); - + std::byte* res{ currentAddrAligned }; _currentAddr = currentAddrAligned + byteCount; @@ -100,4 +100,4 @@ namespace lms::api::subsonic BlockType* _currentBlock{}; std::byte* _currentAddr{}; }; -} \ No newline at end of file +} // namespace lms::api::subsonic \ No newline at end of file diff --git a/src/libs/subsonic/impl/Utils.cpp b/src/libs/subsonic/impl/Utils.cpp index 8bf38dbe..f7746a53 100644 --- a/src/libs/subsonic/impl/Utils.cpp +++ b/src/libs/subsonic/impl/Utils.cpp @@ -22,6 +22,7 @@ #include "core/Service.hpp" #include "core/String.hpp" #include "services/auth/IPasswordService.hpp" + #include "SubsonicResponse.hpp" namespace lms::api::subsonic::utils @@ -38,4 +39,4 @@ namespace lms::api::subsonic::utils return core::stringUtils::replaceInString(name, "/", "_"); } -} \ No newline at end of file +} // namespace lms::api::subsonic::utils \ No newline at end of file diff --git a/src/libs/subsonic/impl/Utils.hpp b/src/libs/subsonic/impl/Utils.hpp index 95b0d3f3..4aff2a80 100644 --- a/src/libs/subsonic/impl/Utils.hpp +++ b/src/libs/subsonic/impl/Utils.hpp @@ -26,4 +26,4 @@ namespace lms::api::subsonic::utils { void checkSetPasswordImplemented(); std::string makeNameFilesystemCompatible(std::string_view name); -} \ No newline at end of file +} // namespace lms::api::subsonic::utils \ No newline at end of file diff --git a/src/libs/subsonic/impl/entrypoints/AlbumSongLists.cpp b/src/libs/subsonic/impl/entrypoints/AlbumSongLists.cpp index 7cfc60ab..00245248 100644 --- a/src/libs/subsonic/impl/entrypoints/AlbumSongLists.cpp +++ b/src/libs/subsonic/impl/entrypoints/AlbumSongLists.cpp @@ -19,6 +19,7 @@ #include "AlbumSongLists.hpp" +#include "core/Service.hpp" #include "database/Artist.hpp" #include "database/Cluster.hpp" #include "database/Release.hpp" @@ -27,12 +28,12 @@ #include "database/User.hpp" #include "services/feedback/IFeedbackService.hpp" #include "services/scrobbling/IScrobblingService.hpp" + +#include "ParameterParsing.hpp" +#include "SubsonicId.hpp" #include "responses/Album.hpp" #include "responses/Artist.hpp" #include "responses/Song.hpp" -#include "core/Service.hpp" -#include "ParameterParsing.hpp" -#include "SubsonicId.hpp" namespace lms::api::subsonic { @@ -245,10 +246,9 @@ namespace lms::api::subsonic params.setRange(Range{ 0, size }); params.setMediaLibrary(mediaLibraryId); - Track::find(context.dbSession, params, [&](const Track::pointer& track) - { - randomSongsNode.addArrayChild("song", createSongNode(context, track, context.user)); - }); + Track::find(context.dbSession, params, [&](const Track::pointer& track) { + randomSongsNode.addArrayChild("song", createSongNode(context, track, context.user)); + }); return response; } @@ -262,7 +262,7 @@ namespace lms::api::subsonic const MediaLibraryId mediaLibrary{ getParameterAs(context.parameters, "musicFolderId").value_or(MediaLibraryId{}) }; std::size_t count{ getParameterAs(context.parameters, "count").value_or(10) }; if (count > defaultMaxCountSize) - throw ParameterValueTooHighGenericError{"count", defaultMaxCountSize}; + throw ParameterValueTooHighGenericError{ "count", defaultMaxCountSize }; std::size_t offset{ getParameterAs(context.parameters, "offset").value_or(0) }; @@ -284,10 +284,9 @@ namespace lms::api::subsonic params.setRange(Range{ offset, count }); params.setMediaLibrary(mediaLibrary); - Track::find(context.dbSession, params, [&](const Track::pointer& track) - { - songsByGenreNode.addArrayChild("song", createSongNode(context, track, context.user)); - }); + Track::find(context.dbSession, params, [&](const Track::pointer& track) { + songsByGenreNode.addArrayChild("song", createSongNode(context, track, context.user)); + }); return response; } @@ -302,4 +301,4 @@ namespace lms::api::subsonic return handleGetStarredRequestCommon(context, true /* id3 */); } -} \ No newline at end of file +} // namespace lms::api::subsonic \ No newline at end of file diff --git a/src/libs/subsonic/impl/entrypoints/AlbumSongLists.hpp b/src/libs/subsonic/impl/entrypoints/AlbumSongLists.hpp index 0d704602..63582d6f 100644 --- a/src/libs/subsonic/impl/entrypoints/AlbumSongLists.hpp +++ b/src/libs/subsonic/impl/entrypoints/AlbumSongLists.hpp @@ -30,4 +30,4 @@ namespace lms::api::subsonic Response handleGetSongsByGenreRequest(RequestContext& context); Response handleGetStarredRequest(RequestContext& context); Response handleGetStarred2Request(RequestContext& context); -} +} // namespace lms::api::subsonic diff --git a/src/libs/subsonic/impl/entrypoints/Bookmarks.cpp b/src/libs/subsonic/impl/entrypoints/Bookmarks.cpp index 98f1a644..94567443 100644 --- a/src/libs/subsonic/impl/entrypoints/Bookmarks.cpp +++ b/src/libs/subsonic/impl/entrypoints/Bookmarks.cpp @@ -20,13 +20,14 @@ #include "Bookmarks.hpp" #include "database/Session.hpp" -#include "database/User.hpp" #include "database/Track.hpp" #include "database/TrackBookmark.hpp" -#include "responses/Bookmark.hpp" -#include "responses/Song.hpp" +#include "database/User.hpp" + #include "ParameterParsing.hpp" #include "SubsonicId.hpp" +#include "responses/Bookmark.hpp" +#include "responses/Song.hpp" namespace lms::api::subsonic { @@ -92,4 +93,4 @@ namespace lms::api::subsonic return Response::createOkResponse(context.serverProtocolVersion); } -} \ No newline at end of file +} // namespace lms::api::subsonic \ No newline at end of file diff --git a/src/libs/subsonic/impl/entrypoints/Bookmarks.hpp b/src/libs/subsonic/impl/entrypoints/Bookmarks.hpp index bcbb7921..b0a24e22 100644 --- a/src/libs/subsonic/impl/entrypoints/Bookmarks.hpp +++ b/src/libs/subsonic/impl/entrypoints/Bookmarks.hpp @@ -27,4 +27,4 @@ namespace lms::api::subsonic Response handleGetBookmarks(RequestContext& context); Response handleCreateBookmark(RequestContext& context); Response handleDeleteBookmark(RequestContext& context); -} +} // namespace lms::api::subsonic diff --git a/src/libs/subsonic/impl/entrypoints/Browsing.cpp b/src/libs/subsonic/impl/entrypoints/Browsing.cpp index a1d37584..660a8a80 100644 --- a/src/libs/subsonic/impl/entrypoints/Browsing.cpp +++ b/src/libs/subsonic/impl/entrypoints/Browsing.cpp @@ -19,31 +19,32 @@ #include "Browsing.hpp" +#include "core/ILogger.hpp" +#include "core/Random.hpp" +#include "core/Service.hpp" #include "database/Artist.hpp" #include "database/Cluster.hpp" #include "database/MediaLibrary.hpp" -#include "database/Session.hpp" #include "database/Release.hpp" +#include "database/Session.hpp" #include "database/Track.hpp" #include "database/User.hpp" #include "services/recommendation/IRecommendationService.hpp" #include "services/scrobbling/IScrobblingService.hpp" -#include "core/ILogger.hpp" -#include "core/Random.hpp" -#include "core/Service.hpp" + +#include "ParameterParsing.hpp" +#include "SubsonicId.hpp" +#include "Utils.hpp" #include "responses/Album.hpp" #include "responses/Artist.hpp" #include "responses/Genre.hpp" #include "responses/Song.hpp" -#include "ParameterParsing.hpp" -#include "SubsonicId.hpp" -#include "Utils.hpp" namespace lms::api::subsonic { using namespace db; - static const unsigned long long reportedDummyDateULong{ 946684800000ULL }; // 2000-01-01T00:00:00 UTC + static const unsigned long long reportedDummyDateULong{ 946684800000ULL }; // 2000-01-01T00:00:00 UTC namespace { @@ -70,7 +71,7 @@ namespace lms::api::subsonic artistInfoNode.createChild("musicBrainzId").setValue(artistMBID->getAsString()); } - auto similarArtistsId{ core::Service::get()->getSimilarArtists(id, {TrackArtistLinkType::Artist, TrackArtistLinkType::ReleaseArtist}, count) }; + auto similarArtistsId{ core::Service::get()->getSimilarArtists(id, { TrackArtistLinkType::Artist, TrackArtistLinkType::ReleaseArtist }, count) }; { auto transaction{ context.dbSession.createReadTransaction() }; @@ -170,7 +171,7 @@ namespace lms::api::subsonic { // API says: "Returns a random collection of songs from the given artist and similar artists" const std::size_t similarArtistCount{ count / 5 }; - std::vector artistIds{ core::Service::get()->getSimilarArtists(artistId, {TrackArtistLinkType::Artist, TrackArtistLinkType::ReleaseArtist}, similarArtistCount) }; + std::vector artistIds{ core::Service::get()->getSimilarArtists(artistId, { TrackArtistLinkType::Artist, TrackArtistLinkType::ReleaseArtist }, similarArtistCount) }; artistIds.push_back(artistId); const std::size_t meanTrackCountPerArtist{ (count / artistIds.size()) + 1 }; @@ -265,7 +266,7 @@ namespace lms::api::subsonic return response; } - } + } // namespace Response handleGetMusicFoldersRequest(RequestContext& context) { @@ -273,13 +274,12 @@ namespace lms::api::subsonic Response::Node& musicFoldersNode{ response.createNode("musicFolders") }; auto transaction{ context.dbSession.createReadTransaction() }; - MediaLibrary::find(context.dbSession, [&](const MediaLibrary::pointer& library) - { - Response::Node& musicFolderNode{ musicFoldersNode.createArrayChild("musicFolder") }; + MediaLibrary::find(context.dbSession, [&](const MediaLibrary::pointer& library) { + Response::Node& musicFolderNode{ musicFoldersNode.createArrayChild("musicFolder") }; - musicFolderNode.setAttribute("id", idToString(library->getId())); - musicFolderNode.setAttribute("name", library->getName()); - }); + musicFolderNode.setAttribute("id", idToString(library->getId())); + musicFolderNode.setAttribute("name", library->getName()); + }); return response; } @@ -310,10 +310,9 @@ namespace lms::api::subsonic directoryNode.setAttribute("name", "Music"); // TODO: this does not scale when a lot of artists are present - Artist::find(context.dbSession, Artist::FindParameters{}.setSortMethod(ArtistSortMethod::SortName), [&](const Artist::pointer& artist) - { - directoryNode.addArrayChild("child", createArtistNode(context, artist, context.user, false /* no id3 */)); - }); + Artist::find(context.dbSession, Artist::FindParameters{}.setSortMethod(ArtistSortMethod::SortName), [&](const Artist::pointer& artist) { + directoryNode.addArrayChild("child", createArtistNode(context, artist, context.user, false /* no id3 */)); + }); } else if (artistId) { @@ -325,10 +324,9 @@ namespace lms::api::subsonic directoryNode.setAttribute("name", utils::makeNameFilesystemCompatible(artist->getName())); - Release::find(context.dbSession, Release::FindParameters{}.setArtist(*artistId), [&](const Release::pointer& release) - { - directoryNode.addArrayChild("child", createAlbumNode(context, release, context.user, false /* no id3 */)); - }); + Release::find(context.dbSession, Release::FindParameters{}.setArtist(*artistId), [&](const Release::pointer& release) { + directoryNode.addArrayChild("child", createAlbumNode(context, release, context.user, false /* no id3 */)); + }); } else if (releaseId) { @@ -340,10 +338,9 @@ namespace lms::api::subsonic directoryNode.setAttribute("name", utils::makeNameFilesystemCompatible(release->getName())); - Track::find(context.dbSession, Track::FindParameters{}.setRelease(*releaseId).setSortMethod(TrackSortMethod::Release), [&](const Track::pointer& track) - { - directoryNode.addArrayChild("child", createSongNode(context, track, context.user)); - }); + Track::find(context.dbSession, Track::FindParameters{}.setRelease(*releaseId).setSortMethod(TrackSortMethod::Release), [&](const Track::pointer& track) { + directoryNode.addArrayChild("child", createSongNode(context, track, context.user)); + }); } else throw BadParameterGenericError{ "id" }; @@ -390,7 +387,7 @@ namespace lms::api::subsonic Response response{ Response::createOkResponse(context.serverProtocolVersion) }; Response::Node artistNode{ createArtistNode(context, artist, context.user, true /* id3 */) }; - const auto releases{ Release::find(context.dbSession, Release::FindParameters {}.setArtist(artist->getId())) }; + const auto releases{ Release::find(context.dbSession, Release::FindParameters{}.setArtist(artist->getId())) }; for (const Release::pointer& release : releases.results) artistNode.addArrayChild("album", createAlbumNode(context, release, context.user, true /* id3 */)); @@ -490,4 +487,4 @@ namespace lms::api::subsonic return response; } -} +} // namespace lms::api::subsonic diff --git a/src/libs/subsonic/impl/entrypoints/Browsing.hpp b/src/libs/subsonic/impl/entrypoints/Browsing.hpp index bfb169e2..48a0f09b 100644 --- a/src/libs/subsonic/impl/entrypoints/Browsing.hpp +++ b/src/libs/subsonic/impl/entrypoints/Browsing.hpp @@ -37,4 +37,4 @@ namespace lms::api::subsonic Response handleGetSimilarSongsRequest(RequestContext& context); Response handleGetSimilarSongs2Request(RequestContext& context); Response handleGetTopSongs(RequestContext& context); -} +} // namespace lms::api::subsonic diff --git a/src/libs/subsonic/impl/entrypoints/MediaAnnotation.cpp b/src/libs/subsonic/impl/entrypoints/MediaAnnotation.cpp index 27a537c1..2abdd212 100644 --- a/src/libs/subsonic/impl/entrypoints/MediaAnnotation.cpp +++ b/src/libs/subsonic/impl/entrypoints/MediaAnnotation.cpp @@ -21,13 +21,14 @@ #include +#include "core/Service.hpp" #include "database/ArtistId.hpp" #include "database/ReleaseId.hpp" #include "database/TrackId.hpp" #include "database/User.hpp" #include "services/feedback/IFeedbackService.hpp" #include "services/scrobbling/IScrobblingService.hpp" -#include "core/Service.hpp" + #include "ParameterParsing.hpp" #include "SubsonicId.hpp" @@ -55,7 +56,7 @@ namespace lms::api::subsonic return res; } - } + } // namespace Response handleStarRequest(RequestContext& context) { @@ -119,11 +120,11 @@ namespace lms::api::subsonic { const TrackId trackId{ ids[i] }; const unsigned long time{ times[i] }; - core::Service::get()->addTimedListen({ {context.user->getId(), trackId}, Wt::WDateTime::fromTime_t(static_cast(time / 1000)) }); + core::Service::get()->addTimedListen({ { context.user->getId(), trackId }, Wt::WDateTime::fromTime_t(static_cast(time / 1000)) }); } } } return Response::createOkResponse(context.serverProtocolVersion); } -} \ No newline at end of file +} // namespace lms::api::subsonic \ No newline at end of file diff --git a/src/libs/subsonic/impl/entrypoints/MediaAnnotation.hpp b/src/libs/subsonic/impl/entrypoints/MediaAnnotation.hpp index 0197afb3..a7b211c8 100644 --- a/src/libs/subsonic/impl/entrypoints/MediaAnnotation.hpp +++ b/src/libs/subsonic/impl/entrypoints/MediaAnnotation.hpp @@ -27,4 +27,4 @@ namespace lms::api::subsonic Response handleStarRequest(RequestContext& context); Response handleUnstarRequest(RequestContext& context); Response handleScrobble(RequestContext& context); -} \ No newline at end of file +} // namespace lms::api::subsonic \ No newline at end of file diff --git a/src/libs/subsonic/impl/entrypoints/MediaLibraryScanning.cpp b/src/libs/subsonic/impl/entrypoints/MediaLibraryScanning.cpp index a692b728..3a899b2b 100644 --- a/src/libs/subsonic/impl/entrypoints/MediaLibraryScanning.cpp +++ b/src/libs/subsonic/impl/entrypoints/MediaLibraryScanning.cpp @@ -19,8 +19,8 @@ #include "MediaLibraryScanning.hpp" -#include "services/scanner/IScannerService.hpp" #include "core/Service.hpp" +#include "services/scanner/IScannerService.hpp" namespace lms::api::subsonic::Scan { @@ -47,7 +47,7 @@ namespace lms::api::subsonic::Scan return statusResponse; } - } + } // namespace Response handleGetScanStatus(RequestContext& context) { @@ -66,5 +66,4 @@ namespace lms::api::subsonic::Scan return response; } -} - +} // namespace lms::api::subsonic::Scan diff --git a/src/libs/subsonic/impl/entrypoints/MediaLibraryScanning.hpp b/src/libs/subsonic/impl/entrypoints/MediaLibraryScanning.hpp index 9cdf3406..a36d9d92 100644 --- a/src/libs/subsonic/impl/entrypoints/MediaLibraryScanning.hpp +++ b/src/libs/subsonic/impl/entrypoints/MediaLibraryScanning.hpp @@ -26,5 +26,4 @@ namespace lms::api::subsonic::Scan { Response handleGetScanStatus(RequestContext& context); Response handleStartScan(RequestContext& context); -} - +} // namespace lms::api::subsonic::Scan diff --git a/src/libs/subsonic/impl/entrypoints/MediaRetrieval.cpp b/src/libs/subsonic/impl/entrypoints/MediaRetrieval.cpp index 843cbd0c..781d0f3a 100644 --- a/src/libs/subsonic/impl/entrypoints/MediaRetrieval.cpp +++ b/src/libs/subsonic/impl/entrypoints/MediaRetrieval.cpp @@ -24,15 +24,16 @@ #include "av/TranscodingParameters.hpp" #include "av/TranscodingResourceHandlerCreator.hpp" #include "av/Types.hpp" -#include "services/cover/ICoverService.hpp" +#include "core/FileResourceHandlerCreator.hpp" +#include "core/ILogger.hpp" +#include "core/IResourceHandler.hpp" +#include "core/String.hpp" +#include "core/Utils.hpp" #include "database/Session.hpp" #include "database/Track.hpp" #include "database/User.hpp" -#include "core/IResourceHandler.hpp" -#include "core/ILogger.hpp" -#include "core/FileResourceHandlerCreator.hpp" -#include "core/Utils.hpp" -#include "core/String.hpp" +#include "services/cover/ICoverService.hpp" + #include "ParameterParsing.hpp" #include "SubsonicId.hpp" @@ -40,15 +41,15 @@ namespace lms::api::subsonic { using namespace db; - namespace + namespace { std::optional subsonicStreamFormatToAvOutputFormat(std::string_view format) { for (const auto& [str, avFormat] : std::initializer_list>{ - {"mp3", av::transcoding::OutputFormat::MP3}, - {"opus", av::transcoding::OutputFormat::OGG_OPUS}, - {"vorbis", av::transcoding::OutputFormat::OGG_VORBIS}, - }) + { "mp3", av::transcoding::OutputFormat::MP3 }, + { "opus", av::transcoding::OutputFormat::OGG_OPUS }, + { "vorbis", av::transcoding::OutputFormat::OGG_VORBIS }, + }) { if (core::stringUtils::stringCaseInsensitiveEqual(str, format)) return avFormat; @@ -60,11 +61,16 @@ namespace lms::api::subsonic { switch (format) { - case db::TranscodingOutputFormat::MP3: return av::transcoding::OutputFormat::MP3; - case db::TranscodingOutputFormat::OGG_OPUS: return av::transcoding::OutputFormat::OGG_OPUS; - case db::TranscodingOutputFormat::MATROSKA_OPUS: return av::transcoding::OutputFormat::MATROSKA_OPUS; - case db::TranscodingOutputFormat::OGG_VORBIS: return av::transcoding::OutputFormat::OGG_VORBIS; - case db::TranscodingOutputFormat::WEBM_VORBIS: return av::transcoding::OutputFormat::WEBM_VORBIS; + case db::TranscodingOutputFormat::MP3: + return av::transcoding::OutputFormat::MP3; + case db::TranscodingOutputFormat::OGG_OPUS: + return av::transcoding::OutputFormat::OGG_OPUS; + case db::TranscodingOutputFormat::MATROSKA_OPUS: + return av::transcoding::OutputFormat::MATROSKA_OPUS; + case db::TranscodingOutputFormat::OGG_VORBIS: + return av::transcoding::OutputFormat::OGG_VORBIS; + case db::TranscodingOutputFormat::WEBM_VORBIS: + return av::transcoding::OutputFormat::WEBM_VORBIS; } return av::transcoding::OutputFormat::OGG_OPUS; } @@ -147,7 +153,7 @@ namespace lms::api::subsonic requestedFormat = userTranscodeFormatToAvFormat(context.user->getSubsonicDefaultTranscodingOutputFormat()); } - if (!requestedFormat && (maxBitRate == 0 || track->getBitrate() <= maxBitRate )) + if (!requestedFormat && (maxBitRate == 0 || track->getBitrate() <= maxBitRate)) { LMS_LOG(API_SUBSONIC, DEBUG, "File's bitrate is compatible with parameters => no transcoding"); return parameters; // no transcoding needed @@ -166,7 +172,7 @@ namespace lms::api::subsonic } bitrate = maxBitRate; } - + if (!requestedFormat) requestedFormat = userTranscodeFormatToAvFormat(context.user->getSubsonicDefaultTranscodingOutputFormat()); if (!bitrate) @@ -181,7 +187,7 @@ namespace lms::api::subsonic return parameters; } - } + } // namespace void handleDownload(RequestContext& context, const Wt::Http::Request& request, Wt::Http::Response& response) { diff --git a/src/libs/subsonic/impl/entrypoints/MediaRetrieval.hpp b/src/libs/subsonic/impl/entrypoints/MediaRetrieval.hpp index 81b854a9..f99085d1 100644 --- a/src/libs/subsonic/impl/entrypoints/MediaRetrieval.hpp +++ b/src/libs/subsonic/impl/entrypoints/MediaRetrieval.hpp @@ -29,5 +29,4 @@ namespace lms::api::subsonic void handleDownload(RequestContext& context, const Wt::Http::Request& request, Wt::Http::Response& response); void handleStream(RequestContext& context, const Wt::Http::Request& request, Wt::Http::Response& response); void handleGetCoverArt(RequestContext& context, const Wt::Http::Request& request, Wt::Http::Response& response); -} - +} // namespace lms::api::subsonic diff --git a/src/libs/subsonic/impl/entrypoints/Playlists.cpp b/src/libs/subsonic/impl/entrypoints/Playlists.cpp index 520e2d9e..536998bd 100644 --- a/src/libs/subsonic/impl/entrypoints/Playlists.cpp +++ b/src/libs/subsonic/impl/entrypoints/Playlists.cpp @@ -23,10 +23,11 @@ #include "database/Track.hpp" #include "database/TrackList.hpp" #include "database/User.hpp" -#include "responses/Playlist.hpp" -#include "responses/Song.hpp" + #include "ParameterParsing.hpp" #include "SubsonicId.hpp" +#include "responses/Playlist.hpp" +#include "responses/Song.hpp" namespace lms::api::subsonic { @@ -200,4 +201,4 @@ namespace lms::api::subsonic return Response::createOkResponse(context.serverProtocolVersion); } -} \ No newline at end of file +} // namespace lms::api::subsonic \ No newline at end of file diff --git a/src/libs/subsonic/impl/entrypoints/Playlists.hpp b/src/libs/subsonic/impl/entrypoints/Playlists.hpp index 01c39d20..0ef17cf1 100644 --- a/src/libs/subsonic/impl/entrypoints/Playlists.hpp +++ b/src/libs/subsonic/impl/entrypoints/Playlists.hpp @@ -29,4 +29,4 @@ namespace lms::api::subsonic Response handleCreatePlaylistRequest(RequestContext& context); Response handleUpdatePlaylistRequest(RequestContext& context); Response handleDeletePlaylistRequest(RequestContext& context); -} \ No newline at end of file +} // namespace lms::api::subsonic \ No newline at end of file diff --git a/src/libs/subsonic/impl/entrypoints/Searching.cpp b/src/libs/subsonic/impl/entrypoints/Searching.cpp index 743be7ed..008f3bdf 100644 --- a/src/libs/subsonic/impl/entrypoints/Searching.cpp +++ b/src/libs/subsonic/impl/entrypoints/Searching.cpp @@ -20,8 +20,8 @@ #include "Searching.hpp" #include -#include #include +#include #include "core/Random.hpp" #include "database/Artist.hpp" @@ -29,11 +29,12 @@ #include "database/Session.hpp" #include "database/Track.hpp" #include "database/User.hpp" + +#include "ParameterParsing.hpp" +#include "SubsonicId.hpp" #include "responses/Album.hpp" #include "responses/Artist.hpp" #include "responses/Song.hpp" -#include "ParameterParsing.hpp" -#include "SubsonicId.hpp" namespace lms::api::subsonic { @@ -44,7 +45,7 @@ namespace lms::api::subsonic // Search endpoints can be used to scan/sync the database // This class is used to keep track of the current scans, in order to retrieve the last objectId // to speed up the query of the following range (avoid the 'offset' cost) - template + template class ScanTracker { public: @@ -71,7 +72,7 @@ namespace lms::api::subsonic }; static constexpr std::size_t maxScanCount{ 50 }; - static constexpr ClockType::duration maxEntryDuration{ std::chrono::seconds{30} }; + static constexpr ClockType::duration maxEntryDuration{ std::chrono::seconds{ 30 } }; std::mutex _mutex; std::map _ongoingScans; @@ -126,20 +127,18 @@ namespace lms::api::subsonic const std::size_t artistOffset{ getParameterAs(context.parameters, "artistOffset").value_or(0) }; ArtistId lastRetrievedId; - auto findArtists{ [&] - { - Artist::FindParameters params; - params.setKeywords(keywords); - params.setRange(Range{ artistOffset, artistCount }); - params.setMediaLibrary(mediaLibrary); - params.setSortMethod(ArtistSortMethod::Id); // must be consistent with both methods + auto findArtists{ [&] { + Artist::FindParameters params; + params.setKeywords(keywords); + params.setRange(Range{ artistOffset, artistCount }); + params.setMediaLibrary(mediaLibrary); + params.setSortMethod(ArtistSortMethod::Id); // must be consistent with both methods - Artist::find(context.dbSession, params, [&](const Artist::pointer& artist) - { - searchResultNode.addArrayChild("artist", createArtistNode(context, artist, user, id3)); - lastRetrievedId = artist->getId(); - }); - } }; + Artist::find(context.dbSession, params, [&](const Artist::pointer& artist) { + searchResultNode.addArrayChild("artist", createArtistNode(context, artist, user, id3)); + lastRetrievedId = artist->getId(); + }); + } }; if (!keywords.empty()) { @@ -147,8 +146,7 @@ namespace lms::api::subsonic } else { - ScanTracker::ScanInfo scanInfo - { + ScanTracker::ScanInfo scanInfo{ .clientAddress = context.clientInfo.ipAddress, .clientName = context.clientInfo.name, .userName = context.clientInfo.user, @@ -158,10 +156,11 @@ namespace lms::api::subsonic if (ArtistId cachedLastRetrievedId{ currentScansInProgress.extractLastRetrievedObjectId(scanInfo) }; cachedLastRetrievedId.isValid()) { - Artist::find(context.dbSession, cachedLastRetrievedId, artistCount, [&](const Artist::pointer& artist) - { + Artist::find( + context.dbSession, cachedLastRetrievedId, artistCount, [&](const Artist::pointer& artist) { searchResultNode.addArrayChild("artist", createArtistNode(context, artist, user, id3)); - }, mediaLibrary); + }, + mediaLibrary); lastRetrievedId = cachedLastRetrievedId; } else @@ -192,19 +191,17 @@ namespace lms::api::subsonic ReleaseId lastRetrievedId; - auto findReleases{ [&] - { + auto findReleases{ [&] { Release::FindParameters params; params.setKeywords(keywords); params.setRange(Range{ albumOffset, albumCount }); params.setMediaLibrary(mediaLibrary); params.setSortMethod(ReleaseSortMethod::Id); // must be consistent with both methods - Release::find(context.dbSession, params, [&](const Release::pointer& release) - { - searchResultNode.addArrayChild("album", createAlbumNode(context, release, user, id3)); - lastRetrievedId = release->getId(); - }); + Release::find(context.dbSession, params, [&](const Release::pointer& release) { + searchResultNode.addArrayChild("album", createAlbumNode(context, release, user, id3)); + lastRetrievedId = release->getId(); + }); } }; if (!keywords.empty()) @@ -213,8 +210,7 @@ namespace lms::api::subsonic } else { - ScanTracker::ScanInfo scanInfo - { + ScanTracker::ScanInfo scanInfo{ .clientAddress = context.clientInfo.ipAddress, .clientName = context.clientInfo.name, .userName = context.clientInfo.user, @@ -224,10 +220,11 @@ namespace lms::api::subsonic if (ReleaseId cachedLastRetrievedId{ currentScansInProgress.extractLastRetrievedObjectId(scanInfo) }; cachedLastRetrievedId.isValid()) { - Release::find(context.dbSession, cachedLastRetrievedId, albumCount, [&](const Release::pointer& release) - { + Release::find( + context.dbSession, cachedLastRetrievedId, albumCount, [&](const Release::pointer& release) { searchResultNode.addArrayChild("album", createAlbumNode(context, release, user, id3)); - }, mediaLibrary); + }, + mediaLibrary); lastRetrievedId = cachedLastRetrievedId; } else @@ -258,19 +255,17 @@ namespace lms::api::subsonic TrackId lastRetrievedId; - auto findTracks{ [&] - { + auto findTracks{ [&] { Track::FindParameters params; params.setKeywords(keywords); params.setRange(Range{ songOffset, songCount }); params.setMediaLibrary(mediaLibrary); params.setSortMethod(TrackSortMethod::Id); // must be consistent with both methods - Track::find(context.dbSession, params, [&](const Track::pointer& track) - { - searchResultNode.addArrayChild("song", createSongNode(context, track, user)); - lastRetrievedId = track->getId(); - }); + Track::find(context.dbSession, params, [&](const Track::pointer& track) { + searchResultNode.addArrayChild("song", createSongNode(context, track, user)); + lastRetrievedId = track->getId(); + }); } }; if (!keywords.empty()) @@ -279,8 +274,7 @@ namespace lms::api::subsonic } else { - ScanTracker::ScanInfo scanInfo - { + ScanTracker::ScanInfo scanInfo{ .clientAddress = context.clientInfo.ipAddress, .clientName = context.clientInfo.name, .userName = context.clientInfo.user, @@ -290,10 +284,11 @@ namespace lms::api::subsonic if (TrackId cachedLastRetrievedId{ currentScansInProgress.extractLastRetrievedObjectId(scanInfo) }; cachedLastRetrievedId.isValid()) { - Track::find(context.dbSession, cachedLastRetrievedId, songCount, [&](const Track::pointer& track) - { + Track::find( + context.dbSession, cachedLastRetrievedId, songCount, [&](const Track::pointer& track) { searchResultNode.addArrayChild("song", createSongNode(context, track, user)); - }, mediaLibrary); + }, + mediaLibrary); lastRetrievedId = cachedLastRetrievedId; } else @@ -308,7 +303,7 @@ namespace lms::api::subsonic } } } - } + } // namespace namespace { @@ -340,7 +335,7 @@ namespace lms::api::subsonic return response; } - } + } // namespace Response handleSearch2Request(RequestContext& context) { @@ -351,4 +346,4 @@ namespace lms::api::subsonic { return handleSearchRequestCommon(context, true /* id3 */); } -} \ No newline at end of file +} // namespace lms::api::subsonic \ No newline at end of file diff --git a/src/libs/subsonic/impl/entrypoints/Searching.hpp b/src/libs/subsonic/impl/entrypoints/Searching.hpp index db433a13..4d852282 100644 --- a/src/libs/subsonic/impl/entrypoints/Searching.hpp +++ b/src/libs/subsonic/impl/entrypoints/Searching.hpp @@ -26,4 +26,4 @@ namespace lms::api::subsonic { Response handleSearch2Request(RequestContext& context); Response handleSearch3Request(RequestContext& context); -} +} // namespace lms::api::subsonic diff --git a/src/libs/subsonic/impl/entrypoints/System.cpp b/src/libs/subsonic/impl/entrypoints/System.cpp index 45ca2d91..b6ae4be6 100644 --- a/src/libs/subsonic/impl/entrypoints/System.cpp +++ b/src/libs/subsonic/impl/entrypoints/System.cpp @@ -37,4 +37,4 @@ namespace lms::api::subsonic return response; }; -} +} // namespace lms::api::subsonic diff --git a/src/libs/subsonic/impl/entrypoints/System.hpp b/src/libs/subsonic/impl/entrypoints/System.hpp index 83e48c33..b5be1347 100644 --- a/src/libs/subsonic/impl/entrypoints/System.hpp +++ b/src/libs/subsonic/impl/entrypoints/System.hpp @@ -27,4 +27,4 @@ namespace lms::api::subsonic Response handlePingRequest(RequestContext& context); Response handleGetLicenseRequest(RequestContext& context); Response handleGetOpenSubsonicExtensions(RequestContext& context); -} +} // namespace lms::api::subsonic diff --git a/src/libs/subsonic/impl/entrypoints/UserManagement.cpp b/src/libs/subsonic/impl/entrypoints/UserManagement.cpp index e9576a78..3e335110 100644 --- a/src/libs/subsonic/impl/entrypoints/UserManagement.cpp +++ b/src/libs/subsonic/impl/entrypoints/UserManagement.cpp @@ -1,24 +1,26 @@ #include "UserManagement.hpp" +#include "core/Service.hpp" #include "database/Session.hpp" #include "database/User.hpp" #include "services/auth/IPasswordService.hpp" -#include "core/Service.hpp" -#include "responses/User.hpp" + #include "ParameterParsing.hpp" #include "Utils.hpp" +#include "responses/User.hpp" namespace lms::api::subsonic { using namespace db; - namespace { + namespace + { void checkUserIsMySelfOrAdmin(RequestContext& context, const std::string& username) { if (context.user->getLoginName() != username && !context.user->isAdmin()) throw UserNotAuthorizedError{}; } - } + } // namespace Response handleGetUserRequest(RequestContext& context) { @@ -44,10 +46,9 @@ namespace lms::api::subsonic Response::Node& usersNode{ response.createNode("users") }; auto transaction{ context.dbSession.createReadTransaction() }; - User::find(context.dbSession, User::FindParameters{}, [&](const User::pointer& user) - { - usersNode.addArrayChild("user", createUserNode(user)); - }); + User::find(context.dbSession, User::FindParameters{}, [&](const User::pointer& user) { + usersNode.addArrayChild("user", createUserNode(user)); + }); return response; } @@ -70,13 +71,12 @@ namespace lms::api::subsonic userId = user->getId(); } - auto removeCreatedUser{ [&] - { - auto transaction {context.dbSession.createWriteTransaction()}; - User::pointer user{ User::find(context.dbSession, userId) }; - if (user) - user.remove(); - } }; + auto removeCreatedUser{ [&] { + auto transaction{ context.dbSession.createWriteTransaction() }; + User::pointer user{ User::find(context.dbSession, userId) }; + if (user) + user.remove(); + } }; try { @@ -198,4 +198,4 @@ namespace lms::api::subsonic return Response::createOkResponse(context.serverProtocolVersion); } -} \ No newline at end of file +} // namespace lms::api::subsonic \ No newline at end of file diff --git a/src/libs/subsonic/impl/entrypoints/UserManagement.hpp b/src/libs/subsonic/impl/entrypoints/UserManagement.hpp index e44203d6..4425ec76 100644 --- a/src/libs/subsonic/impl/entrypoints/UserManagement.hpp +++ b/src/libs/subsonic/impl/entrypoints/UserManagement.hpp @@ -30,4 +30,4 @@ namespace lms::api::subsonic Response handleUpdateUserRequest(RequestContext& context); Response handleDeleteUserRequest(RequestContext& context); Response handleChangePassword(RequestContext& context); -} +} // namespace lms::api::subsonic diff --git a/src/libs/subsonic/impl/responses/Album.cpp b/src/libs/subsonic/impl/responses/Album.cpp index fc3adf03..546a19e7 100644 --- a/src/libs/subsonic/impl/responses/Album.cpp +++ b/src/libs/subsonic/impl/responses/Album.cpp @@ -19,21 +19,21 @@ #include "responses/Album.hpp" +#include "core/ITraceLogger.hpp" +#include "core/Service.hpp" +#include "core/String.hpp" #include "database/Artist.hpp" #include "database/Cluster.hpp" #include "database/Release.hpp" #include "database/User.hpp" #include "services/feedback/IFeedbackService.hpp" #include "services/scrobbling/IScrobblingService.hpp" -#include "core/ITraceLogger.hpp" -#include "core/Service.hpp" -#include "core/String.hpp" +#include "SubsonicId.hpp" #include "responses/Artist.hpp" #include "responses/DiscTitle.hpp" #include "responses/ItemDate.hpp" #include "responses/ItemGenre.hpp" -#include "SubsonicId.hpp" namespace lms::api::subsonic { @@ -45,13 +45,14 @@ namespace lms::api::subsonic Response::Node albumNode; - if (id3) { + if (id3) + { albumNode.setAttribute("name", release->getName()); albumNode.setAttribute("songCount", release->getTrackCount()); albumNode.setAttribute( "duration", std::chrono::duration_cast( - release->getDuration()) - .count()); + release->getDuration()) + .count()); } else { @@ -97,7 +98,7 @@ namespace lms::api::subsonic const ClusterType::pointer genreClusterType{ ClusterType::find(context.dbSession, "GENRE") }; if (genreClusterType) { - auto clusters{ release->getClusterGroups({genreClusterType->getId()}, 1) }; + auto clusters{ release->getClusterGroups({ genreClusterType->getId() }, 1) }; if (!clusters.empty() && !clusters.front().empty()) albumNode.setAttribute("genre", clusters.front().front()->getName()); } @@ -124,19 +125,17 @@ namespace lms::api::subsonic albumNode.setAttribute("musicBrainzId", mbid ? mbid->getAsString() : ""); } - auto addClusters{ [&](Response::Node::Key field, std::string_view clusterTypeName) - { + auto addClusters{ [&](Response::Node::Key field, std::string_view clusterTypeName) { albumNode.createEmptyArrayValue(field); Cluster::FindParameters params; params.setRelease(release->getId()); params.setClusterTypeName(clusterTypeName); - Cluster::find(context.dbSession, params, [&](const Cluster::pointer& cluster) - { - albumNode.addArrayValue(field, cluster->getName()); - }); - }}; + Cluster::find(context.dbSession, params, [&](const Cluster::pointer& cluster) { + albumNode.addArrayValue(field, cluster->getName()); + }); + } }; addClusters("moods", "MOOD"); @@ -148,10 +147,9 @@ namespace lms::api::subsonic params.setRelease(release->getId()); params.setClusterType(genreClusterType->getId()); - Cluster::find(context.dbSession, params, [&](const Cluster::pointer& cluster) - { - albumNode.addArrayChild("genres", createItemGenreNode(cluster->getName())); - }); + Cluster::find(context.dbSession, params, [&](const Cluster::pointer& cluster) { + albumNode.addArrayChild("genres", createItemGenreNode(cluster->getName())); + }); } albumNode.createEmptyArrayChild("artists"); @@ -186,4 +184,4 @@ namespace lms::api::subsonic return albumNode; } -} \ No newline at end of file +} // namespace lms::api::subsonic \ No newline at end of file diff --git a/src/libs/subsonic/impl/responses/Album.hpp b/src/libs/subsonic/impl/responses/Album.hpp index b6780b71..a9508a05 100644 --- a/src/libs/subsonic/impl/responses/Album.hpp +++ b/src/libs/subsonic/impl/responses/Album.hpp @@ -20,6 +20,7 @@ #pragma once #include "database/Object.hpp" + #include "SubsonicResponse.hpp" namespace lms::db @@ -27,7 +28,7 @@ namespace lms::db class Release; class User; class Session; -} +} // namespace lms::db namespace lms::api::subsonic { diff --git a/src/libs/subsonic/impl/responses/Artist.cpp b/src/libs/subsonic/impl/responses/Artist.cpp index bbc40f31..ca382b29 100644 --- a/src/libs/subsonic/impl/responses/Artist.cpp +++ b/src/libs/subsonic/impl/responses/Artist.cpp @@ -19,14 +19,14 @@ #include "responses/Artist.hpp" +#include "core/ITraceLogger.hpp" +#include "core/Service.hpp" +#include "core/String.hpp" #include "database/Artist.hpp" #include "database/Release.hpp" #include "database/TrackArtistLink.hpp" #include "database/User.hpp" #include "services/feedback/IFeedbackService.hpp" -#include "core/ITraceLogger.hpp" -#include "core/Service.hpp" -#include "core/String.hpp" #include "SubsonicId.hpp" @@ -45,8 +45,7 @@ namespace lms::api::subsonic names.resize(artists.size()); std::transform(std::cbegin(artists), std::cend(artists), std::begin(names), - [](const Artist::pointer& artist) - { + [](const Artist::pointer& artist) { return artist->getName(); }); @@ -57,22 +56,33 @@ namespace lms::api::subsonic { switch (type) { - case TrackArtistLinkType::Arranger: return "arranger"; - case TrackArtistLinkType::Artist: return "artist"; - case TrackArtistLinkType::Composer: return "composer"; - case TrackArtistLinkType::Conductor: return "conductor"; - case TrackArtistLinkType::Lyricist: return "lyricist"; - case TrackArtistLinkType::Mixer: return "mixer"; - case TrackArtistLinkType::Performer: return "performer"; - case TrackArtistLinkType::Producer: return "producer"; - case TrackArtistLinkType::ReleaseArtist: return "albumartist"; - case TrackArtistLinkType::Remixer: return "remixer"; - case TrackArtistLinkType::Writer: return "writer"; + case TrackArtistLinkType::Arranger: + return "arranger"; + case TrackArtistLinkType::Artist: + return "artist"; + case TrackArtistLinkType::Composer: + return "composer"; + case TrackArtistLinkType::Conductor: + return "conductor"; + case TrackArtistLinkType::Lyricist: + return "lyricist"; + case TrackArtistLinkType::Mixer: + return "mixer"; + case TrackArtistLinkType::Performer: + return "performer"; + case TrackArtistLinkType::Producer: + return "producer"; + case TrackArtistLinkType::ReleaseArtist: + return "albumartist"; + case TrackArtistLinkType::Remixer: + return "remixer"; + case TrackArtistLinkType::Writer: + return "writer"; } return "unknown"; } - } + } // namespace utils Response::Node createArtistNode(RequestContext& context, const Artist::pointer& artist, const User::pointer& user, bool id3) { @@ -86,7 +96,7 @@ namespace lms::api::subsonic if (id3) { - const std::size_t count{ Release::getCount(context.dbSession, Release::FindParameters {}.setArtist(artist->getId())) }; + const std::size_t count{ Release::getCount(context.dbSession, Release::FindParameters{}.setArtist(artist->getId())) }; artistNode.setAttribute("albumCount", count); } @@ -125,4 +135,4 @@ namespace lms::api::subsonic return artistNode; } -} \ No newline at end of file +} // namespace lms::api::subsonic \ No newline at end of file diff --git a/src/libs/subsonic/impl/responses/Artist.hpp b/src/libs/subsonic/impl/responses/Artist.hpp index fe0e2f4b..b7ebc516 100644 --- a/src/libs/subsonic/impl/responses/Artist.hpp +++ b/src/libs/subsonic/impl/responses/Artist.hpp @@ -21,8 +21,10 @@ #include #include + #include "database/Object.hpp" #include "database/Types.hpp" + #include "SubsonicResponse.hpp" namespace lms::db @@ -30,7 +32,7 @@ namespace lms::db class Artist; class User; class Session; -} +} // namespace lms::db namespace lms::api::subsonic { @@ -38,7 +40,7 @@ namespace lms::api::subsonic { std::string joinArtistNames(const std::vector>& artists); std::string_view toString(db::TrackArtistLinkType type); - } + } // namespace utils Response::Node createArtistNode(RequestContext& context, const db::ObjectPtr& artist, const db::ObjectPtr& user, bool id3); Response::Node createArtistNode(const db::ObjectPtr& artist); // only minimal info -} \ No newline at end of file +} // namespace lms::api::subsonic \ No newline at end of file diff --git a/src/libs/subsonic/impl/responses/Bookmark.cpp b/src/libs/subsonic/impl/responses/Bookmark.cpp index 206b21e5..063f330c 100644 --- a/src/libs/subsonic/impl/responses/Bookmark.cpp +++ b/src/libs/subsonic/impl/responses/Bookmark.cpp @@ -39,4 +39,4 @@ namespace lms::api::subsonic return trackBookmarkNode; } -} \ No newline at end of file +} // namespace lms::api::subsonic \ No newline at end of file diff --git a/src/libs/subsonic/impl/responses/Bookmark.hpp b/src/libs/subsonic/impl/responses/Bookmark.hpp index fc8073ad..13ae9bbb 100644 --- a/src/libs/subsonic/impl/responses/Bookmark.hpp +++ b/src/libs/subsonic/impl/responses/Bookmark.hpp @@ -20,6 +20,7 @@ #pragma once #include "database/Object.hpp" + #include "SubsonicResponse.hpp" namespace lms::db diff --git a/src/libs/subsonic/impl/responses/Contributor.cpp b/src/libs/subsonic/impl/responses/Contributor.cpp index ad2dc2b0..952fc662 100644 --- a/src/libs/subsonic/impl/responses/Contributor.cpp +++ b/src/libs/subsonic/impl/responses/Contributor.cpp @@ -21,6 +21,7 @@ #include "database/Object.hpp" #include "database/TrackArtistLink.hpp" + #include "SubsonicResponse.hpp" #include "responses/Artist.hpp" @@ -37,4 +38,4 @@ namespace lms::api::subsonic return contributorNode; } -} \ No newline at end of file +} // namespace lms::api::subsonic \ No newline at end of file diff --git a/src/libs/subsonic/impl/responses/Contributor.hpp b/src/libs/subsonic/impl/responses/Contributor.hpp index 6c89ed01..a563d7fe 100644 --- a/src/libs/subsonic/impl/responses/Contributor.hpp +++ b/src/libs/subsonic/impl/responses/Contributor.hpp @@ -20,13 +20,14 @@ #pragma once #include "database/Object.hpp" + #include "SubsonicResponse.hpp" namespace lms::db { class Artist; class TrackArtistLink; -} +} // namespace lms::db namespace lms::api::subsonic { diff --git a/src/libs/subsonic/impl/responses/DiscTitle.cpp b/src/libs/subsonic/impl/responses/DiscTitle.cpp index 1ba79f2f..517eb0e2 100644 --- a/src/libs/subsonic/impl/responses/DiscTitle.cpp +++ b/src/libs/subsonic/impl/responses/DiscTitle.cpp @@ -30,4 +30,4 @@ namespace lms::api::subsonic return discTitleNode; } -} \ No newline at end of file +} // namespace lms::api::subsonic \ No newline at end of file diff --git a/src/libs/subsonic/impl/responses/DiscTitle.hpp b/src/libs/subsonic/impl/responses/DiscTitle.hpp index 7881ee38..9ab6aeae 100644 --- a/src/libs/subsonic/impl/responses/DiscTitle.hpp +++ b/src/libs/subsonic/impl/responses/DiscTitle.hpp @@ -20,6 +20,7 @@ #pragma once #include "database/Types.hpp" + #include "SubsonicResponse.hpp" namespace lms::api::subsonic diff --git a/src/libs/subsonic/impl/responses/Genre.cpp b/src/libs/subsonic/impl/responses/Genre.cpp index 6b4fb015..308fe29f 100644 --- a/src/libs/subsonic/impl/responses/Genre.cpp +++ b/src/libs/subsonic/impl/responses/Genre.cpp @@ -33,4 +33,4 @@ namespace lms::api::subsonic return clusterNode; } -} \ No newline at end of file +} // namespace lms::api::subsonic \ No newline at end of file diff --git a/src/libs/subsonic/impl/responses/Genre.hpp b/src/libs/subsonic/impl/responses/Genre.hpp index 15890c1e..45017625 100644 --- a/src/libs/subsonic/impl/responses/Genre.hpp +++ b/src/libs/subsonic/impl/responses/Genre.hpp @@ -20,6 +20,7 @@ #pragma once #include "database/Object.hpp" + #include "SubsonicResponse.hpp" namespace lms::db diff --git a/src/libs/subsonic/impl/responses/ItemDate.cpp b/src/libs/subsonic/impl/responses/ItemDate.cpp index 1f6c7592..703e2557 100644 --- a/src/libs/subsonic/impl/responses/ItemDate.cpp +++ b/src/libs/subsonic/impl/responses/ItemDate.cpp @@ -40,4 +40,4 @@ namespace lms::api::subsonic return itemDateNode; } -} \ No newline at end of file +} // namespace lms::api::subsonic \ No newline at end of file diff --git a/src/libs/subsonic/impl/responses/ItemDate.hpp b/src/libs/subsonic/impl/responses/ItemDate.hpp index 6a9a4320..c071c136 100644 --- a/src/libs/subsonic/impl/responses/ItemDate.hpp +++ b/src/libs/subsonic/impl/responses/ItemDate.hpp @@ -20,6 +20,7 @@ #pragma once #include + #include "SubsonicResponse.hpp" namespace lms::api::subsonic diff --git a/src/libs/subsonic/impl/responses/ItemGenre.cpp b/src/libs/subsonic/impl/responses/ItemGenre.cpp index c746af27..db4dea6c 100644 --- a/src/libs/subsonic/impl/responses/ItemGenre.cpp +++ b/src/libs/subsonic/impl/responses/ItemGenre.cpp @@ -31,4 +31,4 @@ namespace lms::api::subsonic return genreNode; } -} \ No newline at end of file +} // namespace lms::api::subsonic \ No newline at end of file diff --git a/src/libs/subsonic/impl/responses/ItemGenre.hpp b/src/libs/subsonic/impl/responses/ItemGenre.hpp index 0e7038ff..c974b328 100644 --- a/src/libs/subsonic/impl/responses/ItemGenre.hpp +++ b/src/libs/subsonic/impl/responses/ItemGenre.hpp @@ -20,6 +20,7 @@ #pragma once #include + #include "SubsonicResponse.hpp" namespace lms::db diff --git a/src/libs/subsonic/impl/responses/Playlist.cpp b/src/libs/subsonic/impl/responses/Playlist.cpp index 80583363..b0e2e9bb 100644 --- a/src/libs/subsonic/impl/responses/Playlist.cpp +++ b/src/libs/subsonic/impl/responses/Playlist.cpp @@ -22,6 +22,7 @@ #include "database/Track.hpp" #include "database/TrackList.hpp" #include "database/User.hpp" + #include "SubsonicId.hpp" namespace lms::api::subsonic @@ -42,9 +43,9 @@ namespace lms::api::subsonic playlistNode.setAttribute("created", reportedDummyDate); playlistNode.setAttribute("owner", tracklist->getUser()->getLoginName()); - if (const auto entry {tracklist->getEntry(0)}) + if (const auto entry{ tracklist->getEntry(0) }) playlistNode.setAttribute("coverArt", idToString(entry->getTrack()->getId())); return playlistNode; } -} \ No newline at end of file +} // namespace lms::api::subsonic \ No newline at end of file diff --git a/src/libs/subsonic/impl/responses/Playlist.hpp b/src/libs/subsonic/impl/responses/Playlist.hpp index 0d62bc0e..07246674 100644 --- a/src/libs/subsonic/impl/responses/Playlist.hpp +++ b/src/libs/subsonic/impl/responses/Playlist.hpp @@ -20,13 +20,14 @@ #pragma once #include "database/Object.hpp" + #include "SubsonicResponse.hpp" namespace lms::db { class TrackList; class Session; -} +} // namespace lms::db namespace lms::api::subsonic { diff --git a/src/libs/subsonic/impl/responses/ReplayGain.cpp b/src/libs/subsonic/impl/responses/ReplayGain.cpp index 2fb90305..5fd9d821 100644 --- a/src/libs/subsonic/impl/responses/ReplayGain.cpp +++ b/src/libs/subsonic/impl/responses/ReplayGain.cpp @@ -35,4 +35,4 @@ namespace lms::api::subsonic return replayGainNode; } -} \ No newline at end of file +} // namespace lms::api::subsonic \ No newline at end of file diff --git a/src/libs/subsonic/impl/responses/ReplayGain.hpp b/src/libs/subsonic/impl/responses/ReplayGain.hpp index a19f00ff..c88f17da 100644 --- a/src/libs/subsonic/impl/responses/ReplayGain.hpp +++ b/src/libs/subsonic/impl/responses/ReplayGain.hpp @@ -20,6 +20,7 @@ #pragma once #include "database/Object.hpp" + #include "SubsonicResponse.hpp" namespace lms::db diff --git a/src/libs/subsonic/impl/responses/Song.cpp b/src/libs/subsonic/impl/responses/Song.cpp index af5c6f9f..cc4e0365 100644 --- a/src/libs/subsonic/impl/responses/Song.cpp +++ b/src/libs/subsonic/impl/responses/Song.cpp @@ -22,6 +22,9 @@ #include #include "av/IAudioFile.hpp" +#include "core/ITraceLogger.hpp" +#include "core/Service.hpp" +#include "core/String.hpp" #include "database/Artist.hpp" #include "database/Cluster.hpp" #include "database/Release.hpp" @@ -30,15 +33,13 @@ #include "database/User.hpp" #include "services/feedback/IFeedbackService.hpp" #include "services/scrobbling/IScrobblingService.hpp" -#include "core/ITraceLogger.hpp" -#include "core/Service.hpp" -#include "core/String.hpp" + +#include "SubsonicId.hpp" +#include "Utils.hpp" #include "responses/Artist.hpp" #include "responses/Contributor.hpp" #include "responses/ItemGenre.hpp" #include "responses/ReplayGain.hpp" -#include "SubsonicId.hpp" -#include "Utils.hpp" namespace lms::api::subsonic { @@ -50,16 +51,21 @@ namespace lms::api::subsonic { switch (format) { - case TranscodingOutputFormat::MP3: return "mp3"; - case TranscodingOutputFormat::OGG_OPUS: return "opus"; - case TranscodingOutputFormat::MATROSKA_OPUS: return "mka"; - case TranscodingOutputFormat::OGG_VORBIS: return "ogg"; - case TranscodingOutputFormat::WEBM_VORBIS: return "webm"; + case TranscodingOutputFormat::MP3: + return "mp3"; + case TranscodingOutputFormat::OGG_OPUS: + return "opus"; + case TranscodingOutputFormat::MATROSKA_OPUS: + return "mka"; + case TranscodingOutputFormat::OGG_VORBIS: + return "ogg"; + case TranscodingOutputFormat::WEBM_VORBIS: + return "webm"; } return ""; } - } + } // namespace Response::Node createSongNode(RequestContext& context, const Track::pointer& track, const User::pointer& user) { @@ -94,7 +100,7 @@ namespace lms::api::subsonic trackResponse.setAttribute("coverArt", idToString(track->getId())); - const std::vector& artists{ track->getArtists({TrackArtistLinkType::Artist}) }; + const std::vector& artists{ track->getArtists({ TrackArtistLinkType::Artist }) }; if (!artists.empty()) { if (!track->getArtistDisplayName().empty()) @@ -160,18 +166,17 @@ namespace lms::api::subsonic trackResponse.createEmptyArrayChild("artists"); trackResponse.createEmptyArrayChild("contributors"); - TrackArtistLink::find(context.dbSession, track->getId(), [&](const TrackArtistLink::pointer& link, const Artist::pointer& artist) - { + TrackArtistLink::find(context.dbSession, track->getId(), [&](const TrackArtistLink::pointer& link, const Artist::pointer& artist) { switch (link->getType()) { - case TrackArtistLinkType::Artist: - trackResponse.addArrayChild("artists", createArtistNode(artist)); - break; - case TrackArtistLinkType::ReleaseArtist: - trackResponse.addArrayChild("albumartists", createArtistNode(artist)); - break; - default: - trackResponse.addArrayChild("contributors", createContributorNode(link, artist)); + case TrackArtistLinkType::Artist: + trackResponse.addArrayChild("artists", createArtistNode(artist)); + break; + case TrackArtistLinkType::ReleaseArtist: + trackResponse.addArrayChild("albumartists", createArtistNode(artist)); + break; + default: + trackResponse.addArrayChild("contributors", createContributorNode(link, artist)); } }); } @@ -180,8 +185,7 @@ namespace lms::api::subsonic if (release) trackResponse.setAttribute("displayAlbumArtist", release->getArtistDisplayName()); - auto addClusters{ [&](Response::Node::Key field, std::string_view clusterTypeName) - { + auto addClusters{ [&](Response::Node::Key field, std::string_view clusterTypeName) { trackResponse.createEmptyArrayValue(field); Cluster::FindParameters params; @@ -203,4 +207,4 @@ namespace lms::api::subsonic return trackResponse; } -} \ No newline at end of file +} // namespace lms::api::subsonic \ No newline at end of file diff --git a/src/libs/subsonic/impl/responses/Song.hpp b/src/libs/subsonic/impl/responses/Song.hpp index 4b5101b0..1a91549e 100644 --- a/src/libs/subsonic/impl/responses/Song.hpp +++ b/src/libs/subsonic/impl/responses/Song.hpp @@ -20,6 +20,7 @@ #pragma once #include "database/Object.hpp" + #include "SubsonicResponse.hpp" namespace lms::db @@ -27,7 +28,7 @@ namespace lms::db class Track; class User; class Session; -} +} // namespace lms::db namespace lms::api::subsonic { diff --git a/src/libs/subsonic/impl/responses/User.cpp b/src/libs/subsonic/impl/responses/User.cpp index 596f7c20..69c8571a 100644 --- a/src/libs/subsonic/impl/responses/User.cpp +++ b/src/libs/subsonic/impl/responses/User.cpp @@ -49,4 +49,4 @@ namespace lms::api::subsonic return userNode; } -} \ No newline at end of file +} // namespace lms::api::subsonic \ No newline at end of file diff --git a/src/libs/subsonic/impl/responses/User.hpp b/src/libs/subsonic/impl/responses/User.hpp index b6f23ed2..9ced3725 100644 --- a/src/libs/subsonic/impl/responses/User.hpp +++ b/src/libs/subsonic/impl/responses/User.hpp @@ -20,6 +20,7 @@ #pragma once #include "database/Object.hpp" + #include "SubsonicResponse.hpp" namespace lms::db diff --git a/src/libs/subsonic/include/subsonic/SubsonicResource.hpp b/src/libs/subsonic/include/subsonic/SubsonicResource.hpp index c2e89074..2c52bac4 100644 --- a/src/libs/subsonic/include/subsonic/SubsonicResource.hpp +++ b/src/libs/subsonic/include/subsonic/SubsonicResource.hpp @@ -24,10 +24,10 @@ namespace lms::db { - class Db; + class Db; } namespace lms::api::subsonic { - std::unique_ptr createSubsonicResource(db::Db& db); -} // namespace + std::unique_ptr createSubsonicResource(db::Db& db); +} // namespace lms::api::subsonic diff --git a/src/lms/main.cpp b/src/lms/main.cpp index 605114aa..63cb1309 100644 --- a/src/lms/main.cpp +++ b/src/lms/main.cpp @@ -19,19 +19,25 @@ #include +#include +#include #include #include -#include -#include - -#include "image/Image.hpp" -#include "services/auth/IAuthTokenService.hpp" -#include "services/auth/IPasswordService.hpp" -#include "services/auth/IEnvService.hpp" -#include "services/cover/ICoverService.hpp" +#include "core/IChildProcessManager.hpp" +#include "core/IConfig.hpp" +#include "core/IOContextRunner.hpp" +#include "core/ITraceLogger.hpp" +#include "core/Service.hpp" +#include "core/String.hpp" +#include "core/WtLogger.hpp" #include "database/Db.hpp" #include "database/Session.hpp" +#include "image/Image.hpp" +#include "services/auth/IAuthTokenService.hpp" +#include "services/auth/IEnvService.hpp" +#include "services/auth/IPasswordService.hpp" +#include "services/cover/ICoverService.hpp" #include "services/feedback/IFeedbackService.hpp" #include "services/recommendation/IPlaylistGeneratorService.hpp" #include "services/recommendation/IRecommendationService.hpp" @@ -41,13 +47,6 @@ #include "ui/LmsApplication.hpp" #include "ui/LmsApplicationManager.hpp" #include "ui/LmsInitApplication.hpp" -#include "core/IChildProcessManager.hpp" -#include "core/IConfig.hpp" -#include "core/IOContextRunner.hpp" -#include "core/ITraceLogger.hpp" -#include "core/Service.hpp" -#include "core/String.hpp" -#include "core/WtLogger.hpp" namespace lms { @@ -150,7 +149,6 @@ namespace lms pt.add_child("server.application-settings.head-matter.meta", themeColor); } - { std::ofstream oss{ wtConfigPath.string().c_str(), std::ios::out }; if (!oss) @@ -167,60 +165,48 @@ namespace lms void proxyScannerEventsToApplication(scanner::IScannerService& scanner, Wt::WServer& server) { - auto postAll{ [](Wt::WServer& server, std::function cb) - { - server.postAll([cb = std::move(cb)] - { - // may be nullptr, see https://redmine.webtoolkit.eu/issues/8202 - if (LmsApp) - cb(); - }); - } }; - - scanner.getEvents().scanAborted.connect([&] - { - postAll(server, [] - { - LmsApp->getScannerEvents().scanAborted.emit(); - LmsApp->triggerUpdate(); - }); + auto postAll{ [](Wt::WServer& server, std::function cb) { + server.postAll([cb = std::move(cb)] { + // may be nullptr, see https://redmine.webtoolkit.eu/issues/8202 + if (LmsApp) + cb(); }); + } }; - scanner.getEvents().scanStarted.connect([&] - { - postAll(server, [] - { - LmsApp->getScannerEvents().scanStarted.emit(); - LmsApp->triggerUpdate(); - }); + scanner.getEvents().scanAborted.connect([&] { + postAll(server, [] { + LmsApp->getScannerEvents().scanAborted.emit(); + LmsApp->triggerUpdate(); }); + }); - scanner.getEvents().scanComplete.connect([&](const scanner::ScanStats& stats) - { - postAll(server, [=] - { - LmsApp->getScannerEvents().scanComplete.emit(stats); - LmsApp->triggerUpdate(); - }); + scanner.getEvents().scanStarted.connect([&] { + postAll(server, [] { + LmsApp->getScannerEvents().scanStarted.emit(); + LmsApp->triggerUpdate(); }); + }); - scanner.getEvents().scanInProgress.connect([&](const scanner::ScanStepStats& stats) - { - postAll(server, [=] - { - LmsApp->getScannerEvents().scanInProgress.emit(stats); - LmsApp->triggerUpdate(); - }); + scanner.getEvents().scanComplete.connect([&](const scanner::ScanStats& stats) { + postAll(server, [=] { + LmsApp->getScannerEvents().scanComplete.emit(stats); + LmsApp->triggerUpdate(); }); + }); - scanner.getEvents().scanScheduled.connect([&](const Wt::WDateTime dateTime) - { - postAll(server, [=] - { - LmsApp->getScannerEvents().scanScheduled.emit(dateTime); - LmsApp->triggerUpdate(); - }); + scanner.getEvents().scanInProgress.connect([&](const scanner::ScanStepStats& stats) { + postAll(server, [=] { + LmsApp->getScannerEvents().scanInProgress.emit(stats); + LmsApp->triggerUpdate(); }); + }); + + scanner.getEvents().scanScheduled.connect([&](const Wt::WDateTime dateTime) { + postAll(server, [=] { + LmsApp->getScannerEvents().scanScheduled.emit(dateTime); + LmsApp->triggerUpdate(); + }); + }); } int main(int argc, char* argv[]) @@ -236,8 +222,8 @@ namespace lms else if (argc > 2) { std::cerr << "Usage:\t" << argv[0] << "\t[conf_file]\n\n" - << "Options:\n" - << "\tconf_file:\t path to the LMS configuration file (defaults to " << configFilePath << ")\n\n"; + << "Options:\n" + << "\tconf_file:\t path to the LMS configuration file (defaults to " << configFilePath << ")\n\n"; return EXIT_FAILURE; } @@ -278,8 +264,7 @@ namespace lms // As initialization can take a while (db migration, analyze, etc.), we bind a temporary init entry point to warn the user server.addEntryPoint(Wt::EntryPointType::Application, - [&](const Wt::WEnvironment& env) - { + [&](const Wt::WEnvironment& env) { return ui::LmsInitApplication::create(env); }); @@ -307,7 +292,7 @@ namespace lms session.fullAnalyze(); database.getTLSSession().refreshTracingLoggerStats(); } - + ui::LmsApplicationManager appManager; // Service initialization order is important (reverse-order for deinit) @@ -335,13 +320,12 @@ namespace lms core::Service playlistGeneratorService{ recommendation::createPlaylistGeneratorService(database, *recommendationService.get()) }; core::Service scannerService{ scanner::createScannerService(database) }; - scannerService->getEvents().scanComplete.connect([&] - { - // Flush cover cache even if no changes: - // covers may be external files that changed and we don't keep track of them for now (but we should) - coverService->flushCache(); - database.getTLSSession().refreshTracingLoggerStats(); - }); + scannerService->getEvents().scanComplete.connect([&] { + // Flush cover cache even if no changes: + // covers may be external files that changed and we don't keep track of them for now (but we should) + coverService->flushCache(); + database.getTLSSession().refreshTracingLoggerStats(); + }); core::Service feedbackService{ feedback::createFeedbackService(ioContext, database) }; core::Service scrobblingService{ scrobbling::createScrobblingService(ioContext, database) }; @@ -361,8 +345,7 @@ namespace lms // bind UI entry point server.addEntryPoint(Wt::EntryPointType::Application, - [&](const Wt::WEnvironment& env) - { + [&](const Wt::WEnvironment& env) { return ui::LmsApplication::create(env, database, appManager); }); @@ -395,7 +378,7 @@ namespace lms return res; } -} +} // namespace lms int main(int argc, char* argv[]) { diff --git a/src/lms/ui/Auth.cpp b/src/lms/ui/Auth.cpp index 8adea685..9e744802 100644 --- a/src/lms/ui/Auth.cpp +++ b/src/lms/ui/Auth.cpp @@ -19,24 +19,24 @@ #include "Auth.hpp" +#include #include #include #include -#include #include #include -#include "services/auth/IAuthTokenService.hpp" -#include "services/auth/IPasswordService.hpp" -#include "database/Session.hpp" -#include "database/User.hpp" #include "core/ILogger.hpp" #include "core/Service.hpp" +#include "database/Session.hpp" +#include "database/User.hpp" +#include "services/auth/IAuthTokenService.hpp" +#include "services/auth/IPasswordService.hpp" +#include "LmsApplication.hpp" #include "common/LoginNameValidator.hpp" #include "common/MandatoryValidator.hpp" #include "common/PasswordValidator.hpp" -#include "LmsApplication.hpp" namespace lms::ui { @@ -74,7 +74,6 @@ namespace lms::ui setValidator(PasswordField, createMandatoryValidator()); } - void saveData() { bool isDemo; @@ -103,9 +102,9 @@ namespace lms::ui if (field == PasswordField) { const auto checkResult{ core::Service::get()->checkUserPassword( - boost::asio::ip::address::from_string(LmsApp->environment().clientAddress()), - valueText(LoginNameField).toUTF8(), - valueText(PasswordField).toUTF8()) }; + boost::asio::ip::address::from_string(LmsApp->environment().clientAddress()), + valueText(LoginNameField).toUTF8(), + valueText(PasswordField).toUTF8()) }; switch (checkResult.state) { case auth::IPasswordService::CheckResult::State::Granted: @@ -138,7 +137,7 @@ namespace lms::ui const AuthModel::Field AuthModel::LoginNameField{ "login-name" }; const AuthModel::Field AuthModel::PasswordField{ "password" }; const AuthModel::Field AuthModel::RememberMeField{ "remember-me" }; - } + } // namespace std::optional processAuthToken(const Wt::WEnvironment& env) { @@ -162,24 +161,22 @@ namespace lms::ui return res.authTokenInfo->userId; } - Auth::Auth() : Wt::WTemplateFormView{ Wt::WString::tr("Lms.Auth.template") } { auto model{ std::make_shared() }; - auto processAuth = [this, model] - { - updateModel(model.get()); + auto processAuth = [this, model] { + updateModel(model.get()); - if (model->validate()) - { - model->saveData(); - userLoggedIn.emit(*model->getUserId()); - } - else - updateView(model.get()); - }; + if (model->validate()) + { + model->saveData(); + userLoggedIn.emit(*model->getUserId()); + } + else + updateView(model.get()); + }; // LoginName auto loginName{ std::make_unique() }; @@ -212,4 +209,4 @@ namespace lms::ui updateView(model.get()); } -} +} // namespace lms::ui diff --git a/src/lms/ui/Auth.hpp b/src/lms/ui/Auth.hpp index 8a549ca3..b2383620 100644 --- a/src/lms/ui/Auth.hpp +++ b/src/lms/ui/Auth.hpp @@ -20,19 +20,20 @@ #pragma once #include + #include #include "database/UserId.hpp" namespace lms::ui { - std::optional processAuthToken(const Wt::WEnvironment& env); + std::optional processAuthToken(const Wt::WEnvironment& env); - class Auth : public Wt::WTemplateFormView - { - public: - Auth(); + class Auth : public Wt::WTemplateFormView + { + public: + Auth(); - Wt::Signal userLoggedIn; - }; + Wt::Signal userLoggedIn; + }; } // namespace lms::ui diff --git a/src/lms/ui/LmsApplication.cpp b/src/lms/ui/LmsApplication.cpp index 4382f9c6..8624bd38 100644 --- a/src/lms/ui/LmsApplication.cpp +++ b/src/lms/ui/LmsApplication.cpp @@ -26,9 +26,10 @@ #include #include -#include "services/auth/IEnvService.hpp" -#include "services/auth/IPasswordService.hpp" -#include "services/cover/ICoverService.hpp" +#include "core/ILogger.hpp" +#include "core/ITraceLogger.hpp" +#include "core/Service.hpp" +#include "core/String.hpp" #include "database/Artist.hpp" #include "database/Cluster.hpp" #include "database/Db.hpp" @@ -36,25 +37,11 @@ #include "database/Session.hpp" #include "database/TrackList.hpp" #include "database/User.hpp" +#include "services/auth/IEnvService.hpp" +#include "services/auth/IPasswordService.hpp" +#include "services/cover/ICoverService.hpp" #include "services/scrobbling/IScrobblingService.hpp" -#include "core/ILogger.hpp" -#include "core/ITraceLogger.hpp" -#include "core/Service.hpp" -#include "core/String.hpp" -#include "admin/InitWizardView.hpp" -#include "admin/MediaLibrariesView.hpp" -#include "admin/TracingView.hpp" -#include "admin/ScannerController.hpp" -#include "admin/ScanSettingsView.hpp" -#include "admin/UserView.hpp" -#include "admin/UsersView.hpp" -#include "common/Template.hpp" -#include "explore/Explore.hpp" -#include "explore/Filters.hpp" -#include "resource/AudioFileResource.hpp" -#include "resource/AudioTranscodingResource.hpp" -#include "resource/CoverResource.hpp" #include "Auth.hpp" #include "LmsApplicationException.hpp" #include "LmsApplicationManager.hpp" @@ -64,6 +51,19 @@ #include "NotificationContainer.hpp" #include "PlayQueue.hpp" #include "SettingsView.hpp" +#include "admin/InitWizardView.hpp" +#include "admin/MediaLibrariesView.hpp" +#include "admin/ScanSettingsView.hpp" +#include "admin/ScannerController.hpp" +#include "admin/TracingView.hpp" +#include "admin/UserView.hpp" +#include "admin/UsersView.hpp" +#include "common/Template.hpp" +#include "explore/Explore.hpp" +#include "explore/Filters.hpp" +#include "resource/AudioFileResource.hpp" +#include "resource/AudioTranscodingResource.hpp" +#include "resource/CoverResource.hpp" namespace lms::ui { @@ -132,23 +132,22 @@ namespace lms::ui int index; bool admin; std::optional title; - } views[] = - { - { "/artists", IdxExplore, false, Wt::WString::tr("Lms.Explore.artists") }, - { "/artist", IdxExplore, false, std::nullopt }, - { "/releases", IdxExplore, false, Wt::WString::tr("Lms.Explore.releases") }, - { "/release", IdxExplore, false, std::nullopt }, - { "/tracks", IdxExplore, false, Wt::WString::tr("Lms.Explore.tracks") }, - { "/tracklists", IdxExplore, false, Wt::WString::tr("Lms.Explore.tracklists") }, - { "/tracklist", IdxExplore, false, std::nullopt }, - { "/playqueue", IdxPlayQueue, false, Wt::WString::tr("Lms.PlayQueue.playqueue") }, - { "/settings", IdxSettings, false, Wt::WString::tr("Lms.Settings.settings") }, - { "/admin/libraries", IdxAdminLibraries, true, Wt::WString::tr("Lms.Admin.MediaLibraries.media-libraries") }, - { "/admin/scan-settings", IdxAdminScanSettings, true, Wt::WString::tr("Lms.Admin.Database.scan-settings") }, - { "/admin/scanner", IdxAdminScanner, true, Wt::WString::tr("Lms.Admin.ScannerController.scanner") }, - { "/admin/users", IdxAdminUsers, true, Wt::WString::tr("Lms.Admin.Users.users") }, - { "/admin/user", IdxAdminUser, true, std::nullopt }, - { "/admin/tracing", IdxAdminTracing, true, Wt::WString::tr("Lms.Admin.Tracing.tracing") }, + } views[] = { + { "/artists", IdxExplore, false, Wt::WString::tr("Lms.Explore.artists") }, + { "/artist", IdxExplore, false, std::nullopt }, + { "/releases", IdxExplore, false, Wt::WString::tr("Lms.Explore.releases") }, + { "/release", IdxExplore, false, std::nullopt }, + { "/tracks", IdxExplore, false, Wt::WString::tr("Lms.Explore.tracks") }, + { "/tracklists", IdxExplore, false, Wt::WString::tr("Lms.Explore.tracklists") }, + { "/tracklist", IdxExplore, false, std::nullopt }, + { "/playqueue", IdxPlayQueue, false, Wt::WString::tr("Lms.PlayQueue.playqueue") }, + { "/settings", IdxSettings, false, Wt::WString::tr("Lms.Settings.settings") }, + { "/admin/libraries", IdxAdminLibraries, true, Wt::WString::tr("Lms.Admin.MediaLibraries.media-libraries") }, + { "/admin/scan-settings", IdxAdminScanSettings, true, Wt::WString::tr("Lms.Admin.Database.scan-settings") }, + { "/admin/scanner", IdxAdminScanner, true, Wt::WString::tr("Lms.Admin.ScannerController.scanner") }, + { "/admin/users", IdxAdminUsers, true, Wt::WString::tr("Lms.Admin.Users.users") }, + { "/admin/user", IdxAdminUser, true, std::nullopt }, + { "/admin/tracing", IdxAdminTracing, true, Wt::WString::tr("Lms.Admin.Tracing.tracing") }, }; LMS_LOG(UI, DEBUG, "Internal path changed to '" << wApp->internalPath() << "'"); @@ -171,11 +170,11 @@ namespace lms::ui wApp->setInternalPath(defaultPath, true); } - } + } // namespace std::unique_ptr LmsApplication::create(const Wt::WEnvironment& env, db::Db& db, LmsApplicationManager& appManager) { - if (auto * authEnvService{ core::Service::get() }) + if (auto* authEnvService{ core::Service::get() }) { const auto checkResult{ authEnvService->processEnv(env) }; if (checkResult.state != auth::IEnvService::CheckResult::State::Granted) @@ -245,7 +244,7 @@ namespace lms::ui : Wt::WApplication{ env } , _db{ db } , _appManager{ appManager } - , _authenticatedUser{ userId ? std::make_optional(UserAuthInfo {*userId, false}) : std::nullopt } + , _authenticatedUser{ userId ? std::make_optional(UserAuthInfo{ *userId, false }) : std::nullopt } { try { @@ -315,11 +314,10 @@ namespace lms::ui else { Auth* auth{ root()->addNew() }; - auth->userLoggedIn.connect(this, [this](db::UserId userId) - { - _authenticatedUser = { userId, true }; - onUserLoggedIn(); - }); + auth->userLoggedIn.connect(this, [this](db::UserId userId) { + _authenticatedUser = { userId, true }; + onUserLoggedIn(); + }); } } @@ -339,10 +337,9 @@ namespace lms::ui t->bindString("error", e.what(), Wt::TextFormat::Plain); Wt::WPushButton* btn{ t->bindNew("btn-go-home", Wt::WString::tr("Lms.Error.go-home")) }; - btn->clicked().connect([this]() - { - redirect(defaultPath); - }); + btn->clicked().connect([this]() { + redirect(defaultPath); + }); } void LmsApplication::goHomeAndQuit() @@ -369,17 +366,16 @@ namespace lms::ui LMS_LOG(UI, INFO, "User '" << getUserLoginName() << "' logged in from '" << environment().clientAddress() << "', user agent = " << environment().userAgent()); _appManager.registerApplication(*this); - _appManager.applicationRegistered.connect(this, [this](LmsApplication& otherApplication) + _appManager.applicationRegistered.connect(this, [this](LmsApplication& otherApplication) { + // Only one active session by user + if (otherApplication.getUserId() == getUserId()) { - // Only one active session by user - if (otherApplication.getUserId() == getUserId()) + if (LmsApp->getUserType() != db::UserType::DEMO) { - if (LmsApp->getUserType() != db::UserType::DEMO) - { - quit(Wt::WString::tr("Lms.quit-other-session")); - } + quit(Wt::WString::tr("Lms.quit-other-session")); } - }); + } + }); createHome(); } @@ -471,73 +467,63 @@ namespace lms::ui explore->getPlayQueueController().setMaxTrackCountToEnqueue(_playQueue->getCapacity()); // Events from MediaPlayer - _mediaPlayer->playNext.connect([this] - { - LMS_LOG(UI, DEBUG, "Received playNext from player"); - _playQueue->playNext(); - }); - _mediaPlayer->playPrevious.connect([this] - { - LMS_LOG(UI, DEBUG, "Received playPrevious from player"); - _playQueue->playPrevious(); - }); + _mediaPlayer->playNext.connect([this] { + LMS_LOG(UI, DEBUG, "Received playNext from player"); + _playQueue->playNext(); + }); + _mediaPlayer->playPrevious.connect([this] { + LMS_LOG(UI, DEBUG, "Received playPrevious from player"); + _playQueue->playPrevious(); + }); - _mediaPlayer->scrobbleListenNow.connect([this](db::TrackId trackId) - { - LMS_LOG(UI, DEBUG, "Received ScrobbleListenNow from player for trackId = " << trackId.toString()); - const scrobbling::Listen listen{ getUserId(), trackId }; - core::Service::get()->listenStarted(listen); - }); - _mediaPlayer->scrobbleListenFinished.connect([this](db::TrackId trackId, unsigned durationMs) - { - LMS_LOG(UI, DEBUG, "Received ScrobbleListenFinished from player for trackId = " << trackId.toString() << ", duration = " << (durationMs / 1000) << "s"); - const std::chrono::milliseconds duration{ durationMs }; - const scrobbling::Listen listen{ getUserId(), trackId }; - core::Service::get()->listenFinished(listen, std::chrono::duration_cast(duration)); - }); + _mediaPlayer->scrobbleListenNow.connect([this](db::TrackId trackId) { + LMS_LOG(UI, DEBUG, "Received ScrobbleListenNow from player for trackId = " << trackId.toString()); + const scrobbling::Listen listen{ getUserId(), trackId }; + core::Service::get()->listenStarted(listen); + }); + _mediaPlayer->scrobbleListenFinished.connect([this](db::TrackId trackId, unsigned durationMs) { + LMS_LOG(UI, DEBUG, "Received ScrobbleListenFinished from player for trackId = " << trackId.toString() << ", duration = " << (durationMs / 1000) << "s"); + const std::chrono::milliseconds duration{ durationMs }; + const scrobbling::Listen listen{ getUserId(), trackId }; + core::Service::get()->listenFinished(listen, std::chrono::duration_cast(duration)); + }); - _mediaPlayer->playbackEnded.connect([this] - { - LMS_LOG(UI, DEBUG, "Received playbackEnded from player"); - _playQueue->onPlaybackEnded(); - }); + _mediaPlayer->playbackEnded.connect([this] { + LMS_LOG(UI, DEBUG, "Received playbackEnded from player"); + _playQueue->onPlaybackEnded(); + }); - _playQueue->trackSelected.connect([this](db::TrackId trackId, bool play, float replayGain) - { - _mediaPlayer->loadTrack(trackId, play, replayGain); - }); + _playQueue->trackSelected.connect([this](db::TrackId trackId, bool play, float replayGain) { + _mediaPlayer->loadTrack(trackId, play, replayGain); + }); - _playQueue->trackUnselected.connect([this] - { - _mediaPlayer->stop(); - }); - _playQueue->trackCountChanged.connect([this](std::size_t trackCount) - { - _mediaPlayer->onPlayQueueUpdated(trackCount); - }); + _playQueue->trackUnselected.connect([this] { + _mediaPlayer->stop(); + }); + _playQueue->trackCountChanged.connect([this](std::size_t trackCount) { + _mediaPlayer->onPlayQueueUpdated(trackCount); + }); _mediaPlayer->onPlayQueueUpdated(_playQueue->getCount()); const bool isAdmin{ getUserType() == db::UserType::ADMIN }; if (isAdmin) { - _scannerEvents.scanComplete.connect([this](const scanner::ScanStats& stats) - { - notifyMsg(Notification::Type::Info, + _scannerEvents.scanComplete.connect([this](const scanner::ScanStats& stats) { + notifyMsg(Notification::Type::Info, Wt::WString::tr("Lms.Admin.Database.database"), Wt::WString::tr("Lms.Admin.Database.scan-complete") - .arg(static_cast(stats.nbFiles())) + .arg(static_cast(stats.nbFiles())) .arg(static_cast(stats.additions)) .arg(static_cast(stats.updates)) .arg(static_cast(stats.deletions)) .arg(static_cast(stats.duplicates.size())) .arg(static_cast(stats.errors.size()))); - }); + }); } - internalPathChanged().connect(mainStack, [=] - { - handlePathChange(*mainStack, isAdmin); - }); + internalPathChanged().connect(mainStack, [=] { + handlePathChange(*mainStack, isAdmin); + }); handlePathChange(*mainStack, isAdmin); } diff --git a/src/lms/ui/LmsApplication.hpp b/src/lms/ui/LmsApplication.hpp index 68ab0d68..141e442c 100644 --- a/src/lms/ui/LmsApplication.hpp +++ b/src/lms/ui/LmsApplication.hpp @@ -24,18 +24,19 @@ #include #include "database/Object.hpp" -#include "database/UserId.hpp" #include "database/Types.hpp" +#include "database/UserId.hpp" #include "services/scanner/ScannerEvents.hpp" -#include "admin/ScannerController.hpp" + #include "Notification.hpp" +#include "admin/ScannerController.hpp" namespace lms::db { class Db; class Session; class User; -} +} // namespace lms::db namespace lms::ui { @@ -61,11 +62,11 @@ namespace lms::ui db::Db& getDb(); db::Session& getDbSession(); // always thread safe - db::ObjectPtr getUser(); - db::UserId getUserId(); - bool isUserAuthStrong() const; // user must be logged in prior this call - db::UserType getUserType(); // user must be logged in prior this call - std::string getUserLoginName(); // user must be logged in prior this call + db::ObjectPtr getUser(); + db::UserId getUserId(); + bool isUserAuthStrong() const; // user must be logged in prior this call + db::UserType getUserType(); // user must be logged in prior this call + std::string getUserLoginName(); // user must be logged in prior this call // Proxified scanner events scanner::Events& getScannerEvents() { return _scannerEvents; } @@ -100,25 +101,23 @@ namespace lms::ui void createHome(); db::Db& _db; - Wt::Signal<> _preQuit; + Wt::Signal<> _preQuit; LmsApplicationManager& _appManager; - scanner::Events _scannerEvents; + scanner::Events _scannerEvents; struct UserAuthInfo { - db::UserId userId; - bool strongAuth{}; + db::UserId userId; + bool strongAuth{}; }; - std::optional _authenticatedUser; - std::shared_ptr _coverResource; + std::optional _authenticatedUser; + std::shared_ptr _coverResource; MediaPlayer* _mediaPlayer{}; PlayQueue* _playQueue{}; NotificationContainer* _notificationContainer{}; ModalManager* _modalManager{}; }; - // Helper to get session instance -#define LmsApp lms::ui::LmsApplication::instance() +#define LmsApp lms::ui::LmsApplication::instance() } // namespace lms::ui - diff --git a/src/lms/ui/LmsApplicationException.hpp b/src/lms/ui/LmsApplicationException.hpp index 8b07956b..1b986aee 100644 --- a/src/lms/ui/LmsApplicationException.hpp +++ b/src/lms/ui/LmsApplicationException.hpp @@ -19,44 +19,50 @@ #pragma once -#include "database/Types.hpp" #include "core/Exception.hpp" +#include "database/Types.hpp" namespace lms::ui { - class LmsApplicationException : public core::LmsException - { - public: - LmsApplicationException(const Wt::WString& error) : LmsException {error.toUTF8()} {} - }; + class LmsApplicationException : public core::LmsException + { + public: + LmsApplicationException(const Wt::WString& error) + : LmsException{ error.toUTF8() } {} + }; - class ArtistNotFoundException : public LmsApplicationException - { - public: - ArtistNotFoundException() : LmsApplicationException {Wt::WString::tr("Lms.Error.artist-not-found")} {} - }; + class ArtistNotFoundException : public LmsApplicationException + { + public: + ArtistNotFoundException() + : LmsApplicationException{ Wt::WString::tr("Lms.Error.artist-not-found") } {} + }; - class ReleaseNotFoundException : public LmsApplicationException - { - public: - ReleaseNotFoundException() : LmsApplicationException {Wt::WString::tr("Lms.Error.release-not-found")} {} - }; + class ReleaseNotFoundException : public LmsApplicationException + { + public: + ReleaseNotFoundException() + : LmsApplicationException{ Wt::WString::tr("Lms.Error.release-not-found") } {} + }; - class TrackListNotFoundException : public LmsApplicationException - { - public: - TrackListNotFoundException() : LmsApplicationException {Wt::WString::tr("Lms.Error.tracklist-not-found")} {} - }; + class TrackListNotFoundException : public LmsApplicationException + { + public: + TrackListNotFoundException() + : LmsApplicationException{ Wt::WString::tr("Lms.Error.tracklist-not-found") } {} + }; - class UserNotFoundException : public LmsApplicationException - { - public: - UserNotFoundException() : LmsApplicationException {Wt::WString::tr("Lms.Error.user-not-found")} {} - }; + class UserNotFoundException : public LmsApplicationException + { + public: + UserNotFoundException() + : LmsApplicationException{ Wt::WString::tr("Lms.Error.user-not-found") } {} + }; - class UserNotAllowedException : public LmsApplicationException - { - public: - UserNotAllowedException() : LmsApplicationException {Wt::WString::tr("Lms.Error.user-not-allowed")} {} - }; -} // ns UserInterface + class UserNotAllowedException : public LmsApplicationException + { + public: + UserNotAllowedException() + : LmsApplicationException{ Wt::WString::tr("Lms.Error.user-not-allowed") } {} + }; +} // namespace lms::ui diff --git a/src/lms/ui/LmsApplicationManager.cpp b/src/lms/ui/LmsApplicationManager.cpp index 73546f16..f77e43fe 100644 --- a/src/lms/ui/LmsApplicationManager.cpp +++ b/src/lms/ui/LmsApplicationManager.cpp @@ -23,26 +23,24 @@ namespace lms::ui { - void - LmsApplicationManager::registerApplication(LmsApplication& application) - { - { - std::scoped_lock lock {_mutex}; - m_applications[application.getUserId()].insert(&application); - } + void LmsApplicationManager::registerApplication(LmsApplication& application) + { + { + std::scoped_lock lock{ _mutex }; + m_applications[application.getUserId()].insert(&application); + } - applicationRegistered.emit(application); - } + applicationRegistered.emit(application); + } - void - LmsApplicationManager::unregisterApplication(LmsApplication& application) - { - { - std::scoped_lock lock {_mutex}; - m_applications[application.getUserId()].erase(&application); - } + void LmsApplicationManager::unregisterApplication(LmsApplication& application) + { + { + std::scoped_lock lock{ _mutex }; + m_applications[application.getUserId()].erase(&application); + } - applicationUnregistered.emit(application); - } + applicationUnregistered.emit(application); + } -} // UserInterface +} // namespace lms::ui diff --git a/src/lms/ui/LmsApplicationManager.hpp b/src/lms/ui/LmsApplicationManager.hpp index d9d760ca..92c14189 100644 --- a/src/lms/ui/LmsApplicationManager.hpp +++ b/src/lms/ui/LmsApplicationManager.hpp @@ -20,8 +20,8 @@ #pragma once #include -#include #include +#include #include @@ -29,20 +29,20 @@ namespace lms::ui { - class LmsApplication; - class LmsApplicationManager - { - public: - Wt::Signal applicationRegistered; - Wt::Signal applicationUnregistered; + class LmsApplication; + class LmsApplicationManager + { + public: + Wt::Signal applicationRegistered; + Wt::Signal applicationUnregistered; - private: - friend class LmsApplication; + private: + friend class LmsApplication; - void registerApplication(LmsApplication& application); - void unregisterApplication(LmsApplication& application); + void registerApplication(LmsApplication& application); + void unregisterApplication(LmsApplication& application); - std::mutex _mutex; - std::unordered_map> m_applications; - }; -} // UserInterface + std::mutex _mutex; + std::unordered_map> m_applications; + }; +} // namespace lms::ui diff --git a/src/lms/ui/LmsTheme.cpp b/src/lms/ui/LmsTheme.cpp index f59a04a5..2f1a59ba 100644 --- a/src/lms/ui/LmsTheme.cpp +++ b/src/lms/ui/LmsTheme.cpp @@ -12,48 +12,42 @@ namespace lms::ui { - void - LmsTheme::init(Wt::WApplication* app) const - { - app->require("js/bootstrap.bundle.min.js"); - } + void LmsTheme::init(Wt::WApplication* app) const + { + app->require("js/bootstrap.bundle.min.js"); + } - std::string - LmsTheme::name() const - { - return "bootstrap5"; - } + std::string LmsTheme::name() const + { + return "bootstrap5"; + } - std::string - LmsTheme::resourcesUrl() const - { - return ""; - } + std::string LmsTheme::resourcesUrl() const + { + return ""; + } - std::vector - LmsTheme::styleSheets() const - { - static const std::vector files - { - {"css/bootstrap.solar.min.css"}, // TODO parametrize this - {"css/lms.css"}, - }; + std::vector LmsTheme::styleSheets() const + { + static const std::vector files{ + { "css/bootstrap.solar.min.css" }, // TODO parametrize this + { "css/lms.css" }, + }; - return files; - } + return files; + } - void LmsTheme::applyValidationStyle(Wt::WWidget* widget, const Wt::WValidator::Result& validation, Wt::WFlags styles) const - { - { - const bool validStyle {(validation.state() == Wt::ValidationState::Valid) && styles.test(Wt::ValidationStyleFlag::ValidStyle)}; - widget->toggleStyleClass("is-valid", validStyle); - } + void LmsTheme::applyValidationStyle(Wt::WWidget* widget, const Wt::WValidator::Result& validation, Wt::WFlags styles) const + { + { + const bool validStyle{ (validation.state() == Wt::ValidationState::Valid) && styles.test(Wt::ValidationStyleFlag::ValidStyle) }; + widget->toggleStyleClass("is-valid", validStyle); + } - { - const bool invalidStyle {(validation.state() != Wt::ValidationState::Valid) && styles.test(Wt::ValidationStyleFlag::InvalidStyle)}; - widget->toggleStyleClass("is-invalid", invalidStyle); - } - } + { + const bool invalidStyle{ (validation.state() != Wt::ValidationState::Valid) && styles.test(Wt::ValidationStyleFlag::InvalidStyle) }; + widget->toggleStyleClass("is-invalid", invalidStyle); + } + } } // namespace lms::ui - diff --git a/src/lms/ui/LmsTheme.hpp b/src/lms/ui/LmsTheme.hpp index 93cb06a5..59009fd7 100644 --- a/src/lms/ui/LmsTheme.hpp +++ b/src/lms/ui/LmsTheme.hpp @@ -23,23 +23,23 @@ namespace lms::ui { - class LmsTheme : public Wt::WTheme - { - private: - void init(Wt::WApplication *app) const override; + class LmsTheme : public Wt::WTheme + { + private: + void init(Wt::WApplication* app) const override; - std::string name() const override; - std::string resourcesUrl() const override; - std::vector styleSheets() const override; - void apply(Wt::WWidget*, Wt::WWidget*, int) const override {}; - void apply(Wt::WWidget*, Wt::DomElement&, int) const override {}; - std::string disabledClass() const override { return "disabled"; } - std::string activeClass() const override { return "active"; }; - std::string utilityCssClass(int) const override { return ""; }; - bool canStyleAnchorAsButton() const override { return true; }; - void applyValidationStyle(Wt::WWidget* widget, - const Wt::WValidator::Result& validation, - Wt::WFlags flags) const override; - bool canBorderBoxElement(const Wt::DomElement&) const override { return true; } - }; -} + std::string name() const override; + std::string resourcesUrl() const override; + std::vector styleSheets() const override; + void apply(Wt::WWidget*, Wt::WWidget*, int) const override{}; + void apply(Wt::WWidget*, Wt::DomElement&, int) const override{}; + std::string disabledClass() const override { return "disabled"; } + std::string activeClass() const override { return "active"; }; + std::string utilityCssClass(int) const override { return ""; }; + bool canStyleAnchorAsButton() const override { return true; }; + void applyValidationStyle(Wt::WWidget* widget, + const Wt::WValidator::Result& validation, + Wt::WFlags flags) const override; + bool canBorderBoxElement(const Wt::DomElement&) const override { return true; } + }; +} // namespace lms::ui diff --git a/src/lms/ui/MediaPlayer.cpp b/src/lms/ui/MediaPlayer.cpp index ae62ba2d..0897f824 100644 --- a/src/lms/ui/MediaPlayer.cpp +++ b/src/lms/ui/MediaPlayer.cpp @@ -20,12 +20,13 @@ #include "MediaPlayer.hpp" #include -#include #include +#include #include #include "core/ILogger.hpp" - +#include "core/String.hpp" +#include "core/Utils.hpp" #include "database/Artist.hpp" #include "database/Release.hpp" #include "database/Session.hpp" @@ -34,15 +35,11 @@ #include "database/Types.hpp" #include "database/User.hpp" -#include "resource/CoverResource.hpp" -#include "resource/AudioTranscodingResource.hpp" -#include "resource/AudioFileResource.hpp" - -#include "core/String.hpp" -#include "core/Utils.hpp" - #include "LmsApplication.hpp" #include "Utils.hpp" +#include "resource/AudioFileResource.hpp" +#include "resource/AudioTranscodingResource.hpp" +#include "resource/CoverResource.hpp" namespace lms::ui { @@ -184,7 +181,7 @@ namespace lms::ui return settings; } - } + } // namespace MediaPlayer::MediaPlayer() : Wt::WTemplate{ Wt::WString::tr("Lms.MediaPlayer.template") } @@ -208,27 +205,26 @@ namespace lms::ui _playQueue->setLink(Wt::WLink{ Wt::LinkType::InternalPath, "/playqueue" }); _playQueue->setToolTip(tr("Lms.PlayQueue.playqueue")); - _settingsLoaded.connect([this](const std::string& settings) - { - LMS_LOG(UI, DEBUG, "Settings loaded! '" << settings << "'"); + _settingsLoaded.connect([this](const std::string& settings) { + LMS_LOG(UI, DEBUG, "Settings loaded! '" << settings << "'"); - _settings = settingsfromJSString(settings); + _settings = settingsfromJSString(settings); - settingsLoaded.emit(); - }); + settingsLoaded.emit(); + }); - { - Settings defaultSettings; + { + Settings defaultSettings; - std::ostringstream oss; - oss << "LMS.mediaplayer.init(" - << jsRef() - << ", defaultSettings = " << settingsToJSString(defaultSettings) - << ")"; + std::ostringstream oss; + oss << "LMS.mediaplayer.init(" + << jsRef() + << ", defaultSettings = " << settingsToJSString(defaultSettings) + << ")"; - LMS_LOG(UI, DEBUG, "Running js = '" << oss.str() << "'"); - doJavaScript(oss.str()); - } + LMS_LOG(UI, DEBUG, "Running js = '" << oss.str() << "'"); + doJavaScript(oss.str()); + } } void MediaPlayer::loadTrack(db::TrackId trackId, bool play, float replayGain) @@ -246,7 +242,7 @@ namespace lms::ui const std::string transcodingResource{ _audioTranscodingResource->getUrl(trackId) }; const std::string nativeResource{ _audioFileResource->getUrl(trackId) }; - const auto artists{ track->getArtists({db::TrackArtistLinkType::Artist}) }; + const auto artists{ track->getArtists({ db::TrackArtistLinkType::Artist }) }; oss << "var params = {" diff --git a/src/lms/ui/MediaPlayer.hpp b/src/lms/ui/MediaPlayer.hpp index 88b178db..5d627c45 100644 --- a/src/lms/ui/MediaPlayer.hpp +++ b/src/lms/ui/MediaPlayer.hpp @@ -59,9 +59,9 @@ namespace lms::ui static inline constexpr Format defaultFormat{ Format::OGG_OPUS }; static inline constexpr Bitrate defaultBitrate{ 128000 }; - Mode mode{ defaultMode }; - Format format{ defaultFormat }; - Bitrate bitrate{ defaultBitrate }; + Mode mode{ defaultMode }; + Format format{ defaultFormat }; + Bitrate bitrate{ defaultBitrate }; }; struct ReplayGain @@ -74,14 +74,14 @@ namespace lms::ui Release = 3, }; - static inline constexpr Mode defaultMode{ Mode::None }; - static inline constexpr Gain defaultPreAmpGain{}; - static inline constexpr Gain minPreAmpGain{ -15 }; - static inline constexpr Gain maxPreAmpGain{ 15 }; + static inline constexpr Mode defaultMode{ Mode::None }; + static inline constexpr Gain defaultPreAmpGain{}; + static inline constexpr Gain minPreAmpGain{ -15 }; + static inline constexpr Gain maxPreAmpGain{ 15 }; - Mode mode{ defaultMode }; - Gain preAmpGain{ defaultPreAmpGain }; - Gain preAmpGainIfNoInfo{ defaultPreAmpGain }; + Mode mode{ defaultMode }; + Gain preAmpGain{ defaultPreAmpGain }; + Gain preAmpGainIfNoInfo{ defaultPreAmpGain }; }; Transcoding transcoding; @@ -98,30 +98,30 @@ namespace lms::ui void loadTrack(db::TrackId trackId, bool play, float replayGain); void stop(); - std::optional getSettings() const { return _settings; } - void setSettings(const Settings& settings); + std::optional getSettings() const { return _settings; } + void setSettings(const Settings& settings); - void onPlayQueueUpdated(std::size_t trackCount); + void onPlayQueueUpdated(std::size_t trackCount); // Signals - Wt::JSignal<> playPrevious; - Wt::JSignal<> playNext; - Wt::Signal trackLoaded; - Wt::Signal<> settingsLoaded; + Wt::JSignal<> playPrevious; + Wt::JSignal<> playNext; + Wt::Signal trackLoaded; + Wt::Signal<> settingsLoaded; - Wt::JSignal scrobbleListenNow; - Wt::JSignal scrobbleListenFinished; + Wt::JSignal scrobbleListenNow; + Wt::JSignal scrobbleListenFinished; - Wt::JSignal<> playbackEnded; + Wt::JSignal<> playbackEnded; private: - std::unique_ptr _audioFileResource; - std::unique_ptr _audioTranscodingResource; + std::unique_ptr _audioFileResource; + std::unique_ptr _audioTranscodingResource; std::optional _trackIdLoaded; - std::optional _settings; + std::optional _settings; - Wt::JSignal _settingsLoaded; + Wt::JSignal _settingsLoaded; Wt::WText* _title{}; Wt::WAnchor* _release{}; @@ -131,4 +131,3 @@ namespace lms::ui }; } // namespace lms::ui - diff --git a/src/lms/ui/ModalManager.cpp b/src/lms/ui/ModalManager.cpp index c0679e9c..d17e5a41 100644 --- a/src/lms/ui/ModalManager.cpp +++ b/src/lms/ui/ModalManager.cpp @@ -25,20 +25,19 @@ namespace lms::ui ModalManager::ModalManager() : _closed{ this, "closed" } { - _closed.connect([this](const std::string& id) + _closed.connect([this](const std::string& id) { + LMS_LOG(UI, DEBUG, "Received closed for id '" << id << "'"); + for (int i{}; i < count(); ++i) { - LMS_LOG(UI, DEBUG, "Received closed for id '" << id << "'"); - for (int i{}; i < count(); ++i) + Wt::WWidget* widget{ this->widget(i) }; + LMS_LOG(UI, DEBUG, "Widget " << i << ", id = '" << widget->id()); + if (widget->id() == id) { - Wt::WWidget* widget{ this->widget(i) }; - LMS_LOG(UI, DEBUG, "Widget " << i << ", id = '" << widget->id()); - if (widget->id() == id) - { - removeWidget(widget); - break; - } + removeWidget(widget); + break; } - }); + } + }); } void ModalManager::show(std::unique_ptr modalWidget) @@ -76,4 +75,4 @@ namespace lms::ui doJavaScript(oss.str()); } -} +} // namespace lms::ui diff --git a/src/lms/ui/ModalManager.hpp b/src/lms/ui/ModalManager.hpp index 49ac7fc8..17acf033 100644 --- a/src/lms/ui/ModalManager.hpp +++ b/src/lms/ui/ModalManager.hpp @@ -25,17 +25,17 @@ namespace lms::ui { - class ModalManager : public Wt::WContainerWidget - { - public: - ModalManager(); + class ModalManager : public Wt::WContainerWidget + { + public: + ModalManager(); - // should handle only one modal at a time - // Widget must contain a "modal" element - void show(std::unique_ptr modalWidget); - void dispose(Wt::WWidget* modalWidget); + // should handle only one modal at a time + // Widget must contain a "modal" element + void show(std::unique_ptr modalWidget); + void dispose(Wt::WWidget* modalWidget); - private: - Wt::JSignal _closed; - }; -} + private: + Wt::JSignal _closed; + }; +} // namespace lms::ui diff --git a/src/lms/ui/Notification.hpp b/src/lms/ui/Notification.hpp index abd451a5..e35dce6c 100644 --- a/src/lms/ui/Notification.hpp +++ b/src/lms/ui/Notification.hpp @@ -1,11 +1,30 @@ +/* + * Copyright (C) 2024 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 namespace lms::ui::Notification { - enum class Type - { - Info, - Warning, - Danger, - }; -} + enum class Type + { + Info, + Warning, + Danger, + }; +} // namespace lms::ui::Notification diff --git a/src/lms/ui/NotificationContainer.cpp b/src/lms/ui/NotificationContainer.cpp index 20cbd0ab..d76f2ea2 100644 --- a/src/lms/ui/NotificationContainer.cpp +++ b/src/lms/ui/NotificationContainer.cpp @@ -20,9 +20,11 @@ #include "NotificationContainer.hpp" #include + #include #include "core/ILogger.hpp" + #include "LmsApplication.hpp" namespace lms::ui @@ -35,7 +37,7 @@ namespace lms::ui NotificationWidget(Notification::Type type, const Wt::WString& category, const Wt::WString& message, std::chrono::milliseconds duration); Wt::JSignal<> closed{ this, "closed" }; }; - } + } // namespace NotificationWidget::NotificationWidget(Notification::Type type, const Wt::WString& category, const Wt::WString& message, std::chrono::milliseconds duration) : Wt::WTemplate{ Wt::WString::tr("Lms.notifications.template.entry") } @@ -80,9 +82,8 @@ namespace lms::ui { NotificationWidget* notification{ addNew(type, category, message, duration) }; - notification->closed.connect([this, notification] - { - removeWidget(notification); - }); + notification->closed.connect([this, notification] { + removeWidget(notification); + }); } -} +} // namespace lms::ui diff --git a/src/lms/ui/NotificationContainer.hpp b/src/lms/ui/NotificationContainer.hpp index 4f7b7e59..d4ba3921 100644 --- a/src/lms/ui/NotificationContainer.hpp +++ b/src/lms/ui/NotificationContainer.hpp @@ -20,6 +20,7 @@ #pragma once #include + #include #include @@ -27,11 +28,11 @@ namespace lms::ui { - class NotificationContainer : public Wt::WContainerWidget - { - public: - void add(Notification::Type type, const Wt::WString& category, const Wt::WString& message, std::chrono::milliseconds duration); + class NotificationContainer : public Wt::WContainerWidget + { + public: + void add(Notification::Type type, const Wt::WString& category, const Wt::WString& message, std::chrono::milliseconds duration); - private: - }; + private: + }; } // namespace lms::ui diff --git a/src/lms/ui/PlayQueue.cpp b/src/lms/ui/PlayQueue.cpp index d12f7889..3ef281cd 100644 --- a/src/lms/ui/PlayQueue.cpp +++ b/src/lms/ui/PlayQueue.cpp @@ -23,11 +23,16 @@ #include #include #include -#include #include +#include #include #include +#include "core/IConfig.hpp" +#include "core/ILogger.hpp" +#include "core/Random.hpp" +#include "core/Service.hpp" +#include "core/String.hpp" #include "database/Artist.hpp" #include "database/Release.hpp" #include "database/Session.hpp" @@ -36,20 +41,15 @@ #include "database/User.hpp" #include "services/feedback/IFeedbackService.hpp" #include "services/recommendation/IPlaylistGeneratorService.hpp" -#include "core/IConfig.hpp" -#include "core/ILogger.hpp" -#include "core/Random.hpp" -#include "core/Service.hpp" -#include "core/String.hpp" -#include "common/InfiniteScrollingContainer.hpp" -#include "common/MandatoryValidator.hpp" -#include "common/ValueStringModel.hpp" -#include "resource/DownloadResource.hpp" #include "LmsApplication.hpp" #include "MediaPlayer.hpp" #include "ModalManager.hpp" #include "Utils.hpp" +#include "common/InfiniteScrollingContainer.hpp" +#include "common/MandatoryValidator.hpp" +#include "common/ValueStringModel.hpp" +#include "resource/DownloadResource.hpp" namespace lms::ui { @@ -100,17 +100,16 @@ namespace lms::ui params.setUser(LmsApp->getUserId()); params.setSortMethod(TrackListSortMethod::Name); - TrackList::find(LmsApp->getDbSession(), params, [&](const TrackList::pointer& trackList) - { - model->add(Wt::WString::fromUTF8(std::string{ trackList->getName() }), trackList->getId()); - }); + TrackList::find(LmsApp->getDbSession(), params, [&](const TrackList::pointer& trackList) { + model->add(Wt::WString::fromUTF8(std::string{ trackList->getName() }), trackList->getId()); + }); return model; } std::shared_ptr trackListModel{ createTrackListModel() }; }; - } + } // namespace PlayQueue::PlayQueue() : Template{ Wt::WString::tr("Lms.PlayQueue.template") } @@ -122,51 +121,46 @@ namespace lms::ui addFunction("tr", &Wt::WTemplate::Functions::tr); Wt::WPushButton* clearBtn{ bindNew("clear-btn", Wt::WString::tr("Lms.PlayQueue.template.clear-btn"), Wt::TextFormat::XHTML) }; - clearBtn->clicked().connect([this] - { - clearTracks(); - }); + clearBtn->clicked().connect([this] { + clearTracks(); + }); Wt::WPushButton* saveBtn{ bindNew("save-btn", Wt::WString::tr("Lms.PlayQueue.template.save-btn"), Wt::TextFormat::XHTML) }; - saveBtn->clicked().connect([this] - { - saveAsTrackList(); - }); + saveBtn->clicked().connect([this] { + saveAsTrackList(); + }); _entriesContainer = bindNew("entries", Wt::WString::tr("Lms.PlayQueue.template.entry-container")); - _entriesContainer->onRequestElements.connect([this] - { - addSome(); - updateCurrentTrack(true); - }); + _entriesContainer->onRequestElements.connect([this] { + addSome(); + updateCurrentTrack(true); + }); Wt::WPushButton* shuffleBtn{ bindNew("shuffle-btn", Wt::WString::tr("Lms.PlayQueue.template.shuffle-btn"), Wt::TextFormat::XHTML) }; - shuffleBtn->clicked().connect([this] - { - { - // TODO write scope could be reduced - auto transaction{ LmsApp->getDbSession().createWriteTransaction() }; - - db::TrackList::pointer queue{ getQueue() }; - auto entries{ queue->getEntries().results }; - core::random::shuffleContainer(entries); - - queue.modify()->clear(); - for (const db::TrackListEntry::pointer& entry : entries) - LmsApp->getDbSession().create(entry->getTrack(), queue); - } - _entriesContainer->reset(); - addSome(); - }); - - _repeatBtn = bindNew("repeat-btn"); - _repeatBtn->clicked().connect([this] + shuffleBtn->clicked().connect([this] { { + // TODO write scope could be reduced auto transaction{ LmsApp->getDbSession().createWriteTransaction() }; - if (!LmsApp->getUser()->isDemo()) - LmsApp->getUser().modify()->setRepeatAll(isRepeatAllSet()); - }); + db::TrackList::pointer queue{ getQueue() }; + auto entries{ queue->getEntries().results }; + core::random::shuffleContainer(entries); + + queue.modify()->clear(); + for (const db::TrackListEntry::pointer& entry : entries) + LmsApp->getDbSession().create(entry->getTrack(), queue); + } + _entriesContainer->reset(); + addSome(); + }); + + _repeatBtn = bindNew("repeat-btn"); + _repeatBtn->clicked().connect([this] { + auto transaction{ LmsApp->getDbSession().createWriteTransaction() }; + + if (!LmsApp->getUser()->isDemo()) + LmsApp->getUser().modify()->setRepeatAll(isRepeatAllSet()); + }); { auto transaction{ LmsApp->getDbSession().createReadTransaction() }; if (LmsApp->getUser()->isRepeatAllSet()) @@ -174,17 +168,16 @@ namespace lms::ui } _radioBtn = bindNew("radio-btn"); - _radioBtn->clicked().connect([this] + _radioBtn->clicked().connect([this] { { - { - auto transaction{ LmsApp->getDbSession().createWriteTransaction() }; + auto transaction{ LmsApp->getDbSession().createWriteTransaction() }; - if (!LmsApp->getUser()->isDemo()) - LmsApp->getUser().modify()->setRadio(isRadioModeSet()); - } - if (isRadioModeSet()) - enqueueRadioTracksIfNeeded(); - }); + if (!LmsApp->getUser()->isDemo()) + LmsApp->getUser().modify()->setRadio(isRadioModeSet()); + } + if (isRadioModeSet()) + enqueueRadioTracksIfNeeded(); + }); bool isRadioModeSet{}; { @@ -200,34 +193,32 @@ namespace lms::ui _nbTracks = bindNew("track-count"); _duration = bindNew("duration"); - LmsApp->getMediaPlayer().settingsLoaded.connect([this] + LmsApp->getMediaPlayer().settingsLoaded.connect([this] { + if (_mediaPlayerSettingsLoaded) + return; + + _mediaPlayerSettingsLoaded = true; + + std::size_t trackPos{}; + { - if (_mediaPlayerSettingsLoaded) - return; + auto transaction{ LmsApp->getDbSession().createReadTransaction() }; + trackPos = LmsApp->getUser()->getCurPlayingTrackPos(); + } - _mediaPlayerSettingsLoaded = true; + loadTrack(trackPos, false); + }); - std::size_t trackPos{}; + LmsApp->preQuit().connect([this] { + auto transaction{ LmsApp->getDbSession().createWriteTransaction() }; - { - auto transaction{ LmsApp->getDbSession().createReadTransaction() }; - trackPos = LmsApp->getUser()->getCurPlayingTrackPos(); - } - - loadTrack(trackPos, false); - }); - - LmsApp->preQuit().connect([this] + if (LmsApp->getUser()->isDemo()) { - auto transaction{ LmsApp->getDbSession().createWriteTransaction() }; - - if (LmsApp->getUser()->isDemo()) - { - LMS_LOG(UI, DEBUG, "Removing queue (tracklist id " << _queueId.toString() << ")"); - if (db::TrackList::pointer queue{ getQueue() }) - queue.remove(); - } - }); + LMS_LOG(UI, DEBUG, "Removing queue (tracklist id " << _queueId.toString() << ")"); + if (db::TrackList::pointer queue{ getQueue() }) + queue.remove(); + } + }); updateInfo(); } @@ -427,7 +418,7 @@ namespace lms::ui auto transaction{ LmsApp->getDbSession().createWriteTransaction() }; db::TrackList::pointer queue{ getQueue() }; - auto entries{ queue->getEntries(db::Range {_trackPos ? *_trackPos + 1 : 0, getCapacity()}) }; + auto entries{ queue->getEntries(db::Range{ _trackPos ? *_trackPos + 1 : 0, getCapacity() }) }; tracks.reserve(entries.results.size()); for (db::TrackListEntry::pointer& entry : entries.results) { @@ -489,7 +480,7 @@ namespace lms::ui auto transaction{ LmsApp->getDbSession().createReadTransaction() }; const db::TrackList::pointer queue{ getQueue() }; - const auto entries{ queue->getEntries(db::Range {_entriesContainer->getCount(), _batchSize}) }; + const auto entries{ queue->getEntries(db::Range{ _entriesContainer->getCount(), _batchSize }) }; for (const db::TrackListEntry::pointer& tracklistEntry : entries.results) addEntry(tracklistEntry); @@ -507,7 +498,7 @@ namespace lms::ui entry->bindString("name", Wt::WString::fromUTF8(track->getName()), Wt::TextFormat::Plain); - const auto artists{ track->getArtistIds({db::TrackArtistLinkType::Artist}) }; + const auto artists{ track->getArtistIds({ db::TrackArtistLinkType::Artist }) }; if (!artists.empty()) { entry->setCondition("if-has-artists", true); @@ -536,66 +527,63 @@ namespace lms::ui entry->bindString("duration", utils::durationToString(track->getDuration()), Wt::TextFormat::Plain); Wt::WPushButton* playBtn{ entry->bindNew("play-btn", Wt::WString::tr("Lms.template.play-btn"), Wt::TextFormat::XHTML) }; - playBtn->clicked().connect([this, entry] + playBtn->clicked().connect([this, entry] { + const std::optional pos{ _entriesContainer->getIndexOf(*entry) }; + if (pos) + loadTrack(*pos, true); + }); + + Wt::WPushButton* delBtn{ entry->bindNew("del-btn", Wt::WString::tr("Lms.template.delete-btn"), Wt::TextFormat::XHTML) }; + delBtn->setToolTip(Wt::WString::tr("Lms.delete")); + delBtn->clicked().connect([this, tracklistEntryId, entry] { + // Remove the entry n both the widget tree and the playqueue { + auto transaction{ LmsApp->getDbSession().createWriteTransaction() }; + + db::TrackListEntry::pointer entryToRemove{ db::TrackListEntry::getById(LmsApp->getDbSession(), tracklistEntryId) }; + entryToRemove.remove(); + } + + if (_trackPos) + { + const std::optional pos{ _entriesContainer->getIndexOf(*entry) }; + if (pos && *_trackPos >= *pos) + (*_trackPos)--; + else if (*_trackPos >= _entriesContainer->getCount()) + _trackPos.reset(); + } + + _entriesContainer->remove(*entry); + + updateInfo(); + }); + + entry->bindNew("more-btn", Wt::WString::tr("Lms.template.more-btn"), Wt::TextFormat::XHTML); + entry->bindNew("play", Wt::WString::tr("Lms.Explore.play")) + ->clicked() + .connect([this, entry] { const std::optional pos{ _entriesContainer->getIndexOf(*entry) }; if (pos) loadTrack(*pos, true); }); - Wt::WPushButton* delBtn{ entry->bindNew("del-btn", Wt::WString::tr("Lms.template.delete-btn"), Wt::TextFormat::XHTML) }; - delBtn->setToolTip(Wt::WString::tr("Lms.delete")); - delBtn->clicked().connect([this, tracklistEntryId, entry] - { - // Remove the entry n both the widget tree and the playqueue - { - auto transaction{ LmsApp->getDbSession().createWriteTransaction() }; - - db::TrackListEntry::pointer entryToRemove{ db::TrackListEntry::getById(LmsApp->getDbSession(), tracklistEntryId) }; - entryToRemove.remove(); - } - - if (_trackPos) - { - const std::optional pos{ _entriesContainer->getIndexOf(*entry) }; - if (pos && *_trackPos >= *pos) - (*_trackPos)--; - else if (*_trackPos >= _entriesContainer->getCount()) - _trackPos.reset(); - } - - _entriesContainer->remove(*entry); - - updateInfo(); - }); - - entry->bindNew("more-btn", Wt::WString::tr("Lms.template.more-btn"), Wt::TextFormat::XHTML); - entry->bindNew("play", Wt::WString::tr("Lms.Explore.play")) - ->clicked().connect([this, entry] - { - const std::optional pos{ _entriesContainer->getIndexOf(*entry) }; - if (pos) - loadTrack(*pos, true); - }); - auto isStarred{ [=] { return core::Service::get()->isStarred(LmsApp->getUserId(), trackId); } }; Wt::WPushButton* starBtn{ entry->bindNew("star", Wt::WString::tr(isStarred() ? "Lms.Explore.unstar" : "Lms.Explore.star")) }; - starBtn->clicked().connect([=] - { - auto transaction{ LmsApp->getDbSession().createWriteTransaction() }; + starBtn->clicked().connect([=] { + auto transaction{ LmsApp->getDbSession().createWriteTransaction() }; - if (isStarred()) - { - core::Service::get()->unstar(LmsApp->getUserId(), trackId); - starBtn->setText(Wt::WString::tr("Lms.Explore.star")); - } - else - { - core::Service::get()->star(LmsApp->getUserId(), trackId); - starBtn->setText(Wt::WString::tr("Lms.Explore.unstar")); - } - }); + if (isStarred()) + { + core::Service::get()->unstar(LmsApp->getUserId(), trackId); + starBtn->setText(Wt::WString::tr("Lms.Explore.star")); + } + else + { + core::Service::get()->star(LmsApp->getUserId(), trackId); + starBtn->setText(Wt::WString::tr("Lms.Explore.unstar")); + } + }); entry->bindNew("download", Wt::WString::tr("Lms.Explore.download")) ->setLink(Wt::WLink{ std::make_unique(trackId) }); @@ -651,27 +639,26 @@ namespace lms::ui break; case MediaPlayer::Settings::ReplayGain::Mode::Auto: - { - const db::TrackList::pointer queue{ getQueue() }; - const db::TrackListEntry::pointer prevEntry{ pos > 0 ? queue->getEntry(pos - 1) : db::TrackListEntry::pointer {} }; - const db::TrackListEntry::pointer nextEntry{ queue->getEntry(pos + 1) }; - const db::Track::pointer prevTrack{ prevEntry ? prevEntry->getTrack() : db::Track::pointer {} }; - const db::Track::pointer nextTrack{ nextEntry ? nextEntry->getTrack() : db::Track::pointer {} }; + { + const db::TrackList::pointer queue{ getQueue() }; + const db::TrackListEntry::pointer prevEntry{ pos > 0 ? queue->getEntry(pos - 1) : db::TrackListEntry::pointer{} }; + const db::TrackListEntry::pointer nextEntry{ queue->getEntry(pos + 1) }; + const db::Track::pointer prevTrack{ prevEntry ? prevEntry->getTrack() : db::Track::pointer{} }; + const db::Track::pointer nextTrack{ nextEntry ? nextEntry->getTrack() : db::Track::pointer{} }; - if ((prevTrack && prevTrack->getRelease() && prevTrack->getRelease() == track->getRelease()) - || - (nextTrack && nextTrack->getRelease() && nextTrack->getRelease() == track->getRelease())) - { - gain = track->getReleaseReplayGain(); - if (!gain) + if ((prevTrack && prevTrack->getRelease() && prevTrack->getRelease() == track->getRelease()) + || (nextTrack && nextTrack->getRelease() && nextTrack->getRelease() == track->getRelease())) + { + gain = track->getReleaseReplayGain(); + if (!gain) + gain = track->getTrackReplayGain(); + } + else + { gain = track->getTrackReplayGain(); + } + break; } - else - { - gain = track->getTrackReplayGain(); - } - break; - } } if (gain) @@ -688,10 +675,9 @@ namespace lms::ui Wt::WWidget* modalPtr{ modal.get() }; auto* cancelBtn{ modal->bindNew("cancel-btn", Wt::WString::tr("Lms.cancel")) }; - cancelBtn->clicked().connect([=] - { - LmsApp->getModalManager().dispose(modalPtr); - }); + cancelBtn->clicked().connect([=] { + LmsApp->getModalManager().dispose(modalPtr); + }); Wt::WStackedWidget* contentStack{ modal->bindNew("contents") }; @@ -703,17 +689,16 @@ namespace lms::ui }; { modal->bindNew("replace-tracklist-btn") - ->clicked().connect([=] - { - contentStack->setCurrentIndex(Index::ReplaceTrackList); - }); + ->clicked() + .connect([=] { + contentStack->setCurrentIndex(Index::ReplaceTrackList); + }); Wt::WRadioButton* createTrackListBtn{ modal->bindNew("create-tracklist-btn") }; createTrackListBtn->setChecked(); - createTrackListBtn->clicked().connect([=] - { - contentStack->setCurrentIndex(Index::CreateTrackList); - }); + createTrackListBtn->clicked().connect([=] { + contentStack->setCurrentIndex(Index::CreateTrackList); + }); } // Create TrackList @@ -733,35 +718,34 @@ namespace lms::ui replaceTrackList->updateView(replaceTrackListModel.get()); auto* saveBtn{ modal->bindNew("save-btn", Wt::WString::tr("Lms.save")) }; - saveBtn->clicked().connect([=, this] + saveBtn->clicked().connect([=, this] { + bool success{}; + switch (contentStack->currentIndex()) { - bool success{}; - switch (contentStack->currentIndex()) + case Index::CreateTrackList: + createTrackList->updateModel(createTrackListModel.get()); + if (createTrackListModel->validate()) { - case Index::CreateTrackList: - createTrackList->updateModel(createTrackListModel.get()); - if (createTrackListModel->validate()) - { - exportToNewTrackList(createTrackListModel->getName()); - success = true; - } - createTrackList->updateView(createTrackListModel.get()); - break; - - case Index::ReplaceTrackList: - replaceTrackList->updateModel(replaceTrackListModel.get()); - if (replaceTrackListModel->validate()) - { - exportToTrackList(replaceTrackListModel->getTrackListId()); - success = true; - } - replaceTrackList->updateView(replaceTrackListModel.get()); - break; + exportToNewTrackList(createTrackListModel->getName()); + success = true; } + createTrackList->updateView(createTrackListModel.get()); + break; - if (success) - LmsApp->getModalManager().dispose(modalPtr); - }); + case Index::ReplaceTrackList: + replaceTrackList->updateModel(replaceTrackListModel.get()); + if (replaceTrackListModel->validate()) + { + exportToTrackList(replaceTrackListModel->getTrackListId()); + success = true; + } + replaceTrackList->updateView(replaceTrackListModel.get()); + break; + } + + if (success) + LmsApp->getModalManager().dispose(modalPtr); + }); LmsApp->getModalManager().show(std::move(modal)); } @@ -796,9 +780,8 @@ namespace lms::ui params.setTrackList(_queueId); params.setSortMethod(TrackSortMethod::TrackList); - Track::find(session, params, [&](const Track::pointer& track) - { - session.create(track, trackList); - }); + Track::find(session, params, [&](const Track::pointer& track) { + session.create(track, trackList); + }); } } // namespace lms::ui diff --git a/src/lms/ui/PlayQueue.hpp b/src/lms/ui/PlayQueue.hpp index d797e7e3..a6debe27 100644 --- a/src/lms/ui/PlayQueue.hpp +++ b/src/lms/ui/PlayQueue.hpp @@ -32,90 +32,89 @@ #include "common/Template.hpp" - namespace lms::db { - class Track; - class TrackList; - class TrackListEntry; -} + class Track; + class TrackList; + class TrackListEntry; +} // namespace lms::db -namespace lms::ui { - -class InfiniteScrollingContainer; - -class PlayQueue : public Template +namespace lms::ui { - public: - PlayQueue(); - void play(const std::vector& trackIds); - void playNext(const std::vector& trackIds); - void playShuffled(const std::vector& trackIds); - void playOrAddLast(const std::vector& trackIds); // play if queue empty, otherwise just add last - void playAtIndex(const std::vector& trackIds, std::size_t index); + class InfiniteScrollingContainer; - // play the next track in the queue - void playNext(); + class PlayQueue : public Template + { + public: + PlayQueue(); - // play the previous track in the queue - void playPrevious(); + void play(const std::vector& trackIds); + void playNext(const std::vector& trackIds); + void playShuffled(const std::vector& trackIds); + void playOrAddLast(const std::vector& trackIds); // play if queue empty, otherwise just add last + void playAtIndex(const std::vector& trackIds, std::size_t index); - // Signal emitted when a track is to be load(and optionally played) - Wt::Signal trackSelected; + // play the next track in the queue + void playNext(); - // Signal emitted when track is unselected (has to be stopped) - Wt::Signal<> trackUnselected; + // play the previous track in the queue + void playPrevious(); - // Signal emitted when track count changed - Wt::Signal trackCountChanged; + // Signal emitted when a track is to be load(and optionally played) + Wt::Signal trackSelected; - void onPlaybackEnded(); + // Signal emitted when track is unselected (has to be stopped) + Wt::Signal<> trackUnselected; - std::size_t getCapacity() const { return _capacity; } - std::size_t getCount(); + // Signal emitted when track count changed + Wt::Signal trackCountChanged; - private: - void initTrackLists(); + void onPlaybackEnded(); - void notifyAddedTracks(std::size_t nbAddedTracks) const; - db::ObjectPtr getQueue() const; - bool isFull() const; + std::size_t getCapacity() const { return _capacity; } + std::size_t getCount(); - void clearTracks(); - void enqueueTracks(const std::vector& trackIds); - std::vector getAndClearNextTracks(); - void addSome(); - void addEntry(const db::ObjectPtr& entry); - void enqueueRadioTracksIfNeeded(); - void enqueueRadioTracks(); - void updateInfo(); - void updateCurrentTrack(bool selected); - bool isRepeatAllSet() const; - bool isRadioModeSet() const; + private: + void initTrackLists(); - void loadTrack(std::size_t pos, bool play); - void stop(); + void notifyAddedTracks(std::size_t nbAddedTracks) const; + db::ObjectPtr getQueue() const; + bool isFull() const; - std::optional getReplayGain(std::size_t pos, const db::ObjectPtr& track) const; - void saveAsTrackList(); + void clearTracks(); + void enqueueTracks(const std::vector& trackIds); + std::vector getAndClearNextTracks(); + void addSome(); + void addEntry(const db::ObjectPtr& entry); + void enqueueRadioTracksIfNeeded(); + void enqueueRadioTracks(); + void updateInfo(); + void updateCurrentTrack(bool selected); + bool isRepeatAllSet() const; + bool isRadioModeSet() const; - void exportToNewTrackList(const Wt::WString& name); - void exportToTrackList(db::TrackListId trackList); + void loadTrack(std::size_t pos, bool play); + void stop(); - const std::size_t _capacity; - static inline constexpr std::size_t _batchSize {12}; + std::optional getReplayGain(std::size_t pos, const db::ObjectPtr& track) const; + void saveAsTrackList(); - bool _mediaPlayerSettingsLoaded {}; - db::TrackListId _queueId {}; - InfiniteScrollingContainer* _entriesContainer {}; - Wt::WText* _nbTracks {}; - Wt::WText* _duration {}; - Wt::WCheckBox* _repeatBtn {}; - Wt::WCheckBox* _radioBtn {}; - std::optional _trackPos; // current track position, if set - bool _isTrackSelected {}; -}; + void exportToNewTrackList(const Wt::WString& name); + void exportToTrackList(db::TrackListId trackList); + + const std::size_t _capacity; + static inline constexpr std::size_t _batchSize{ 12 }; + + bool _mediaPlayerSettingsLoaded{}; + db::TrackListId _queueId{}; + InfiniteScrollingContainer* _entriesContainer{}; + Wt::WText* _nbTracks{}; + Wt::WText* _duration{}; + Wt::WCheckBox* _repeatBtn{}; + Wt::WCheckBox* _radioBtn{}; + std::optional _trackPos; // current track position, if set + bool _isTrackSelected{}; + }; } // namespace lms::ui - diff --git a/src/lms/ui/SettingsView.cpp b/src/lms/ui/SettingsView.cpp index 9604f672..f82c8445 100644 --- a/src/lms/ui/SettingsView.cpp +++ b/src/lms/ui/SettingsView.cpp @@ -28,22 +28,21 @@ #include #include +#include "core/IConfig.hpp" +#include "core/ILogger.hpp" +#include "core/Service.hpp" +#include "database/Session.hpp" +#include "database/User.hpp" +#include "services/auth/IPasswordService.hpp" + +#include "LmsApplication.hpp" +#include "MediaPlayer.hpp" #include "common/DoubleValidator.hpp" #include "common/MandatoryValidator.hpp" #include "common/PasswordValidator.hpp" #include "common/UUIDValidator.hpp" #include "common/ValueStringModel.hpp" -#include "services/auth/IPasswordService.hpp" -#include "database/Session.hpp" -#include "database/User.hpp" -#include "core/IConfig.hpp" -#include "core/ILogger.hpp" -#include "core/Service.hpp" - -#include "LmsApplication.hpp" -#include "MediaPlayer.hpp" - namespace lms::ui { using namespace db; @@ -111,8 +110,7 @@ namespace lms::ui setValidator(TranscodeBitrateField, createMandatoryValidator()); setValidator(TranscodeFormatField, createMandatoryValidator()); setValidator(ReplayGainModeField, createMandatoryValidator()); - auto createPreAmpValidator{ [] - { + auto createPreAmpValidator{ [] { return createDoubleValidator(MediaPlayer::Settings::ReplayGain::minPreAmpGain, MediaPlayer::Settings::ReplayGain::maxPreAmpGain); } }; @@ -124,13 +122,13 @@ namespace lms::ui loadData(); } - std::shared_ptr getTranscodingModeModel() { return _transcodingModeModeModel; } - std::shared_ptr getTranscodingOutputBitrateModel() { return _transcodingOutputBitrateModel; } - std::shared_ptr getTranscodingOutputFormatModel() { return _transcodingOutputFormatModel; } - std::shared_ptr getReplayGainModeModel() { return _replayGainModeModel; } - std::shared_ptr getSubsonicArtistListModeModel() { return _subsonicArtistListModeModel; } - std::shared_ptr getFeedbackBackendModel() { return _feedbackBackendModel; } - std::shared_ptr getScrobblingBackendModel() { return _scrobblingBackendModel; } + std::shared_ptr getTranscodingModeModel() { return _transcodingModeModeModel; } + std::shared_ptr getTranscodingOutputBitrateModel() { return _transcodingOutputBitrateModel; } + std::shared_ptr getTranscodingOutputFormatModel() { return _transcodingOutputFormatModel; } + std::shared_ptr getReplayGainModeModel() { return _replayGainModeModel; } + std::shared_ptr getSubsonicArtistListModeModel() { return _subsonicArtistListModeModel; } + std::shared_ptr getFeedbackBackendModel() { return _feedbackBackendModel; } + std::shared_ptr getScrobblingBackendModel() { return _scrobblingBackendModel; } void saveData() { @@ -315,7 +313,6 @@ namespace lms::ui } private: - void initializeModels() { _transcodingModeModeModel = std::make_shared(); @@ -324,10 +321,9 @@ namespace lms::ui _transcodingModeModeModel->add(Wt::WString::tr("Lms.Settings.transcoding-mode.if-format-not-supported"), MediaPlayer::Settings::Transcoding::Mode::IfFormatNotSupported); _transcodingOutputBitrateModel = std::make_shared>(); - visitAllowedAudioBitrates([&](const Bitrate bitrate) - { - _transcodingOutputBitrateModel->add(Wt::WString::fromUTF8(std::to_string(bitrate / 1000)), bitrate); - }); + visitAllowedAudioBitrates([&](const Bitrate bitrate) { + _transcodingOutputBitrateModel->add(Wt::WString::fromUTF8(std::to_string(bitrate / 1000)), bitrate); + }); _transcodingOutputFormatModel = std::make_shared>(); _transcodingOutputFormatModel->add(Wt::WString::tr("Lms.Settings.transcoding-output-format.mp3"), TranscodingOutputFormat::MP3); @@ -359,32 +355,30 @@ namespace lms::ui auth::IPasswordService* _authPasswordService{}; bool _withOldPassword{}; - std::shared_ptr _transcodingModeModeModel; - std::shared_ptr> _transcodingOutputBitrateModel; - std::shared_ptr> _transcodingOutputFormatModel; - std::shared_ptr _replayGainModeModel; - std::shared_ptr> _subsonicArtistListModeModel; - std::shared_ptr _feedbackBackendModel; - std::shared_ptr _scrobblingBackendModel; + std::shared_ptr _transcodingModeModeModel; + std::shared_ptr> _transcodingOutputBitrateModel; + std::shared_ptr> _transcodingOutputFormatModel; + std::shared_ptr _replayGainModeModel; + std::shared_ptr> _subsonicArtistListModeModel; + std::shared_ptr _feedbackBackendModel; + std::shared_ptr _scrobblingBackendModel; }; SettingsView::SettingsView() { - wApp->internalPathChanged().connect(this, [this] - { - refreshView(); - }); + wApp->internalPathChanged().connect(this, [this] { + refreshView(); + }); - LmsApp->getMediaPlayer().settingsLoaded.connect([this] - { - refreshView(); - }); + LmsApp->getMediaPlayer().settingsLoaded.connect([this] { + refreshView(); + }); refreshView(); } void - SettingsView::refreshView() + SettingsView::refreshView() { if (!wApp->internalPathMatches("/settings")) return; @@ -449,14 +443,13 @@ namespace lms::ui transcodingOutputBitrate->setModel(model->getTranscodingOutputBitrateModel()); t->setFormWidget(SettingsModel::TranscodeBitrateField, std::move(transcodingOutputBitrate)); - transcodingModeRaw->activated().connect([=](int row) - { - const bool enable{ model->getTranscodingModeModel()->getValue(row) != MediaPlayer::Settings::Transcoding::Mode::Never }; - model->setReadOnly(SettingsModel::TranscodeFormatField, !enable); - model->setReadOnly(SettingsModel::TranscodeBitrateField, !enable); - t->updateModel(model.get()); - t->updateView(model.get()); - }); + transcodingModeRaw->activated().connect([=](int row) { + const bool enable{ model->getTranscodingModeModel()->getValue(row) != MediaPlayer::Settings::Transcoding::Mode::Never }; + model->setReadOnly(SettingsModel::TranscodeFormatField, !enable); + model->setReadOnly(SettingsModel::TranscodeBitrateField, !enable); + t->updateModel(model.get()); + t->updateView(model.get()); + }); // Replay gain mode auto replayGainMode{ std::make_unique() }; @@ -474,14 +467,13 @@ namespace lms::ui replayGainPreampGainIfNoInfo->setRange(MediaPlayer::Settings::ReplayGain::minPreAmpGain, MediaPlayer::Settings::ReplayGain::maxPreAmpGain); t->setFormWidget(SettingsModel::ReplayGainPreAmpGainIfNoInfoField, std::move(replayGainPreampGainIfNoInfo)); - replayGainModeRaw->activated().connect([=](int row) - { - const bool enable{ model->getReplayGainModeModel()->getValue(row) != MediaPlayer::Settings::ReplayGain::Mode::None }; - model->setReadOnly(SettingsModel::SettingsModel::ReplayGainPreAmpGainField, !enable); - model->setReadOnly(SettingsModel::SettingsModel::ReplayGainPreAmpGainIfNoInfoField, !enable); - t->updateModel(model.get()); - t->updateView(model.get()); - }); + replayGainModeRaw->activated().connect([=](int row) { + const bool enable{ model->getReplayGainModeModel()->getValue(row) != MediaPlayer::Settings::ReplayGain::Mode::None }; + model->setReadOnly(SettingsModel::SettingsModel::ReplayGainPreAmpGainField, !enable); + model->setReadOnly(SettingsModel::SettingsModel::ReplayGainPreAmpGainIfNoInfoField, !enable); + t->updateModel(model.get()); + t->updateView(model.get()); + }); if (LmsApp->getMediaPlayer().getSettings()->replayGain.mode == MediaPlayer::Settings::ReplayGain::Mode::None) { model->setReadOnly(SettingsModel::SettingsModel::ReplayGainPreAmpGainField, true); @@ -536,10 +528,9 @@ namespace lms::ui t->setFormWidget(SettingsModel::ListenBrainzTokenField, std::move(listenbrainzToken)); } - auto updateListenBrainzTokenField{ [=] - { + auto updateListenBrainzTokenField{ [=] { const bool enable{ model->getFeedbackBackendModel()->getValue(feedbackBackendRaw->currentIndex()) == FeedbackBackend::ListenBrainz - || model->getScrobblingBackendModel()->getValue(scrobblingBackendRaw->currentIndex()) == ScrobblingBackend::ListenBrainz }; + || model->getScrobblingBackendModel()->getValue(scrobblingBackendRaw->currentIndex()) == ScrobblingBackend::ListenBrainz }; model->setReadOnly(SettingsModel::ListenBrainzTokenField, !enable); model->validator(SettingsModel::ListenBrainzTokenField)->setMandatory(enable); @@ -548,42 +539,40 @@ namespace lms::ui } }; feedbackBackendRaw->activated().connect([=] { updateListenBrainzTokenField(); }); - scrobblingBackendRaw->activated().connect([=] { updateListenBrainzTokenField();}); + scrobblingBackendRaw->activated().connect([=] { updateListenBrainzTokenField(); }); // Buttons Wt::WPushButton* saveBtn{ t->bindWidget("save-btn", std::make_unique(Wt::WString::tr("Lms.save"))) }; Wt::WPushButton* discardBtn{ t->bindWidget("discard-btn", std::make_unique(Wt::WString::tr("Lms.discard"))) }; - saveBtn->clicked().connect([=] + saveBtn->clicked().connect([=] { { + auto transaction{ LmsApp->getDbSession().createReadTransaction() }; + + if (LmsApp->getUser()->isDemo()) { - auto transaction{ LmsApp->getDbSession().createReadTransaction() }; - - if (LmsApp->getUser()->isDemo()) - { - LmsApp->notifyMsg(Notification::Type::Warning, Wt::WString::tr("Lms.Settings.settings"), Wt::WString::tr("Lms.Settings.demo-cannot-save")); - return; - } + LmsApp->notifyMsg(Notification::Type::Warning, Wt::WString::tr("Lms.Settings.settings"), Wt::WString::tr("Lms.Settings.demo-cannot-save")); + return; } + } - t->updateModel(model.get()); + t->updateModel(model.get()); - if (model->validate()) - { - model->saveData(); - LmsApp->notifyMsg(Notification::Type::Info, Wt::WString::tr("Lms.Settings.settings"), Wt::WString::tr("Lms.Settings.settings-saved")); - } - - // Udate the view: Delete any validation message in the view, etc. - t->updateView(model.get()); - }); - - discardBtn->clicked().connect([=] + if (model->validate()) { - model->loadData(); - model->validate(); - t->updateView(model.get()); - }); + model->saveData(); + LmsApp->notifyMsg(Notification::Type::Info, Wt::WString::tr("Lms.Settings.settings"), Wt::WString::tr("Lms.Settings.settings-saved")); + } + + // Udate the view: Delete any validation message in the view, etc. + t->updateView(model.get()); + }); + + discardBtn->clicked().connect([=] { + model->loadData(); + model->validate(); + t->updateView(model.get()); + }); t->updateView(model.get()); } diff --git a/src/lms/ui/SettingsView.hpp b/src/lms/ui/SettingsView.hpp index fc95809b..3a4c7db4 100644 --- a/src/lms/ui/SettingsView.hpp +++ b/src/lms/ui/SettingsView.hpp @@ -21,16 +21,16 @@ #include -namespace lms::ui { - -class SettingsView : public Wt::WContainerWidget +namespace lms::ui { - public: - SettingsView(); - private: - void refreshView(); -}; + class SettingsView : public Wt::WContainerWidget + { + public: + SettingsView(); + + private: + void refreshView(); + }; } // namespace lms::ui - diff --git a/src/lms/ui/Utils.cpp b/src/lms/ui/Utils.cpp index cc36f3fa..1fef4158 100644 --- a/src/lms/ui/Utils.cpp +++ b/src/lms/ui/Utils.cpp @@ -32,8 +32,9 @@ #include "database/Session.hpp" #include "database/Track.hpp" #include "database/TrackList.hpp" -#include "explore/Filters.hpp" + #include "LmsApplication.hpp" +#include "explore/Filters.hpp" namespace lms::ui::utils { @@ -61,12 +62,11 @@ namespace lms::ui::utils return oss.str(); } - std::unique_ptr createCover(db::ReleaseId releaseId, CoverResource::Size size) { auto cover{ std::make_unique() }; cover->setImageLink(LmsApp->getCoverResource()->getReleaseUrl(releaseId, size)); - cover->setStyleClass("Lms-cover img-fluid"); // HACK + cover->setStyleClass("Lms-cover img-fluid"); // HACK cover->setAttributeValue("onload", LmsApp->javaScriptClass() + ".onLoadCover(this)"); // HACK return cover; } @@ -75,7 +75,7 @@ namespace lms::ui::utils { auto cover{ std::make_unique() }; cover->setImageLink(LmsApp->getCoverResource()->getTrackUrl(trackId, size)); - cover->setStyleClass("Lms-cover img-fluid"); // HACK + cover->setStyleClass("Lms-cover img-fluid"); // HACK cover->setAttributeValue("onload", LmsApp->javaScriptClass() + ".onLoadCover(this)"); // HACK return cover; } @@ -99,18 +99,25 @@ namespace lms::ui::utils if (!cluster) return {}; - auto getStyleClass{ [](const db::Cluster::pointer& cluster) -> std::string_view - { + auto getStyleClass{ [](const db::Cluster::pointer& cluster) -> std::string_view { switch (cluster->getType()->getId().getValue() % 8) { - case 0: return "bg-primary"; - case 1: return "bg-secondary"; - case 2: return "bg-success"; - case 3: return "bg-danger"; - case 4: return "bg-warning text-dark"; - case 5: return "bg-info text-dark"; - case 6: return "bg-light text-dark"; - case 7: return "bg-dark"; + case 0: + return "bg-primary"; + case 1: + return "bg-secondary"; + case 2: + return "bg-success"; + case 3: + return "bg-danger"; + case 4: + return "bg-warning text-dark"; + case 5: + return "bg-info text-dark"; + case 6: + return "bg-light text-dark"; + case 7: + return "bg-dark"; } return "bg-primary"; @@ -135,10 +142,9 @@ namespace lms::ui::utils { const ClusterId clusterId{ cluster->getId() }; Wt::WInteractWidget* entry{ clusterContainer->addWidget(createFilterCluster(clusterId)) }; - entry->clicked().connect([&filters, clusterId] - { - filters.add(clusterId); - }); + entry->clicked().connect([&filters, clusterId] { + filters.add(clusterId); + }); } } @@ -199,7 +205,7 @@ namespace lms::ui::utils result->addNew(std::string{ displayName.substr(currentOffset, pos - currentOffset) }, Wt::TextFormat::Plain); auto anchor{ createArtistAnchor(artist) }; - anchor->addStyleClass("text-decoration-none"); // hack + anchor->addStyleClass("text-decoration-none"); // hack anchor->addStyleClass(std::string{ cssAnchorClass }); // hack result->addWidget(std::move(anchor)); currentOffset = pos + artist->getName().size(); @@ -251,7 +257,7 @@ namespace lms::ui::utils Wt::WLink createArtistLink(db::Artist::pointer artist) { if (const auto mbid{ artist->getMBID() }) - return Wt::WLink{ Wt::LinkType::InternalPath, "/artist/mbid/" + std::string {mbid->getAsString()} }; + return Wt::WLink{ Wt::LinkType::InternalPath, "/artist/mbid/" + std::string{ mbid->getAsString() } }; else return Wt::WLink{ Wt::LinkType::InternalPath, "/artist/" + artist->getId().toString() }; } @@ -273,7 +279,7 @@ namespace lms::ui::utils Wt::WLink createReleaseLink(db::Release::pointer release) { if (const auto mbid{ release->getMBID() }) - return Wt::WLink{ Wt::LinkType::InternalPath, "/release/mbid/" + std::string {mbid->getAsString()} }; + return Wt::WLink{ Wt::LinkType::InternalPath, "/release/mbid/" + std::string{ mbid->getAsString() } }; else return Wt::WLink{ Wt::LinkType::InternalPath, "/release/" + release->getId().toString() }; } @@ -300,7 +306,7 @@ namespace lms::ui::utils if (setText) { - const Wt::WString name{ Wt::WString::fromUTF8(std::string {trackList->getName()}) }; + const Wt::WString name{ Wt::WString::fromUTF8(std::string{ trackList->getName() }) }; res->setTextFormat(Wt::TextFormat::Plain); res->setText(name); res->setToolTip(name, Wt::TextFormat::Plain); @@ -308,4 +314,4 @@ namespace lms::ui::utils return res; } -} +} // namespace lms::ui::utils diff --git a/src/lms/ui/Utils.hpp b/src/lms/ui/Utils.hpp index f1db77c1..aab8de54 100644 --- a/src/lms/ui/Utils.hpp +++ b/src/lms/ui/Utils.hpp @@ -38,36 +38,36 @@ namespace lms::db { - class Artist; - class Cluster; - class Release; - class Track; - class TrackList; -} + class Artist; + class Cluster; + class Release; + class Track; + class TrackList; +} // namespace lms::db namespace lms::ui { - class Filters; + class Filters; } namespace lms::ui::utils { - std::string durationToString(std::chrono::milliseconds msDuration); + std::string durationToString(std::chrono::milliseconds msDuration); - std::unique_ptr createCover(db::ReleaseId releaseId, CoverResource::Size size); - std::unique_ptr createCover(db::TrackId trackId, CoverResource::Size size); + std::unique_ptr createCover(db::ReleaseId releaseId, CoverResource::Size size); + std::unique_ptr createCover(db::TrackId trackId, CoverResource::Size size); - std::unique_ptr createFilter(const Wt::WString& name, const Wt::WString& tooltip, std::string_view colorStyleClass, bool canDelete = false); - std::unique_ptr createFilterCluster(db::ClusterId clusterId, bool canDelete = false); - std::unique_ptr createFilterClustersForTrack(db::ObjectPtr track, Filters& filters); + std::unique_ptr createFilter(const Wt::WString& name, const Wt::WString& tooltip, std::string_view colorStyleClass, bool canDelete = false); + std::unique_ptr createFilterCluster(db::ClusterId clusterId, bool canDelete = false); + std::unique_ptr createFilterClustersForTrack(db::ObjectPtr track, Filters& filters); - std::unique_ptr createArtistAnchorList(const std::vector& artistIds, std::string_view cssAnchorClass = "link-success"); - std::unique_ptr createArtistDisplayNameWithAnchors(std::string_view displayName, const std::vector& artistIds, std::string_view cssAnchorClass = "link-success"); - std::unique_ptr createArtistsAnchorsForRelease(db::ObjectPtr release, db::ArtistId omitIfMatchThisArtist = {}, std::string_view cssAnchorClass = "link-success"); + std::unique_ptr createArtistAnchorList(const std::vector& artistIds, std::string_view cssAnchorClass = "link-success"); + std::unique_ptr createArtistDisplayNameWithAnchors(std::string_view displayName, const std::vector& artistIds, std::string_view cssAnchorClass = "link-success"); + std::unique_ptr createArtistsAnchorsForRelease(db::ObjectPtr release, db::ArtistId omitIfMatchThisArtist = {}, std::string_view cssAnchorClass = "link-success"); - Wt::WLink createArtistLink(db::ObjectPtr artist); - std::unique_ptr createArtistAnchor(db::ObjectPtr artist, bool setText = true); - Wt::WLink createReleaseLink(db::ObjectPtr release); - std::unique_ptr createReleaseAnchor(db::ObjectPtr release, bool setText = true); - std::unique_ptr createTrackListAnchor(db::ObjectPtr trackList, bool setText = true); -} + Wt::WLink createArtistLink(db::ObjectPtr artist); + std::unique_ptr createArtistAnchor(db::ObjectPtr artist, bool setText = true); + Wt::WLink createReleaseLink(db::ObjectPtr release); + std::unique_ptr createReleaseAnchor(db::ObjectPtr release, bool setText = true); + std::unique_ptr createTrackListAnchor(db::ObjectPtr trackList, bool setText = true); +} // namespace lms::ui::utils diff --git a/src/lms/ui/admin/InitWizardView.cpp b/src/lms/ui/admin/InitWizardView.cpp index da3536d0..0a4ca1eb 100644 --- a/src/lms/ui/admin/InitWizardView.cpp +++ b/src/lms/ui/admin/InitWizardView.cpp @@ -24,130 +24,129 @@ #include #include -#include "services/auth/IPasswordService.hpp" -#include "database/Session.hpp" -#include "database/User.hpp" #include "core/Exception.hpp" #include "core/ILogger.hpp" #include "core/Service.hpp" +#include "database/Session.hpp" +#include "database/User.hpp" +#include "services/auth/IPasswordService.hpp" +#include "LmsApplication.hpp" #include "common/LoginNameValidator.hpp" #include "common/MandatoryValidator.hpp" #include "common/PasswordValidator.hpp" -#include "LmsApplication.hpp" -namespace lms::ui { - -class InitWizardModel : public Wt::WFormModel +namespace lms::ui { - public: - // Associate each field with a unique string literal. - static inline const Field AdminLoginField {"admin-login"}; - static inline const Field PasswordField {"password"}; - static inline const Field PasswordConfirmField {"password-confirm"}; - InitWizardModel() : Wt::WFormModel() - { - addField(AdminLoginField); - addField(PasswordField); - addField(PasswordConfirmField); + class InitWizardModel : public Wt::WFormModel + { + public: + // Associate each field with a unique string literal. + static inline const Field AdminLoginField{ "admin-login" }; + static inline const Field PasswordField{ "password" }; + static inline const Field PasswordConfirmField{ "password-confirm" }; - setValidator(AdminLoginField, createLoginNameValidator()); - setValidator(PasswordField, createPasswordStrengthValidator([this] { return auth::PasswordValidationContext {valueText(AdminLoginField).toUTF8(), db::UserType::ADMIN}; })); - validator(PasswordField)->setMandatory(true); - setValidator(PasswordConfirmField, createMandatoryValidator()); - } + InitWizardModel() + : Wt::WFormModel() + { + addField(AdminLoginField); + addField(PasswordField); + addField(PasswordConfirmField); - void saveData() - { - auto transaction(LmsApp->getDbSession().createWriteTransaction()); + setValidator(AdminLoginField, createLoginNameValidator()); + setValidator(PasswordField, createPasswordStrengthValidator([this] { return auth::PasswordValidationContext{ valueText(AdminLoginField).toUTF8(), db::UserType::ADMIN }; })); + validator(PasswordField)->setMandatory(true); + setValidator(PasswordConfirmField, createMandatoryValidator()); + } - // Check if a user already exist - // If it's the case, just do nothing - if (db::User::getCount(LmsApp->getDbSession()) > 0) - throw core::LmsException {"Admin user already created"}; + void saveData() + { + auto transaction(LmsApp->getDbSession().createWriteTransaction()); - db::User::pointer user {LmsApp->getDbSession().create(valueText(AdminLoginField).toUTF8())}; - user.modify()->setType(db::UserType::ADMIN); - core::Service::get()->setPassword(user->getId(), valueText(PasswordField).toUTF8()); - } + // Check if a user already exist + // If it's the case, just do nothing + if (db::User::getCount(LmsApp->getDbSession()) > 0) + throw core::LmsException{ "Admin user already created" }; - bool validateField(Field field) - { - Wt::WString error; + db::User::pointer user{ LmsApp->getDbSession().create(valueText(AdminLoginField).toUTF8()) }; + user.modify()->setType(db::UserType::ADMIN); + core::Service::get()->setPassword(user->getId(), valueText(PasswordField).toUTF8()); + } - if (field == PasswordConfirmField) - { - if (validation(PasswordField).state() == Wt::ValidationState::Valid - && valueText(PasswordField) != valueText(PasswordConfirmField)) - { - error = Wt::WString::tr("Lms.passwords-dont-match"); - } - else - return Wt::WFormModel::validateField(field); - } - else - { - return Wt::WFormModel::validateField(field); - } + bool validateField(Field field) + { + Wt::WString error; - setValidation(field, Wt::WValidator::Result {Wt::ValidationState::Invalid, error}); + if (field == PasswordConfirmField) + { + if (validation(PasswordField).state() == Wt::ValidationState::Valid + && valueText(PasswordField) != valueText(PasswordConfirmField)) + { + error = Wt::WString::tr("Lms.passwords-dont-match"); + } + else + return Wt::WFormModel::validateField(field); + } + else + { + return Wt::WFormModel::validateField(field); + } - return false; - } -}; + setValidation(field, Wt::WValidator::Result{ Wt::ValidationState::Invalid, error }); -InitWizardView::InitWizardView() -: Wt::WTemplateFormView {Wt::WString::tr("Lms.Admin.InitWizard.template")} -{ - auto model = std::make_shared(); + return false; + } + }; - // AdminLogin - { - auto adminLogin {std::make_unique()}; - adminLogin->setAttributeValue("autocomplete", "username"); - setFormWidget(InitWizardModel::AdminLoginField, std::move(adminLogin)); - } + InitWizardView::InitWizardView() + : Wt::WTemplateFormView{ Wt::WString::tr("Lms.Admin.InitWizard.template") } + { + auto model = std::make_shared(); - // Password - { - auto passwordEdit = std::make_unique(); - passwordEdit->setEchoMode(Wt::EchoMode::Password); - passwordEdit->setAttributeValue("autocomplete", "current-password"); - setFormWidget(InitWizardModel::PasswordField, std::move(passwordEdit) ); - } + // AdminLogin + { + auto adminLogin{ std::make_unique() }; + adminLogin->setAttributeValue("autocomplete", "username"); + setFormWidget(InitWizardModel::AdminLoginField, std::move(adminLogin)); + } - // Password confirmation - { - auto passwordConfirmEdit = std::make_unique(); - passwordConfirmEdit->setEchoMode(Wt::EchoMode::Password); - passwordConfirmEdit->setAttributeValue("autocomplete", "current-password"); - setFormWidget(InitWizardModel::PasswordConfirmField, std::move(passwordConfirmEdit)); - } + // Password + { + auto passwordEdit = std::make_unique(); + passwordEdit->setEchoMode(Wt::EchoMode::Password); + passwordEdit->setAttributeValue("autocomplete", "current-password"); + setFormWidget(InitWizardModel::PasswordField, std::move(passwordEdit)); + } - // Result notification - Wt::WText* resultNotification {bindNew("info")}; - resultNotification->setHidden(true); + // Password confirmation + { + auto passwordConfirmEdit = std::make_unique(); + passwordConfirmEdit->setEchoMode(Wt::EchoMode::Password); + passwordConfirmEdit->setAttributeValue("autocomplete", "current-password"); + setFormWidget(InitWizardModel::PasswordConfirmField, std::move(passwordConfirmEdit)); + } + // Result notification + Wt::WText* resultNotification{ bindNew("info") }; + resultNotification->setHidden(true); - Wt::WPushButton* saveButton = bindNew("create-btn", Wt::WString::tr("Lms.create")); - saveButton->clicked().connect([=, this] - { - updateModel(model.get()); + Wt::WPushButton* saveButton = bindNew("create-btn", Wt::WString::tr("Lms.create")); + saveButton->clicked().connect([=, this] { + updateModel(model.get()); - if (model->validate()) - { - model->saveData(); - resultNotification->setText(Wt::WString::tr("Lms.Admin.InitWizard.done")); - resultNotification->setHidden(false); - saveButton->setEnabled(false); - } + if (model->validate()) + { + model->saveData(); + resultNotification->setText(Wt::WString::tr("Lms.Admin.InitWizard.done")); + resultNotification->setHidden(false); + saveButton->setEnabled(false); + } - updateView(model.get()); - }); + updateView(model.get()); + }); - updateView(model.get()); -} + updateView(model.get()); + } } // namespace lms::ui - diff --git a/src/lms/ui/admin/InitWizardView.hpp b/src/lms/ui/admin/InitWizardView.hpp index de7813af..dd416ea0 100644 --- a/src/lms/ui/admin/InitWizardView.hpp +++ b/src/lms/ui/admin/InitWizardView.hpp @@ -21,14 +21,13 @@ #include -namespace lms::ui { - -class InitWizardView : public Wt::WTemplateFormView +namespace lms::ui { - public: - InitWizardView(); -}; + + class InitWizardView : public Wt::WTemplateFormView + { + public: + InitWizardView(); + }; } // namespace lms::ui - - diff --git a/src/lms/ui/admin/MediaLibrariesView.cpp b/src/lms/ui/admin/MediaLibrariesView.cpp index 776c213d..57731d91 100644 --- a/src/lms/ui/admin/MediaLibrariesView.cpp +++ b/src/lms/ui/admin/MediaLibrariesView.cpp @@ -21,13 +21,13 @@ #include +#include "core/Service.hpp" #include "database/MediaLibrary.hpp" #include "database/Session.hpp" #include "services/scanner/IScannerService.hpp" -#include "core/Service.hpp" -#include "MediaLibraryModal.hpp" #include "LmsApplication.hpp" +#include "MediaLibraryModal.hpp" #include "ModalManager.hpp" namespace lms::ui @@ -39,33 +39,29 @@ namespace lms::ui _libraries = bindNew("libraries"); Wt::WPushButton* addBtn{ bindNew("add-btn", Wt::WString::tr("Lms.add")) }; - addBtn->clicked().connect(this, [this] - { - auto mediaLibraryModal{ std::make_unique(db::MediaLibraryId{}) }; - MediaLibraryModal* mediaLibraryModalPtr{ mediaLibraryModal.get() }; + addBtn->clicked().connect(this, [this] { + auto mediaLibraryModal{ std::make_unique(db::MediaLibraryId{}) }; + MediaLibraryModal* mediaLibraryModalPtr{ mediaLibraryModal.get() }; - mediaLibraryModalPtr->saved().connect(this, [this, mediaLibraryModalPtr](db::MediaLibraryId newMediaLibraryId) - { - Wt::WTemplate* entry{ addEntry() }; - updateEntry(newMediaLibraryId, entry); - // No need to stop the current scan if we add stuff - LmsApp->notifyMsg(Notification::Type::Info, Wt::WString::tr("Lms.Admin.MediaLibraries.media-libraries"), Wt::WString::tr("Lms.Admin.MediaLibrary.library-created")); - LmsApp->getModalManager().dispose(mediaLibraryModalPtr); - }); - - mediaLibraryModalPtr->cancelled().connect(this, [mediaLibraryModalPtr] - { - LmsApp->getModalManager().dispose(mediaLibraryModalPtr); - }); - - LmsApp->getModalManager().show(std::move(mediaLibraryModal)); + mediaLibraryModalPtr->saved().connect(this, [this, mediaLibraryModalPtr](db::MediaLibraryId newMediaLibraryId) { + Wt::WTemplate* entry{ addEntry() }; + updateEntry(newMediaLibraryId, entry); + // No need to stop the current scan if we add stuff + LmsApp->notifyMsg(Notification::Type::Info, Wt::WString::tr("Lms.Admin.MediaLibraries.media-libraries"), Wt::WString::tr("Lms.Admin.MediaLibrary.library-created")); + LmsApp->getModalManager().dispose(mediaLibraryModalPtr); }); - wApp->internalPathChanged().connect(this, [this] - { - refreshView(); + mediaLibraryModalPtr->cancelled().connect(this, [mediaLibraryModalPtr] { + LmsApp->getModalManager().dispose(mediaLibraryModalPtr); }); + LmsApp->getModalManager().show(std::move(mediaLibraryModal)); + }); + + wApp->internalPathChanged().connect(this, [this] { + refreshView(); + }); + refreshView(); } @@ -78,15 +74,14 @@ namespace lms::ui auto transaction{ LmsApp->getDbSession().createReadTransaction() }; - db::MediaLibrary::find(LmsApp->getDbSession(), [&](const db::MediaLibrary::pointer& mediaLibrary) - { - const db::MediaLibraryId mediaLibraryId{ mediaLibrary->getId() }; - Wt::WTemplate* entry{ addEntry() }; - updateEntry(mediaLibraryId, entry); - }); + db::MediaLibrary::find(LmsApp->getDbSession(), [&](const db::MediaLibrary::pointer& mediaLibrary) { + const db::MediaLibraryId mediaLibraryId{ mediaLibrary->getId() }; + Wt::WTemplate* entry{ addEntry() }; + updateEntry(mediaLibraryId, entry); + }); } - void MediaLibrariesView::showDeleteLibraryModal(db::MediaLibraryId mediaLibraryId, Wt::WTemplate* libraryEntry) + void MediaLibrariesView::showDeleteLibraryModal(db::MediaLibraryId mediaLibraryId, Wt::WTemplate* libraryEntry) { using namespace db; @@ -95,30 +90,28 @@ namespace lms::ui Wt::WWidget* modalPtr{ modal.get() }; auto* delBtn{ modal->bindNew("del-btn", Wt::WString::tr("Lms.delete")) }; - delBtn->clicked().connect([=, this] + delBtn->clicked().connect([=, this] { { - { - auto transaction{ LmsApp->getDbSession().createWriteTransaction() }; + auto transaction{ LmsApp->getDbSession().createWriteTransaction() }; - db::MediaLibrary::pointer mediaLibrary{ MediaLibrary::find(LmsApp->getDbSession(), mediaLibraryId) }; - if (mediaLibrary) - mediaLibrary.remove(); - } + db::MediaLibrary::pointer mediaLibrary{ MediaLibrary::find(LmsApp->getDbSession(), mediaLibraryId) }; + if (mediaLibrary) + mediaLibrary.remove(); + } - // Don't want the scanner to go on with wrong settings - core::Service::get()->requestReload(); - LmsApp->notifyMsg(Notification::Type::Info, Wt::WString::tr("Lms.Admin.MediaLibraries.media-libraries"), Wt::WString::tr("Lms.Admin.MediaLibrary.library-deleted")); + // Don't want the scanner to go on with wrong settings + core::Service::get()->requestReload(); + LmsApp->notifyMsg(Notification::Type::Info, Wt::WString::tr("Lms.Admin.MediaLibraries.media-libraries"), Wt::WString::tr("Lms.Admin.MediaLibrary.library-deleted")); - _libraries->removeWidget(libraryEntry); + _libraries->removeWidget(libraryEntry); - LmsApp->getModalManager().dispose(modalPtr); - }); + LmsApp->getModalManager().dispose(modalPtr); + }); auto* cancelBtn{ modal->bindNew("cancel-btn", Wt::WString::tr("Lms.cancel")) }; - cancelBtn->clicked().connect([=] - { - LmsApp->getModalManager().dispose(modalPtr); - }); + cancelBtn->clicked().connect([=] { + LmsApp->getModalManager().dispose(modalPtr); + }); LmsApp->getModalManager().show(std::move(modal)); } @@ -138,35 +131,31 @@ namespace lms::ui Wt::WPushButton* editBtn{ entry->bindNew("edit-btn", Wt::WString::tr("Lms.template.edit-btn"), Wt::TextFormat::XHTML) }; editBtn->setToolTip(Wt::WString::tr("Lms.edit")); - editBtn->clicked().connect([this, mediaLibraryId, entry] - { - auto mediaLibraryModal{ std::make_unique(mediaLibraryId) }; - MediaLibraryModal* mediaLibraryModalPtr{ mediaLibraryModal.get() }; + editBtn->clicked().connect([this, mediaLibraryId, entry] { + auto mediaLibraryModal{ std::make_unique(mediaLibraryId) }; + MediaLibraryModal* mediaLibraryModalPtr{ mediaLibraryModal.get() }; - mediaLibraryModalPtr->saved().connect(this, [=, this](db::MediaLibraryId newMediaLibraryId) - { - updateEntry(newMediaLibraryId, entry); + mediaLibraryModalPtr->saved().connect(this, [=, this](db::MediaLibraryId newMediaLibraryId) { + updateEntry(newMediaLibraryId, entry); - // Don't want the scanner to go on with wrong settings - core::Service::get()->requestReload(); - LmsApp->notifyMsg(Notification::Type::Info, Wt::WString::tr("Lms.Admin.MediaLibraries.media-libraries"), Wt::WString::tr("Lms.settings-saved")); + // Don't want the scanner to go on with wrong settings + core::Service::get()->requestReload(); + LmsApp->notifyMsg(Notification::Type::Info, Wt::WString::tr("Lms.Admin.MediaLibraries.media-libraries"), Wt::WString::tr("Lms.settings-saved")); - LmsApp->getModalManager().dispose(mediaLibraryModalPtr); - }); - - mediaLibraryModalPtr->cancelled().connect(this, [mediaLibraryModalPtr] - { - LmsApp->getModalManager().dispose(mediaLibraryModalPtr); - }); - - LmsApp->getModalManager().show(std::move(mediaLibraryModal)); + LmsApp->getModalManager().dispose(mediaLibraryModalPtr); }); + mediaLibraryModalPtr->cancelled().connect(this, [mediaLibraryModalPtr] { + LmsApp->getModalManager().dispose(mediaLibraryModalPtr); + }); + + LmsApp->getModalManager().show(std::move(mediaLibraryModal)); + }); + Wt::WPushButton* delBtn{ entry->bindNew("del-btn", Wt::WString::tr("Lms.template.trash-btn"), Wt::TextFormat::XHTML) }; delBtn->setToolTip(Wt::WString::tr("Lms.delete")); - delBtn->clicked().connect([this, mediaLibraryId, entry] - { - showDeleteLibraryModal(mediaLibraryId, entry); - }); + delBtn->clicked().connect([this, mediaLibraryId, entry] { + showDeleteLibraryModal(mediaLibraryId, entry); + }); } -} \ No newline at end of file +} // namespace lms::ui \ No newline at end of file diff --git a/src/lms/ui/admin/MediaLibrariesView.hpp b/src/lms/ui/admin/MediaLibrariesView.hpp index dbe35b8d..8ba277e7 100644 --- a/src/lms/ui/admin/MediaLibrariesView.hpp +++ b/src/lms/ui/admin/MediaLibrariesView.hpp @@ -19,8 +19,8 @@ #pragma once -#include #include +#include #include "database/MediaLibraryId.hpp" @@ -39,4 +39,4 @@ namespace lms::ui Wt::WContainerWidget* _libraries{}; }; -} \ No newline at end of file +} // namespace lms::ui \ No newline at end of file diff --git a/src/lms/ui/admin/MediaLibraryModal.cpp b/src/lms/ui/admin/MediaLibraryModal.cpp index 4e33a56f..d0221850 100644 --- a/src/lms/ui/admin/MediaLibraryModal.cpp +++ b/src/lms/ui/admin/MediaLibraryModal.cpp @@ -24,10 +24,11 @@ #include #include -#include "database/MediaLibrary.hpp" -#include "database/Session.hpp" #include "core/Path.hpp" #include "core/String.hpp" +#include "database/MediaLibrary.hpp" +#include "database/Session.hpp" + #include "LmsApplication.hpp" namespace lms::ui @@ -39,7 +40,8 @@ namespace lms::ui class LibraryNameValidator : public Wt::WValidator { public: - LibraryNameValidator(MediaLibraryId libraryId) : _libraryId{ libraryId } {} + LibraryNameValidator(MediaLibraryId libraryId) + : _libraryId{ libraryId } {} private: Wt::WValidator::Result validate(const Wt::WString& input) const override @@ -53,14 +55,13 @@ namespace lms::ui auto& session{ LmsApp->getDbSession() }; auto transaction{ LmsApp->getDbSession().createReadTransaction() }; - db::MediaLibrary::find(session, [&](const db::MediaLibrary::pointer library) - { - if (library->getId() == _libraryId) - return; + db::MediaLibrary::find(session, [&](const db::MediaLibrary::pointer library) { + if (library->getId() == _libraryId) + return; - if (core::stringUtils::stringCaseInsensitiveEqual(name, library->getName())) - result = Wt::WValidator::Result{ Wt::ValidationState::Invalid, Wt::WString::tr("Lms.Admin.MediaLibrary.name-already-exists") }; - }); + if (core::stringUtils::stringCaseInsensitiveEqual(name, library->getName())) + result = Wt::WValidator::Result{ Wt::ValidationState::Invalid, Wt::WString::tr("Lms.Admin.MediaLibrary.name-already-exists") }; + }); return result; } @@ -71,7 +72,8 @@ namespace lms::ui class LibraryRootPathValidator : public Wt::WValidator { public: - LibraryRootPathValidator(MediaLibraryId libraryId) : _libraryId{ libraryId } {} + LibraryRootPathValidator(MediaLibraryId libraryId) + : _libraryId{ libraryId } {} private: Wt::WValidator::Result validate(const Wt::WString& input) const override @@ -96,20 +98,19 @@ namespace lms::ui auto transaction{ LmsApp->getDbSession().createReadTransaction() }; Wt::WValidator::Result result{ Wt::ValidationState::Valid }; - const std::filesystem::path rootPath{ std::filesystem::path{input.toUTF8()}.lexically_normal() }; - db::MediaLibrary::find(session, [&](const db::MediaLibrary::pointer library) + const std::filesystem::path rootPath{ std::filesystem::path{ input.toUTF8() }.lexically_normal() }; + db::MediaLibrary::find(session, [&](const db::MediaLibrary::pointer library) { + if (library->getId() == _libraryId) + return; + + const std::filesystem::path libraryRootPath{ library->getPath().lexically_normal() }; + + if (core::pathUtils::isPathInRootPath(rootPath, libraryRootPath) + || core::pathUtils::isPathInRootPath(libraryRootPath, rootPath)) { - if (library->getId() == _libraryId) - return; - - const std::filesystem::path libraryRootPath{ library->getPath().lexically_normal() }; - - if (core::pathUtils::isPathInRootPath(rootPath, libraryRootPath) - || core::pathUtils::isPathInRootPath(libraryRootPath, rootPath)) - { - result = Wt::WValidator::Result{ Wt::ValidationState::Invalid, Wt::WString::tr("Lms.Admin.MediaLibrary.path-must-not-overlap") }; - } - }); + result = Wt::WValidator::Result{ Wt::ValidationState::Invalid, Wt::WString::tr("Lms.Admin.MediaLibrary.path-must-not-overlap") }; + } + }); return result; } @@ -176,7 +177,7 @@ namespace lms::ui const MediaLibraryId _libraryId; }; - } + } // namespace MediaLibraryModal::MediaLibraryModal(MediaLibraryId mediaLibraryId) : Wt::WTemplateFormView{ Wt::WString::tr("Lms.Admin.MediaLibrary.template") } @@ -189,24 +190,23 @@ namespace lms::ui setFormWidget(MediaLibraryModel::DirectoryField, std::make_unique()); Wt::WPushButton* saveBtn{ bindNew("save-btn", Wt::WString::tr(mediaLibraryId.isValid() ? "Lms.save" : "Lms.create")) }; - saveBtn->clicked().connect(this, [this, model] - { - updateModel(model.get()); + saveBtn->clicked().connect(this, [this, model] { + updateModel(model.get()); - if (model->validate()) - { - db::MediaLibraryId mediaLibraryId{ model->saveData() }; - saved().emit(mediaLibraryId); - } - else - { - updateView(model.get()); - } - }); + if (model->validate()) + { + db::MediaLibraryId mediaLibraryId{ model->saveData() }; + saved().emit(mediaLibraryId); + } + else + { + updateView(model.get()); + } + }); Wt::WPushButton* cancelBtn{ bindNew("cancel-btn", Wt::WString::tr("Lms.cancel")) }; cancelBtn->clicked().connect(this, [this] { cancelled().emit(); }); updateView(model.get()); } -} +} // namespace lms::ui diff --git a/src/lms/ui/admin/MediaLibraryModal.hpp b/src/lms/ui/admin/MediaLibraryModal.hpp index aae9616d..03f20689 100644 --- a/src/lms/ui/admin/MediaLibraryModal.hpp +++ b/src/lms/ui/admin/MediaLibraryModal.hpp @@ -21,6 +21,7 @@ #include #include + #include "database/MediaLibraryId.hpp" namespace lms::ui @@ -37,4 +38,4 @@ namespace lms::ui Wt::Signal _saved; Wt::Signal<> _cancelled; }; -} \ No newline at end of file +} // namespace lms::ui \ No newline at end of file diff --git a/src/lms/ui/admin/ScanSettingsView.cpp b/src/lms/ui/admin/ScanSettingsView.cpp index f1878101..6621aa57 100644 --- a/src/lms/ui/admin/ScanSettingsView.cpp +++ b/src/lms/ui/admin/ScanSettingsView.cpp @@ -26,18 +26,18 @@ #include #include +#include "core/ILogger.hpp" +#include "core/Service.hpp" +#include "core/String.hpp" #include "database/ScanSettings.hpp" #include "database/Session.hpp" #include "services/recommendation/IRecommendationService.hpp" #include "services/scanner/IScannerService.hpp" -#include "core/ILogger.hpp" -#include "core/Service.hpp" -#include "core/String.hpp" +#include "LmsApplication.hpp" #include "common/MandatoryValidator.hpp" #include "common/UppercaseValidator.hpp" #include "common/ValueStringModel.hpp" -#include "LmsApplication.hpp" namespace lms::ui { @@ -56,7 +56,7 @@ namespace lms::ui std::string inputStr{ input.toUTF8() }; if (std::all_of(std::cbegin(inputStr), std::cend(inputStr), [](char c) { return std::isspace(c); })) return Wt::WValidator::Result{ Wt::ValidationState::Invalid, Wt::WString::tr("Lms.Admin.Database.tag-delimiter-must-not-contain-only-spaces") }; - + return Wt::WValidator::Result{ Wt::ValidationState::Valid }; } @@ -160,7 +160,7 @@ namespace lms::ui scanSettings.modify()->setSimilarityEngineType(_similarityEngineTypeModel->getValue(*similarityEngineTypeRow)); scanSettings.modify()->setExtraTagsToScan(core::stringUtils::splitString(valueText(ExtraTagsField).toUTF8(), extraTagsDelimiter)); - + { std::vector artistDelimiters; if (std::string artistDelimiter{ valueText(ArtistTagDelimiterField).toUTF8() }; !artistDelimiter.empty()) @@ -168,7 +168,7 @@ namespace lms::ui scanSettings.modify()->setArtistTagDelimiters(artistDelimiters); } - { + { std::vector defaultDelimiters; if (std::string defaultDelimiter{ valueText(DefaultTagDelimiterField).toUTF8() }; !defaultDelimiter.empty()) defaultDelimiters.push_back(std::move(defaultDelimiter)); @@ -198,18 +198,17 @@ namespace lms::ui _similarityEngineTypeModel->add(Wt::WString::tr("Lms.Admin.Database.similarity-engine-type.none"), ScanSettings::SimilarityEngineType::None); } - std::shared_ptr _updatePeriodModel; - std::shared_ptr> _updateStartTimeModel; - std::shared_ptr> _similarityEngineTypeModel; + std::shared_ptr _updatePeriodModel; + std::shared_ptr> _updateStartTimeModel; + std::shared_ptr> _similarityEngineTypeModel; }; - } + } // namespace ScanSettingsView::ScanSettingsView() { - wApp->internalPathChanged().connect(this, [this]() - { - refreshView(); - }); + wApp->internalPathChanged().connect(this, [this]() { + refreshView(); + }); refreshView(); } @@ -227,13 +226,12 @@ namespace lms::ui // Update Period auto updatePeriod{ std::make_unique() }; updatePeriod->setModel(model->updatePeriodModel()); - updatePeriod->activated().connect([=](int row) - { - const ScanSettings::UpdatePeriod period{ model->updatePeriodModel()->getValue(row) }; - model->setReadOnly(DatabaseSettingsModel::UpdateStartTimeField, period == ScanSettings::UpdatePeriod::Hourly || period == ScanSettings::UpdatePeriod::Never); - t->updateModel(model.get()); - t->updateView(model.get()); - }); + updatePeriod->activated().connect([=](int row) { + const ScanSettings::UpdatePeriod period{ model->updatePeriodModel()->getValue(row) }; + model->setReadOnly(DatabaseSettingsModel::UpdateStartTimeField, period == ScanSettings::UpdatePeriod::Hourly || period == ScanSettings::UpdatePeriod::Never); + t->updateModel(model.get()); + t->updateView(model.get()); + }); t->setFormWidget(DatabaseSettingsModel::UpdatePeriodField, std::move(updatePeriod)); // Update Start Time @@ -259,30 +257,28 @@ namespace lms::ui Wt::WPushButton* saveBtn = t->bindWidget("save-btn", std::make_unique(Wt::WString::tr("Lms.save"))); Wt::WPushButton* discardBtn = t->bindWidget("discard-btn", std::make_unique(Wt::WString::tr("Lms.discard"))); - saveBtn->clicked().connect([=] + saveBtn->clicked().connect([=] { + t->updateModel(model.get()); + + if (model->validate()) { - t->updateModel(model.get()); + model->saveData(); - if (model->validate()) - { - model->saveData(); + core::Service::get()->load(); + // Don't want the scanner to go on with wrong settings + core::Service::get()->requestReload(); + LmsApp->notifyMsg(Notification::Type::Info, Wt::WString::tr("Lms.Admin.Database.database"), Wt::WString::tr("Lms.settings-saved")); + } - core::Service::get()->load(); - // Don't want the scanner to go on with wrong settings - core::Service::get()->requestReload(); - LmsApp->notifyMsg(Notification::Type::Info, Wt::WString::tr("Lms.Admin.Database.database"), Wt::WString::tr("Lms.settings-saved")); - } + // Udate the view: Delete any validation message in the view, etc. + t->updateView(model.get()); + }); - // Udate the view: Delete any validation message in the view, etc. - t->updateView(model.get()); - }); - - discardBtn->clicked().connect([=] - { - model->loadData(); - model->validate(); - t->updateView(model.get()); - }); + discardBtn->clicked().connect([=] { + model->loadData(); + model->validate(); + t->updateView(model.get()); + }); t->updateView(model.get()); } diff --git a/src/lms/ui/admin/ScannerController.cpp b/src/lms/ui/admin/ScannerController.cpp index 467504ec..33b4aa50 100644 --- a/src/lms/ui/admin/ScannerController.cpp +++ b/src/lms/ui/admin/ScannerController.cpp @@ -27,10 +27,11 @@ #include #include +#include "core/Service.hpp" #include "database/Session.hpp" #include "database/Track.hpp" #include "services/scanner/IScannerService.hpp" -#include "core/Service.hpp" + #include "LmsApplication.hpp" namespace lms::ui @@ -51,7 +52,7 @@ namespace lms::ui return oss.str(); } - } + } // namespace class ReportResource : public Wt::WResource { @@ -116,10 +117,14 @@ namespace lms::ui { switch (error) { - case scanner::ScanErrorType::CannotReadFile: return Wt::WString::tr("Lms.Admin.ScannerController.cannot-read-file"); - case scanner::ScanErrorType::CannotParseFile: return Wt::WString::tr("Lms.Admin.ScannerController.cannot-parse-file"); - case scanner::ScanErrorType::NoAudioTrack: return Wt::WString::tr("Lms.Admin.ScannerController.no-audio-track"); - case scanner::ScanErrorType::BadDuration: return Wt::WString::tr("Lms.Admin.ScannerController.bad-duration"); + case scanner::ScanErrorType::CannotReadFile: + return Wt::WString::tr("Lms.Admin.ScannerController.cannot-read-file"); + case scanner::ScanErrorType::CannotParseFile: + return Wt::WString::tr("Lms.Admin.ScannerController.cannot-parse-file"); + case scanner::ScanErrorType::NoAudioTrack: + return Wt::WString::tr("Lms.Admin.ScannerController.no-audio-track"); + case scanner::ScanErrorType::BadDuration: + return Wt::WString::tr("Lms.Admin.ScannerController.bad-duration"); } return "?"; } @@ -128,8 +133,10 @@ namespace lms::ui { switch (reason) { - case scanner::DuplicateReason::SameHash: return Wt::WString::tr("Lms.Admin.ScannerController.same-hash"); - case scanner::DuplicateReason::SameTrackMBID: return Wt::WString::tr("Lms.Admin.ScannerController.same-mbid"); + case scanner::DuplicateReason::SameHash: + return Wt::WString::tr("Lms.Admin.ScannerController.same-hash"); + case scanner::DuplicateReason::SameTrackMBID: + return Wt::WString::tr("Lms.Admin.ScannerController.same-mbid"); } return "?"; } @@ -161,16 +168,14 @@ namespace lms::ui Wt::WCheckBox* forceOptimize{ bindNew("force-optimize") }; Wt::WCheckBox* compact{ bindNew("compact") }; Wt::WPushButton* scanBtn{ bindNew("scan-btn", Wt::WString::tr("Lms.Admin.ScannerController.scan-now")) }; - scanBtn->clicked().connect([=] - { - const scanner::ScanOptions scanOptions - { - .fullScan = fullScan->isChecked(), - .forceOptimize = forceOptimize->isChecked(), - .compact = compact->isChecked(), - }; - core::Service::get()->requestImmediateScan(scanOptions); - }); + scanBtn->clicked().connect([=] { + const scanner::ScanOptions scanOptions{ + .fullScan = fullScan->isChecked(), + .forceOptimize = forceOptimize->isChecked(), + .compact = compact->isChecked(), + }; + core::Service::get()->requestImmediateScan(scanOptions); + }); _lastScanStatus = bindNew("last-scan"); _lastScanStatus->setReadOnly(true); @@ -183,14 +188,12 @@ namespace lms::ui auto onDbEvent{ [&]() { refreshContents(); } }; - LmsApp->getScannerEvents().scanAborted.connect(this, [] - { - LmsApp->notifyMsg(Notification::Type::Info, Wt::WString::tr("Lms.Admin.Database.database"), Wt::WString::tr("Lms.Admin.Database.scan-aborted")); - }); - LmsApp->getScannerEvents().scanStarted.connect(this, [] - { - LmsApp->notifyMsg(Notification::Type::Info, Wt::WString::tr("Lms.Admin.Database.database"), Wt::WString::tr("Lms.Admin.Database.scan-launched")); - }); + LmsApp->getScannerEvents().scanAborted.connect(this, [] { + LmsApp->notifyMsg(Notification::Type::Info, Wt::WString::tr("Lms.Admin.Database.database"), Wt::WString::tr("Lms.Admin.Database.scan-aborted")); + }); + LmsApp->getScannerEvents().scanStarted.connect(this, [] { + LmsApp->notifyMsg(Notification::Type::Info, Wt::WString::tr("Lms.Admin.Database.database"), Wt::WString::tr("Lms.Admin.Database.scan-launched")); + }); LmsApp->getScannerEvents().scanComplete.connect(this, onDbEvent); LmsApp->getScannerEvents().scanInProgress.connect(this, onDbEvent); LmsApp->getScannerEvents().scanScheduled.connect(this, onDbEvent); @@ -213,16 +216,14 @@ namespace lms::ui if (status.lastCompleteScanStats) { _lastScanStatus->setText(Wt::WString::tr("Lms.Admin.ScannerController.last-scan-status") - .arg(status.lastCompleteScanStats->nbFiles()) - .arg(durationToString(status.lastCompleteScanStats->startTime, status.lastCompleteScanStats->stopTime)) - .arg(status.lastCompleteScanStats->stopTime.toString()) - .arg(status.lastCompleteScanStats->errors.size()) - .arg(status.lastCompleteScanStats->duplicates.size()) - ); + .arg(status.lastCompleteScanStats->nbFiles()) + .arg(durationToString(status.lastCompleteScanStats->startTime, status.lastCompleteScanStats->stopTime)) + .arg(status.lastCompleteScanStats->stopTime.toString()) + .arg(status.lastCompleteScanStats->errors.size()) + .arg(status.lastCompleteScanStats->duplicates.size())); _reportResource->setScanStats(*status.lastCompleteScanStats); _reportBtn->setEnabled(true); - } else { @@ -244,7 +245,7 @@ namespace lms::ui case IScannerService::State::Scheduled: _status->setText(Wt::WString::tr("Lms.Admin.ScannerController.status-scheduled") - .arg(status.nextScheduledScan.toString())); + .arg(status.nextScheduledScan.toString())); _stepStatus->setText(""); break; @@ -252,8 +253,8 @@ namespace lms::ui assert(status.currentScanStepStats); _status->setText(Wt::WString::tr("Lms.Admin.ScannerController.status-in-progress") - .arg(status.currentScanStepStats->stepIndex + 1) - .arg(scanner::ScanProgressStepCount)); + .arg(status.currentScanStepStats->stepIndex + 1) + .arg(scanner::ScanProgressStepCount)); refreshCurrentStep(*status.currentScanStepStats); break; @@ -268,12 +269,12 @@ namespace lms::ui { case ScanStep::CheckForDuplicateFiles: _stepStatus->setText(Wt::WString::tr("Lms.Admin.ScannerController.step-checking-for-duplicate-files") - .arg(stepStats.processedElems)); + .arg(stepStats.processedElems)); break; case scanner::ScanStep::CheckForMissingFiles: _stepStatus->setText(Wt::WString::tr("Lms.Admin.ScannerController.step-checking-for-missing-files") - .arg(stepStats.progress())); + .arg(stepStats.progress())); break; case scanner::ScanStep::Compact: @@ -282,38 +283,38 @@ namespace lms::ui case scanner::ScanStep::ComputeClusterStats: _stepStatus->setText(Wt::WString::tr("Lms.Admin.ScannerController.step-compute-cluster-stats") - .arg(stepStats.progress())); + .arg(stepStats.progress())); break; case scanner::ScanStep::DiscoverFiles: _stepStatus->setText(Wt::WString::tr("Lms.Admin.ScannerController.step-discovering-files") - .arg(stepStats.processedElems)); + .arg(stepStats.processedElems)); break; case scanner::ScanStep::FetchTrackFeatures: _stepStatus->setText(Wt::WString::tr("Lms.Admin.ScannerController.step-fetching-track-features") - .arg(stepStats.processedElems) - .arg(stepStats.totalElems) - .arg(stepStats.progress())); + .arg(stepStats.processedElems) + .arg(stepStats.totalElems) + .arg(stepStats.progress())); break; case scanner::ScanStep::Optimize: _stepStatus->setText(Wt::WString::tr("Lms.Admin.ScannerController.step-optimize") - .arg(stepStats.processedElems) - .arg(stepStats.totalElems) - .arg(stepStats.progress())); + .arg(stepStats.processedElems) + .arg(stepStats.totalElems) + .arg(stepStats.progress())); break; case scanner::ScanStep::ReloadSimilarityEngine: _stepStatus->setText(Wt::WString::tr("Lms.Admin.ScannerController.step-reloading-similarity-engine") - .arg(stepStats.progress())); + .arg(stepStats.progress())); break; case scanner::ScanStep::ScanFiles: _stepStatus->setText(Wt::WString::tr("Lms.Admin.ScannerController.step-scanning-files") - .arg(stepStats.processedElems) - .arg(stepStats.totalElems) - .arg(stepStats.progress())); + .arg(stepStats.processedElems) + .arg(stepStats.totalElems) + .arg(stepStats.progress())); break; } } diff --git a/src/lms/ui/admin/ScannerController.hpp b/src/lms/ui/admin/ScannerController.hpp index e8091c7b..e394f573 100644 --- a/src/lms/ui/admin/ScannerController.hpp +++ b/src/lms/ui/admin/ScannerController.hpp @@ -19,9 +19,9 @@ #pragma once +#include #include #include -#include #include "services/scanner/IScannerService.hpp" @@ -44,4 +44,4 @@ namespace lms::ui Wt::WLineEdit* _stepStatus; class ReportResource* _reportResource; }; -} // namespace lms::dbStatus +} // namespace lms::ui diff --git a/src/lms/ui/admin/TracingView.cpp b/src/lms/ui/admin/TracingView.cpp index 91265b77..2d6b6812 100644 --- a/src/lms/ui/admin/TracingView.cpp +++ b/src/lms/ui/admin/TracingView.cpp @@ -19,13 +19,12 @@ #include "TracingView.hpp" -#include -#include - #include #include #include #include +#include +#include #include "core/ITraceLogger.hpp" #include "core/String.hpp" @@ -62,7 +61,7 @@ namespace lms::ui private: core::tracing::ITraceLogger& _traceLogger; }; - } + } // namespace TracingView::TracingView() : Wt::WTemplate{ Wt::WString::tr("Lms.Admin.Tracing.template") } diff --git a/src/lms/ui/admin/UserView.cpp b/src/lms/ui/admin/UserView.cpp index 2fee0feb..cfb15b81 100644 --- a/src/lms/ui/admin/UserView.cpp +++ b/src/lms/ui/admin/UserView.cpp @@ -27,19 +27,19 @@ #include -#include "services/auth/IPasswordService.hpp" -#include "database/User.hpp" -#include "database/Session.hpp" -#include "core/IConfig.hpp" #include "core/Exception.hpp" +#include "core/IConfig.hpp" #include "core/ILogger.hpp" #include "core/Service.hpp" #include "core/String.hpp" +#include "database/Session.hpp" +#include "database/User.hpp" +#include "services/auth/IPasswordService.hpp" -#include "common/LoginNameValidator.hpp" -#include "common/PasswordValidator.hpp" #include "LmsApplication.hpp" #include "LmsApplicationException.hpp" +#include "common/LoginNameValidator.hpp" +#include "common/PasswordValidator.hpp" namespace lms::ui { @@ -181,10 +181,9 @@ namespace lms::ui UserView::UserView() { - wApp->internalPathChanged().connect(this, [this]() - { - refreshView(); - }); + wApp->internalPathChanged().connect(this, [this]() { + refreshView(); + }); refreshView(); } @@ -249,23 +248,22 @@ namespace lms::ui t->setCondition("if-demo", true); Wt::WPushButton* saveBtn{ t->bindNew("save-btn", Wt::WString::tr(userId ? "Lms.save" : "Lms.create")) }; - saveBtn->clicked().connect([=]() - { - t->updateModel(model.get()); + saveBtn->clicked().connect([=]() { + t->updateModel(model.get()); - if (model->validate()) - { - model->saveData(); - LmsApp->notifyMsg(Notification::Type::Info, - Wt::WString::tr("Lms.Admin.Users.users"), - Wt::WString::tr(userId ? "Lms.Admin.User.user-updated" : "Lms.Admin.User.user-created")); - LmsApp->setInternalPath("/admin/users", true); - } - else - { - t->updateView(model.get()); - } - }); + if (model->validate()) + { + model->saveData(); + LmsApp->notifyMsg(Notification::Type::Info, + Wt::WString::tr("Lms.Admin.Users.users"), + Wt::WString::tr(userId ? "Lms.Admin.User.user-updated" : "Lms.Admin.User.user-created")); + LmsApp->setInternalPath("/admin/users", true); + } + else + { + t->updateView(model.get()); + } + }); t->updateView(model.get()); } diff --git a/src/lms/ui/admin/UserView.hpp b/src/lms/ui/admin/UserView.hpp index e98eafb0..2215fa11 100644 --- a/src/lms/ui/admin/UserView.hpp +++ b/src/lms/ui/admin/UserView.hpp @@ -21,17 +21,16 @@ #include -namespace lms::ui { - -class UserView : public Wt::WContainerWidget +namespace lms::ui { - public: - UserView(); - private: - void refreshView(); -}; + class UserView : public Wt::WContainerWidget + { + public: + UserView(); + + private: + void refreshView(); + }; } // namespace lms::ui - - diff --git a/src/lms/ui/admin/UsersView.cpp b/src/lms/ui/admin/UsersView.cpp index c5340974..7ad07c99 100644 --- a/src/lms/ui/admin/UsersView.cpp +++ b/src/lms/ui/admin/UsersView.cpp @@ -19,15 +19,15 @@ #include "UsersView.hpp" -#include #include +#include #include -#include "services/auth/IPasswordService.hpp" -#include "database/User.hpp" -#include "database/Session.hpp" #include "core/ILogger.hpp" #include "core/Service.hpp" +#include "database/Session.hpp" +#include "database/User.hpp" +#include "services/auth/IPasswordService.hpp" #include "LmsApplication.hpp" #include "ModalManager.hpp" @@ -48,16 +48,14 @@ namespace lms::ui setCondition("if-can-create-user", true); Wt::WPushButton* addBtn = bindNew("add-btn", Wt::WString::tr("Lms.Admin.Users.add")); - addBtn->clicked().connect([] - { - LmsApp->setInternalPath("/admin/user", true); - }); + addBtn->clicked().connect([] { + LmsApp->setInternalPath("/admin/user", true); + }); } - wApp->internalPathChanged().connect(this, [this]() - { - refreshView(); - }); + wApp->internalPathChanged().connect(this, [this]() { + refreshView(); + }); refreshView(); } @@ -72,65 +70,60 @@ namespace lms::ui auto transaction{ LmsApp->getDbSession().createReadTransaction() }; const UserId currentUserId{ LmsApp->getUserId() }; - User::find(LmsApp->getDbSession(), User::FindParameters{}, [&](const User::pointer& user) + User::find(LmsApp->getDbSession(), User::FindParameters{}, [&](const User::pointer& user) { + const UserId userId{ user->getId() }; + + Wt::WTemplate* entry{ _container->addNew(Wt::WString::tr("Lms.Admin.Users.template.entry")) }; + + entry->bindString("name", user->getLoginName(), Wt::TextFormat::Plain); + + // Create tag + if (user->isAdmin() || user->isDemo()) { - const UserId userId{ user->getId() }; + entry->setCondition("if-tag", true); + entry->bindString("tag", Wt::WString::tr(user->isAdmin() ? "Lms.Admin.Users.admin" : "Lms.Admin.Users.demo")); + } - Wt::WTemplate* entry{ _container->addNew(Wt::WString::tr("Lms.Admin.Users.template.entry")) }; + // Don't edit ourself this way + if (user->getId() == currentUserId) + return; - entry->bindString("name", user->getLoginName(), Wt::TextFormat::Plain); - - // Create tag - if (user->isAdmin() || user->isDemo()) - { - entry->setCondition("if-tag", true); - entry->bindString("tag", Wt::WString::tr(user->isAdmin() ? "Lms.Admin.Users.admin" : "Lms.Admin.Users.demo")); - } - - // Don't edit ourself this way - if (user->getId() == currentUserId) - return; - - entry->setCondition("if-edit", true); - Wt::WPushButton* editBtn = entry->bindNew("edit-btn", Wt::WString::tr("Lms.template.edit-btn"), Wt::TextFormat::XHTML); - editBtn->setToolTip(Wt::WString::tr("Lms.edit")); - editBtn->clicked().connect([userId]() - { - LmsApp->setInternalPath("/admin/user/" + userId.toString(), true); - }); - - Wt::WPushButton* delBtn = entry->bindNew("del-btn", Wt::WString::tr("Lms.template.trash-btn"), Wt::TextFormat::XHTML); - delBtn->setToolTip(Wt::WString::tr("Lms.delete")); - delBtn->clicked().connect([this, userId, entry] - { - auto modal{ std::make_unique(Wt::WString::tr("Lms.Admin.Users.template.delete-user")) }; - modal->addFunction("tr", &Wt::WTemplate::Functions::tr); - Wt::WWidget* modalPtr{ modal.get() }; - - auto* delBtn{ modal->bindNew("del-btn", Wt::WString::tr("Lms.delete")) }; - delBtn->clicked().connect([=, this] - { - { - auto transaction{ LmsApp->getDbSession().createWriteTransaction() }; - - User::pointer user{ User::find(LmsApp->getDbSession(), userId) }; - if (user) - user.remove(); - } - - _container->removeWidget(entry); - - LmsApp->getModalManager().dispose(modalPtr); - }); - - auto* cancelBtn{ modal->bindNew("cancel-btn", Wt::WString::tr("Lms.cancel")) }; - cancelBtn->clicked().connect([=] - { - LmsApp->getModalManager().dispose(modalPtr); - }); - - LmsApp->getModalManager().show(std::move(modal)); - }); + entry->setCondition("if-edit", true); + Wt::WPushButton* editBtn = entry->bindNew("edit-btn", Wt::WString::tr("Lms.template.edit-btn"), Wt::TextFormat::XHTML); + editBtn->setToolTip(Wt::WString::tr("Lms.edit")); + editBtn->clicked().connect([userId]() { + LmsApp->setInternalPath("/admin/user/" + userId.toString(), true); }); + + Wt::WPushButton* delBtn = entry->bindNew("del-btn", Wt::WString::tr("Lms.template.trash-btn"), Wt::TextFormat::XHTML); + delBtn->setToolTip(Wt::WString::tr("Lms.delete")); + delBtn->clicked().connect([this, userId, entry] { + auto modal{ std::make_unique(Wt::WString::tr("Lms.Admin.Users.template.delete-user")) }; + modal->addFunction("tr", &Wt::WTemplate::Functions::tr); + Wt::WWidget* modalPtr{ modal.get() }; + + auto* delBtn{ modal->bindNew("del-btn", Wt::WString::tr("Lms.delete")) }; + delBtn->clicked().connect([=, this] { + { + auto transaction{ LmsApp->getDbSession().createWriteTransaction() }; + + User::pointer user{ User::find(LmsApp->getDbSession(), userId) }; + if (user) + user.remove(); + } + + _container->removeWidget(entry); + + LmsApp->getModalManager().dispose(modalPtr); + }); + + auto* cancelBtn{ modal->bindNew("cancel-btn", Wt::WString::tr("Lms.cancel")) }; + cancelBtn->clicked().connect([=] { + LmsApp->getModalManager().dispose(modalPtr); + }); + + LmsApp->getModalManager().show(std::move(modal)); + }); + }); } } // namespace lms::ui diff --git a/src/lms/ui/admin/UsersView.hpp b/src/lms/ui/admin/UsersView.hpp index a3915bb7..2122de15 100644 --- a/src/lms/ui/admin/UsersView.hpp +++ b/src/lms/ui/admin/UsersView.hpp @@ -22,19 +22,18 @@ #include #include -namespace lms::ui { - -class UsersView : public Wt::WTemplate +namespace lms::ui { - public: - UsersView(); - private: - void refreshView(); + class UsersView : public Wt::WTemplate + { + public: + UsersView(); - Wt::WContainerWidget* _container; -}; + private: + void refreshView(); + + Wt::WContainerWidget* _container; + }; } // namespace lms::ui - - diff --git a/src/lms/ui/common/DoubleValidator.cpp b/src/lms/ui/common/DoubleValidator.cpp index 02a8be1e..f9d49597 100644 --- a/src/lms/ui/common/DoubleValidator.cpp +++ b/src/lms/ui/common/DoubleValidator.cpp @@ -23,19 +23,18 @@ namespace lms::ui { - class DoubleValidator : public Wt::WDoubleValidator - { - public: - using Wt::WDoubleValidator::WDoubleValidator; + class DoubleValidator : public Wt::WDoubleValidator + { + public: + using Wt::WDoubleValidator::WDoubleValidator; - private: - std::string javaScriptValidate() const override { return {}; } - }; + private: + std::string javaScriptValidate() const override { return {}; } + }; - std::unique_ptr - createDoubleValidator(double min, double max) - { - auto validator {std::make_unique(min, max)}; - return validator; - } + std::unique_ptr createDoubleValidator(double min, double max) + { + auto validator{ std::make_unique(min, max) }; + return validator; + } } // namespace lms::ui diff --git a/src/lms/ui/common/DoubleValidator.hpp b/src/lms/ui/common/DoubleValidator.hpp index 4bec825a..132c14a4 100644 --- a/src/lms/ui/common/DoubleValidator.hpp +++ b/src/lms/ui/common/DoubleValidator.hpp @@ -23,6 +23,5 @@ namespace lms::ui { - std::unique_ptr createDoubleValidator(double min, double max); + std::unique_ptr createDoubleValidator(double min, double max); } // namespace lms::ui - diff --git a/src/lms/ui/common/InfiniteScrollingContainer.cpp b/src/lms/ui/common/InfiniteScrollingContainer.cpp index 6f33dd22..4a008ab0 100644 --- a/src/lms/ui/common/InfiniteScrollingContainer.cpp +++ b/src/lms/ui/common/InfiniteScrollingContainer.cpp @@ -20,6 +20,7 @@ #include "InfiniteScrollingContainer.hpp" #include + #include "LoadingIndicator.hpp" namespace lms::ui @@ -96,17 +97,15 @@ namespace lms::ui return _elements->indexOf(&widget); } - void InfiniteScrollingContainer::displayLoadingIndicator() { _loadingIndicator = bindWidget("loading-indicator", createLoadingIndicator()); - _loadingIndicator->scrollVisibilityChanged().connect([this](bool visible) - { - if (!visible) - return; + _loadingIndicator->scrollVisibilityChanged().connect([this](bool visible) { + if (!visible) + return; - onRequestElements.emit(); - }); + onRequestElements.emit(); + }); } void InfiniteScrollingContainer::hideLoadingIndicator() @@ -114,4 +113,4 @@ namespace lms::ui _loadingIndicator = nullptr; bindEmpty("loading-indicator"); } -} +} // namespace lms::ui diff --git a/src/lms/ui/common/InfiniteScrollingContainer.hpp b/src/lms/ui/common/InfiniteScrollingContainer.hpp index d2fa6888..7167e398 100644 --- a/src/lms/ui/common/InfiniteScrollingContainer.hpp +++ b/src/lms/ui/common/InfiniteScrollingContainer.hpp @@ -30,41 +30,41 @@ namespace lms::ui { - // Atomatically raises onRequestElements signal when the sentinel is displayed - // can add elements afterwards by calling setHasMoreElements() - class InfiniteScrollingContainer final : public Wt::WTemplate - { - public: - // "text" must contain loading-indicator and "elements" - InfiniteScrollingContainer(const Wt::WString& text = Wt::WString::tr("Lms.infinite-scrolling-container.template")); + // Atomatically raises onRequestElements signal when the sentinel is displayed + // can add elements afterwards by calling setHasMoreElements() + class InfiniteScrollingContainer final : public Wt::WTemplate + { + public: + // "text" must contain loading-indicator and "elements" + InfiniteScrollingContainer(const Wt::WString& text = Wt::WString::tr("Lms.infinite-scrolling-container.template")); - void reset(); - std::size_t getCount(); - void add(std::unique_ptr result); + void reset(); + std::size_t getCount(); + void add(std::unique_ptr result); - template - T* addNew(Args&&... args) - { - return _elements->addNew(std::forward(args)...); - } + template + T* addNew(Args&&... args) + { + return _elements->addNew(std::forward(args)...); + } - void remove(Wt::WWidget& widget); - void remove(std::size_t first, std::size_t last); + void remove(Wt::WWidget& widget); + void remove(std::size_t first, std::size_t last); - Wt::WWidget* getWidget(std::size_t pos) const; - std::optional getIndexOf(Wt::WWidget& widget) const; - void setHasMore(); // can be used to add elements afterwards + Wt::WWidget* getWidget(std::size_t pos) const; + std::optional getIndexOf(Wt::WWidget& widget) const; + void setHasMore(); // can be used to add elements afterwards - Wt::Signal<> onRequestElements; + Wt::Signal<> onRequestElements; - void setHasMore(bool hasMore); // can be used to add elements afterwards + void setHasMore(bool hasMore); // can be used to add elements afterwards - private: - void clear() override; - void displayLoadingIndicator(); - void hideLoadingIndicator(); + private: + void clear() override; + void displayLoadingIndicator(); + void hideLoadingIndicator(); - Wt::WContainerWidget* _elements; - Wt::WTemplate* _loadingIndicator; - }; -} + Wt::WContainerWidget* _elements; + Wt::WTemplate* _loadingIndicator; + }; +} // namespace lms::ui diff --git a/src/lms/ui/common/LoadingIndicator.cpp b/src/lms/ui/common/LoadingIndicator.cpp index 0912f4b6..c5196c5f 100644 --- a/src/lms/ui/common/LoadingIndicator.cpp +++ b/src/lms/ui/common/LoadingIndicator.cpp @@ -23,7 +23,7 @@ namespace lms::ui { std::unique_ptr createLoadingIndicator() { - auto res {std::make_unique(Wt::WString::tr("Lms.LoadingIndicator.template"))}; + auto res{ std::make_unique(Wt::WString::tr("Lms.LoadingIndicator.template")) }; res->addFunction("tr", &Wt::WTemplate::Functions::tr); res->setScrollVisibilityEnabled(true); @@ -31,5 +31,4 @@ namespace lms::ui return res; } -} - +} // namespace lms::ui diff --git a/src/lms/ui/common/LoadingIndicator.hpp b/src/lms/ui/common/LoadingIndicator.hpp index fcd49397..5d5715f6 100644 --- a/src/lms/ui/common/LoadingIndicator.hpp +++ b/src/lms/ui/common/LoadingIndicator.hpp @@ -23,6 +23,5 @@ namespace lms::ui { - std::unique_ptr createLoadingIndicator(); + std::unique_ptr createLoadingIndicator(); } - diff --git a/src/lms/ui/common/LoginNameValidator.cpp b/src/lms/ui/common/LoginNameValidator.cpp index 8eeb4d20..aeb3e23d 100644 --- a/src/lms/ui/common/LoginNameValidator.cpp +++ b/src/lms/ui/common/LoginNameValidator.cpp @@ -20,6 +20,7 @@ #include "LoginNameValidator.hpp" #include + #include "database/User.hpp" namespace lms::ui @@ -31,7 +32,7 @@ namespace lms::ui private: std::string javaScriptValidate() const override { return {}; } }; - } + } // namespace std::unique_ptr createLoginNameValidator() { diff --git a/src/lms/ui/common/LoginNameValidator.hpp b/src/lms/ui/common/LoginNameValidator.hpp index 6e76eb34..e93691b0 100644 --- a/src/lms/ui/common/LoginNameValidator.hpp +++ b/src/lms/ui/common/LoginNameValidator.hpp @@ -23,6 +23,5 @@ namespace lms::ui { - std::unique_ptr createLoginNameValidator(); + std::unique_ptr createLoginNameValidator(); } // namespace lms::ui - diff --git a/src/lms/ui/common/MandatoryValidator.cpp b/src/lms/ui/common/MandatoryValidator.cpp index f6fcf3db..06505183 100644 --- a/src/lms/ui/common/MandatoryValidator.cpp +++ b/src/lms/ui/common/MandatoryValidator.cpp @@ -21,17 +21,17 @@ namespace lms::ui { - class MandatoryValidator : public Wt::WValidator - { - private: - std::string javaScriptValidate() const override { return {}; } - }; + class MandatoryValidator : public Wt::WValidator + { + private: + std::string javaScriptValidate() const override { return {}; } + }; - std::unique_ptr - createMandatoryValidator() - { - auto v {std::make_unique()}; - v->setMandatory(true); - return v; - } + std::unique_ptr + createMandatoryValidator() + { + auto v{ std::make_unique() }; + v->setMandatory(true); + return v; + } } // namespace lms::ui diff --git a/src/lms/ui/common/MandatoryValidator.hpp b/src/lms/ui/common/MandatoryValidator.hpp index 66b0f8cd..b0b78ed1 100644 --- a/src/lms/ui/common/MandatoryValidator.hpp +++ b/src/lms/ui/common/MandatoryValidator.hpp @@ -23,6 +23,5 @@ namespace lms::ui { - std::unique_ptr createMandatoryValidator(); + std::unique_ptr createMandatoryValidator(); } // namespace lms::ui - diff --git a/src/lms/ui/common/PasswordValidator.cpp b/src/lms/ui/common/PasswordValidator.cpp index 259b60cc..f6cb31d6 100644 --- a/src/lms/ui/common/PasswordValidator.cpp +++ b/src/lms/ui/common/PasswordValidator.cpp @@ -21,8 +21,9 @@ #include -#include "services/auth/IPasswordService.hpp" #include "core/Service.hpp" +#include "services/auth/IPasswordService.hpp" + #include "LmsApplication.hpp" namespace lms::ui @@ -34,7 +35,8 @@ namespace lms::ui public: PasswordStrengthValidator(PasswordValidationContextGetFunc passwordValidationContextGetFunc) : _passwordValidationContextGetFunc{ std::move(passwordValidationContextGetFunc) } - {} + { + } private: Wt::WValidator::Result validate(const Wt::WString& input) const override; @@ -42,7 +44,7 @@ namespace lms::ui PasswordValidationContextGetFunc _passwordValidationContextGetFunc; }; - } + } // namespace Wt::WValidator::Result PasswordStrengthValidator::validate(const Wt::WString& input) const { @@ -82,9 +84,9 @@ namespace lms::ui return Wt::WValidator::validate(input); const auto checkResult{ core::Service::get()->checkUserPassword( - boost::asio::ip::address::from_string(LmsApp->environment().clientAddress()), - LmsApp->getUserLoginName(), - input.toUTF8()) }; + boost::asio::ip::address::from_string(LmsApp->environment().clientAddress()), + LmsApp->getUserLoginName(), + input.toUTF8()) }; switch (checkResult.state) { case auth::IPasswordService::CheckResult::State::Granted: diff --git a/src/lms/ui/common/PasswordValidator.hpp b/src/lms/ui/common/PasswordValidator.hpp index 757d1831..adeeebbe 100644 --- a/src/lms/ui/common/PasswordValidator.hpp +++ b/src/lms/ui/common/PasswordValidator.hpp @@ -20,16 +20,16 @@ #pragma once #include + #include #include "services/auth/Types.hpp" namespace lms::ui { - using PasswordValidationContextGetFunc = std::function; - std::unique_ptr createPasswordStrengthValidator(PasswordValidationContextGetFunc passwordValidationContextGetFunc); + using PasswordValidationContextGetFunc = std::function; + std::unique_ptr createPasswordStrengthValidator(PasswordValidationContextGetFunc passwordValidationContextGetFunc); - // Check current user password - std::unique_ptr createPasswordCheckValidator(); + // Check current user password + std::unique_ptr createPasswordCheckValidator(); } // namespace lms::ui - diff --git a/src/lms/ui/common/Template.hpp b/src/lms/ui/common/Template.hpp index d5cce8a0..840e43f4 100644 --- a/src/lms/ui/common/Template.hpp +++ b/src/lms/ui/common/Template.hpp @@ -23,14 +23,12 @@ namespace lms::ui { + class Template : public Wt::WTemplate + { + public: + using Wt::WTemplate::WTemplate; - class Template : public Wt::WTemplate - { - public: - using Wt::WTemplate::WTemplate; - - private: - void applyArguments(Wt::WWidget* w, const std::vector& args) override; - }; - + private: + void applyArguments(Wt::WWidget* w, const std::vector& args) override; + }; } // namespace lms::ui diff --git a/src/lms/ui/common/UUIDValidator.cpp b/src/lms/ui/common/UUIDValidator.cpp index 4a7da07a..a0629b16 100644 --- a/src/lms/ui/common/UUIDValidator.cpp +++ b/src/lms/ui/common/UUIDValidator.cpp @@ -23,18 +23,18 @@ namespace lms::ui { - class RegExpValidator : public Wt::WRegExpValidator - { - public: - using Wt::WRegExpValidator::WRegExpValidator; + class RegExpValidator : public Wt::WRegExpValidator + { + public: + using Wt::WRegExpValidator::WRegExpValidator; - private: - std::string javaScriptValidate() const override { return {}; } - }; + private: + std::string javaScriptValidate() const override { return {}; } + }; - std::unique_ptr - createUUIDValidator() - { - return std::make_unique("[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}"); - } + std::unique_ptr + createUUIDValidator() + { + return std::make_unique("[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}"); + } } // namespace lms::ui diff --git a/src/lms/ui/common/UUIDValidator.hpp b/src/lms/ui/common/UUIDValidator.hpp index a19de2e0..c8029734 100644 --- a/src/lms/ui/common/UUIDValidator.hpp +++ b/src/lms/ui/common/UUIDValidator.hpp @@ -23,6 +23,5 @@ namespace lms::ui { - std::unique_ptr createUUIDValidator(); + std::unique_ptr createUUIDValidator(); } // namespace lms::ui - diff --git a/src/lms/ui/common/UppercaseValidator.cpp b/src/lms/ui/common/UppercaseValidator.cpp index b103dd74..a5623766 100644 --- a/src/lms/ui/common/UppercaseValidator.cpp +++ b/src/lms/ui/common/UppercaseValidator.cpp @@ -38,7 +38,7 @@ namespace lms::ui return Wt::WValidator::validate(input); const std::string str{ input.toUTF8() }; - const bool valid{ std::all_of(std::cbegin(str), std::cend(str), [&](char c) { return !std::isalpha(c) || std::isupper(c);}) }; + const bool valid{ std::all_of(std::cbegin(str), std::cend(str), [&](char c) { return !std::isalpha(c) || std::isupper(c); }) }; if (!valid) return Wt::WValidator::Result(Wt::ValidationState::Invalid, Wt::WString::tr("Lms.field-must-be-in-upper-case")); diff --git a/src/lms/ui/common/ValueStringModel.hpp b/src/lms/ui/common/ValueStringModel.hpp index 39682bd9..c4fded62 100644 --- a/src/lms/ui/common/ValueStringModel.hpp +++ b/src/lms/ui/common/ValueStringModel.hpp @@ -26,7 +26,7 @@ namespace lms::ui { // Helper class - template + template class ValueStringModel : public Wt::WStringListModel { public: diff --git a/src/lms/ui/explore/ArtistCollector.cpp b/src/lms/ui/explore/ArtistCollector.cpp index 098ffa49..eaf08daa 100644 --- a/src/lms/ui/explore/ArtistCollector.cpp +++ b/src/lms/ui/explore/ArtistCollector.cpp @@ -19,13 +19,14 @@ #include "ArtistCollector.hpp" +#include "core/Service.hpp" #include "database/Artist.hpp" #include "database/Session.hpp" #include "database/TrackList.hpp" #include "database/User.hpp" #include "services/feedback/IFeedbackService.hpp" #include "services/scrobbling/IScrobblingService.hpp" -#include "core/Service.hpp" + #include "Filters.hpp" #include "LmsApplication.hpp" @@ -50,80 +51,80 @@ namespace lms::ui break; case Mode::Starred: - { - feedback::IFeedbackService::ArtistFindParameters params; - params.setUser(LmsApp->getUserId()); - params.setClusters(filters.getClusters()); - params.setKeywords(getSearchKeywords()); - params.setMediaLibrary(filters.getMediaLibrary()); - params.setLinkType(_linkType); - params.setSortMethod(ArtistSortMethod::StarredDateDesc); - params.setRange(range); - artists = feedbackService.findStarredArtists(params); - break; - } + { + feedback::IFeedbackService::ArtistFindParameters params; + params.setUser(LmsApp->getUserId()); + params.setClusters(filters.getClusters()); + params.setKeywords(getSearchKeywords()); + params.setMediaLibrary(filters.getMediaLibrary()); + params.setLinkType(_linkType); + params.setSortMethod(ArtistSortMethod::StarredDateDesc); + params.setRange(range); + artists = feedbackService.findStarredArtists(params); + break; + } case Mode::RecentlyPlayed: - { - scrobbling::IScrobblingService::ArtistFindParameters params; - params.setUser(LmsApp->getUserId()); - params.setClusters(filters.getClusters()); - params.setKeywords(getSearchKeywords()); - params.setMediaLibrary(filters.getMediaLibrary()); - params.setLinkType(_linkType); - params.setRange(range); + { + scrobbling::IScrobblingService::ArtistFindParameters params; + params.setUser(LmsApp->getUserId()); + params.setClusters(filters.getClusters()); + params.setKeywords(getSearchKeywords()); + params.setMediaLibrary(filters.getMediaLibrary()); + params.setLinkType(_linkType); + params.setRange(range); - artists = scrobblingService.getRecentArtists(params); - break; - } + artists = scrobblingService.getRecentArtists(params); + break; + } case Mode::MostPlayed: - { - scrobbling::IScrobblingService::ArtistFindParameters params; - params.setUser(LmsApp->getUserId()); - params.setClusters(filters.getClusters()); - params.setKeywords(getSearchKeywords()); - params.setMediaLibrary(filters.getMediaLibrary()); - params.setLinkType(_linkType); - params.setRange(range); + { + scrobbling::IScrobblingService::ArtistFindParameters params; + params.setUser(LmsApp->getUserId()); + params.setClusters(filters.getClusters()); + params.setKeywords(getSearchKeywords()); + params.setMediaLibrary(filters.getMediaLibrary()); + params.setLinkType(_linkType); + params.setRange(range); - artists = scrobblingService.getTopArtists(params); - break; - } + artists = scrobblingService.getTopArtists(params); + break; + } case Mode::RecentlyAdded: - { - Artist::FindParameters params; - params.setClusters(filters.getClusters()); - params.setKeywords(getSearchKeywords()); - params.setMediaLibrary(filters.getMediaLibrary()); - params.setLinkType(_linkType); - params.setSortMethod(ArtistSortMethod::LastWritten); - params.setRange(range); - { - auto transaction{ LmsApp->getDbSession().createReadTransaction() }; - artists = Artist::findIds(LmsApp->getDbSession(), params); + Artist::FindParameters params; + params.setClusters(filters.getClusters()); + params.setKeywords(getSearchKeywords()); + params.setMediaLibrary(filters.getMediaLibrary()); + params.setLinkType(_linkType); + params.setSortMethod(ArtistSortMethod::LastWritten); + params.setRange(range); + + { + auto transaction{ LmsApp->getDbSession().createReadTransaction() }; + artists = Artist::findIds(LmsApp->getDbSession(), params); + } + break; } - break; - } case Mode::All: - { - Artist::FindParameters params; - params.setClusters(filters.getClusters()); - params.setMediaLibrary(filters.getMediaLibrary()); - params.setKeywords(getSearchKeywords()); - params.setLinkType(_linkType); - params.setSortMethod(ArtistSortMethod::SortName); - params.setRange(range); - { - auto transaction{ LmsApp->getDbSession().createReadTransaction() }; - artists = Artist::findIds(LmsApp->getDbSession(), params); + Artist::FindParameters params; + params.setClusters(filters.getClusters()); + params.setMediaLibrary(filters.getMediaLibrary()); + params.setKeywords(getSearchKeywords()); + params.setLinkType(_linkType); + params.setSortMethod(ArtistSortMethod::SortName); + params.setRange(range); + + { + auto transaction{ LmsApp->getDbSession().createReadTransaction() }; + artists = Artist::findIds(LmsApp->getDbSession(), params); + } + break; } - break; - } } if (range.offset + range.size == getMaxCount()) @@ -154,4 +155,4 @@ namespace lms::ui return _randomArtists->getSubRange(range); } -} // ns UserInterface +} // namespace lms::ui diff --git a/src/lms/ui/explore/ArtistCollector.hpp b/src/lms/ui/explore/ArtistCollector.hpp index ab628894..9e5967ac 100644 --- a/src/lms/ui/explore/ArtistCollector.hpp +++ b/src/lms/ui/explore/ArtistCollector.hpp @@ -27,24 +27,23 @@ namespace lms::db { - class Artist; + class Artist; } namespace lms::ui { - class ArtistCollector : public DatabaseCollectorBase - { - public: - using DatabaseCollectorBase::DatabaseCollectorBase; + class ArtistCollector : public DatabaseCollectorBase + { + public: + using DatabaseCollectorBase::DatabaseCollectorBase; - db::RangeResults get(std::optional range = std::nullopt); - void reset() { _randomArtists.reset(); } - void setArtistLinkType(std::optional linkType) { _linkType = linkType; } - - private: - db::RangeResults getRandomArtists(Range range); - std::optional> _randomArtists; - std::optional _linkType; - }; -} // ns UserInterface + db::RangeResults get(std::optional range = std::nullopt); + void reset() { _randomArtists.reset(); } + void setArtistLinkType(std::optional linkType) { _linkType = linkType; } + private: + db::RangeResults getRandomArtists(Range range); + std::optional> _randomArtists; + std::optional _linkType; + }; +} // namespace lms::ui diff --git a/src/lms/ui/explore/ArtistListHelpers.cpp b/src/lms/ui/explore/ArtistListHelpers.cpp index cd501789..c8dbb038 100644 --- a/src/lms/ui/explore/ArtistListHelpers.cpp +++ b/src/lms/ui/explore/ArtistListHelpers.cpp @@ -20,6 +20,7 @@ #include "database/Artist.hpp" #include "database/Session.hpp" + #include "LmsApplication.hpp" #include "Utils.hpp" @@ -32,4 +33,4 @@ namespace lms::ui::ArtistListHelpers return res; } -} \ No newline at end of file +} // namespace lms::ui::ArtistListHelpers \ No newline at end of file diff --git a/src/lms/ui/explore/ArtistListHelpers.hpp b/src/lms/ui/explore/ArtistListHelpers.hpp index ca9164ba..55a7fd0c 100644 --- a/src/lms/ui/explore/ArtistListHelpers.hpp +++ b/src/lms/ui/explore/ArtistListHelpers.hpp @@ -29,16 +29,15 @@ namespace lms::db { - class Artist; + class Artist; } namespace lms::ui { - using ArtistLinkTypesModel = ValueStringModel>; - - namespace ArtistListHelpers - { - std::unique_ptr createEntry(const db::ObjectPtr& artist); - } -} + using ArtistLinkTypesModel = ValueStringModel>; + namespace ArtistListHelpers + { + std::unique_ptr createEntry(const db::ObjectPtr& artist); + } +} // namespace lms::ui diff --git a/src/lms/ui/explore/ArtistView.cpp b/src/lms/ui/explore/ArtistView.cpp index 6c6b9d23..a05b9a9e 100644 --- a/src/lms/ui/explore/ArtistView.cpp +++ b/src/lms/ui/explore/ArtistView.cpp @@ -21,6 +21,8 @@ #include +#include "core/ILogger.hpp" +#include "core/String.hpp" #include "database/Artist.hpp" #include "database/Cluster.hpp" #include "database/Release.hpp" @@ -30,11 +32,7 @@ #include "database/User.hpp" #include "services/feedback/IFeedbackService.hpp" #include "services/recommendation/IRecommendationService.hpp" -#include "core/ILogger.hpp" -#include "core/String.hpp" -#include "common/InfiniteScrollingContainer.hpp" -#include "resource/DownloadResource.hpp" #include "ArtistListHelpers.hpp" #include "Filters.hpp" #include "LmsApplication.hpp" @@ -43,11 +41,13 @@ #include "ReleaseHelpers.hpp" #include "TrackListHelpers.hpp" #include "Utils.hpp" +#include "common/InfiniteScrollingContainer.hpp" +#include "resource/DownloadResource.hpp" namespace lms::ui { using namespace db; - + namespace { std::optional extractArtistIdFromInternalPath() @@ -67,7 +67,7 @@ namespace lms::ui return core::stringUtils::readAs(wApp->internalPathNextPart("/artist/")); } - } + } // namespace Artist::Artist(Filters& filters, PlayQueueController& controller) : Template{ Wt::WString::tr("Lms.Explore.Artist.template") } @@ -77,16 +77,14 @@ namespace lms::ui addFunction("tr", &Wt::WTemplate::Functions::tr); addFunction("id", &Wt::WTemplate::Functions::id); - LmsApp->internalPathChanged().connect(this, [this] - { - refreshView(); - }); + LmsApp->internalPathChanged().connect(this, [this] { + refreshView(); + }); - filters.updated().connect([this] - { - _needForceRefresh = true; - refreshView(); - }); + filters.updated().connect([this] { + _needForceRefresh = true; + refreshView(); + }); refreshView(); } @@ -110,7 +108,7 @@ namespace lms::ui if (!artistId) throw ArtistNotFoundException{}; - const auto similarArtistIds{ core::Service::get()->getSimilarArtists(*artistId, {TrackArtistLinkType::Artist, TrackArtistLinkType::ReleaseArtist}, 5) }; + const auto similarArtistIds{ core::Service::get()->getSimilarArtists(*artistId, { TrackArtistLinkType::Artist, TrackArtistLinkType::ReleaseArtist }, 5) }; auto transaction{ LmsApp->getDbSession().createReadTransaction() }; @@ -139,10 +137,9 @@ namespace lms::ui { const db::ClusterId clusterId = cluster->getId(); Wt::WInteractWidget* entry{ clusterContainers->addWidget(utils::createFilterCluster(clusterId)) }; - entry->clicked().connect([this, clusterId] - { - _filters.add(clusterId); - }); + entry->clicked().connect([this, clusterId] { + _filters.add(clusterId); + }); } } } @@ -150,26 +147,26 @@ namespace lms::ui bindString("name", Wt::WString::fromUTF8(artist->getName()), Wt::TextFormat::Plain); bindNew("play-btn", Wt::WString::tr("Lms.Explore.play"), Wt::TextFormat::XHTML) - ->clicked().connect([this] - { - _playQueueController.processCommand(PlayQueueController::Command::Play, { _artistId }); - }); + ->clicked() + .connect([this] { + _playQueueController.processCommand(PlayQueueController::Command::Play, { _artistId }); + }); bindNew("play-shuffled", Wt::WString::tr("Lms.Explore.play-shuffled"), Wt::TextFormat::Plain) - ->clicked().connect([this] - { - _playQueueController.processCommand(PlayQueueController::Command::PlayShuffled, { _artistId }); - }); + ->clicked() + .connect([this] { + _playQueueController.processCommand(PlayQueueController::Command::PlayShuffled, { _artistId }); + }); bindNew("play-next", Wt::WString::tr("Lms.Explore.play-next"), Wt::TextFormat::Plain) - ->clicked().connect([this] - { - _playQueueController.processCommand(PlayQueueController::Command::PlayNext, { _artistId }); - }); + ->clicked() + .connect([this] { + _playQueueController.processCommand(PlayQueueController::Command::PlayNext, { _artistId }); + }); bindNew("play-last", Wt::WString::tr("Lms.Explore.play-last"), Wt::TextFormat::Plain) - ->clicked().connect([this] - { - _playQueueController.processCommand(PlayQueueController::Command::PlayOrAddLast, { _artistId }); - }); + ->clicked() + .connect([this] { + _playQueueController.processCommand(PlayQueueController::Command::PlayOrAddLast, { _artistId }); + }); bindNew("download", Wt::WString::tr("Lms.Explore.download")) ->setLink(Wt::WLink{ std::make_unique(_artistId) }); @@ -177,19 +174,18 @@ namespace lms::ui auto isStarred{ [this] { return core::Service::get()->isStarred(LmsApp->getUserId(), _artistId); } }; Wt::WPushButton* starBtn{ bindNew("star", Wt::WString::tr(isStarred() ? "Lms.Explore.unstar" : "Lms.Explore.star")) }; - starBtn->clicked().connect([=, this] + starBtn->clicked().connect([=, this] { + if (isStarred()) { - if (isStarred()) - { - core::Service::get()->unstar(LmsApp->getUserId(), _artistId); - starBtn->setText(Wt::WString::tr("Lms.Explore.star")); - } - else - { - core::Service::get()->star(LmsApp->getUserId(), _artistId); - starBtn->setText(Wt::WString::tr("Lms.Explore.unstar")); - } - }); + core::Service::get()->unstar(LmsApp->getUserId(), _artistId); + starBtn->setText(Wt::WString::tr("Lms.Explore.star")); + } + else + { + core::Service::get()->star(LmsApp->getUserId(), _artistId); + starBtn->setText(Wt::WString::tr("Lms.Explore.unstar")); + } + }); } } @@ -211,7 +207,7 @@ namespace lms::ui { const db::Release::pointer release{ db::Release::find(LmsApp->getDbSession(), releaseId) }; - ReleaseType releaseType{ parseReleaseType(release->getReleaseTypeNames())}; + ReleaseType releaseType{ parseReleaseType(release->getReleaseTypeNames()) }; _releaseContainers[releaseType].releases.push_back(releaseId); } @@ -225,12 +221,11 @@ namespace lms::ui releaseContainer->bindString("release-type", releaseHelpers::buildReleaseTypeString(releaseType)); else releaseContainer->bindString("release-type", Wt::WString::tr("Lms.Explore.releases")); // fallback when not tagged with MB or custom type - + releases.container = releaseContainer->bindNew("releases", Wt::WString::tr("Lms.Explore.Releases.template.container")); - releases.container->onRequestElements.connect(this, [this, &releases = releases] - { - addSomeReleases(releases); - }); + releases.container->onRequestElements.connect(this, [this, &releases = releases] { + addSomeReleases(releases); + }); } } else @@ -241,8 +236,7 @@ namespace lms::ui void Artist::refreshAppearsOnReleases() { - constexpr core::EnumSet types - { + constexpr core::EnumSet types{ TrackArtistLinkType::Artist, TrackArtistLinkType::Arranger, TrackArtistLinkType::Composer, @@ -270,10 +264,9 @@ namespace lms::ui releaseContainer->bindString("release-type", Wt::WString::tr("Lms.Explore.Artist.appears-on")); _appearsOnReleaseContainer.releases = releases.results; _appearsOnReleaseContainer.container = releaseContainer->bindNew("releases", Wt::WString::tr("Lms.Explore.Releases.template.container")); - _appearsOnReleaseContainer.container->onRequestElements.connect(this, [this] - { - addSomeReleases(_appearsOnReleaseContainer); - }); + _appearsOnReleaseContainer.container->onRequestElements.connect(this, [this] { + addSomeReleases(_appearsOnReleaseContainer); + }); } else { @@ -285,10 +278,9 @@ namespace lms::ui { setCondition("if-has-non-release-tracks", true); _trackContainer = bindNew("tracks"); - _trackContainer->onRequestElements.connect(this, [this] - { - addSomeNonReleaseTracks(); - }); + _trackContainer->onRequestElements.connect(this, [this] { + addSomeNonReleaseTracks(); + }); const bool added{ addSomeNonReleaseTracks() }; setCondition("if-has-non-release-tracks", added); @@ -372,4 +364,3 @@ namespace lms::ui } } // namespace lms::ui - diff --git a/src/lms/ui/explore/ArtistView.hpp b/src/lms/ui/explore/ArtistView.hpp index 07dfeace..7220e625 100644 --- a/src/lms/ui/explore/ArtistView.hpp +++ b/src/lms/ui/explore/ArtistView.hpp @@ -21,18 +21,20 @@ #include #include + +#include "core/EnumSet.hpp" #include "database/ArtistId.hpp" #include "database/Object.hpp" #include "database/ReleaseId.hpp" -#include "core/EnumSet.hpp" -#include "common/Template.hpp" + #include "ReleaseTypes.hpp" +#include "common/Template.hpp" namespace lms::db { class Artist; class Release; -} +} // namespace lms::db namespace lms::ui { @@ -70,10 +72,9 @@ namespace lms::ui std::vector releases; }; std::map _releaseContainers; - ReleaseContainer _appearsOnReleaseContainer{}; + ReleaseContainer _appearsOnReleaseContainer{}; InfiniteScrollingContainer* _trackContainer{}; - db::ArtistId _artistId{}; - bool _needForceRefresh{}; + db::ArtistId _artistId{}; + bool _needForceRefresh{}; }; } // namespace lms::ui - diff --git a/src/lms/ui/explore/ArtistsView.cpp b/src/lms/ui/explore/ArtistsView.cpp index 25d61ebe..5bce4d67 100644 --- a/src/lms/ui/explore/ArtistsView.cpp +++ b/src/lms/ui/explore/ArtistsView.cpp @@ -26,12 +26,12 @@ #include "database/Session.hpp" #include "database/TrackArtistLink.hpp" -#include "common/InfiniteScrollingContainer.hpp" #include "ArtistListHelpers.hpp" #include "Filters.hpp" #include "LmsApplication.hpp" #include "SortModeSelector.hpp" #include "TrackArtistLinkTypeSelector.hpp" +#include "common/InfiniteScrollingContainer.hpp" namespace lms::ui { @@ -46,33 +46,28 @@ namespace lms::ui Wt::WLineEdit* searEdit{ bindNew("search") }; searEdit->setPlaceholderText(Wt::WString::tr("Lms.Explore.Search.search-placeholder")); - searEdit->textInput().connect([this, searEdit] - { - refreshView(searEdit->text()); - }); + searEdit->textInput().connect([this, searEdit] { + refreshView(searEdit->text()); + }); SortModeSelector* sortModeSelector{ bindNew("sort-mode", _defaultSortMode) }; - sortModeSelector->itemSelected.connect([this](ArtistCollector::Mode sortMode) - { - refreshView(sortMode); - }); + sortModeSelector->itemSelected.connect([this](ArtistCollector::Mode sortMode) { + refreshView(sortMode); + }); TrackArtistLinkTypeSelector* linkTypeSelector{ bindNew("link-type", _defaultLinkType) }; - linkTypeSelector->itemSelected.connect([this](std::optional linkType) - { - refreshView(linkType); - }); + linkTypeSelector->itemSelected.connect([this](std::optional linkType) { + refreshView(linkType); + }); _container = bindNew("artists", Wt::WString::tr("Lms.Explore.Artists.template.container")); - _container->onRequestElements.connect([this] - { - addSome(); - }); + _container->onRequestElements.connect([this] { + addSome(); + }); - filters.updated().connect([this] - { - refreshView(); - }); + filters.updated().connect([this] { + refreshView(); + }); refreshView(_artistCollector.getMode()); } @@ -103,7 +98,7 @@ namespace lms::ui void Artists::addSome() { - const auto artistIds{ _artistCollector.get(Range {static_cast(_container->getCount()), _batchSize}) }; + const auto artistIds{ _artistCollector.get(Range{ static_cast(_container->getCount()), _batchSize }) }; { auto transaction{ LmsApp->getDbSession().createReadTransaction() }; @@ -119,4 +114,3 @@ namespace lms::ui } } // namespace lms::ui - diff --git a/src/lms/ui/explore/ArtistsView.hpp b/src/lms/ui/explore/ArtistsView.hpp index 95d8fc60..d22c0a93 100644 --- a/src/lms/ui/explore/ArtistsView.hpp +++ b/src/lms/ui/explore/ArtistsView.hpp @@ -26,8 +26,9 @@ #include #include "database/Types.hpp" -#include "common/Template.hpp" + #include "ArtistCollector.hpp" +#include "common/Template.hpp" namespace lms::ui { @@ -51,9 +52,8 @@ namespace lms::ui Wt::WWidget* _currentLinkTypeActiveItem{}; InfiniteScrollingContainer* _container{}; - ArtistCollector _artistCollector; + ArtistCollector _artistCollector; static constexpr ArtistCollector::Mode _defaultSortMode{ ArtistCollector::Mode::Random }; static constexpr std::optional _defaultLinkType{ std::nullopt }; }; } // namespace lms::ui - diff --git a/src/lms/ui/explore/DatabaseCollectorBase.cpp b/src/lms/ui/explore/DatabaseCollectorBase.cpp index 601ff01d..e2e39f73 100644 --- a/src/lms/ui/explore/DatabaseCollectorBase.cpp +++ b/src/lms/ui/explore/DatabaseCollectorBase.cpp @@ -65,5 +65,4 @@ namespace lms::ui _searchKeywords.clear(); } -} // ns UserInterface - +} // namespace lms::ui diff --git a/src/lms/ui/explore/DatabaseCollectorBase.hpp b/src/lms/ui/explore/DatabaseCollectorBase.hpp index 63bfe960..fe8f03eb 100644 --- a/src/lms/ui/explore/DatabaseCollectorBase.hpp +++ b/src/lms/ui/explore/DatabaseCollectorBase.hpp @@ -55,16 +55,16 @@ namespace lms::ui void setSearch(std::string_view search); protected: - Range getActualRange(std::optional range) const; + Range getActualRange(std::optional range) const; std::size_t getMaxCount() const; - const Filters& getFilters() { return _filters; } + const Filters& getFilters() { return _filters; } const std::vector& getSearchKeywords() const { return _searchKeywords; } private: Filters& _filters; std::string _searchText; std::vector _searchKeywords; - Mode _mode; + Mode _mode; std::size_t _maxCount; }; -} // ns UserInterface +} // namespace lms::ui diff --git a/src/lms/ui/explore/DropDownMenuSelector.hpp b/src/lms/ui/explore/DropDownMenuSelector.hpp index 16ed6903..43b930f2 100644 --- a/src/lms/ui/explore/DropDownMenuSelector.hpp +++ b/src/lms/ui/explore/DropDownMenuSelector.hpp @@ -20,14 +20,15 @@ #pragma once #include + #include +#include #include #include -#include namespace lms::ui { - template + template class DropDownMenuSelector : public Wt::WTemplate { public: @@ -43,15 +44,14 @@ namespace lms::ui void bindItem(const std::string& var, const Wt::WString& title, ItemType item) { auto* menuItem{ bindNew(var, title) }; - menuItem->clicked().connect([this, menuItem, title, item] - { - _currentActiveItem->removeStyleClass("active"); - menuItem->addStyleClass("active"); - _currentActiveItem = menuItem; - _selectedItem->setText(title); + menuItem->clicked().connect([this, menuItem, title, item] { + _currentActiveItem->removeStyleClass("active"); + menuItem->addStyleClass("active"); + _currentActiveItem = menuItem; + _selectedItem->setText(title); - itemSelected.emit(item); - }); + itemSelected.emit(item); + }); if (item == _defaultItem) { @@ -68,4 +68,4 @@ namespace lms::ui Wt::WWidget* _currentActiveItem{}; Wt::WText* _selectedItem{}; }; -} \ No newline at end of file +} // namespace lms::ui \ No newline at end of file diff --git a/src/lms/ui/explore/Explore.cpp b/src/lms/ui/explore/Explore.cpp index b1daf755..6050aea5 100644 --- a/src/lms/ui/explore/Explore.cpp +++ b/src/lms/ui/explore/Explore.cpp @@ -22,11 +22,11 @@ #include #include -#include "ArtistsView.hpp" #include "ArtistView.hpp" +#include "ArtistsView.hpp" #include "Filters.hpp" -#include "ReleasesView.hpp" #include "ReleaseView.hpp" +#include "ReleasesView.hpp" #include "TrackListView.hpp" #include "TrackListsView.hpp" #include "TracksView.hpp" @@ -48,15 +48,14 @@ namespace lms::ui IdxTracks, }; - static const std::map indexes = - { - { "/artists", IdxArtists }, - { "/artist", IdxArtist }, - { "/tracklists", IdxTrackLists }, - { "/tracklist", IdxTrackList }, - { "/releases", IdxReleases }, - { "/release", IdxRelease }, - { "/tracks", IdxTracks }, + static const std::map indexes = { + { "/artists", IdxArtists }, + { "/artist", IdxArtist }, + { "/tracklists", IdxTrackLists }, + { "/tracklist", IdxTrackList }, + { "/releases", IdxReleases }, + { "/release", IdxRelease }, + { "/tracks", IdxTracks }, }; for (const auto& index : indexes) @@ -103,10 +102,9 @@ namespace lms::ui auto tracks = std::make_unique(filters, _playQueueController); contentsStack->addWidget(std::move(tracks)); - wApp->internalPathChanged().connect(this, [contentsStack] - { - handleContentsPathChange(contentsStack); - }); + wApp->internalPathChanged().connect(this, [contentsStack] { + handleContentsPathChange(contentsStack); + }); handleContentsPathChange(contentsStack); } diff --git a/src/lms/ui/explore/Explore.hpp b/src/lms/ui/explore/Explore.hpp index 48163c3c..090404f4 100644 --- a/src/lms/ui/explore/Explore.hpp +++ b/src/lms/ui/explore/Explore.hpp @@ -41,4 +41,3 @@ namespace lms::ui SearchView* _search{}; }; } // namespace lms::ui - diff --git a/src/lms/ui/explore/Filters.cpp b/src/lms/ui/explore/Filters.cpp index 4d6e6d9e..cc8bd236 100644 --- a/src/lms/ui/explore/Filters.cpp +++ b/src/lms/ui/explore/Filters.cpp @@ -30,16 +30,18 @@ #include "database/MediaLibrary.hpp" #include "database/Session.hpp" -#include "common/ValueStringModel.hpp" #include "LmsApplication.hpp" -#include "Utils.hpp" #include "ModalManager.hpp" +#include "Utils.hpp" +#include "common/ValueStringModel.hpp" namespace lms::ui { namespace { - struct MediaLibraryTag {}; + struct MediaLibraryTag + { + }; using TypeVariant = std::variant; using TypeModel = ValueStringModel; @@ -50,10 +52,9 @@ namespace lms::ui { auto transaction{ LmsApp->getDbSession().createReadTransaction() }; - db::ClusterType::find(LmsApp->getDbSession(), [&](const db::ClusterType::pointer& clusterType) - { - typeModel->add(Wt::WString::fromUTF8(std::string{ clusterType->getName() }), clusterType->getId()); - }); + db::ClusterType::find(LmsApp->getDbSession(), [&](const db::ClusterType::pointer& clusterType) { + typeModel->add(Wt::WString::fromUTF8(std::string{ clusterType->getName() }), clusterType->getId()); + }); } typeModel->add(Wt::WString::tr("Lms.Explore.media-library"), MediaLibraryTag{}); @@ -74,10 +75,9 @@ namespace lms::ui if (std::holds_alternative(type)) { - db::MediaLibrary::find(session, [&](const db::MediaLibrary::pointer& library) - { - valueModel->add(Wt::WString::fromUTF8(std::string{ library->getName() }), library->getId()); - }); + db::MediaLibrary::find(session, [&](const db::MediaLibrary::pointer& library) { + valueModel->add(Wt::WString::fromUTF8(std::string{ library->getName() }), library->getId()); + }); } else if (const db::ClusterTypeId * clusterTypeId{ std::get_if(&type) }) { @@ -85,15 +85,14 @@ namespace lms::ui params.setClusterType(*clusterTypeId); params.setSortMethod(db::ClusterSortMethod::Name); - db::Cluster::find(session, params, [&](const db::Cluster::pointer& cluster) - { - valueModel->add(Wt::WString::fromUTF8(std::string{ cluster->getName() }), cluster->getId()); - }); + db::Cluster::find(session, params, [&](const db::Cluster::pointer& cluster) { + valueModel->add(Wt::WString::fromUTF8(std::string{ cluster->getName() }), cluster->getId()); + }); } return valueModel; } - } + } // namespace void Filters::showDialog() { @@ -109,38 +108,35 @@ namespace lms::ui Wt::WComboBox* valueCombo{ dialog->bindNew("value") }; Wt::WPushButton* addBtn{ dialog->bindNew("add-btn", Wt::WString::tr("Lms.Explore.add-filter")) }; - addBtn->clicked().connect([this, valueCombo, dialogPtr] + addBtn->clicked().connect([this, valueCombo, dialogPtr] { + const auto valueModel{ std::static_pointer_cast(valueCombo->model()) }; + const ValueVariant value{ valueModel->getValue(valueCombo->currentIndex()) }; + + if (const db::MediaLibraryId * mediaLibraryId{ std::get_if(&value) }) { - const auto valueModel{ std::static_pointer_cast(valueCombo->model()) }; - const ValueVariant value{ valueModel->getValue(valueCombo->currentIndex()) }; + set(*mediaLibraryId); + } + else if (const db::ClusterId * clusterId{ std::get_if(&value) }) + { + add(*clusterId); + } - if (const db::MediaLibraryId * mediaLibraryId{ std::get_if(&value) }) - { - set(*mediaLibraryId); - } - else if (const db::ClusterId * clusterId{ std::get_if(&value) }) - { - add(*clusterId); - } - - // TODO - LmsApp->getModalManager().dispose(dialogPtr); - }); + // TODO + LmsApp->getModalManager().dispose(dialogPtr); + }); Wt::WPushButton* cancelBtn{ dialog->bindNew("cancel-btn", Wt::WString::tr("Lms.cancel")) }; - cancelBtn->clicked().connect([=] - { - LmsApp->getModalManager().dispose(dialogPtr); - }); + cancelBtn->clicked().connect([=] { + LmsApp->getModalManager().dispose(dialogPtr); + }); - typeCombo->activated().connect([valueCombo, typeModel](int row) - { - const TypeVariant type{ typeModel->getValue(row) }; + typeCombo->activated().connect([valueCombo, typeModel](int row) { + const TypeVariant type{ typeModel->getValue(row) }; - const std::shared_ptr valueModel{ createValueModel(type) }; - valueCombo->clear(); - valueCombo->setModel(valueModel); - }); + const std::shared_ptr valueModel{ createValueModel(type) }; + valueCombo->clear(); + valueCombo->setModel(valueModel); + }); typeCombo->activated().emit(0); // force emit to refresh the type combo model @@ -176,12 +172,11 @@ namespace lms::ui _clusterIds.push_back(clusterId); - filter->clicked().connect([this, filter, clusterId] - { - _filters->removeWidget(filter); - _clusterIds.erase(std::remove_if(std::begin(_clusterIds), std::end(_clusterIds), [clusterId](db::ClusterId id) { return id == clusterId; }), std::end(_clusterIds)); - _sigUpdated.emit(); - }); + filter->clicked().connect([this, filter, clusterId] { + _filters->removeWidget(filter); + _clusterIds.erase(std::remove_if(std::begin(_clusterIds), std::end(_clusterIds), [clusterId](db::ClusterId id) { return id == clusterId; }), std::end(_clusterIds)); + _sigUpdated.emit(); + }); emitFilterAddedNotification(); } @@ -208,13 +203,12 @@ namespace lms::ui _mediaLibraryId = mediaLibraryId; _mediaLibraryFilter = _filters->addWidget(utils::createFilter(Wt::WString::fromUTF8(libraryName), Wt::WString::tr("Lms.Explore.media-library"), "bg-primary", true)); - _mediaLibraryFilter->clicked().connect(_mediaLibraryFilter, [this] - { - _filters->removeWidget(_mediaLibraryFilter); - _mediaLibraryId = db::MediaLibraryId{}; - _mediaLibraryFilter = nullptr; - _sigUpdated.emit(); - }); + _mediaLibraryFilter->clicked().connect(_mediaLibraryFilter, [this] { + _filters->removeWidget(_mediaLibraryFilter); + _mediaLibraryId = db::MediaLibraryId{}; + _mediaLibraryFilter = nullptr; + _sigUpdated.emit(); + }); emitFilterAddedNotification(); } diff --git a/src/lms/ui/explore/Filters.hpp b/src/lms/ui/explore/Filters.hpp index f13a1d5d..d1a01175 100644 --- a/src/lms/ui/explore/Filters.hpp +++ b/src/lms/ui/explore/Filters.hpp @@ -21,6 +21,7 @@ #include #include + #include #include #include @@ -57,4 +58,3 @@ namespace lms::ui db::MediaLibraryId _mediaLibraryId; }; } // namespace lms::ui - diff --git a/src/lms/ui/explore/PlayQueueController.cpp b/src/lms/ui/explore/PlayQueueController.cpp index 71606e46..3af83380 100644 --- a/src/lms/ui/explore/PlayQueueController.cpp +++ b/src/lms/ui/explore/PlayQueueController.cpp @@ -17,14 +17,16 @@ * along with LMS. If not, see . */ +#include "explore/PlayQueueController.hpp" + #include "database/ClusterId.hpp" #include "database/Release.hpp" #include "database/Session.hpp" #include "database/Track.hpp" -#include "explore/Filters.hpp" -#include "explore/PlayQueueController.hpp" -#include "PlayQueue.hpp" + #include "LmsApplication.hpp" +#include "PlayQueue.hpp" +#include "explore/Filters.hpp" namespace lms::ui { @@ -136,7 +138,7 @@ namespace lms::ui return db::Track::findIds(session, params).results; } - } + } // namespace PlayQueueController::PlayQueueController(Filters& filters, PlayQueue& playQueue) : _filters{ filters } @@ -200,7 +202,7 @@ namespace lms::ui releaseId = track->getRelease()->getId(); } - const std::vector tracks{ getReleasesTracks(LmsApp->getDbSession(), {releaseId}, _filters, _maxTrackCountToEnqueue) }; + const std::vector tracks{ getReleasesTracks(LmsApp->getDbSession(), { releaseId }, _filters, _maxTrackCountToEnqueue) }; auto itTrack{ std::find(std::cbegin(tracks), std::cend(tracks), trackId) }; if (itTrack == std::cend(tracks)) return; diff --git a/src/lms/ui/explore/PlayQueueController.hpp b/src/lms/ui/explore/PlayQueueController.hpp index 29f03c89..03771646 100644 --- a/src/lms/ui/explore/PlayQueueController.hpp +++ b/src/lms/ui/explore/PlayQueueController.hpp @@ -28,42 +28,41 @@ namespace lms::ui { - class Filters; - class PlayQueue; + class Filters; + class PlayQueue; - // Used to interact with the play queue, using the current exploration filters - class PlayQueueController - { - public: - PlayQueueController(Filters& filters, PlayQueue& playQueue); + // Used to interact with the play queue, using the current exploration filters + class PlayQueueController + { + public: + PlayQueueController(Filters& filters, PlayQueue& playQueue); - enum class Command - { - Play, - PlayNext, - PlayOrAddLast, - PlayShuffled, - }; + enum class Command + { + Play, + PlayNext, + PlayOrAddLast, + PlayShuffled, + }; - void processCommand(Command command, const std::vector& artists); - void processCommand(Command command, const std::vector& releases); - void processCommand(Command command, const std::vector& tracks); + void processCommand(Command command, const std::vector& artists); + void processCommand(Command command, const std::vector& releases); + void processCommand(Command command, const std::vector& tracks); - struct Disc - { - db::ReleaseId releaseId; - size_t discNumber; - }; - void processCommand(Command command, const std::vector& discs); - void processCommand(Command command, db::TrackListId trackList); - void playTrackInRelease(db::TrackId track); + struct Disc + { + db::ReleaseId releaseId; + size_t discNumber; + }; + void processCommand(Command command, const std::vector& discs); + void processCommand(Command command, db::TrackListId trackList); + void playTrackInRelease(db::TrackId track); - void setMaxTrackCountToEnqueue(std::size_t maxTrackCount) { _maxTrackCountToEnqueue = maxTrackCount; } - - private: - Filters& _filters; - PlayQueue& _playQueue; - std::size_t _maxTrackCountToEnqueue {}; - }; -} + void setMaxTrackCountToEnqueue(std::size_t maxTrackCount) { _maxTrackCountToEnqueue = maxTrackCount; } + private: + Filters& _filters; + PlayQueue& _playQueue; + std::size_t _maxTrackCountToEnqueue{}; + }; +} // namespace lms::ui diff --git a/src/lms/ui/explore/ReleaseCollector.cpp b/src/lms/ui/explore/ReleaseCollector.cpp index b166b9e5..8d60907c 100644 --- a/src/lms/ui/explore/ReleaseCollector.cpp +++ b/src/lms/ui/explore/ReleaseCollector.cpp @@ -19,12 +19,13 @@ #include "ReleaseCollector.hpp" +#include "core/Service.hpp" #include "database/Release.hpp" #include "database/Session.hpp" #include "database/User.hpp" #include "services/feedback/IFeedbackService.hpp" #include "services/scrobbling/IScrobblingService.hpp" -#include "core/Service.hpp" + #include "Filters.hpp" #include "LmsApplication.hpp" @@ -48,74 +49,74 @@ namespace lms::ui break; case Mode::Starred: - { - feedback::IFeedbackService::FindParameters params; - params.setUser(LmsApp->getUserId()); - params.setClusters(getFilters().getClusters()); - params.setMediaLibrary(getFilters().getMediaLibrary()); - params.setKeywords(getSearchKeywords()); - params.setRange(range); - releases = feedbackService.findStarredReleases(params); - break; - } + { + feedback::IFeedbackService::FindParameters params; + params.setUser(LmsApp->getUserId()); + params.setClusters(getFilters().getClusters()); + params.setMediaLibrary(getFilters().getMediaLibrary()); + params.setKeywords(getSearchKeywords()); + params.setRange(range); + releases = feedbackService.findStarredReleases(params); + break; + } case ReleaseCollector::Mode::RecentlyPlayed: - { - scrobbling::IScrobblingService::FindParameters params; - params.setUser(LmsApp->getUserId()); - params.setClusters(getFilters().getClusters()); - params.setMediaLibrary(getFilters().getMediaLibrary()); - params.setKeywords(getSearchKeywords()); - params.setRange(range); + { + scrobbling::IScrobblingService::FindParameters params; + params.setUser(LmsApp->getUserId()); + params.setClusters(getFilters().getClusters()); + params.setMediaLibrary(getFilters().getMediaLibrary()); + params.setKeywords(getSearchKeywords()); + params.setRange(range); - releases = scrobblingService.getRecentReleases(params); - break; - } + releases = scrobblingService.getRecentReleases(params); + break; + } case Mode::MostPlayed: - { - scrobbling::IScrobblingService::FindParameters params; - params.setUser(LmsApp->getUserId()); - params.setClusters(getFilters().getClusters()); - params.setMediaLibrary(getFilters().getMediaLibrary()); - params.setKeywords(getSearchKeywords()); - params.setRange(range); + { + scrobbling::IScrobblingService::FindParameters params; + params.setUser(LmsApp->getUserId()); + params.setClusters(getFilters().getClusters()); + params.setMediaLibrary(getFilters().getMediaLibrary()); + params.setKeywords(getSearchKeywords()); + params.setRange(range); - releases = scrobblingService.getTopReleases(params); - break; - } + releases = scrobblingService.getTopReleases(params); + break; + } case Mode::RecentlyAdded: - { - Release::FindParameters params; - params.setClusters(getFilters().getClusters()); - params.setMediaLibrary(getFilters().getMediaLibrary()); - params.setKeywords(getSearchKeywords()); - params.setSortMethod(ReleaseSortMethod::LastWritten); - params.setRange(range); - { - auto transaction{ LmsApp->getDbSession().createReadTransaction() }; - releases = Release::findIds(LmsApp->getDbSession(), params); + Release::FindParameters params; + params.setClusters(getFilters().getClusters()); + params.setMediaLibrary(getFilters().getMediaLibrary()); + params.setKeywords(getSearchKeywords()); + params.setSortMethod(ReleaseSortMethod::LastWritten); + params.setRange(range); + + { + auto transaction{ LmsApp->getDbSession().createReadTransaction() }; + releases = Release::findIds(LmsApp->getDbSession(), params); + } + break; } - break; - } case Mode::All: - { - Release::FindParameters params; - params.setClusters(getFilters().getClusters()); - params.setMediaLibrary(getFilters().getMediaLibrary()); - params.setSortMethod(ReleaseSortMethod::Name); - params.setKeywords(getSearchKeywords()); - params.setRange(range); - { - auto transaction{ LmsApp->getDbSession().createReadTransaction() }; - releases = Release::findIds(LmsApp->getDbSession(), params); + Release::FindParameters params; + params.setClusters(getFilters().getClusters()); + params.setMediaLibrary(getFilters().getMediaLibrary()); + params.setSortMethod(ReleaseSortMethod::Name); + params.setKeywords(getSearchKeywords()); + params.setRange(range); + + { + auto transaction{ LmsApp->getDbSession().createReadTransaction() }; + releases = Release::findIds(LmsApp->getDbSession(), params); + } + break; } - break; - } } if (range.offset + range.size == getMaxCount()) @@ -146,5 +147,4 @@ namespace lms::ui return _randomReleases->getSubRange(range); } -} // ns UserInterface - +} // namespace lms::ui diff --git a/src/lms/ui/explore/ReleaseCollector.hpp b/src/lms/ui/explore/ReleaseCollector.hpp index 999b2cc6..a4a54940 100644 --- a/src/lms/ui/explore/ReleaseCollector.hpp +++ b/src/lms/ui/explore/ReleaseCollector.hpp @@ -29,22 +29,21 @@ namespace lms::db { - class Release; + class Release; } namespace lms::ui { - class ReleaseCollector : public DatabaseCollectorBase - { - public: - using DatabaseCollectorBase::DatabaseCollectorBase; + class ReleaseCollector : public DatabaseCollectorBase + { + public: + using DatabaseCollectorBase::DatabaseCollectorBase; - db::RangeResults get(std::optional range = std::nullopt); - void reset() { _randomReleases.reset(); } - - private: - db::RangeResults getRandomReleases(Range range); - std::optional> _randomReleases; - }; -} // ns UserInterface + db::RangeResults get(std::optional range = std::nullopt); + void reset() { _randomReleases.reset(); } + private: + db::RangeResults getRandomReleases(Range range); + std::optional> _randomReleases; + }; +} // namespace lms::ui diff --git a/src/lms/ui/explore/ReleaseHelpers.cpp b/src/lms/ui/explore/ReleaseHelpers.cpp index 4586e120..675fea52 100644 --- a/src/lms/ui/explore/ReleaseHelpers.cpp +++ b/src/lms/ui/explore/ReleaseHelpers.cpp @@ -48,7 +48,7 @@ namespace lms::ui::releaseListHelpers anchor->setImage(std::move(cover)); } - auto artistAnchors{ utils::createArtistsAnchorsForRelease(release, artist ? artist->getId() : ArtistId{}, "link-secondary") }; + auto artistAnchors{ utils::createArtistsAnchorsForRelease(release, artist ? artist->getId() : ArtistId{}, "link-secondary") }; if (artistAnchors) { entry->setCondition("if-has-artist", true); @@ -67,7 +67,7 @@ namespace lms::ui::releaseListHelpers return entry; } - } + } // namespace std::unique_ptr createEntry(const Release::pointer& release, const Artist::pointer& artist, bool showYear) { @@ -83,7 +83,7 @@ namespace lms::ui::releaseListHelpers { return createEntry(release, artist, true); } -} // namespace lms::ui +} // namespace lms::ui::releaseListHelpers namespace lms::ui::releaseHelpers { @@ -95,11 +95,21 @@ namespace lms::ui::releaseHelpers { switch (*releaseType.primaryType) { - case PrimaryReleaseType::Album: res = Wt::WString::tr("Lms.Explore.Release.type-primary-album"); break; - case PrimaryReleaseType::Broadcast: res = Wt::WString::tr("Lms.Explore.Release.type-primary-broadcast"); break; - case PrimaryReleaseType::EP: res = Wt::WString::tr("Lms.Explore.Release.type-primary-ep"); break; - case PrimaryReleaseType::Single: res = Wt::WString::tr("Lms.Explore.Release.type-primary-single"); break; - case PrimaryReleaseType::Other: res = Wt::WString::tr("Lms.Explore.Release.type-primary-other"); break; + case PrimaryReleaseType::Album: + res = Wt::WString::tr("Lms.Explore.Release.type-primary-album"); + break; + case PrimaryReleaseType::Broadcast: + res = Wt::WString::tr("Lms.Explore.Release.type-primary-broadcast"); + break; + case PrimaryReleaseType::EP: + res = Wt::WString::tr("Lms.Explore.Release.type-primary-ep"); + break; + case PrimaryReleaseType::Single: + res = Wt::WString::tr("Lms.Explore.Release.type-primary-single"); + break; + case PrimaryReleaseType::Other: + res = Wt::WString::tr("Lms.Explore.Release.type-primary-other"); + break; } } @@ -110,18 +120,42 @@ namespace lms::ui::releaseHelpers switch (secondaryType) { - case SecondaryReleaseType::Compilation: res += Wt::WString::tr("Lms.Explore.Release.type-secondary-compilation"); break; - case SecondaryReleaseType::Spokenword: res += Wt::WString::tr("Lms.Explore.Release.type-secondary-spokenword"); break; - case SecondaryReleaseType::Soundtrack: res += Wt::WString::tr("Lms.Explore.Release.type-secondary-soundtrack"); break; - case SecondaryReleaseType::Interview: res += Wt::WString::tr("Lms.Explore.Release.type-secondary-interview"); break; - case SecondaryReleaseType::Audiobook: res += Wt::WString::tr("Lms.Explore.Release.type-secondary-audiobook"); break; - case SecondaryReleaseType::AudioDrama: res += Wt::WString::tr("Lms.Explore.Release.type-secondary-audiodrama"); break; - case SecondaryReleaseType::Live: res += Wt::WString::tr("Lms.Explore.Release.type-secondary-live"); break; - case SecondaryReleaseType::Remix: res += Wt::WString::tr("Lms.Explore.Release.type-secondary-remix"); break; - case SecondaryReleaseType::DJMix: res += Wt::WString::tr("Lms.Explore.Release.type-secondary-djmix"); break; - case SecondaryReleaseType::Mixtape_Street: res += Wt::WString::tr("Lms.Explore.Release.type-secondary-mixtape-street"); break; - case SecondaryReleaseType::Demo: res += Wt::WString::tr("Lms.Explore.Release.type-secondary-demo"); break; - case SecondaryReleaseType::FieldRecording: res += Wt::WString::tr("Lms.Explore.Release.type-secondary-field-recording"); break; + case SecondaryReleaseType::Compilation: + res += Wt::WString::tr("Lms.Explore.Release.type-secondary-compilation"); + break; + case SecondaryReleaseType::Spokenword: + res += Wt::WString::tr("Lms.Explore.Release.type-secondary-spokenword"); + break; + case SecondaryReleaseType::Soundtrack: + res += Wt::WString::tr("Lms.Explore.Release.type-secondary-soundtrack"); + break; + case SecondaryReleaseType::Interview: + res += Wt::WString::tr("Lms.Explore.Release.type-secondary-interview"); + break; + case SecondaryReleaseType::Audiobook: + res += Wt::WString::tr("Lms.Explore.Release.type-secondary-audiobook"); + break; + case SecondaryReleaseType::AudioDrama: + res += Wt::WString::tr("Lms.Explore.Release.type-secondary-audiodrama"); + break; + case SecondaryReleaseType::Live: + res += Wt::WString::tr("Lms.Explore.Release.type-secondary-live"); + break; + case SecondaryReleaseType::Remix: + res += Wt::WString::tr("Lms.Explore.Release.type-secondary-remix"); + break; + case SecondaryReleaseType::DJMix: + res += Wt::WString::tr("Lms.Explore.Release.type-secondary-djmix"); + break; + case SecondaryReleaseType::Mixtape_Street: + res += Wt::WString::tr("Lms.Explore.Release.type-secondary-mixtape-street"); + break; + case SecondaryReleaseType::Demo: + res += Wt::WString::tr("Lms.Explore.Release.type-secondary-demo"); + break; + case SecondaryReleaseType::FieldRecording: + res += Wt::WString::tr("Lms.Explore.Release.type-secondary-field-recording"); + break; } } diff --git a/src/lms/ui/explore/ReleaseHelpers.hpp b/src/lms/ui/explore/ReleaseHelpers.hpp index 86885620..547efa42 100644 --- a/src/lms/ui/explore/ReleaseHelpers.hpp +++ b/src/lms/ui/explore/ReleaseHelpers.hpp @@ -22,28 +22,30 @@ #include #include +#include #include #include -#include + +#include "core/EnumSet.hpp" #include "database/Object.hpp" #include "database/Types.hpp" -#include "core/EnumSet.hpp" + #include "ReleaseTypes.hpp" namespace lms::db { class Artist; class Release; -} +} // namespace lms::db namespace lms::ui::releaseListHelpers { std::unique_ptr createEntry(const db::ObjectPtr& release); std::unique_ptr createEntryForArtist(const db::ObjectPtr& release, const db::ObjectPtr& artist); -} // namespace lms::ui +} // namespace lms::ui::releaseListHelpers namespace lms::ui::releaseHelpers { Wt::WString buildReleaseTypeString(const ReleaseType& releaseType); Wt::WString buildReleaseYearString(std::optional year, std::optional originalYear); -} +} // namespace lms::ui::releaseHelpers diff --git a/src/lms/ui/explore/ReleaseTypes.cpp b/src/lms/ui/explore/ReleaseTypes.cpp index 65320c70..b844daac 100644 --- a/src/lms/ui/explore/ReleaseTypes.cpp +++ b/src/lms/ui/explore/ReleaseTypes.cpp @@ -28,13 +28,12 @@ namespace lms::core::stringUtils template<> std::optional readAs(std::string_view str) { - static const std::unordered_map entries - { - {"album", ui::PrimaryReleaseType::Album}, - {"single", ui::PrimaryReleaseType::Single}, - {"ep", ui::PrimaryReleaseType::EP}, - {"broadcast", ui::PrimaryReleaseType::Broadcast}, - {"other", ui::PrimaryReleaseType::Other}, + static const std::unordered_map entries{ + { "album", ui::PrimaryReleaseType::Album }, + { "single", ui::PrimaryReleaseType::Single }, + { "ep", ui::PrimaryReleaseType::EP }, + { "broadcast", ui::PrimaryReleaseType::Broadcast }, + { "other", ui::PrimaryReleaseType::Other }, }; const auto it{ entries.find(stringToLower(stringTrim(str))) }; @@ -47,20 +46,19 @@ namespace lms::core::stringUtils template<> std::optional readAs(std::string_view str) { - static const std::unordered_map entries - { - {"compilation", ui::SecondaryReleaseType::Compilation}, - {"soundtrack", ui::SecondaryReleaseType::Soundtrack}, - {"spokenword", ui::SecondaryReleaseType::Spokenword}, - {"interview", ui::SecondaryReleaseType::Interview}, - {"audiobook", ui::SecondaryReleaseType::Audiobook}, - {"audio drama", ui::SecondaryReleaseType::AudioDrama}, - {"live", ui::SecondaryReleaseType::Live}, - {"remix", ui::SecondaryReleaseType::Remix}, - {"dj-mix", ui::SecondaryReleaseType::DJMix}, - {"mixtape/street", ui::SecondaryReleaseType::Mixtape_Street}, - {"demo", ui::SecondaryReleaseType::Demo}, - {"field recording", ui::SecondaryReleaseType::FieldRecording}, + static const std::unordered_map entries{ + { "compilation", ui::SecondaryReleaseType::Compilation }, + { "soundtrack", ui::SecondaryReleaseType::Soundtrack }, + { "spokenword", ui::SecondaryReleaseType::Spokenword }, + { "interview", ui::SecondaryReleaseType::Interview }, + { "audiobook", ui::SecondaryReleaseType::Audiobook }, + { "audio drama", ui::SecondaryReleaseType::AudioDrama }, + { "live", ui::SecondaryReleaseType::Live }, + { "remix", ui::SecondaryReleaseType::Remix }, + { "dj-mix", ui::SecondaryReleaseType::DJMix }, + { "mixtape/street", ui::SecondaryReleaseType::Mixtape_Street }, + { "demo", ui::SecondaryReleaseType::Demo }, + { "field recording", ui::SecondaryReleaseType::FieldRecording }, }; const auto it{ entries.find(stringToLower(stringTrim(str))) }; @@ -69,7 +67,7 @@ namespace lms::core::stringUtils return it->second; } -} +} // namespace lms::core::stringUtils namespace lms::ui { @@ -104,7 +102,7 @@ namespace lms::ui else if (typeA && !typeB) return true; else - return static_cast(*typeA) < static_cast(*typeB); + return static_cast(*typeA) < static_cast(*typeB); } bool operator<(core::EnumSet typesA, core::EnumSet typesB) diff --git a/src/lms/ui/explore/ReleaseView.cpp b/src/lms/ui/explore/ReleaseView.cpp index 587b6d09..d58f2bfa 100644 --- a/src/lms/ui/explore/ReleaseView.cpp +++ b/src/lms/ui/explore/ReleaseView.cpp @@ -20,11 +20,13 @@ #include "ReleaseView.hpp" #include + #include #include #include #include "av/IAudioFile.hpp" +#include "core/ILogger.hpp" #include "database/Artist.hpp" #include "database/Cluster.hpp" #include "database/Release.hpp" @@ -34,21 +36,20 @@ #include "database/TrackArtistLink.hpp" #include "database/User.hpp" #include "services/feedback/IFeedbackService.hpp" -#include "services/scrobbling/IScrobblingService.hpp" #include "services/recommendation/IRecommendationService.hpp" -#include "core/ILogger.hpp" +#include "services/scrobbling/IScrobblingService.hpp" -#include "common/Template.hpp" -#include "resource/DownloadResource.hpp" -#include "explore/Filters.hpp" -#include "explore/PlayQueueController.hpp" -#include "explore/ReleaseHelpers.hpp" -#include "explore/TrackListHelpers.hpp" #include "LmsApplication.hpp" #include "LmsApplicationException.hpp" #include "MediaPlayer.hpp" #include "ModalManager.hpp" #include "Utils.hpp" +#include "common/Template.hpp" +#include "explore/Filters.hpp" +#include "explore/PlayQueueController.hpp" +#include "explore/ReleaseHelpers.hpp" +#include "explore/TrackListHelpers.hpp" +#include "resource/DownloadResource.hpp" namespace lms::ui { @@ -76,30 +77,27 @@ namespace lms::ui std::map> artistMap; - auto addArtists = [&](TrackArtistLinkType linkType, const char* type) - { - Artist::FindParameters params; - params.setRelease(releaseId); - params.setLinkType(linkType); - const auto artistIds{ Artist::findIds(LmsApp->getDbSession(), params) }; - if (artistIds.results.empty()) - return; + auto addArtists = [&](TrackArtistLinkType linkType, const char* type) { + Artist::FindParameters params; + params.setRelease(releaseId); + params.setLinkType(linkType); + const auto artistIds{ Artist::findIds(LmsApp->getDbSession(), params) }; + if (artistIds.results.empty()) + return; - Wt::WString typeStr{ Wt::WString::trn(type, artistIds.results.size()) }; - for (ArtistId artistId : artistIds.results) - artistMap[typeStr].insert(artistId); - }; + Wt::WString typeStr{ Wt::WString::trn(type, artistIds.results.size()) }; + for (ArtistId artistId : artistIds.results) + artistMap[typeStr].insert(artistId); + }; - auto addPerformerArtists = [&] - { - TrackArtistLink::FindParameters params; - params.setRelease(releaseId); - params.setLinkType(TrackArtistLinkType::Performer); - TrackArtistLink::find(LmsApp->getDbSession(), params, [&](const TrackArtistLink::pointer& link) - { - artistMap[std::string{ link->getSubType() }].insert(link->getArtist()->getId()); - }); - }; + auto addPerformerArtists = [&] { + TrackArtistLink::FindParameters params; + params.setRelease(releaseId); + params.setLinkType(TrackArtistLinkType::Performer); + TrackArtistLink::find(LmsApp->getDbSession(), params, [&](const TrackArtistLink::pointer& link) { + artistMap[std::string{ link->getSubType() }].insert(link->getArtist()->getId()); + }); + }; addArtists(TrackArtistLinkType::Composer, "Lms.Explore.Artists.linktype-composer"); addArtists(TrackArtistLinkType::Conductor, "Lms.Explore.Artists.linktype-conductor"); @@ -155,10 +153,9 @@ namespace lms::ui releaseInfo->bindInt("playcount", core::Service::get()->getCount(LmsApp->getUserId(), release->getId())); Wt::WPushButton* okBtn{ releaseInfo->bindNew("ok-btn", Wt::WString::tr("Lms.ok")) }; - okBtn->clicked().connect([=] - { - LmsApp->getModalManager().dispose(releaseInfoPtr); - }); + okBtn->clicked().connect([=] { + LmsApp->getModalManager().dispose(releaseInfoPtr); + }); LmsApp->getModalManager().show(std::move(releaseInfo)); } @@ -180,7 +177,7 @@ namespace lms::ui return core::stringUtils::readAs(wApp->internalPathNextPart("/release/")); } - } + } // namespace Release::Release(Filters& filters, PlayQueueController& playQueueController) : Template{ Wt::WString::tr("Lms.Explore.Release.template") } @@ -190,16 +187,14 @@ namespace lms::ui addFunction("tr", &Wt::WTemplate::Functions::tr); addFunction("id", &Wt::WTemplate::Functions::id); - wApp->internalPathChanged().connect(this, [this] - { - refreshView(); - }); + wApp->internalPathChanged().connect(this, [this] { + refreshView(); + }); - _filters.updated().connect([this] - { - _needForceRefresh = true; - refreshView(); - }); + _filters.updated().connect([this] { + _needForceRefresh = true; + refreshView(); + }); refreshView(); } @@ -263,64 +258,62 @@ namespace lms::ui { const ClusterId clusterId{ cluster->getId() }; Wt::WInteractWidget* entry{ clusterContainers->addWidget(utils::createFilterCluster(clusterId)) }; - entry->clicked().connect([this, clusterId] - { - _filters.add(clusterId); - }); + entry->clicked().connect([this, clusterId] { + _filters.add(clusterId); + }); } } } bindNew("play-btn", Wt::WString::tr("Lms.Explore.play"), Wt::TextFormat::XHTML) - ->clicked().connect([this] - { - _playQueueController.processCommand(PlayQueueController::Command::Play, { _releaseId }); - }); + ->clicked() + .connect([this] { + _playQueueController.processCommand(PlayQueueController::Command::Play, { _releaseId }); + }); bindNew("play-shuffled", Wt::WString::tr("Lms.Explore.play-shuffled"), Wt::TextFormat::Plain) - ->clicked().connect([this] - { - _playQueueController.processCommand(PlayQueueController::Command::PlayShuffled, { _releaseId }); - }); + ->clicked() + .connect([this] { + _playQueueController.processCommand(PlayQueueController::Command::PlayShuffled, { _releaseId }); + }); bindNew("play-next", Wt::WString::tr("Lms.Explore.play-next"), Wt::TextFormat::Plain) - ->clicked().connect([this] - { - _playQueueController.processCommand(PlayQueueController::Command::PlayNext, { _releaseId }); - }); + ->clicked() + .connect([this] { + _playQueueController.processCommand(PlayQueueController::Command::PlayNext, { _releaseId }); + }); bindNew("play-last", Wt::WString::tr("Lms.Explore.play-last"), Wt::TextFormat::Plain) - ->clicked().connect([this] - { - _playQueueController.processCommand(PlayQueueController::Command::PlayOrAddLast, { _releaseId }); - }); + ->clicked() + .connect([this] { + _playQueueController.processCommand(PlayQueueController::Command::PlayOrAddLast, { _releaseId }); + }); bindNew("download", Wt::WString::tr("Lms.Explore.download")) ->setLink(Wt::WLink{ std::make_unique(_releaseId) }); bindNew("release-info", Wt::WString::tr("Lms.Explore.release-info")) - ->clicked().connect([this] - { - showReleaseInfoModal(_releaseId); - }); + ->clicked() + .connect([this] { + showReleaseInfoModal(_releaseId); + }); { auto isStarred{ [this] { return core::Service::get()->isStarred(LmsApp->getUserId(), _releaseId); } }; Wt::WPushButton* starBtn{ bindNew("star", Wt::WString::tr(isStarred() ? "Lms.Explore.unstar" : "Lms.Explore.star")) }; - starBtn->clicked().connect([=, this] + starBtn->clicked().connect([=, this] { + if (isStarred()) { - if (isStarred()) - { - core::Service::get()->unstar(LmsApp->getUserId(), _releaseId); - starBtn->setText(Wt::WString::tr("Lms.Explore.star")); - } - else - { - core::Service::get()->star(LmsApp->getUserId(), _releaseId); - starBtn->setText(Wt::WString::tr("Lms.Explore.unstar")); - } - }); + core::Service::get()->unstar(LmsApp->getUserId(), _releaseId); + starBtn->setText(Wt::WString::tr("Lms.Explore.star")); + } + else + { + core::Service::get()->star(LmsApp->getUserId(), _releaseId); + starBtn->setText(Wt::WString::tr("Lms.Explore.unstar")); + } + }); } Wt::WContainerWidget* rootContainer{ bindNew("container") }; @@ -332,64 +325,61 @@ namespace lms::ui // Expect to be called in asc order std::map trackContainers; - auto getOrAddDiscContainer = [&, releaseId = _releaseId](std::size_t discNumber, const std::string& discSubtitle) -> Wt::WContainerWidget* - { - if (auto it{ trackContainers.find(discNumber) }; it != std::cend(trackContainers)) - return it->second; + auto getOrAddDiscContainer = [&, releaseId = _releaseId](std::size_t discNumber, const std::string& discSubtitle) -> Wt::WContainerWidget* { + if (auto it{ trackContainers.find(discNumber) }; it != std::cend(trackContainers)) + return it->second; - Template* disc{ rootContainer->addNew