From 5c67297dcef63bef4a52b506ebcc55d670f34867 Mon Sep 17 00:00:00 2001 From: Deluan Date: Mon, 10 Mar 2025 07:14:17 -0400 Subject: [PATCH 01/51] fix(server): panic when logging tag type. Fix #3790 Signed-off-by: Deluan --- model/tag_mappings.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/model/tag_mappings.go b/model/tag_mappings.go index 3215feb35..b0cf85fae 100644 --- a/model/tag_mappings.go +++ b/model/tag_mappings.go @@ -55,6 +55,7 @@ func (c TagConf) SplitTagValue(values []string) []string { type TagType string const ( + TagTypeString TagType = "string" TagTypeInteger TagType = "int" TagTypeFloat TagType = "float" TagTypeDate TagType = "date" @@ -113,8 +114,9 @@ func collectTags(tagMappings, normalized map[TagName]TagConf) { aliases = append(aliases, strings.ToLower(val)) } if v.Split != nil { - if v.Type != "" { - log.Error("Tag splitting only available for string types", "tag", k, "split", v.Split, "type", v.Type) + if v.Type != "" && v.Type != TagTypeString { + log.Error("Tag splitting only available for string types", "tag", k, "split", v.Split, + "type", string(v.Type)) v.Split = nil } else { v.SplitRx = compileSplitRegex(k, v.Split) From a28462a7abd2d4e26c4fc44ea51065ab8338922a Mon Sep 17 00:00:00 2001 From: Kendall Garner <17521368+kgarner7@users.noreply.github.com> Date: Mon, 10 Mar 2025 18:50:16 +0000 Subject: [PATCH 02/51] fix(ui): fix `make dev` (#3795) 1. For some bizarre reason, importing inflection by itself is undefined. But you can import specific functions 2. Per https://github.com/vite-pwa/vite-plugin-pwa/issues/419, `type: 'module',` is only for non-chromium browsers --- ui/src/album/AlbumInfo.jsx | 4 ++-- ui/src/album/AlbumList.jsx | 6 ++---- ui/src/common/QuickFilter.jsx | 6 +++--- ui/src/common/SongInfo.jsx | 4 ++-- ui/src/dialogs/AboutDialog.jsx | 4 ++-- ui/src/dialogs/HelpDialog.jsx | 4 ++-- ui/src/layout/Menu.jsx | 4 ++-- ui/vite.config.js | 1 - 8 files changed, 15 insertions(+), 18 deletions(-) diff --git a/ui/src/album/AlbumInfo.jsx b/ui/src/album/AlbumInfo.jsx index 6ddfda96f..d6d123895 100644 --- a/ui/src/album/AlbumInfo.jsx +++ b/ui/src/album/AlbumInfo.jsx @@ -1,6 +1,6 @@ import Table from '@material-ui/core/Table' import TableBody from '@material-ui/core/TableBody' -import inflection from 'inflection' +import { humanize, underscore } from 'inflection' import TableCell from '@material-ui/core/TableCell' import TableContainer from '@material-ui/core/TableContainer' import TableRow from '@material-ui/core/TableRow' @@ -112,7 +112,7 @@ const AlbumInfo = (props) => { className={classes.tableCell} > {translate(`resources.album.fields.${key}`, { - _: inflection.humanize(inflection.underscore(key)), + _: humanize(underscore(key)), })} : diff --git a/ui/src/album/AlbumList.jsx b/ui/src/album/AlbumList.jsx index 336c605ba..142457f12 100644 --- a/ui/src/album/AlbumList.jsx +++ b/ui/src/album/AlbumList.jsx @@ -31,7 +31,7 @@ import albumLists, { defaultAlbumList } from './albumLists' import config from '../config' import AlbumInfo from './AlbumInfo' import ExpandInfoDialog from '../dialogs/ExpandInfoDialog' -import inflection from 'inflection' +import { humanize } from 'inflection' import { makeStyles } from '@material-ui/core/styles' const useStyles = makeStyles({ @@ -140,9 +140,7 @@ const AlbumFilter = (props) => { - record?.tagValue - ? inflection.humanize(record?.tagValue) - : '-- None --' + record?.tagValue ? humanize(record?.tagValue) : '-- None --' } /> diff --git a/ui/src/common/QuickFilter.jsx b/ui/src/common/QuickFilter.jsx index 62263ffc5..79b09b333 100644 --- a/ui/src/common/QuickFilter.jsx +++ b/ui/src/common/QuickFilter.jsx @@ -1,7 +1,7 @@ import React from 'react' import { Chip, makeStyles } from '@material-ui/core' import { useTranslate } from 'react-admin' -import inflection from 'inflection' +import { humanize, underscore } from 'inflection' const useQuickFilterStyles = makeStyles((theme) => ({ chip: { @@ -16,11 +16,11 @@ export const QuickFilter = ({ source, resource, label, defaultValue }) => { if (typeof lbl === 'string' || lbl instanceof String) { if (label) { lbl = translate(lbl, { - _: inflection.humanize(inflection.underscore(lbl)), + _: humanize(underscore(lbl)), }) } else { lbl = translate(`resources.${resource}.fields.${source}`, { - _: inflection.humanize(inflection.underscore(source)), + _: humanize(underscore(source)), }) } } diff --git a/ui/src/common/SongInfo.jsx b/ui/src/common/SongInfo.jsx index bce0e750f..d94685633 100644 --- a/ui/src/common/SongInfo.jsx +++ b/ui/src/common/SongInfo.jsx @@ -13,7 +13,7 @@ import { useTranslate, useRecordContext, } from 'react-admin' -import inflection from 'inflection' +import { humanize, underscore } from 'inflection' import { ArtistLinkField, BitrateField, @@ -140,7 +140,7 @@ export const SongInfo = (props) => { {translate(`resources.song.fields.${key}`, { - _: inflection.humanize(inflection.underscore(key)), + _: humanize(underscore(key)), })} : diff --git a/ui/src/dialogs/AboutDialog.jsx b/ui/src/dialogs/AboutDialog.jsx index facc056e0..4f074002b 100644 --- a/ui/src/dialogs/AboutDialog.jsx +++ b/ui/src/dialogs/AboutDialog.jsx @@ -10,7 +10,7 @@ import TableRow from '@material-ui/core/TableRow' import TableCell from '@material-ui/core/TableCell' import Paper from '@material-ui/core/Paper' import FavoriteBorderIcon from '@material-ui/icons/FavoriteBorder' -import inflection from 'inflection' +import { humanize, underscore } from 'inflection' import { useGetOne, usePermissions, useTranslate } from 'react-admin' import config from '../config' import { DialogTitle } from './DialogTitle' @@ -136,7 +136,7 @@ const AboutDialog = ({ open, onClose }) => { {translate(`about.links.${key}`, { - _: inflection.humanize(inflection.underscore(key)), + _: humanize(underscore(key)), })} : diff --git a/ui/src/dialogs/HelpDialog.jsx b/ui/src/dialogs/HelpDialog.jsx index adbce99b2..1aa9db60e 100644 --- a/ui/src/dialogs/HelpDialog.jsx +++ b/ui/src/dialogs/HelpDialog.jsx @@ -9,7 +9,7 @@ import TableBody from '@material-ui/core/TableBody' import TableRow from '@material-ui/core/TableRow' import TableCell from '@material-ui/core/TableCell' import { useTranslate } from 'react-admin' -import inflection from 'inflection' +import { humanize } from 'inflection' import { keyMap } from '../hotkeys' import { DialogTitle } from './DialogTitle' import { DialogContent } from './DialogContent' @@ -29,7 +29,7 @@ const HelpTable = (props) => { {Object.keys(keyMap).map((key) => { const { sequences, name } = keyMap[key] const description = translate(`help.hotkeys.${name}`, { - _: inflection.humanize(name), + _: humanize(name), }) return ( diff --git a/ui/src/layout/Menu.jsx b/ui/src/layout/Menu.jsx index 2cb8a9824..bd1e37ee0 100644 --- a/ui/src/layout/Menu.jsx +++ b/ui/src/layout/Menu.jsx @@ -6,7 +6,7 @@ import { useTranslate, MenuItemLink, getResources } from 'react-admin' import ViewListIcon from '@material-ui/icons/ViewList' import AlbumIcon from '@material-ui/icons/Album' import SubMenu from './SubMenu' -import inflection from 'inflection' +import { humanize, pluralize } from 'inflection' import albumLists from '../album/albumLists' import PlaylistsSubMenu from './PlaylistsSubMenu' import config from '../config' @@ -42,7 +42,7 @@ const translatedResourceName = (resource, translate) => smart_count: 2, _: resource.options.label, }) - : inflection.humanize(inflection.pluralize(resource.name)), + : humanize(pluralize(resource.name)), }) const Menu = ({ dense = false }) => { diff --git a/ui/vite.config.js b/ui/vite.config.js index 590313ffc..dee9d3939 100644 --- a/ui/vite.config.js +++ b/ui/vite.config.js @@ -16,7 +16,6 @@ export default defineConfig({ filename: 'sw.js', devOptions: { enabled: true, - type: 'module', }, }), ], From 2a15a217deb49f6838bed6634f81c49e5a4f43da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Deluan=20Quint=C3=A3o?= Date: Tue, 11 Mar 2025 10:09:09 -0400 Subject: [PATCH 03/51] fix(server): db migration does not work for MusicFolders ending with a trailing slash. (#3797) * fix(server): db migration was not working for MusicFolders ending with a trailing slash. Signed-off-by: Deluan * fix(server): db migration for relative paths Signed-off-by: Deluan --------- Signed-off-by: Deluan --- db/migrations/20241026183640_support_new_scanner.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/db/migrations/20241026183640_support_new_scanner.go b/db/migrations/20241026183640_support_new_scanner.go index a9c48cc7d..bdf68c7cc 100644 --- a/db/migrations/20241026183640_support_new_scanner.go +++ b/db/migrations/20241026183640_support_new_scanner.go @@ -178,7 +178,7 @@ join library on media_file.library_id = library.id`, string(os.PathSeparator))) f := model.NewFolder(lib, path) _, err = stmt.ExecContext(ctx, f.ID, lib.ID, f.Path, f.Name, f.ParentID) if err != nil { - log.Error("Error writing folder to DB", "path", path, err) + log.Error("error writing folder to DB", "path", path, err) } } return err @@ -187,7 +187,12 @@ join library on media_file.library_id = library.id`, string(os.PathSeparator))) return fmt.Errorf("error populating folder table: %w", err) } - libPathLen := utf8.RuneCountInString(lib.Path) + // Count the number of characters in the library path + libPath := filepath.Clean(lib.Path) + libPathLen := utf8.RuneCountInString(libPath) + + // In one go, update all paths in the media_file table, removing the library path prefix + // and replacing any backslashes with slashes (the path separator used by the io/fs package) _, err = tx.ExecContext(ctx, fmt.Sprintf(` update media_file set path = replace(substr(path, %d), '\', '/');`, libPathLen+2)) if err != nil { From 70f536e04df0e7603a68ce1a9f7bb60c35873e4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Deluan=20Quint=C3=A3o?= Date: Tue, 11 Mar 2025 20:19:46 -0400 Subject: [PATCH 04/51] fix(ui): skip missing files in bulk operations (#3807) * fix(ui): skip missing files when adding to playqueue Signed-off-by: Deluan * fix(ui): skip missing files when adding to playlists * fix(ui): skip missing files when shuffling songs Signed-off-by: Deluan --------- Signed-off-by: Deluan --- ui/src/actions/player.js | 15 +++++++++++---- ui/src/album/AlbumActions.jsx | 5 +++-- ui/src/common/ContextMenus.jsx | 3 ++- ui/src/common/ShuffleAllButton.jsx | 1 + 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/ui/src/actions/player.js b/ui/src/actions/player.js index a9e2577f4..acef2e9b2 100644 --- a/ui/src/actions/player.js +++ b/ui/src/actions/player.js @@ -14,10 +14,17 @@ export const setTrack = (data) => ({ }) export const filterSongs = (data, ids) => { - if (!ids) { - return data - } - return ids.reduce((acc, id) => ({ ...acc, [id]: data[id] }), {}) + const filteredData = Object.fromEntries( + Object.entries(data).filter(([_, song]) => !song.missing), + ) + return !ids + ? filteredData + : ids.reduce((acc, id) => { + if (filteredData[id]) { + return { ...acc, [id]: filteredData[id] } + } + return acc + }, {}) } export const addTracks = (data, ids) => { diff --git a/ui/src/album/AlbumActions.jsx b/ui/src/album/AlbumActions.jsx index 65d6fe64c..96cfab09a 100644 --- a/ui/src/album/AlbumActions.jsx +++ b/ui/src/album/AlbumActions.jsx @@ -73,8 +73,9 @@ const AlbumActions = ({ }, [dispatch, data, ids]) const handleAddToPlaylist = React.useCallback(() => { - dispatch(openAddToPlaylist({ selectedIds: ids })) - }, [dispatch, ids]) + const selectedIds = ids.filter((id) => !data[id].missing) + dispatch(openAddToPlaylist({ selectedIds })) + }, [dispatch, data, ids]) const handleShare = React.useCallback(() => { dispatch(openShareMenu([record.id], 'album', record.name)) diff --git a/ui/src/common/ContextMenus.jsx b/ui/src/common/ContextMenus.jsx index 623b01a24..855825496 100644 --- a/ui/src/common/ContextMenus.jsx +++ b/ui/src/common/ContextMenus.jsx @@ -233,6 +233,7 @@ export const AlbumContextMenu = (props) => album_id: props.record.id, release_date: props.releaseDate, disc_number: props.discNumber, + missing: false, }, }} /> @@ -262,7 +263,7 @@ export const ArtistContextMenu = (props) => field: 'album', order: 'ASC', }, - filter: { album_artist_id: props.record.id }, + filter: { album_artist_id: props.record.id, missing: false }, }} /> ) : null diff --git a/ui/src/common/ShuffleAllButton.jsx b/ui/src/common/ShuffleAllButton.jsx index bc455b615..1631e2cf5 100644 --- a/ui/src/common/ShuffleAllButton.jsx +++ b/ui/src/common/ShuffleAllButton.jsx @@ -10,6 +10,7 @@ export const ShuffleAllButton = ({ filters }) => { const dataProvider = useDataProvider() const dispatch = useDispatch() const notify = useNotify() + filters = { ...filters, missing: false } const handleOnClick = () => { dataProvider From 0bb4b881e905a2ffa07aef1dbb7308a1ddae141d Mon Sep 17 00:00:00 2001 From: Rodrigo Iglesias <8595185+RigleGit@users.noreply.github.com> Date: Wed, 12 Mar 2025 01:42:09 +0100 Subject: [PATCH 05/51] =?UTF-8?q?fix(ui):=20update=20Espa=C3=B1ol=20transl?= =?UTF-8?q?ation=20(#3805)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Corrected "aletorio" and added some more translations --- resources/i18n/es.json | 68 +++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/resources/i18n/es.json b/resources/i18n/es.json index 83c7d4b1f..4c811b447 100644 --- a/resources/i18n/es.json +++ b/resources/i18n/es.json @@ -27,12 +27,12 @@ "playDate": "Últimas reproducciones", "channels": "Canales", "createdAt": "Creado el", - "grouping": "", + "grouping": "Agrupación", "mood": "", - "participants": "", - "tags": "", - "mappedTags": "", - "rawTags": "" + "participants": "Participantes", + "tags": "Etiquetas", + "mappedTags": "Etiquetas asignadas", + "rawTags": "Etiquetas sin procesar" }, "actions": { "addToQueue": "Reproducir después", @@ -65,10 +65,10 @@ "releaseDate": "Publicado", "releases": "Lanzamiento |||| Lanzamientos", "released": "Publicado", - "recordLabel": "", - "catalogNum": "", - "releaseType": "", - "grouping": "", + "recordLabel": "Discográfica", + "catalogNum": "Número de catálogo", + "releaseType": "Tipo de lanzamiento", + "grouping": "Agrupación", "media": "", "mood": "" }, @@ -76,7 +76,7 @@ "playAll": "Reproducir", "playNext": "Reproducir siguiente", "addToQueue": "Reproducir después", - "shuffle": "Aletorio", + "shuffle": "Aleatorio", "addToPlaylist": "Agregar a la lista", "download": "Descargar", "info": "Obtener información", @@ -102,22 +102,22 @@ "rating": "Calificación", "genre": "Género", "size": "Tamaño", - "role": "" + "role": "Rol" }, "roles": { - "albumartist": "", - "artist": "", - "composer": "", - "conductor": "", - "lyricist": "", - "arranger": "", - "producer": "", - "director": "", - "engineer": "", - "mixer": "", - "remixer": "", - "djmixer": "", - "performer": "" + "albumartist": "Artista del álbum", + "artist": "Artista", + "composer": "Compositor", + "conductor": "Director de orquesta", + "lyricist": "Letrista", + "arranger": "Arreglista", + "producer": "Productor", + "director": "Director", + "engineer": "Ingeniero de sonido", + "mixer": "Mezclador", + "remixer": "Remixer", + "djmixer": "DJ Mixer", + "performer": "Intérprete" } }, "user": { @@ -141,7 +141,7 @@ }, "notifications": { "created": "Usuario creado", - "updated": "Usuario actulalizado", + "updated": "Usuario actualizado", "deleted": "Usuario eliminado" }, "message": { @@ -228,17 +228,17 @@ } }, "missing": { - "name": "", + "name": "Faltante", "fields": { - "path": "", - "size": "", - "updatedAt": "" + "path": "Ruta", + "size": "Tamaño", + "updatedAt": "Actualizado el" }, "actions": { - "remove": "" + "remove": "Eliminar" }, "notifications": { - "removed": "" + "removed": "Eliminado" } } }, @@ -413,12 +413,12 @@ "downloadOriginalFormat": "Descargar formato original", "shareOriginalFormat": "Compartir formato original", "shareDialogTitle": "Compartir %{resource} '%{name}'", - "shareBatchDialogTitle": "Compartir 1 %{resource} |||| Share %{smart_count} %{resource}", + "shareBatchDialogTitle": "Compartir 1 %{resource} |||| Compartir %{smart_count} %{resource}", "shareSuccess": "URL copiada al portapapeles: %{url}", "shareFailure": "Error al copiar la URL %{url} al portapapeles", "downloadDialogTitle": "Descargar %{resource} '%{name}' (%{size})", "shareCopyToClipboard": "Copiar al portapapeles: Ctrl+C, Intro", - "remove_missing_title": "", + "remove_missing_title": "Eliminar elemento faltante", "remove_missing_content": "" }, "menu": { @@ -509,4 +509,4 @@ "current_song": "Canción actual" } } -} \ No newline at end of file +} From 7c1387807567519e588c398ec94d74b3041fa1af Mon Sep 17 00:00:00 2001 From: Deluan Date: Wed, 12 Mar 2025 17:34:39 -0400 Subject: [PATCH 06/51] fix(subsonic): getRandomSongs with `genre` filter fix https://github.com/dweymouth/supersonic/issues/577 Signed-off-by: Deluan --- persistence/mediafile_repository_test.go | 12 ------------ server/subsonic/filter/filters.go | 16 ++++++++++------ 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/persistence/mediafile_repository_test.go b/persistence/mediafile_repository_test.go index 3b64d89fe..41b48c0c6 100644 --- a/persistence/mediafile_repository_test.go +++ b/persistence/mediafile_repository_test.go @@ -4,7 +4,6 @@ import ( "context" "time" - "github.com/Masterminds/squirrel" "github.com/navidrome/navidrome/log" "github.com/navidrome/navidrome/model" "github.com/navidrome/navidrome/model/id" @@ -53,17 +52,6 @@ var _ = Describe("MediaRepository", func() { Expect(err).To(MatchError(model.ErrNotFound)) }) - XIt("filters by genre", func() { - Expect(mr.GetAll(model.QueryOptions{ - Sort: "genre.name asc, title asc", - Filters: squirrel.Eq{"genre.name": "Rock"}, - })).To(Equal(model.MediaFiles{ - songDayInALife, - songAntenna, - songComeTogether, - })) - }) - Context("Annotations", func() { It("increments play count when the tracks does not have annotations", func() { id := "incplay.firsttime" diff --git a/server/subsonic/filter/filters.go b/server/subsonic/filter/filters.go index 1cac0b674..8a333c8e2 100644 --- a/server/subsonic/filter/filters.go +++ b/server/subsonic/filter/filters.go @@ -95,7 +95,7 @@ func SongsByRandom(genre string, fromYear, toYear int) Options { } ff := And{} if genre != "" { - ff = append(ff, Eq{"genre.name": genre}) + ff = append(ff, filterByGenre(genre)) } if fromYear != 0 { ff = append(ff, GtOrEq{"year": fromYear}) @@ -118,11 +118,15 @@ func SongWithLyrics(artist, title string) Options { func ByGenre(genre string) Options { return addDefaultFilters(Options{ - Sort: "name asc", - Filters: persistence.Exists("json_tree(tags)", And{ - Like{"value": genre}, - NotEq{"atom": nil}, - }), + Sort: "name asc", + Filters: filterByGenre(genre), + }) +} + +func filterByGenre(genre string) Sqlizer { + return persistence.Exists("json_tree(tags)", And{ + Like{"value": genre}, + NotEq{"atom": nil}, }) } From 226be78bf538b2bd025d4ad5b683d6368683c695 Mon Sep 17 00:00:00 2001 From: Deluan Date: Wed, 12 Mar 2025 17:51:36 -0400 Subject: [PATCH 07/51] fix(scanner): full_text not being updated on scan Fixes #3813 Signed-off-by: Deluan --- scanner/phase_1_folders.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scanner/phase_1_folders.go b/scanner/phase_1_folders.go index 2894878d1..ca7851f17 100644 --- a/scanner/phase_1_folders.go +++ b/scanner/phase_1_folders.go @@ -334,7 +334,8 @@ func (p *phaseFolders) persistChanges(entry *folderEntry) (*folderEntry, error) // Save all new/modified artists to DB. Their information will be incomplete, but they will be refreshed later for i := range entry.artists { - err = artistRepo.Put(&entry.artists[i], "name", "mbz_artist_id", "sort_artist_name", "order_artist_name") + err = artistRepo.Put(&entry.artists[i], "name", + "mbz_artist_id", "sort_artist_name", "order_artist_name", "full_text") if err != nil { log.Error(p.ctx, "Scanner: Error persisting artist to DB", "folder", entry.path, "artist", entry.artists[i].Name, err) return err From 5fb1db60314ee800cb6ead9a9f7100da3c206661 Mon Sep 17 00:00:00 2001 From: Deluan Date: Wed, 12 Mar 2025 18:13:22 -0400 Subject: [PATCH 08/51] fix(scanner): watcher not working with relative MusicFolder Signed-off-by: Deluan --- scanner/watcher.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/scanner/watcher.go b/scanner/watcher.go index 3090966a7..bf4f7f9d0 100644 --- a/scanner/watcher.go +++ b/scanner/watcher.go @@ -101,22 +101,27 @@ func watchLib(ctx context.Context, lib model.Library, watchChan chan struct{}) { log.Error(ctx, "Watcher: Error watching library", "library", lib.ID, "path", lib.Path, err) return } - log.Info(ctx, "Watcher started", "library", lib.ID, "path", lib.Path) + absLibPath, err := filepath.Abs(lib.Path) + if err != nil { + log.Error(ctx, "Watcher: Error converting lib.Path to absolute", "library", lib.ID, "path", lib.Path, err) + return + } + log.Info(ctx, "Watcher started", "library", lib.ID, "libPath", lib.Path, "absoluteLibPath", absLibPath) for { select { case <-ctx.Done(): return case path := <-c: - path, err = filepath.Rel(lib.Path, path) + path, err = filepath.Rel(absLibPath, path) if err != nil { - log.Error(ctx, "Watcher: Error getting relative path", "library", lib.ID, "path", path, err) + log.Error(ctx, "Watcher: Error getting relative path", "library", lib.ID, "libPath", absLibPath, "path", path, err) continue } if isIgnoredPath(ctx, fsys, path) { log.Trace(ctx, "Watcher: Ignoring change", "library", lib.ID, "path", path) continue } - log.Trace(ctx, "Watcher: Detected change", "library", lib.ID, "path", path) + log.Trace(ctx, "Watcher: Detected change", "library", lib.ID, "path", path, "libPath", absLibPath) watchChan <- struct{}{} } } From 5c0b6fb9b7363582e351f90e594ef5e17f5e50d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Deluan=20Quint=C3=A3o?= Date: Thu, 13 Mar 2025 07:10:45 -0400 Subject: [PATCH 09/51] fix(server): skip non-UTF encoding during the database migration. (#3803) Fix #3787 Signed-off-by: Deluan --- .../20241026183640_support_new_scanner.go | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/db/migrations/20241026183640_support_new_scanner.go b/db/migrations/20241026183640_support_new_scanner.go index bdf68c7cc..3e7c47f54 100644 --- a/db/migrations/20241026183640_support_new_scanner.go +++ b/db/migrations/20241026183640_support_new_scanner.go @@ -172,14 +172,20 @@ join library on media_file.library_id = library.id`, string(os.PathSeparator))) // Finally, walk the in-mem filesystem and insert all folders into the DB. err = fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error { if err != nil { - return err + // Don't abort the walk, just log the error + log.Error("error walking folder to DB", "path", path, err) + return nil } - if d.IsDir() { - f := model.NewFolder(lib, path) - _, err = stmt.ExecContext(ctx, f.ID, lib.ID, f.Path, f.Name, f.ParentID) - if err != nil { - log.Error("error writing folder to DB", "path", path, err) - } + // Skip entries that are not directories + if !d.IsDir() { + return nil + } + + // Create a folder in the DB + f := model.NewFolder(lib, path) + _, err = stmt.ExecContext(ctx, f.ID, lib.ID, f.Path, f.Name, f.ParentID) + if err != nil { + log.Error("error writing folder to DB", "path", path, err) } return err }) From b952672877be6f927a0c0a44b84b3415e243fd13 Mon Sep 17 00:00:00 2001 From: Deluan Date: Thu, 13 Mar 2025 19:25:07 -0400 Subject: [PATCH 10/51] fix(scanner): add back the Scanner.GenreSeparators as a deprecated option This allows easy upgrade of containers in PikaPods Signed-off-by: Deluan --- conf/configuration.go | 7 +++++-- model/tag_mappings.go | 9 +++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/conf/configuration.go b/conf/configuration.go index 2636fbf94..b4e38add2 100644 --- a/conf/configuration.go +++ b/conf/configuration.go @@ -128,7 +128,8 @@ type scannerOptions struct { WatcherWait time.Duration ScanOnStartup bool Extractor string - GroupAlbumReleases bool // Deprecated: BFR Update docs + GenreSeparators string // Deprecated: Use Tags.genre.Split instead + GroupAlbumReleases bool // Deprecated: Use PID.Album instead } type subsonicOptions struct { @@ -307,6 +308,7 @@ func Load(noConfigDump bool) { log.Warn(fmt.Sprintf("Extractor '%s' is not implemented, using 'taglib'", Server.Scanner.Extractor)) Server.Scanner.Extractor = consts.DefaultScannerExtractor } + logDeprecatedOptions("Scanner.GenreSeparators") logDeprecatedOptions("Scanner.GroupAlbumReleases") // Call init hooks @@ -489,9 +491,10 @@ func init() { viper.SetDefault("scanner.enabled", true) viper.SetDefault("scanner.schedule", "0") viper.SetDefault("scanner.extractor", consts.DefaultScannerExtractor) - viper.SetDefault("scanner.groupalbumreleases", false) viper.SetDefault("scanner.watcherwait", consts.DefaultWatcherWait) viper.SetDefault("scanner.scanonstartup", true) + viper.SetDefault("scanner.genreseparators", "") + viper.SetDefault("scanner.groupalbumreleases", false) viper.SetDefault("subsonic.appendsubtitle", true) viper.SetDefault("subsonic.artistparticipations", false) diff --git a/model/tag_mappings.go b/model/tag_mappings.go index b0cf85fae..14edd3b0e 100644 --- a/model/tag_mappings.go +++ b/model/tag_mappings.go @@ -175,6 +175,15 @@ func loadTagMappings() { log.Error("No tag mappings found in mappings.yaml, check the format") } + // Use Scanner.GenreSeparators if specified and Tags.genre is not defined + if conf.Server.Scanner.GenreSeparators != "" && len(conf.Server.Tags["genre"].Aliases) == 0 { + genreConf := _mappings.Main[TagName("genre")] + genreConf.Split = strings.Split(conf.Server.Scanner.GenreSeparators, "") + genreConf.SplitRx = compileSplitRegex("genre", genreConf.Split) + _mappings.Main[TagName("genre")] = genreConf + log.Debug("Loading deprecated list of genre separators", "separators", genreConf.Split) + } + // Overwrite the default mappings with the ones from the config for tag, cfg := range conf.Server.Tags { if len(cfg.Aliases) == 0 { From 2838ac36df72fefbe796e0fa88316ea6d7f106f9 Mon Sep 17 00:00:00 2001 From: Deluan Date: Thu, 13 Mar 2025 19:47:34 -0400 Subject: [PATCH 11/51] feat(scanner): allow disabling tags with `Tags..Ignore=true` Signed-off-by: Deluan --- conf/configuration.go | 1 + model/tag_mappings.go | 29 +++++++++++++++++++++-------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/conf/configuration.go b/conf/configuration.go index b4e38add2..e1e6b2f67 100644 --- a/conf/configuration.go +++ b/conf/configuration.go @@ -140,6 +140,7 @@ type subsonicOptions struct { } type TagConf struct { + Ignore bool `yaml:"ignore"` Aliases []string `yaml:"aliases"` Type string `yaml:"type"` MaxLength int `yaml:"maxLength"` diff --git a/model/tag_mappings.go b/model/tag_mappings.go index 14edd3b0e..d8caa0c5d 100644 --- a/model/tag_mappings.go +++ b/model/tag_mappings.go @@ -1,6 +1,7 @@ package model import ( + "cmp" "maps" "regexp" "slices" @@ -186,19 +187,31 @@ func loadTagMappings() { // Overwrite the default mappings with the ones from the config for tag, cfg := range conf.Server.Tags { - if len(cfg.Aliases) == 0 { + if cfg.Ignore { delete(_mappings.Main, TagName(tag)) delete(_mappings.Additional, TagName(tag)) continue } - c := TagConf{ - Aliases: cfg.Aliases, - Type: TagType(cfg.Type), - MaxLength: cfg.MaxLength, - Split: cfg.Split, - Album: cfg.Album, - SplitRx: compileSplitRegex(TagName(tag), cfg.Split), + oldValue, ok := _mappings.Main[TagName(tag)] + if !ok { + oldValue = _mappings.Additional[TagName(tag)] } + aliases := cfg.Aliases + if len(aliases) == 0 { + aliases = oldValue.Aliases + } + split := cfg.Split + if len(split) == 0 { + split = oldValue.Split + } + c := TagConf{ + Aliases: aliases, + Split: split, + Type: cmp.Or(TagType(cfg.Type), oldValue.Type), + MaxLength: cmp.Or(cfg.MaxLength, oldValue.MaxLength), + Album: cmp.Or(cfg.Album, oldValue.Album), + } + c.SplitRx = compileSplitRegex(TagName(tag), c.Split) if _, ok := _mappings.Main[TagName(tag)]; ok { _mappings.Main[TagName(tag)] = c } else { From 938c3d44ccb96c2f0f1751d2b07f8ae29c4f061c Mon Sep 17 00:00:00 2001 From: Kendall Garner <17521368+kgarner7@users.noreply.github.com> Date: Fri, 14 Mar 2025 11:01:07 +0000 Subject: [PATCH 12/51] fix(scanner): restore setsubtitle as discsubtitle for non-WMA (#3821) With old metadata, Disc Subtitle was one of `tsst`, `discsubtitle`, or `setsubtitle`. With the updated, `setsubtitle` is only available for flac. Update `mappings.yaml` to maintain prior behavior. --- resources/mappings.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/mappings.yaml b/resources/mappings.yaml index a42ceab47..45810e140 100644 --- a/resources/mappings.yaml +++ b/resources/mappings.yaml @@ -96,7 +96,7 @@ main: aliases: [ disctotal, totaldiscs ] album: true discsubtitle: - aliases: [ tsst, discsubtitle, ----:com.apple.itunes:discsubtitle, wm/setsubtitle ] + aliases: [ tsst, discsubtitle, ----:com.apple.itunes:discsubtitle, setsubtitle, wm/setsubtitle ] bpm: aliases: [ tbpm, bpm, tmpo, wm/beatsperminute ] lyrics: From 422ba2284e4baa45ed939505b12fcd378e6e339a Mon Sep 17 00:00:00 2001 From: Deluan Date: Fri, 14 Mar 2025 17:44:00 -0400 Subject: [PATCH 13/51] chore(scanner): add logs to .ndignore processing Signed-off-by: Deluan --- scanner/walk_dir_tree.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/scanner/walk_dir_tree.go b/scanner/walk_dir_tree.go index 1b7bb36f1..323ba0392 100644 --- a/scanner/walk_dir_tree.go +++ b/scanner/walk_dir_tree.go @@ -145,7 +145,10 @@ func loadIgnoredPatterns(ctx context.Context, fsys fs.FS, currentFolder string, } // If the .ndignore file is empty, mimic the current behavior and ignore everything if len(newPatterns) == 0 { + log.Trace(ctx, "Scanner: .ndignore file is empty, ignoring everything", "path", currentFolder) newPatterns = []string{"**/*"} + } else { + log.Trace(ctx, "Scanner: .ndignore file found ", "path", ignoreFilePath, "patterns", newPatterns) } } // Combine the patterns from the .ndignore file with the ones passed as argument @@ -180,7 +183,7 @@ func loadDir(ctx context.Context, job *scanJob, dirPath string, ignorePatterns [ children = make([]string, 0, len(entries)) for _, entry := range entries { entryPath := path.Join(dirPath, entry.Name()) - if len(ignorePatterns) > 0 && isScanIgnored(ignoreMatcher, entryPath) { + if len(ignorePatterns) > 0 && isScanIgnored(ctx, ignoreMatcher, entryPath) { log.Trace(ctx, "Scanner: Ignoring entry", "path", entryPath) continue } @@ -309,6 +312,10 @@ func isEntryIgnored(name string) bool { return strings.HasPrefix(name, ".") && !strings.HasPrefix(name, "..") } -func isScanIgnored(matcher *ignore.GitIgnore, entryPath string) bool { - return matcher.MatchesPath(entryPath) +func isScanIgnored(ctx context.Context, matcher *ignore.GitIgnore, entryPath string) bool { + matches := matcher.MatchesPath(entryPath) + if matches { + log.Trace(ctx, "Scanner: Ignoring entry matching .ndignore: ", "path", entryPath) + } + return matches } From 98808e4b6dd7c2f6af82cf1dbeeb847f67c47538 Mon Sep 17 00:00:00 2001 From: Deluan Date: Fri, 14 Mar 2025 19:32:26 -0400 Subject: [PATCH 14/51] docs(scanner): clarifies the purpose of the mappings.yaml file for regular users Signed-off-by: Deluan --- resources/mappings.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/resources/mappings.yaml b/resources/mappings.yaml index 45810e140..f4de96a74 100644 --- a/resources/mappings.yaml +++ b/resources/mappings.yaml @@ -1,6 +1,14 @@ #file: noinspection SpellCheckingInspection # Tag mapping adapted from https://picard-docs.musicbrainz.org/downloads/MusicBrainz_Picard_Tag_Map.html # +# NOTE FOR USERS: +# +# This file can be used as a reference to understand how Navidrome maps the tags in your music files to its fields. +# If you want to customize these mappings, please refer to https://www.navidrome.org/docs/usage/customtags/ +# +# +# NOTE FOR DEVELOPERS: +# # This file contains the mapping between the tags in your music files and the fields in Navidrome. # You can add new tags, change the aliases, or add new split characters to the existing tags. # The artists and roles keys are used to define how to split the tag values into multiple values. From ed1109ddb232184d69e655b72a2a44f9c1033e5b Mon Sep 17 00:00:00 2001 From: Kendall Garner <17521368+kgarner7@users.noreply.github.com> Date: Sat, 15 Mar 2025 01:21:03 +0000 Subject: [PATCH 15/51] fix(subsonic): fix albumCount in artists (#3827) * only do subsonic instead * make sure to actually populate response first * navidrome artist filtering * address discord feedback * perPage min 36 * various artist artist_id -> albumartist_id * artist_id, role_id separate * remove all ui changes I guess * Revert role filters Signed-off-by: Deluan --------- Signed-off-by: Deluan Co-authored-by: Deluan --- server/subsonic/browsing.go | 50 +++++++++++-------- server/subsonic/helpers.go | 19 ++++++- server/subsonic/helpers_test.go | 29 +++++++++++ ...onses Indexes with data should match .JSON | 1 - ...ponses Indexes with data should match .XML | 2 +- server/subsonic/responses/responses.go | 3 +- server/subsonic/responses/responses_test.go | 1 - server/subsonic/searching.go | 1 - 8 files changed, 78 insertions(+), 28 deletions(-) diff --git a/server/subsonic/browsing.go b/server/subsonic/browsing.go index df4083aef..82bf50dc5 100644 --- a/server/subsonic/browsing.go +++ b/server/subsonic/browsing.go @@ -270,30 +270,43 @@ func (api *Router) GetGenres(r *http.Request) (*responses.Subsonic, error) { return response, nil } -func (api *Router) GetArtistInfo(r *http.Request) (*responses.Subsonic, error) { +func (api *Router) getArtistInfo(r *http.Request) (*responses.ArtistInfoBase, *model.Artists, error) { ctx := r.Context() p := req.Params(r) id, err := p.String("id") if err != nil { - return nil, err + return nil, nil, err } count := p.IntOr("count", 20) includeNotPresent := p.BoolOr("includeNotPresent", false) artist, err := api.externalMetadata.UpdateArtistInfo(ctx, id, count, includeNotPresent) + if err != nil { + return nil, nil, err + } + + base := responses.ArtistInfoBase{} + base.Biography = artist.Biography + base.SmallImageUrl = public.ImageURL(r, artist.CoverArtID(), 300) + base.MediumImageUrl = public.ImageURL(r, artist.CoverArtID(), 600) + base.LargeImageUrl = public.ImageURL(r, artist.CoverArtID(), 1200) + base.LastFmUrl = artist.ExternalUrl + base.MusicBrainzID = artist.MbzArtistID + + return &base, &artist.SimilarArtists, nil +} + +func (api *Router) GetArtistInfo(r *http.Request) (*responses.Subsonic, error) { + base, similarArtists, err := api.getArtistInfo(r) if err != nil { return nil, err } response := newResponse() response.ArtistInfo = &responses.ArtistInfo{} - response.ArtistInfo.Biography = artist.Biography - response.ArtistInfo.SmallImageUrl = public.ImageURL(r, artist.CoverArtID(), 300) - response.ArtistInfo.MediumImageUrl = public.ImageURL(r, artist.CoverArtID(), 600) - response.ArtistInfo.LargeImageUrl = public.ImageURL(r, artist.CoverArtID(), 1200) - response.ArtistInfo.LastFmUrl = artist.ExternalUrl - response.ArtistInfo.MusicBrainzID = artist.MbzArtistID - for _, s := range artist.SimilarArtists { + response.ArtistInfo.ArtistInfoBase = *base + + for _, s := range *similarArtists { similar := toArtist(r, s) if s.ID == "" { similar.Id = "-1" @@ -304,23 +317,20 @@ func (api *Router) GetArtistInfo(r *http.Request) (*responses.Subsonic, error) { } func (api *Router) GetArtistInfo2(r *http.Request) (*responses.Subsonic, error) { - info, err := api.GetArtistInfo(r) + base, similarArtists, err := api.getArtistInfo(r) if err != nil { return nil, err } response := newResponse() response.ArtistInfo2 = &responses.ArtistInfo2{} - response.ArtistInfo2.ArtistInfoBase = info.ArtistInfo.ArtistInfoBase - for _, s := range info.ArtistInfo.SimilarArtist { - similar := responses.ArtistID3{} - similar.Id = s.Id - similar.Name = s.Name - similar.AlbumCount = s.AlbumCount - similar.Starred = s.Starred - similar.UserRating = s.UserRating - similar.CoverArt = s.CoverArt - similar.ArtistImageUrl = s.ArtistImageUrl + response.ArtistInfo2.ArtistInfoBase = *base + + for _, s := range *similarArtists { + similar := toArtistID3(r, s) + if s.ID == "" { + similar.Id = "-1" + } response.ArtistInfo2.SimilarArtist = append(response.ArtistInfo2.SimilarArtist, similar) } return response, nil diff --git a/server/subsonic/helpers.go b/server/subsonic/helpers.go index 880bb6ddf..0fb35a7b7 100644 --- a/server/subsonic/helpers.go +++ b/server/subsonic/helpers.go @@ -77,11 +77,26 @@ func sortName(sortName, orderName string) string { return orderName } +func getArtistAlbumCount(a model.Artist) int32 { + albumStats := a.Stats[model.RoleAlbumArtist] + + // If ArtistParticipations are set, then `getArtist` will return albums + // where the artist is an album artist OR artist. While it may be an underestimate, + // guess the count by taking a max of the album artist and artist count. This is + // guaranteed to be <= the actual count. + // Otherwise, return just the roles as album artist (precise) + if conf.Server.Subsonic.ArtistParticipations { + artistStats := a.Stats[model.RoleArtist] + return int32(max(artistStats.AlbumCount, albumStats.AlbumCount)) + } else { + return int32(albumStats.AlbumCount) + } +} + func toArtist(r *http.Request, a model.Artist) responses.Artist { artist := responses.Artist{ Id: a.ID, Name: a.Name, - AlbumCount: int32(a.AlbumCount), UserRating: int32(a.Rating), CoverArt: a.CoverArtID().String(), ArtistImageUrl: public.ImageURL(r, a.CoverArtID(), 600), @@ -96,7 +111,7 @@ func toArtistID3(r *http.Request, a model.Artist) responses.ArtistID3 { artist := responses.ArtistID3{ Id: a.ID, Name: a.Name, - AlbumCount: int32(a.AlbumCount), + AlbumCount: getArtistAlbumCount(a), CoverArt: a.CoverArtID().String(), ArtistImageUrl: public.ImageURL(r, a.CoverArtID(), 600), UserRating: int32(a.Rating), diff --git a/server/subsonic/helpers_test.go b/server/subsonic/helpers_test.go index dd8bd88b1..d703607ba 100644 --- a/server/subsonic/helpers_test.go +++ b/server/subsonic/helpers_test.go @@ -10,6 +10,10 @@ import ( ) var _ = Describe("helpers", func() { + BeforeEach(func() { + DeferCleanup(configtest.SetupConfig()) + }) + Describe("fakePath", func() { var mf model.MediaFile BeforeEach(func() { @@ -134,4 +138,29 @@ var _ = Describe("helpers", func() { Entry("returns \"explicit\" when the db value is \"e\"", "e", "explicit"), Entry("returns an empty string when the db value is \"\"", "", ""), Entry("returns an empty string when there are unexpected values on the db", "abc", "")) + + Describe("getArtistAlbumCount", func() { + artist := model.Artist{ + Stats: map[model.Role]model.ArtistStats{ + model.RoleAlbumArtist: { + AlbumCount: 3, + }, + model.RoleArtist: { + AlbumCount: 4, + }, + }, + } + + It("Handles album count without artist participations", func() { + conf.Server.Subsonic.ArtistParticipations = false + result := getArtistAlbumCount(artist) + Expect(result).To(Equal(int32(3))) + }) + + It("Handles album count without with participations", func() { + conf.Server.Subsonic.ArtistParticipations = true + result := getArtistAlbumCount(artist) + Expect(result).To(Equal(int32(4))) + }) + }) }) diff --git a/server/subsonic/responses/.snapshots/Responses Indexes with data should match .JSON b/server/subsonic/responses/.snapshots/Responses Indexes with data should match .JSON index 585815fba..9f835da1a 100644 --- a/server/subsonic/responses/.snapshots/Responses Indexes with data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses Indexes with data should match .JSON @@ -12,7 +12,6 @@ { "id": "111", "name": "aaa", - "albumCount": 2, "starred": "2016-03-02T20:30:00Z", "userRating": 3, "artistImageUrl": "https://lastfm.freetls.fastly.net/i/u/300x300/2a96cbd8b46e442fc41c2b86b821562f.png" diff --git a/server/subsonic/responses/.snapshots/Responses Indexes with data should match .XML b/server/subsonic/responses/.snapshots/Responses Indexes with data should match .XML index 86495a75f..595f2ff03 100644 --- a/server/subsonic/responses/.snapshots/Responses Indexes with data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses Indexes with data should match .XML @@ -1,7 +1,7 @@ - + diff --git a/server/subsonic/responses/responses.go b/server/subsonic/responses/responses.go index f329fae4b..c0f499ef2 100644 --- a/server/subsonic/responses/responses.go +++ b/server/subsonic/responses/responses.go @@ -92,7 +92,6 @@ type MusicFolders struct { type Artist struct { Id string `xml:"id,attr" json:"id"` Name string `xml:"name,attr" json:"name"` - AlbumCount int32 `xml:"albumCount,attr,omitempty" json:"albumCount,omitempty"` Starred *time.Time `xml:"starred,attr,omitempty" json:"starred,omitempty"` UserRating int32 `xml:"userRating,attr,omitempty" json:"userRating,omitempty"` CoverArt string `xml:"coverArt,attr,omitempty" json:"coverArt,omitempty"` @@ -233,7 +232,7 @@ type ArtistID3 struct { Id string `xml:"id,attr" json:"id"` Name string `xml:"name,attr" json:"name"` CoverArt string `xml:"coverArt,attr,omitempty" json:"coverArt,omitempty"` - AlbumCount int32 `xml:"albumCount,attr,omitempty" json:"albumCount,omitempty"` + AlbumCount int32 `xml:"albumCount,attr" json:"albumCount"` Starred *time.Time `xml:"starred,attr,omitempty" json:"starred,omitempty"` UserRating int32 `xml:"userRating,attr,omitempty" json:"userRating,omitempty"` ArtistImageUrl string `xml:"artistImageUrl,attr,omitempty" json:"artistImageUrl,omitempty"` diff --git a/server/subsonic/responses/responses_test.go b/server/subsonic/responses/responses_test.go index fed454195..f3796f10a 100644 --- a/server/subsonic/responses/responses_test.go +++ b/server/subsonic/responses/responses_test.go @@ -103,7 +103,6 @@ var _ = Describe("Responses", func() { Name: "aaa", Starred: &t, UserRating: 3, - AlbumCount: 2, ArtistImageUrl: "https://lastfm.freetls.fastly.net/i/u/300x300/2a96cbd8b46e442fc41c2b86b821562f.png", } index := make([]Index, 1) diff --git a/server/subsonic/searching.go b/server/subsonic/searching.go index 235ebc13f..f66846f35 100644 --- a/server/subsonic/searching.go +++ b/server/subsonic/searching.go @@ -94,7 +94,6 @@ func (api *Router) Search2(r *http.Request) (*responses.Subsonic, error) { a := responses.Artist{ Id: artist.ID, Name: artist.Name, - AlbumCount: int32(artist.AlbumCount), UserRating: int32(artist.Rating), CoverArt: artist.CoverArtID().String(), ArtistImageUrl: public.ImageURL(r, artist.CoverArtID(), 600), From beb768cd9cd00f01581fe190a345ccf8617950db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Deluan=20Quint=C3=A3o?= Date: Fri, 14 Mar 2025 21:43:52 -0400 Subject: [PATCH 16/51] feat(server): add Role filters to albums (#3829) * navidrome artist filtering * address discord feedback * perPage min 36 * various artist artist_id -> albumartist_id * artist_id, role_id separate * remove all ui changes I guess * Add tests, check for possible SQL injection Signed-off-by: Deluan --------- Signed-off-by: Deluan Co-authored-by: Kendall Garner <17521368+kgarner7@users.noreply.github.com> --- persistence/album_repository.go | 28 ++++++++++++++--- persistence/album_repository_test.go | 47 ++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 5 deletions(-) diff --git a/persistence/album_repository.go b/persistence/album_repository.go index f98375f21..b29a44701 100644 --- a/persistence/album_repository.go +++ b/persistence/album_repository.go @@ -6,6 +6,7 @@ import ( "fmt" "maps" "slices" + "strings" "sync" "time" @@ -119,11 +120,17 @@ var albumFilters = sync.OnceValue(func() map[string]filterFunc { "has_rating": hasRatingFilter, "missing": booleanFilter, "genre_id": tagIDFilter, + "role_total_id": allRolesFilter, } // Add all album tags as filters for tag := range model.AlbumLevelTags() { filters[string(tag)] = tagIDFilter } + + for role := range model.AllRoles { + filters["role_"+role+"_id"] = artistRoleFilter + } + return filters }) @@ -153,14 +160,25 @@ func yearFilter(_ string, value interface{}) Sqlizer { } } -// BFR: Support other roles func artistFilter(_ string, value interface{}) Sqlizer { return Or{ - Exists("json_tree(Participants, '$.albumartist')", Eq{"value": value}), - Exists("json_tree(Participants, '$.artist')", Eq{"value": value}), + Exists("json_tree(participants, '$.albumartist')", Eq{"value": value}), + Exists("json_tree(participants, '$.artist')", Eq{"value": value}), } - // For any role: - //return Like{"Participants": fmt.Sprintf(`%%"%s"%%`, value)} +} + +func artistRoleFilter(name string, value interface{}) Sqlizer { + roleName := strings.TrimSuffix(strings.TrimPrefix(name, "role_"), "_id") + + // Check if the role name is valid. If not, return an invalid filter + if _, ok := model.AllRoles[roleName]; !ok { + return Gt{"": nil} + } + return Exists(fmt.Sprintf("json_tree(participants, '$.%s')", roleName), Eq{"value": value}) +} + +func allRolesFilter(_ string, value interface{}) Sqlizer { + return Like{"participants": fmt.Sprintf(`%%"%s"%%`, value)} } func (r *albumRepository) CountAll(options ...model.QueryOptions) (int64, error) { diff --git a/persistence/album_repository_test.go b/persistence/album_repository_test.go index dba347b30..529458c26 100644 --- a/persistence/album_repository_test.go +++ b/persistence/album_repository_test.go @@ -2,6 +2,7 @@ package persistence import ( "context" + "fmt" "time" "github.com/navidrome/navidrome/conf" @@ -236,6 +237,52 @@ var _ = Describe("AlbumRepository", func() { } }) }) + + Describe("artistRoleFilter", func() { + DescribeTable("creates correct SQL expressions for artist roles", + func(filterName, artistID, expectedSQL string) { + sqlizer := artistRoleFilter(filterName, artistID) + sql, args, err := sqlizer.ToSql() + Expect(err).ToNot(HaveOccurred()) + Expect(sql).To(Equal(expectedSQL)) + Expect(args).To(Equal([]interface{}{artistID})) + }, + Entry("artist role", "role_artist_id", "123", + "exists (select 1 from json_tree(participants, '$.artist') where value = ?)"), + Entry("albumartist role", "role_albumartist_id", "456", + "exists (select 1 from json_tree(participants, '$.albumartist') where value = ?)"), + Entry("composer role", "role_composer_id", "789", + "exists (select 1 from json_tree(participants, '$.composer') where value = ?)"), + ) + + It("works with the actual filter map", func() { + filters := albumFilters() + + for roleName := range model.AllRoles { + filterName := "role_" + roleName + "_id" + filterFunc, exists := filters[filterName] + Expect(exists).To(BeTrue(), fmt.Sprintf("Filter %s should exist", filterName)) + + sqlizer := filterFunc(filterName, "test-id") + sql, args, err := sqlizer.ToSql() + Expect(err).ToNot(HaveOccurred()) + Expect(sql).To(Equal(fmt.Sprintf("exists (select 1 from json_tree(participants, '$.%s') where value = ?)", roleName))) + Expect(args).To(Equal([]interface{}{"test-id"})) + } + }) + + It("rejects invalid roles", func() { + sqlizer := artistRoleFilter("role_invalid_id", "123") + _, _, err := sqlizer.ToSql() + Expect(err).To(HaveOccurred()) + }) + + It("rejects invalid filter names", func() { + sqlizer := artistRoleFilter("invalid_name", "123") + _, _, err := sqlizer.ToSql() + Expect(err).To(HaveOccurred()) + }) + }) }) func _p(id, name string, sortName ...string) model.Participant { From 212887214c823c72d90bef3501d75c38acb9f118 Mon Sep 17 00:00:00 2001 From: Kendall Garner <17521368+kgarner7@users.noreply.github.com> Date: Sun, 16 Mar 2025 23:39:19 +0000 Subject: [PATCH 17/51] fix(ui): minor icon inconsistencies and "no missing files" translation (#3837) * chore(ui): Fix minor inconsistencies 1. The icons in the user menu are a mix of MUI and react-icons. Move them all to react-icons, and use a standard size (24px) 2. On missing files page, provide a custom Empty component that just removes 'yet' * use RA's builtin support for custom empty message Signed-off-by: Deluan --------- Signed-off-by: Deluan Co-authored-by: Deluan --- resources/i18n/pt.json | 1 + ui/src/i18n/en.json | 1 + ui/src/layout/AppBar.jsx | 14 +++++++------- ui/src/layout/PersonalMenu.jsx | 4 ++-- ui/src/missing/MissingFilesList.jsx | 2 +- ui/src/transcoding/index.js | 4 ++-- 6 files changed, 14 insertions(+), 12 deletions(-) diff --git a/resources/i18n/pt.json b/resources/i18n/pt.json index 6a45ccfde..c3c65ca57 100644 --- a/resources/i18n/pt.json +++ b/resources/i18n/pt.json @@ -229,6 +229,7 @@ }, "missing": { "name": "Arquivo ausente |||| Arquivos ausentes", + "empty": "Nenhum arquivo ausente", "fields": { "path": "Caminho", "size": "Tamanho", diff --git a/ui/src/i18n/en.json b/ui/src/i18n/en.json index 476786640..cd377932c 100644 --- a/ui/src/i18n/en.json +++ b/ui/src/i18n/en.json @@ -231,6 +231,7 @@ }, "missing": { "name": "Missing File|||| Missing Files", + "empty": "No Missing Files", "fields": { "path": "Path", "size": "Size", diff --git a/ui/src/layout/AppBar.jsx b/ui/src/layout/AppBar.jsx index 943119fd5..a8c36cd14 100644 --- a/ui/src/layout/AppBar.jsx +++ b/ui/src/layout/AppBar.jsx @@ -6,12 +6,10 @@ import { usePermissions, getResources, } from 'react-admin' +import { MdInfo, MdPerson, MdSupervisorAccount } from 'react-icons/md' import { useSelector } from 'react-redux' import { makeStyles, MenuItem, ListItemIcon, Divider } from '@material-ui/core' import ViewListIcon from '@material-ui/icons/ViewList' -import InfoIcon from '@material-ui/icons/Info' -import PersonIcon from '@material-ui/icons/Person' -import SupervisorAccountIcon from '@material-ui/icons/SupervisorAccount' import { Dialogs } from '../dialogs/Dialogs' import { AboutDialog } from '../dialogs' import PersonalMenu from './PersonalMenu' @@ -51,7 +49,7 @@ const AboutMenuItem = forwardRef(({ onClick, ...rest }, ref) => { <> - + {label} @@ -86,9 +84,9 @@ const CustomUserMenu = ({ onClick, ...rest }) => { if (!config.enableUserEditing) { return null } - userResource.icon = PersonIcon + userResource.icon = MdPerson } else { - userResource.icon = SupervisorAccountIcon + userResource.icon = MdSupervisorAccount } return renderSettingsMenuItemLink( userResource, @@ -109,7 +107,9 @@ const CustomUserMenu = ({ onClick, ...rest }) => { to={link} primaryText={label} leftIcon={ - (resource.icon && createElement(resource.icon)) || + (resource.icon && createElement(resource.icon, { size: 24 })) || ( + + ) } onClick={onClick} sidebarIsOpen={true} diff --git a/ui/src/layout/PersonalMenu.jsx b/ui/src/layout/PersonalMenu.jsx index f97985c98..12f8beeb1 100644 --- a/ui/src/layout/PersonalMenu.jsx +++ b/ui/src/layout/PersonalMenu.jsx @@ -1,7 +1,7 @@ import React, { forwardRef } from 'react' import { MenuItemLink, useTranslate } from 'react-admin' +import { MdTune } from 'react-icons/md' import { makeStyles } from '@material-ui/core' -import TuneIcon from '@material-ui/icons/Tune' const useStyles = makeStyles((theme) => ({ menuItem: { @@ -17,7 +17,7 @@ const PersonalMenu = forwardRef(({ onClick, sidebarIsOpen, dense }, ref) => { ref={ref} to="/personal" primaryText={translate('menu.personal.name')} - leftIcon={} + leftIcon={} onClick={onClick} className={classes.menuItem} sidebarIsOpen={sidebarIsOpen} diff --git a/ui/src/missing/MissingFilesList.jsx b/ui/src/missing/MissingFilesList.jsx index c7703ea0a..8f73023fa 100644 --- a/ui/src/missing/MissingFilesList.jsx +++ b/ui/src/missing/MissingFilesList.jsx @@ -1,4 +1,4 @@ -import { List, SizeField } from '../common/index.js' +import { List, SizeField } from '../common/index' import { Datagrid, DateField, diff --git a/ui/src/transcoding/index.js b/ui/src/transcoding/index.js index cb3491920..0bff293b3 100644 --- a/ui/src/transcoding/index.js +++ b/ui/src/transcoding/index.js @@ -1,4 +1,4 @@ -import TransformIcon from '@material-ui/icons/Transform' +import { MdTransform } from 'react-icons/md' import TranscodingList from './TranscodingList' import TranscodingEdit from './TranscodingEdit' import TranscodingCreate from './TranscodingCreate' @@ -10,5 +10,5 @@ export default { edit: config.enableTranscodingConfig && TranscodingEdit, create: config.enableTranscodingConfig && TranscodingCreate, show: !config.enableTranscodingConfig && TranscodingShow, - icon: TransformIcon, + icon: MdTransform, } From 2adb098f3232f4597f404ce9f5bdac7c3c5e26b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Deluan=20Quint=C3=A3o?= Date: Mon, 17 Mar 2025 19:21:33 -0400 Subject: [PATCH 18/51] fix(scanner): fix displayArtist logic (#3835) * fix displayArtist logic Signed-off-by: Deluan * remove unneeded value Signed-off-by: Deluan * refactor Signed-off-by: Deluan * Use first albumartist if it cannot figure out the display name Signed-off-by: Deluan --------- Signed-off-by: Deluan --- consts/consts.go | 20 +-- model/metadata/map_mediafile.go | 2 +- model/metadata/map_participants.go | 43 +++---- model/metadata/map_participants_test.go | 163 ++++++++++++++++++++++-- server/subsonic/helpers.go | 2 +- 5 files changed, 186 insertions(+), 44 deletions(-) diff --git a/consts/consts.go b/consts/consts.go index 7f46fe39a..75271bec8 100644 --- a/consts/consts.go +++ b/consts/consts.go @@ -151,13 +151,17 @@ var ( UnknownArtistID = id.NewHash(strings.ToLower(UnknownArtist)) VariousArtistsMbzId = "89ad4ac3-39f7-470e-963a-56509c546377" - ServerStart = time.Now() + ArtistJoiner = " • " ) -var InContainer = func() bool { - // Check if the /.nddockerenv file exists - if _, err := os.Stat("/.nddockerenv"); err == nil { - return true - } - return false -}() +var ( + ServerStart = time.Now() + + InContainer = func() bool { + // Check if the /.nddockerenv file exists + if _, err := os.Stat("/.nddockerenv"); err == nil { + return true + } + return false + }() +) diff --git a/model/metadata/map_mediafile.go b/model/metadata/map_mediafile.go index 53c5a8db2..47d2578ec 100644 --- a/model/metadata/map_mediafile.go +++ b/model/metadata/map_mediafile.go @@ -72,7 +72,7 @@ func (md Metadata) ToMediaFile(libID int, folderID string) model.MediaFile { mf.UpdatedAt = md.ModTime() mf.Participants = md.mapParticipants() - mf.Artist = md.mapDisplayArtist(mf) + mf.Artist = md.mapDisplayArtist() mf.AlbumArtist = md.mapDisplayAlbumArtist(mf) // Persistent IDs diff --git a/model/metadata/map_participants.go b/model/metadata/map_participants.go index 9d47c676d..9305d8791 100644 --- a/model/metadata/map_participants.go +++ b/model/metadata/map_participants.go @@ -2,6 +2,7 @@ package metadata import ( "cmp" + "strings" "github.com/navidrome/navidrome/consts" "github.com/navidrome/navidrome/model" @@ -199,32 +200,28 @@ func (md Metadata) getArtistValues(single, multi model.TagName) []string { return vSingle } -func (md Metadata) getTags(tagNames ...model.TagName) []string { - for _, tagName := range tagNames { - values := md.Strings(tagName) - if len(values) > 0 { - return values - } - } - return nil -} -func (md Metadata) mapDisplayRole(mf model.MediaFile, role model.Role, tagNames ...model.TagName) string { - artistNames := md.getTags(tagNames...) - values := []string{ - "", - mf.Participants.First(role).Name, - consts.UnknownArtist, - } - if len(artistNames) == 1 { - values[0] = artistNames[0] - } - return cmp.Or(values...) +func (md Metadata) mapDisplayName(singularTagName, pluralTagName model.TagName) string { + return cmp.Or( + strings.Join(md.tags[singularTagName], consts.ArtistJoiner), + strings.Join(md.tags[pluralTagName], consts.ArtistJoiner), + ) } -func (md Metadata) mapDisplayArtist(mf model.MediaFile) string { - return md.mapDisplayRole(mf, model.RoleArtist, model.TagTrackArtist, model.TagTrackArtists) +func (md Metadata) mapDisplayArtist() string { + return cmp.Or( + md.mapDisplayName(model.TagTrackArtist, model.TagTrackArtists), + consts.UnknownArtist, + ) } func (md Metadata) mapDisplayAlbumArtist(mf model.MediaFile) string { - return md.mapDisplayRole(mf, model.RoleAlbumArtist, model.TagAlbumArtist, model.TagAlbumArtists) + fallbackName := consts.UnknownArtist + if md.Bool(model.TagCompilation) { + fallbackName = consts.VariousArtists + } + return cmp.Or( + md.mapDisplayName(model.TagAlbumArtist, model.TagAlbumArtists), + mf.Participants.First(model.RoleAlbumArtist).Name, + fallbackName, + ) } diff --git a/model/metadata/map_participants_test.go b/model/metadata/map_participants_test.go index a1c8ed527..5317a4bcf 100644 --- a/model/metadata/map_participants_test.go +++ b/model/metadata/map_participants_test.go @@ -45,6 +45,10 @@ var _ = Describe("Participants", func() { mf = toMediaFile(model.RawTags{}) }) + It("should set the display name to Unknown Artist", func() { + Expect(mf.Artist).To(Equal("[Unknown Artist]")) + }) + It("should set artist to Unknown Artist", func() { Expect(mf.Artist).To(Equal("[Unknown Artist]")) }) @@ -92,6 +96,7 @@ var _ = Describe("Participants", func() { Expect(artist.MbzArtistID).To(Equal(mbid1)) }) }) + Context("Multiple values in a Single-valued ARTIST tags, no ARTISTS tags", func() { BeforeEach(func() { mf = toMediaFile(model.RawTags{ @@ -101,12 +106,13 @@ var _ = Describe("Participants", func() { }) }) - It("should split the tag", func() { - By("keeping the first artist as the display name") + It("should use the full string as display name", func() { Expect(mf.Artist).To(Equal("Artist Name feat. Someone Else")) Expect(mf.SortArtistName).To(Equal("Name, Artist")) Expect(mf.OrderArtistName).To(Equal("artist name")) + }) + It("should split the tag", func() { participants := mf.Participants Expect(participants).To(SatisfyAll( HaveKeyWithValue(model.RoleArtist, HaveLen(2)), @@ -130,6 +136,7 @@ var _ = Describe("Participants", func() { Expect(artist1.SortArtistName).To(Equal("Else, Someone")) Expect(artist1.MbzArtistID).To(BeEmpty()) }) + It("should split the tag using case-insensitive separators", func() { mf = toMediaFile(model.RawTags{ "ARTIST": {"A1 FEAT. A2"}, @@ -167,8 +174,8 @@ var _ = Describe("Participants", func() { }) }) - It("should use the first artist name as display name", func() { - Expect(mf.Artist).To(Equal("First Artist")) + It("should concatenate all ARTIST values as display name", func() { + Expect(mf.Artist).To(Equal("First Artist • Second Artist")) }) It("should populate the participants with all artists", func() { @@ -194,6 +201,101 @@ var _ = Describe("Participants", func() { }) }) + Context("Single-valued ARTIST tag, single-valued ARTISTS tag, same values", func() { + BeforeEach(func() { + mf = toMediaFile(model.RawTags{ + "ARTIST": {"Artist Name"}, + "ARTISTS": {"Artist Name"}, + "ARTISTSORT": {"Name, Artist"}, + "MUSICBRAINZ_ARTISTID": {mbid1}, + }) + }) + + It("should use the ARTIST tag as display name", func() { + Expect(mf.Artist).To(Equal("Artist Name")) + }) + + It("should populate the participants with the ARTIST", func() { + participants := mf.Participants + Expect(participants).To(HaveLen(2)) // ARTIST and ALBUMARTIST + Expect(participants).To(SatisfyAll( + HaveKeyWithValue(model.RoleArtist, HaveLen(1)), + )) + + artist := participants[model.RoleArtist][0] + Expect(artist.ID).ToNot(BeEmpty()) + Expect(artist.Name).To(Equal("Artist Name")) + Expect(artist.OrderArtistName).To(Equal("artist name")) + Expect(artist.SortArtistName).To(Equal("Name, Artist")) + Expect(artist.MbzArtistID).To(Equal(mbid1)) + }) + }) + + Context("Single-valued ARTIST tag, single-valued ARTISTS tag, different values", func() { + BeforeEach(func() { + mf = toMediaFile(model.RawTags{ + "ARTIST": {"Artist Name"}, + "ARTISTS": {"Artist Name 2"}, + "ARTISTSORT": {"Name, Artist"}, + "MUSICBRAINZ_ARTISTID": {mbid1}, + }) + }) + + It("should use the ARTIST tag as display name", func() { + Expect(mf.Artist).To(Equal("Artist Name")) + }) + + It("should use only artists from ARTISTS", func() { + participants := mf.Participants + Expect(participants).To(HaveLen(2)) // ARTIST and ALBUMARTIST + Expect(participants).To(SatisfyAll( + HaveKeyWithValue(model.RoleArtist, HaveLen(1)), + )) + + artist := participants[model.RoleArtist][0] + Expect(artist.ID).ToNot(BeEmpty()) + Expect(artist.Name).To(Equal("Artist Name 2")) + Expect(artist.OrderArtistName).To(Equal("artist name 2")) + Expect(artist.SortArtistName).To(Equal("Name, Artist")) + Expect(artist.MbzArtistID).To(Equal(mbid1)) + }) + }) + + Context("No ARTIST tag, multi-valued ARTISTS tag", func() { + BeforeEach(func() { + mf = toMediaFile(model.RawTags{ + "ARTISTS": {"First Artist", "Second Artist"}, + "ARTISTSSORT": {"Name, First Artist", "Name, Second Artist"}, + }) + }) + + It("should concatenate ARTISTS as display name", func() { + Expect(mf.Artist).To(Equal("First Artist • Second Artist")) + }) + + It("should populate the participants with all artists", func() { + participants := mf.Participants + Expect(participants).To(HaveLen(2)) // ARTIST and ALBUMARTIST + Expect(participants).To(SatisfyAll( + HaveKeyWithValue(model.RoleArtist, HaveLen(2)), + )) + + artist0 := participants[model.RoleArtist][0] + Expect(artist0.ID).ToNot(BeEmpty()) + Expect(artist0.Name).To(Equal("First Artist")) + Expect(artist0.OrderArtistName).To(Equal("first artist")) + Expect(artist0.SortArtistName).To(Equal("Name, First Artist")) + Expect(artist0.MbzArtistID).To(BeEmpty()) + + artist1 := participants[model.RoleArtist][1] + Expect(artist1.ID).ToNot(BeEmpty()) + Expect(artist1.Name).To(Equal("Second Artist")) + Expect(artist1.OrderArtistName).To(Equal("second artist")) + Expect(artist1.SortArtistName).To(Equal("Name, Second Artist")) + Expect(artist1.MbzArtistID).To(BeEmpty()) + }) + }) + Context("Single-valued ARTIST tags, multi-valued ARTISTS tags", func() { BeforeEach(func() { mf = toMediaFile(model.RawTags{ @@ -231,6 +333,7 @@ var _ = Describe("Participants", func() { }) }) + // Not a good tagging strategy, but supported anyway. Context("Multi-valued ARTIST tags, multi-valued ARTISTS tags", func() { BeforeEach(func() { mf = toMediaFile(model.RawTags{ @@ -242,13 +345,8 @@ var _ = Describe("Participants", func() { }) }) - XIt("should use the values concatenated as a display name ", func() { - Expect(mf.Artist).To(Equal("First Artist + Second Artist")) - }) - - // TODO: remove when the above is implemented - It("should use the first artist name as display name", func() { - Expect(mf.Artist).To(Equal("First Artist 2")) + It("should use ARTIST values concatenated as a display name ", func() { + Expect(mf.Artist).To(Equal("First Artist • Second Artist")) }) It("should prioritize ARTISTS tags", func() { @@ -275,6 +373,7 @@ var _ = Describe("Participants", func() { }) Describe("ALBUMARTIST(S) tags", func() { + // Only test specific scenarios for ALBUMARTIST(S) tags, as the logic is the same as for ARTIST(S) tags. Context("No ALBUMARTIST/ALBUMARTISTS tags", func() { When("the COMPILATION tag is not set", func() { BeforeEach(func() { @@ -305,6 +404,35 @@ var _ = Describe("Participants", func() { }) }) + When("the COMPILATION tag is not set and there is no ALBUMARTIST tag", func() { + BeforeEach(func() { + mf = toMediaFile(model.RawTags{ + "ARTIST": {"Artist Name", "Another Artist"}, + "ARTISTSORT": {"Name, Artist", "Artist, Another"}, + }) + }) + + It("should use the first ARTIST as ALBUMARTIST", func() { + Expect(mf.AlbumArtist).To(Equal("Artist Name")) + }) + + It("should add the ARTIST to participants as ALBUMARTIST", func() { + participants := mf.Participants + Expect(participants).To(HaveLen(2)) + Expect(participants).To(SatisfyAll( + HaveKeyWithValue(model.RoleAlbumArtist, HaveLen(2)), + )) + + albumArtist := participants[model.RoleAlbumArtist][0] + Expect(albumArtist.Name).To(Equal("Artist Name")) + Expect(albumArtist.SortArtistName).To(Equal("Name, Artist")) + + albumArtist = participants[model.RoleAlbumArtist][1] + Expect(albumArtist.Name).To(Equal("Another Artist")) + Expect(albumArtist.SortArtistName).To(Equal("Artist, Another")) + }) + }) + When("the COMPILATION tag is true", func() { BeforeEach(func() { mf = toMediaFile(model.RawTags{ @@ -331,6 +459,19 @@ var _ = Describe("Participants", func() { Expect(albumArtist.MbzArtistID).To(Equal(consts.VariousArtistsMbzId)) }) }) + + When("the COMPILATION tag is true and there are ALBUMARTIST tags", func() { + BeforeEach(func() { + mf = toMediaFile(model.RawTags{ + "COMPILATION": {"1"}, + "ALBUMARTIST": {"Album Artist Name 1", "Album Artist Name 2"}, + }) + }) + + It("should use the ALBUMARTIST names as display name", func() { + Expect(mf.AlbumArtist).To(Equal("Album Artist Name 1 • Album Artist Name 2")) + }) + }) }) Context("ALBUMARTIST tag is set", func() { diff --git a/server/subsonic/helpers.go b/server/subsonic/helpers.go index 0fb35a7b7..fa98a985b 100644 --- a/server/subsonic/helpers.go +++ b/server/subsonic/helpers.go @@ -241,7 +241,7 @@ func osChildFromMediaFile(ctx context.Context, mf model.MediaFile) *responses.Op child.DisplayAlbumArtist = mf.AlbumArtist child.AlbumArtists = artistRefs(mf.Participants[model.RoleAlbumArtist]) var contributors []responses.Contributor - child.DisplayComposer = mf.Participants[model.RoleComposer].Join(" • ") + child.DisplayComposer = mf.Participants[model.RoleComposer].Join(consts.ArtistJoiner) for role, participants := range mf.Participants { if role == model.RoleArtist || role == model.RoleAlbumArtist { continue From b04647309f6a32a19716ba4a9b0c4796b308b7f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Deluan=20Quint=C3=A3o?= Date: Mon, 17 Mar 2025 21:08:10 -0400 Subject: [PATCH 19/51] chore(deps): upgrade to Go 1.24.1 (#3851) * chore(deps): upgrade to Go 1.24.1 Signed-off-by: Deluan * chore(deps): add reflex as go.mod tool Signed-off-by: Deluan * chore(deps): add wire as go.mod tool Signed-off-by: Deluan * chore(deps): add goimports as go.mod tool Signed-off-by: Deluan * chore(deps): add ginkgo as go.mod tool Signed-off-by: Deluan --------- Signed-off-by: Deluan --- .devcontainer/devcontainer.json | 2 +- Dockerfile | 2 +- Makefile | 10 +++++----- Procfile.dev | 2 +- git/pre-commit | 2 +- go.mod | 15 ++++++++++++++- go.sum | 16 ++++++++++++++++ 7 files changed, 39 insertions(+), 10 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index d27ff208c..f339f62f7 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -4,7 +4,7 @@ "dockerfile": "Dockerfile", "args": { // Update the VARIANT arg to pick a version of Go: 1, 1.15, 1.14 - "VARIANT": "1.23", + "VARIANT": "1.24", // Options "INSTALL_NODE": "true", "NODE_VERSION": "v20" diff --git a/Dockerfile b/Dockerfile index 224595d93..9dda15cc6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -61,7 +61,7 @@ COPY --from=ui /build /build ######################################################################################################################## ### Build Navidrome binary -FROM --platform=$BUILDPLATFORM public.ecr.aws/docker/library/golang:1.23-bookworm AS base +FROM --platform=$BUILDPLATFORM public.ecr.aws/docker/library/golang:1.24-bookworm AS base RUN apt-get update && apt-get install -y clang lld COPY --from=xx / / WORKDIR /workspace diff --git a/Makefile b/Makefile index c6ff60c97..cd78e1193 100644 --- a/Makefile +++ b/Makefile @@ -29,11 +29,11 @@ dev: check_env ##@Development Start Navidrome in development mode, with hot-re .PHONY: dev server: check_go_env buildjs ##@Development Start the backend in development mode - @ND_ENABLEINSIGHTSCOLLECTOR="false" go run github.com/cespare/reflex@latest -d none -c reflex.conf + @ND_ENABLEINSIGHTSCOLLECTOR="false" go tool reflex -d none -c reflex.conf .PHONY: server watch: ##@Development Start Go tests in watch mode (re-run when code changes) - go run github.com/onsi/ginkgo/v2/ginkgo@latest watch -tags=netgo -notify ./... + go tool ginkgo watch -tags=netgo -notify ./... .PHONY: watch test: ##@Development Run Go tests @@ -59,16 +59,16 @@ lintall: lint ##@Development Lint Go and JS code format: ##@Development Format code @(cd ./ui && npm run prettier) - @go run golang.org/x/tools/cmd/goimports@latest -w `find . -name '*.go' | grep -v _gen.go$$` + @go tool goimports -w `find . -name '*.go' | grep -v _gen.go$$` @go mod tidy .PHONY: format wire: check_go_env ##@Development Update Dependency Injection - go run github.com/google/wire/cmd/wire@latest gen -tags=netgo ./... + go tool wire gen -tags=netgo ./... .PHONY: wire snapshots: ##@Development Update (GoLang) Snapshot tests - UPDATE_SNAPSHOTS=true go run github.com/onsi/ginkgo/v2/ginkgo@latest ./server/subsonic/responses/... + UPDATE_SNAPSHOTS=true go tool ginkgo ./server/subsonic/responses/... .PHONY: snapshots migration-sql: ##@Development Create an empty SQL migration file diff --git a/Procfile.dev b/Procfile.dev index 5af64f49b..0c187e811 100644 --- a/Procfile.dev +++ b/Procfile.dev @@ -1,2 +1,2 @@ JS: sh -c "cd ./ui && npm start" -GO: go run github.com/cespare/reflex@latest -d none -c reflex.conf +GO: go tool reflex -d none -c reflex.conf diff --git a/git/pre-commit b/git/pre-commit index 6bb2b314f..04f87994b 100755 --- a/git/pre-commit +++ b/git/pre-commit @@ -10,7 +10,7 @@ # # This script does not handle file names that contain spaces. -gofmtcmd="go run golang.org/x/tools/cmd/goimports@latest" +gofmtcmd="go tool goimports" gofiles=$(git diff --cached --name-only --diff-filter=ACM | grep '.go$' | grep -v '_gen.go$') [ -z "$gofiles" ] && exit 0 diff --git a/go.mod b/go.mod index eafc17544..f88a05abc 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/navidrome/navidrome -go 1.23.4 +go 1.24.1 // Fork to fix https://github.com/navidrome/navidrome/pull/3254 replace github.com/dhowden/tag v0.0.0-20240417053706-3d75831295e8 => github.com/deluan/tag v0.0.0-20241002021117-dfe5e6ea396d @@ -68,7 +68,9 @@ require ( require ( github.com/aymerick/douceur v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/reflex v0.3.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/creack/pty v1.1.11 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/fsnotify/fsnotify v1.8.0 // indirect @@ -77,10 +79,12 @@ require ( github.com/goccy/go-json v0.10.5 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/pprof v0.0.0-20250302191652-9094ed2288e7 // indirect + github.com/google/subcommands v1.2.0 // indirect github.com/gorilla/css v1.0.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/klauspost/compress v1.17.11 // indirect github.com/kr/text v0.2.0 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect @@ -94,6 +98,7 @@ require ( github.com/mfridman/interpolate v0.0.2 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/ogier/pflag v0.0.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.62.0 // indirect @@ -111,8 +116,16 @@ require ( github.com/subosito/gotenv v1.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.36.0 // indirect + golang.org/x/mod v0.24.0 // indirect golang.org/x/tools v0.31.0 // indirect google.golang.org/protobuf v1.36.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect ) + +tool ( + github.com/cespare/reflex + github.com/google/wire/cmd/wire + github.com/onsi/ginkgo/v2/ginkgo + golang.org/x/tools/cmd/goimports +) diff --git a/go.sum b/go.sum index eadda96b3..61d6ab157 100644 --- a/go.sum +++ b/go.sum @@ -14,10 +14,14 @@ github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR github.com/bmatcuk/doublestar/v4 v4.8.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M= github.com/bradleyjkemp/cupaloy/v2 v2.8.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0= +github.com/cespare/reflex v0.3.1 h1:N4Y/UmRrjwOkNT0oQQnYsdr6YBxvHqtSfPB4mqOyAKk= +github.com/cespare/reflex v0.3.1/go.mod h1:I+0Pnu2W693i7Hv6ZZG76qHTY0mgUa7uCIfCtikXojE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -48,6 +52,7 @@ github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8= @@ -78,6 +83,7 @@ github.com/google/go-pipeline v0.0.0-20230411140531-6cbedfc1d3fc h1:hd+uUVsB1vdx github.com/google/go-pipeline v0.0.0-20230411140531-6cbedfc1d3fc/go.mod h1:SL66SJVysrh7YbDCP9tH30b8a9o/N2HeiQNUm85EKhc= github.com/google/pprof v0.0.0-20250302191652-9094ed2288e7 h1:+J3r2e8+RsmN3vKfo75g0YSY61ms37qzPglu4p0sGro= github.com/google/pprof v0.0.0-20250302191652-9094ed2288e7/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -105,11 +111,16 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60= github.com/kardianos/service v1.2.2/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= @@ -150,6 +161,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/ogier/pflag v0.0.1 h1:RW6JSWSu/RkSatfcLtogGfFgpim5p7ARQ10ECk5O750= +github.com/ogier/pflag v0.0.1/go.mod h1:zkFki7tvTa0tafRvTBIZTvzYyAu6kQhPZFnshFFPE+g= github.com/onsi/ginkgo/v2 v2.23.0 h1:FA1xjp8ieYDzlgS5ABTpdUDB7wtngggONc8a7ku2NqQ= github.com/onsi/ginkgo/v2 v2.23.0/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM= github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= @@ -253,6 +266,8 @@ golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= +golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -276,6 +291,7 @@ golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= From e457f2130632aa745ef4942b7686792d36742ed1 Mon Sep 17 00:00:00 2001 From: Deluan Date: Tue, 18 Mar 2025 12:43:48 -0400 Subject: [PATCH 20/51] chore(server): show square flag in resize artwork logs Signed-off-by: Deluan --- core/artwork/reader_resized.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/artwork/reader_resized.go b/core/artwork/reader_resized.go index 46d0f8866..83e6e25c2 100644 --- a/core/artwork/reader_resized.go +++ b/core/artwork/reader_resized.go @@ -63,12 +63,12 @@ func (a *resizedArtworkReader) Reader(ctx context.Context) (io.ReadCloser, strin resized, origSize, err := resizeImage(orig, a.size, a.square) if resized == nil { - log.Trace(ctx, "Image smaller than requested size", "artID", a.artID, "original", origSize, "resized", a.size) + log.Trace(ctx, "Image smaller than requested size", "artID", a.artID, "original", origSize, "resized", a.size, "square", a.square) } else { - log.Trace(ctx, "Resizing artwork", "artID", a.artID, "original", origSize, "resized", a.size) + log.Trace(ctx, "Resizing artwork", "artID", a.artID, "original", origSize, "resized", a.size, "square", a.square) } if err != nil { - log.Warn(ctx, "Could not resize image. Will return image as is", "artID", a.artID, "size", a.size, err) + log.Warn(ctx, "Could not resize image. Will return image as is", "artID", a.artID, "size", a.size, "square", a.square, err) } if err != nil || resized == nil { // if we couldn't resize the image, return the original From 1ed893010756be1efbaac4dff52b29d56107d4a3 Mon Sep 17 00:00:00 2001 From: Rob Emery Date: Tue, 18 Mar 2025 22:23:04 +0000 Subject: [PATCH 21/51] fix(msi): don't override custom ini config (#3836) Previously addLine would add-or-update, resulting in the custom settings being overriden on upgrade. createLine will only add to the ini if the key doesn't already exist. --- release/wix/navidrome.wxs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/release/wix/navidrome.wxs b/release/wix/navidrome.wxs index 22ad93f86..ec8b164e8 100644 --- a/release/wix/navidrome.wxs +++ b/release/wix/navidrome.wxs @@ -43,9 +43,9 @@ - - - + + + From 0147bb5f12a659daea8abeeee445788de25e4e04 Mon Sep 17 00:00:00 2001 From: Deluan Date: Tue, 18 Mar 2025 19:12:07 -0400 Subject: [PATCH 22/51] chore(deps): upgrade viper to 1.20.0, add tests for the supported config formats Signed-off-by: Deluan --- conf/configuration.go | 5 ++++ conf/configuration_test.go | 50 ++++++++++++++++++++++++++++++++++++++ conf/export_test.go | 5 ++++ conf/testdata/cfg.ini | 6 +++++ conf/testdata/cfg.json | 12 +++++++++ conf/testdata/cfg.toml | 5 ++++ conf/testdata/cfg.yaml | 7 ++++++ go.mod | 8 +++--- go.sum | 17 +++++-------- 9 files changed, 99 insertions(+), 16 deletions(-) create mode 100644 conf/configuration_test.go create mode 100644 conf/export_test.go create mode 100644 conf/testdata/cfg.ini create mode 100644 conf/testdata/cfg.json create mode 100644 conf/testdata/cfg.toml create mode 100644 conf/testdata/cfg.yaml diff --git a/conf/configuration.go b/conf/configuration.go index e1e6b2f67..9abb7e163 100644 --- a/conf/configuration.go +++ b/conf/configuration.go @@ -10,6 +10,7 @@ import ( "time" "github.com/bmatcuk/doublestar/v4" + "github.com/go-viper/encoding/ini" "github.com/kr/pretty" "github.com/navidrome/navidrome/consts" "github.com/navidrome/navidrome/log" @@ -549,6 +550,10 @@ func init() { } func InitConfig(cfgFile string) { + codecRegistry := viper.NewCodecRegistry() + _ = codecRegistry.RegisterCodec("ini", ini.Codec{}) + viper.SetOptions(viper.WithCodecRegistry(codecRegistry)) + cfgFile = getConfigFile(cfgFile) if cfgFile != "" { // Use config file from the flag. diff --git a/conf/configuration_test.go b/conf/configuration_test.go new file mode 100644 index 000000000..f57764709 --- /dev/null +++ b/conf/configuration_test.go @@ -0,0 +1,50 @@ +package conf_test + +import ( + "fmt" + "path/filepath" + "testing" + + . "github.com/navidrome/navidrome/conf" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/spf13/viper" +) + +func TestConfiguration(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Configuration Suite") +} + +var _ = Describe("Configuration", func() { + BeforeEach(func() { + // Reset viper configuration + viper.Reset() + viper.SetDefault("datafolder", GinkgoT().TempDir()) + viper.SetDefault("loglevel", "error") + ResetConf() + }) + + DescribeTable("should load configuration from", + func(format string) { + filename := filepath.Join("testdata", "cfg."+format) + + // Initialize config with the test file + InitConfig(filename) + // Load the configuration (with noConfigDump=true) + Load(true) + + // Execute the format-specific assertions + Expect(Server.MusicFolder).To(Equal(fmt.Sprintf("/%s/music", format))) + Expect(Server.UIWelcomeMessage).To(Equal("Welcome " + format)) + Expect(Server.Tags["custom"].Aliases).To(Equal([]string{format, "test"})) + + // The config file used should be the one we created + Expect(Server.ConfigFile).To(Equal(filename)) + }, + Entry("TOML format", "toml"), + Entry("YAML format", "yaml"), + Entry("INI format", "ini"), + Entry("JSON format", "json"), + ) +}) diff --git a/conf/export_test.go b/conf/export_test.go new file mode 100644 index 000000000..0bd7819eb --- /dev/null +++ b/conf/export_test.go @@ -0,0 +1,5 @@ +package conf + +func ResetConf() { + Server = &configOptions{} +} diff --git a/conf/testdata/cfg.ini b/conf/testdata/cfg.ini new file mode 100644 index 000000000..cec7d3c70 --- /dev/null +++ b/conf/testdata/cfg.ini @@ -0,0 +1,6 @@ +[default] +MusicFolder = /ini/music +UIWelcomeMessage = Welcome ini + +[Tags] +Custom.Aliases = ini,test \ No newline at end of file diff --git a/conf/testdata/cfg.json b/conf/testdata/cfg.json new file mode 100644 index 000000000..37cf74f08 --- /dev/null +++ b/conf/testdata/cfg.json @@ -0,0 +1,12 @@ +{ + "musicFolder": "/json/music", + "uiWelcomeMessage": "Welcome json", + "Tags": { + "custom": { + "aliases": [ + "json", + "test" + ] + } + } +} \ No newline at end of file diff --git a/conf/testdata/cfg.toml b/conf/testdata/cfg.toml new file mode 100644 index 000000000..1dc852b18 --- /dev/null +++ b/conf/testdata/cfg.toml @@ -0,0 +1,5 @@ +musicFolder = "/toml/music" +uiWelcomeMessage = "Welcome toml" + +[Tags.custom] +aliases = ["toml", "test"] diff --git a/conf/testdata/cfg.yaml b/conf/testdata/cfg.yaml new file mode 100644 index 000000000..38b98d4aa --- /dev/null +++ b/conf/testdata/cfg.yaml @@ -0,0 +1,7 @@ +musicFolder: "/yaml/music" +uiWelcomeMessage: "Welcome yaml" +Tags: + custom: + aliases: + - yaml + - test diff --git a/go.mod b/go.mod index f88a05abc..158409f53 100644 --- a/go.mod +++ b/go.mod @@ -26,6 +26,7 @@ require ( github.com/go-chi/cors v1.2.1 github.com/go-chi/httprate v0.14.1 github.com/go-chi/jwtauth/v5 v5.3.2 + github.com/go-viper/encoding/ini v0.1.1 github.com/gohugoio/hashstructure v0.5.0 github.com/google/go-pipeline v0.0.0-20230411140531-6cbedfc1d3fc github.com/google/uuid v1.6.0 @@ -50,7 +51,7 @@ require ( github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.9.1 - github.com/spf13/viper v1.19.0 + github.com/spf13/viper v1.20.0 github.com/stretchr/testify v1.10.0 github.com/unrolled/secure v1.17.0 github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 @@ -76,13 +77,13 @@ require ( github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect + github.com/go-viper/mapstructure/v2 v2.2.1 // indirect github.com/goccy/go-json v0.10.5 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/pprof v0.0.0-20250302191652-9094ed2288e7 // indirect github.com/google/subcommands v1.2.0 // indirect github.com/gorilla/css v1.0.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/klauspost/compress v1.17.11 // indirect @@ -94,9 +95,7 @@ require ( github.com/lestrrat-go/httprc v1.0.6 // indirect github.com/lestrrat-go/iter v1.0.2 // indirect github.com/lestrrat-go/option v1.0.1 // indirect - github.com/magiconair/properties v1.8.9 // indirect github.com/mfridman/interpolate v0.0.2 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/ogier/pflag v0.0.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect @@ -105,7 +104,6 @@ require ( github.com/prometheus/procfs v0.15.1 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/sagikazarmark/locafero v0.7.0 // indirect - github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/segmentio/asm v1.2.0 // indirect github.com/sethvargo/go-retry v0.3.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect diff --git a/go.sum b/go.sum index 61d6ab157..b4d8b72aa 100644 --- a/go.sum +++ b/go.sum @@ -70,6 +70,10 @@ github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpv github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/go-viper/encoding/ini v0.1.1 h1:MVWY7B2XNw7lnOqHutGRc97bF3rP7omOdgjdMPAJgbs= +github.com/go-viper/encoding/ini v0.1.1/go.mod h1:Pfi4M2V1eAGJVZ5q6FrkHPhtHED2YgLlXhvgMVrB+YQ= +github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= +github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gohugoio/hashstructure v0.5.0 h1:G2fjSBU36RdwEJBWJ+919ERvOVqAg9tfcYp47K9swqg= @@ -98,11 +102,8 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jellydator/ttlcache/v3 v3.3.0 h1:BdoC9cE81qXfrxeb9eoJi9dWrdhSuwXMAnHTbnBm4Wc= @@ -141,8 +142,6 @@ github.com/lestrrat-go/jwx/v2 v2.1.4 h1:uBCMmJX8oRZStmKuMMOFb0Yh9xmEMgNJLgjuKKt4 github.com/lestrrat-go/jwx/v2 v2.1.4/go.mod h1:nWRbDFR1ALG2Z6GJbBXzfQaYyvn751KuuyySN2yR6is= github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= -github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= -github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/matoous/go-nanoid/v2 v2.1.0 h1:P64+dmq21hhWdtvZfEAofnvJULaRR1Yib0+PnU669bE= github.com/matoous/go-nanoid/v2 v2.1.0/go.mod h1:KlbGNQ+FhrUNIHUxZdL63t7tl4LaPkZNpUULS8H4uVM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= @@ -155,8 +154,6 @@ github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwX github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= github.com/mileusna/useragent v1.3.5 h1:SJM5NzBmh/hO+4LGeATKpaEX9+b4vcGg2qXGLiNGDws= github.com/mileusna/useragent v1.3.5/go.mod h1:3d8TOmwL/5I8pJjyVDteHtgDGcefrFUX4ccGOMKNYYc= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= @@ -199,8 +196,6 @@ github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 h1:OkMGxebDj github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs= github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= -github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= -github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE= @@ -222,8 +217,8 @@ github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= -github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= +github.com/spf13/viper v1.20.0 h1:zrxIyR3RQIOsarIrgL8+sAvALXul9jeEPa06Y0Ph6vY= +github.com/spf13/viper v1.20.0/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= From ee2c2b19e95917dc20c1b086d2a90baccafdb232 Mon Sep 17 00:00:00 2001 From: Deluan Date: Wed, 19 Mar 2025 20:18:56 -0400 Subject: [PATCH 23/51] fix(dockerfile): remove the healthcheck, it gives more headaches than benefits. Signed-off-by: Deluan --- Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 9dda15cc6..0ec64f769 100644 --- a/Dockerfile +++ b/Dockerfile @@ -138,7 +138,6 @@ ENV GODEBUG="asyncpreemptoff=1" RUN touch /.nddockerenv EXPOSE ${ND_PORT} -HEALTHCHECK CMD wget -O- http://localhost:${ND_PORT}/ping || exit 1 WORKDIR /app ENTRYPOINT ["/app/navidrome"] From cd552a55efc812a2bc9b3302125146f9a7171e66 Mon Sep 17 00:00:00 2001 From: Deluan Date: Wed, 19 Mar 2025 22:15:20 -0400 Subject: [PATCH 24/51] fix(scanner): pass datafolder and cachefolder to scanner subprocess Fix #3831 Signed-off-by: Deluan --- scanner/external.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scanner/external.go b/scanner/external.go index b00c67cb9..c4a29efa3 100644 --- a/scanner/external.go +++ b/scanner/external.go @@ -33,6 +33,8 @@ func (s *scannerExternal) scanAll(ctx context.Context, fullScan bool, progress c cmd := exec.CommandContext(ctx, exe, "scan", "--nobanner", "--subprocess", "--configfile", conf.Server.ConfigFile, + "--datafolder", conf.Server.DataFolder, + "--cachefolder", conf.Server.CacheFolder, If(fullScan, "--full", "")) in, out := io.Pipe() From 491210ac1207239292181c31fdaf1b5b00fb48c2 Mon Sep 17 00:00:00 2001 From: Deluan Date: Thu, 20 Mar 2025 12:39:40 -0400 Subject: [PATCH 25/51] fix(scanner): ignore NaN ReplayGain values Fix: https://github.com/navidrome/navidrome/issues/3858 Signed-off-by: Deluan --- model/metadata/metadata.go | 2 +- model/metadata/metadata_test.go | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/model/metadata/metadata.go b/model/metadata/metadata.go index 3d5d64dd1..471c2434c 100644 --- a/model/metadata/metadata.go +++ b/model/metadata/metadata.go @@ -120,7 +120,7 @@ func (md Metadata) first(key model.TagName) string { func float(value string, def ...float64) float64 { v, err := strconv.ParseFloat(value, 64) - if err != nil || v == math.Inf(-1) || v == math.Inf(1) { + if err != nil || v == math.Inf(-1) || math.IsInf(v, 1) || math.IsNaN(v) { if len(def) > 0 { return def[0] } diff --git a/model/metadata/metadata_test.go b/model/metadata/metadata_test.go index f3478ccba..5d9c4a3ed 100644 --- a/model/metadata/metadata_test.go +++ b/model/metadata/metadata_test.go @@ -264,6 +264,7 @@ var _ = Describe("Metadata", func() { Entry("1.2dB", "1.2dB", 1.2), Entry("Infinity", "Infinity", 0.0), Entry("Invalid value", "INVALID VALUE", 0.0), + Entry("NaN", "NaN", 0.0), ) DescribeTable("Peak", func(tagValue string, expected float64) { @@ -275,6 +276,7 @@ var _ = Describe("Metadata", func() { Entry("Invalid dB suffix", "0.7dB", 1.0), Entry("Infinity", "Infinity", 1.0), Entry("Invalid value", "INVALID VALUE", 1.0), + Entry("NaN", "NaN", 1.0), ) DescribeTable("getR128GainValue", func(tagValue string, expected float64) { From 59ece403931373a085378537da904a5d162b488f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Deluan=20Quint=C3=A3o?= Date: Thu, 20 Mar 2025 19:26:40 -0400 Subject: [PATCH 26/51] fix(server): better embedded artwork extraction with ffmpeg (#3860) - `-map 0:v` selects all video streams from the input - `-map -0:V` excludes all "main" video streams (capital V) This combination effectively selects only the attached pictures Signed-off-by: Deluan --- core/ffmpeg/ffmpeg.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/ffmpeg/ffmpeg.go b/core/ffmpeg/ffmpeg.go index bb57e5101..2e0d5a4b7 100644 --- a/core/ffmpeg/ffmpeg.go +++ b/core/ffmpeg/ffmpeg.go @@ -29,7 +29,7 @@ func New() FFmpeg { } const ( - extractImageCmd = "ffmpeg -i %s -an -vcodec copy -f image2pipe -" + extractImageCmd = "ffmpeg -i %s -map 0:v -map -0:V -vcodec copy -f image2pipe -" probeCmd = "ffmpeg %s -f ffmetadata" ) From d78c6f6a04df4f8c2b6758d0991c894e859852cc Mon Sep 17 00:00:00 2001 From: Deluan Date: Thu, 20 Mar 2025 22:10:42 -0400 Subject: [PATCH 27/51] fix(subsonic): ArtistID3 should contain list of AlbumID3 Signed-off-by: Deluan --- server/subsonic/browsing.go | 2 +- server/subsonic/filter/filters.go | 4 ++-- server/subsonic/responses/responses.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/server/subsonic/browsing.go b/server/subsonic/browsing.go index 82bf50dc5..d46c7937d 100644 --- a/server/subsonic/browsing.go +++ b/server/subsonic/browsing.go @@ -424,7 +424,7 @@ func (api *Router) buildArtist(r *http.Request, artist *model.Artist) (*response return nil, err } - a.Album = slice.MapWithArg(albums, ctx, childFromAlbum) + a.Album = slice.MapWithArg(albums, ctx, buildAlbumID3) return a, nil } diff --git a/server/subsonic/filter/filters.go b/server/subsonic/filter/filters.go index 8a333c8e2..1b5416695 100644 --- a/server/subsonic/filter/filters.go +++ b/server/subsonic/filter/filters.go @@ -48,11 +48,11 @@ func AlbumsByArtist() Options { func AlbumsByArtistID(artistId string) Options { filters := []Sqlizer{ - persistence.Exists("json_tree(Participants, '$.albumartist')", Eq{"value": artistId}), + persistence.Exists("json_tree(participants, '$.albumartist')", Eq{"value": artistId}), } if conf.Server.Subsonic.ArtistParticipations { filters = append(filters, - persistence.Exists("json_tree(Participants, '$.artist')", Eq{"value": artistId}), + persistence.Exists("json_tree(participants, '$.artist')", Eq{"value": artistId}), ) } return addDefaultFilters(Options{ diff --git a/server/subsonic/responses/responses.go b/server/subsonic/responses/responses.go index c0f499ef2..0d22ef50b 100644 --- a/server/subsonic/responses/responses.go +++ b/server/subsonic/responses/responses.go @@ -284,7 +284,7 @@ type OpenSubsonicAlbumID3 struct { type ArtistWithAlbumsID3 struct { ArtistID3 - Album []Child `xml:"album" json:"album,omitempty"` + Album []AlbumID3 `xml:"album" json:"album,omitempty"` } type AlbumWithSongsID3 struct { From 1e1dce92b6a2a508f35a30d8ff8ac60274a780ce Mon Sep 17 00:00:00 2001 From: Xabi <888924+xabirequejo@users.noreply.github.com> Date: Sat, 22 Mar 2025 17:29:43 +0100 Subject: [PATCH 28/51] fix(ui): update Basque translation (#3864) * Update Basque localisation added missing strings * Update eu.json --- resources/i18n/eu.json | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/resources/i18n/eu.json b/resources/i18n/eu.json index a28e5751d..067310c14 100644 --- a/resources/i18n/eu.json +++ b/resources/i18n/eu.json @@ -216,6 +216,7 @@ "username": "Partekatzailea:", "url": "URLa", "description": "Deskribapena", + "downloadable": "Deskargatzea ahalbidetu?", "contents": "Edukia", "expiresAt": "Iraungitze-data:", "lastVisitedAt": "Azkenekoz bisitatu zen:", @@ -223,22 +224,24 @@ "format": "Formatua", "maxBitRate": "Gehienezko bit tasa", "updatedAt": "Eguneratze-data:", - "createdAt": "Sortze-data:", - "downloadable": "Deskargatzea ahalbidetu?" - } + "createdAt": "Sortze-data:" + }, + "notifications": {}, + "actions": {} }, "missing": { - "name": "", + "name": "Fitxategia falta da|||| Fitxategiak falta dira", + "empty": "Ez da fitxategirik falta", "fields": { - "path": "", - "size": "", - "updatedAt": "" + "path": "Bidea", + "size": "Tamaina", + "updatedAt": "Desagertze-data:" }, "actions": { - "remove": "" + "remove": "Kendu" }, "notifications": { - "removed": "" + "removed": "Faltan zeuden fitxategiak kendu dira" } } }, @@ -509,4 +512,4 @@ "current_song": "Uneko abestia" } } -} \ No newline at end of file +} From 63dc0e2062723171d2b54de3b7a232f5f6b6fb16 Mon Sep 17 00:00:00 2001 From: Nicolas Derive Date: Sat, 22 Mar 2025 17:31:32 +0100 Subject: [PATCH 29/51] =?UTF-8?q?fix(ui):=20update=20Fran=C3=A7ais,=20reor?= =?UTF-8?q?der=20translation=20according=20to=20en.json=20template=20(#383?= =?UTF-8?q?9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update french translation and reorder the file the same way as the en.json template, making comparison easier. --- resources/i18n/fr.json | 108 +++++++++++++++++++++++++++++------------ 1 file changed, 77 insertions(+), 31 deletions(-) diff --git a/resources/i18n/fr.json b/resources/i18n/fr.json index 7f8403bc3..50bc0d449 100644 --- a/resources/i18n/fr.json +++ b/resources/i18n/fr.json @@ -25,8 +25,13 @@ "quality": "Qualité", "bpm": "BPM", "playDate": "Derniers joués", - "channels": "Canaux", - "createdAt": "Date d'ajout" + "createdAt": "Date d'ajout", + "grouping": "Regroupement", + "mood": "Humeur", + "participants": "Participants supplémentaires", + "tags": "Étiquettes supplémentaires", + "mappedTags": "Étiquettes correspondantes", + "rawTags": "Étiquettes brutes" }, "actions": { "addToQueue": "Ajouter à la file", @@ -46,29 +51,35 @@ "duration": "Durée", "songCount": "Nombre de pistes", "playCount": "Nombre d'écoutes", + "size": "Taille", "name": "Nom", "genre": "Genre", "compilation": "Compilation", "year": "Année", + "originalDate": "Original", + "releaseDate": "Sortie", + "releases": "Sortie |||| Sorties", + "released": "Sortie", "updatedAt": "Mis à jour le", "comment": "Commentaire", "rating": "Classement", "createdAt": "Date d'ajout", - "size": "Taille", - "originalDate": "Original", - "releaseDate": "Sortie", - "releases": "Sortie |||| Sorties", - "released": "Sortie" + "recordLabel": "Label", + "catalogNum": "Numéro de catalogue", + "releaseType": "Type", + "grouping": "Regroupement", + "media": "Média", + "mood": "Humeur" }, "actions": { "playAll": "Lire", "playNext": "Lire ensuite", "addToQueue": "Ajouter à la file", + "share": "Partager", "shuffle": "Mélanger", "addToPlaylist": "Ajouter à la playlist", "download": "Télécharger", - "info": "Plus d'informations", - "share": "Partager" + "info": "Plus d'informations" }, "lists": { "all": "Tous", @@ -86,10 +97,26 @@ "name": "Nom", "albumCount": "Nombre d'albums", "songCount": "Nombre de pistes", + "size": "Taille", "playCount": "Lectures", "rating": "Classement", "genre": "Genre", - "size": "Taille" + "role": "Rôle" + }, + "roles": { + "albumartist": "Artiste de l'album |||| Artistes de l'album", + "artist": "Artiste |||| Artistes", + "composer": "Compositeur |||| Compositeurs", + "conductor": "Chef d'orchestre |||| Chefs d'orchestre", + "lyricist": "Parolier |||| Paroliers", + "arranger": "Arrangeur |||| Arrangeurs", + "producer": "Producteur |||| Producteurs", + "director": "Réalisateur |||| Réalisateurs", + "engineer": "Ingénieur |||| Ingénieurs", + "mixer": "Mixeur |||| Mixeurs", + "remixer": "Remixeur |||| Remixeurs", + "djmixer": "Mixeur DJ |||| Mixeurs DJ", + "performer": "Interprète |||| Interprètes" } }, "user": { @@ -98,6 +125,7 @@ "userName": "Nom d'utilisateur", "isAdmin": "Administrateur", "lastLoginAt": "Dernière connexion", + "lastAccessAt": "Dernier accès", "updatedAt": "Dernière mise à jour", "name": "Nom", "password": "Mot de passe", @@ -105,8 +133,7 @@ "changePassword": "Changer le mot de passe ?", "currentPassword": "Mot de passe actuel", "newPassword": "Nouveau mot de passe", - "token": "Token", - "lastAccessAt": "Dernier accès" + "token": "Token" }, "helperTexts": { "name": "Les changements liés à votre nom ne seront reflétés qu'à la prochaine connexion" @@ -152,7 +179,7 @@ "public": "Publique", "updatedAt": "Mise à jour le", "createdAt": "Créée le", - "songCount": "Titres", + "songCount": "Morceaux", "comment": "Commentaire", "sync": "Import automatique", "path": "Importer depuis" @@ -188,6 +215,7 @@ "username": "Partagé(e) par", "url": "Lien URL", "description": "Description", + "downloadable": "Autoriser les téléchargements ?", "contents": "Contenu", "expiresAt": "Expire le", "lastVisitedAt": "Visité pour la dernière fois", @@ -195,8 +223,24 @@ "format": "Format", "maxBitRate": "Bitrate maximum", "updatedAt": "Mis à jour le", - "createdAt": "Créé le", - "downloadable": "Autoriser les téléchargements ?" + "createdAt": "Créé le" + }, + "notifications": {}, + "actions": {} + }, + "missing": { + "name": "Fichier manquant|||| Fichiers manquants", + "empty": "Aucun fichier manquant", + "fields": { + "path": "Chemin", + "size": "Taille", + "updatedAt": "A disparu le" + }, + "actions": { + "remove": "Supprimer" + }, + "notifications": { + "removed": "Fichier(s) manquant(s) supprimé(s)" } } }, @@ -235,6 +279,7 @@ "add": "Ajouter", "back": "Retour", "bulk_actions": "%{smart_count} sélectionné |||| %{smart_count} sélectionnés", + "bulk_actions_mobile": "1 |||| %{smart_count}", "cancel": "Annuler", "clear_input_value": "Vider le champ", "clone": "Dupliquer", @@ -258,7 +303,6 @@ "close_menu": "Fermer le menu", "unselect": "Désélectionner", "skip": "Ignorer", - "bulk_actions_mobile": "1 |||| %{smart_count}", "share": "Partager", "download": "Télécharger" }, @@ -273,10 +317,10 @@ "error": "Un problème est survenu", "list": "%{name}", "loading": "Chargement", - "not_found": "Page manquante", + "not_found": "Introuvable", "show": "%{name} #%{id}", "empty": "Pas encore de %{name}.", - "invite": "Voulez-vous en créer ?" + "invite": "Voulez-vous en créer un ?" }, "input": { "file": { @@ -353,29 +397,31 @@ "noPlaylistsAvailable": "Aucune playlist", "delete_user_title": "Supprimer l'utilisateur '%{name}'", "delete_user_content": "Êtes-vous sûr(e) de vouloir supprimer cet utilisateur et ses données associées (y compris ses playlists et préférences) ?", + "remove_missing_title": "Supprimer les fichiers manquants", + "remove_missing_content": "Êtes-vous sûr(e) de vouloir supprimer les fichiers manquants sélectionnés de la base de données ? Ceci supprimera définiviement toute référence à ceux-ci, y compris leurs nombres d'écoutes et leurs notations.", "notifications_blocked": "Votre navigateur bloque les notifications de ce site", "notifications_not_available": "Votre navigateur ne permet pas d'afficher les notifications sur le bureau ou vous n'accédez pas à Navidrome via HTTPS", "lastfmLinkSuccess": "Last.fm a été correctement relié et le scrobble a été activé", "lastfmLinkFailure": "Last.fm n'a pas pu être correctement relié", "lastfmUnlinkSuccess": "Last.fm n'est plus relié et le scrobble a été désactivé", "lastfmUnlinkFailure": "Erreur pendant la suppression du lien avec Last.fm", + "listenBrainzLinkSuccess": "La liaison et le scrobble avec ListenBrainz sont maintenant activés pour l'utilisateur : %{user}", + "listenBrainzLinkFailure": "Échec lors de la liaison avec ListenBrainz : %{error}", + "listenBrainzUnlinkSuccess": "La liaison et le scrobble avec ListenBrainz sont maintenant désactivés", + "listenBrainzUnlinkFailure": "Échec lors de la désactivation de la liaison avec ListenBrainz", "openIn": { "lastfm": "Ouvrir dans Last.fm", "musicbrainz": "Ouvrir dans MusicBrainz" }, "lastfmLink": "Lire plus...", - "listenBrainzLinkSuccess": "La liaison et le scrobble avec ListenBrainz sont maintenant activés pour l'utilisateur : %{user}", - "listenBrainzLinkFailure": "Échec lors de la liaison avec ListenBrainz : %{error}", - "listenBrainzUnlinkSuccess": "La liaison et le scrobble avec ListenBrainz sont maintenant désactivés", - "listenBrainzUnlinkFailure": "Échec lors de la désactivation de la liaison avec ListenBrainz", - "downloadOriginalFormat": "Télécharger au format original", "shareOriginalFormat": "Partager avec le format original", "shareDialogTitle": "Partager %{resource} '%{name}'", "shareBatchDialogTitle": "Partager 1 %{resource} |||| Partager %{smart_count} %{resource}", + "shareCopyToClipboard": "Copier vers le presse-papier : Ctrl+C, Enter", "shareSuccess": "Lien copié vers le presse-papier : %{url}", "shareFailure": "Erreur en copiant le lien %{url} vers le presse-papier", "downloadDialogTitle": "Télécharger %{resource} '%{name}' (%{size})", - "shareCopyToClipboard": "Copier vers le presse-papier : Ctrl+C, Enter" + "downloadOriginalFormat": "Télécharger au format original" }, "menu": { "library": "Bibliothèque", @@ -389,6 +435,7 @@ "language": "Langue", "defaultView": "Vue par défaut", "desktop_notifications": "Notifications de bureau", + "lastfmNotConfigured": "La clef API de Last.fm n'est pas configurée", "lastfmScrobbling": "Scrobbler vers Last.fm", "listenBrainzScrobbling": "Scrobbler vers ListenBrainz", "replaygain": "Mode ReplayGain", @@ -397,14 +444,13 @@ "none": "Désactivé", "album": "Utiliser le gain de l'album", "track": "Utiliser le gain des pistes" - }, - "lastfmNotConfigured": "La clef API de Last.fm n'est pas configurée" + } } }, "albumList": "Albums", - "about": "À propos", "playlists": "Playlists", - "sharedPlaylists": "Playlists partagées" + "sharedPlaylists": "Playlists partagées", + "about": "À propos" }, "player": { "playListsText": "File de lecture", @@ -459,10 +505,10 @@ "toggle_play": "Lecture/Pause", "prev_song": "Morceau précédent", "next_song": "Morceau suivant", + "current_song": "Aller à la chanson en cours", "vol_up": "Augmenter le volume", "vol_down": "Baisser le volume", - "toggle_love": "Ajouter/Enlever le morceau des favoris", - "current_song": "Aller à la chanson en cours" + "toggle_love": "Ajouter/Enlever le morceau des favoris" } } -} \ No newline at end of file +} From be7cb59dc5255b845f491326ce936e7ab6165819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Deluan=20Quint=C3=A3o?= Date: Sat, 22 Mar 2025 12:34:35 -0400 Subject: [PATCH 30/51] fix(scanner): allow disabling splitting with the `Tags` config option (#3869) Signed-off-by: Deluan --- model/metadata/map_participants.go | 12 ++++++++++-- model/tag_mappings.go | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/model/metadata/map_participants.go b/model/metadata/map_participants.go index 9305d8791..a871f64fa 100644 --- a/model/metadata/map_participants.go +++ b/model/metadata/map_participants.go @@ -176,7 +176,11 @@ func (md Metadata) getRoleValues(role model.TagName) []string { if len(values) == 0 { return nil } - if conf := model.TagRolesConf(); len(conf.Split) > 0 { + conf := model.TagMainMappings()[role] + if conf.Split == nil { + conf = model.TagRolesConf() + } + if len(conf.Split) > 0 { values = conf.SplitTagValue(values) return filterDuplicatedOrEmptyValues(values) } @@ -193,7 +197,11 @@ func (md Metadata) getArtistValues(single, multi model.TagName) []string { if len(vSingle) != 1 { return vSingle } - if conf := model.TagArtistsConf(); len(conf.Split) > 0 { + conf := model.TagMainMappings()[single] + if conf.Split == nil { + conf = model.TagArtistsConf() + } + if len(conf.Split) > 0 { vSingle = conf.SplitTagValue(vSingle) return filterDuplicatedOrEmptyValues(vSingle) } diff --git a/model/tag_mappings.go b/model/tag_mappings.go index d8caa0c5d..d11b58fdc 100644 --- a/model/tag_mappings.go +++ b/model/tag_mappings.go @@ -201,7 +201,7 @@ func loadTagMappings() { aliases = oldValue.Aliases } split := cfg.Split - if len(split) == 0 { + if split == nil { split = oldValue.Split } c := TagConf{ From b386981b7f06b00ab154ba2136d4a316c6a08558 Mon Sep 17 00:00:00 2001 From: Deluan Date: Sat, 22 Mar 2025 15:07:51 -0400 Subject: [PATCH 31/51] fix(scanner): better log message when AutoImportPlaylists is disabled Fix #3861 Signed-off-by: Deluan --- scanner/phase_4_playlists.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scanner/phase_4_playlists.go b/scanner/phase_4_playlists.go index c3e76cb8c..c98b51ee6 100644 --- a/scanner/phase_4_playlists.go +++ b/scanner/phase_4_playlists.go @@ -45,8 +45,12 @@ func (p *phasePlaylists) producer() ppl.Producer[*model.Folder] { } func (p *phasePlaylists) produce(put func(entry *model.Folder)) error { + if !conf.Server.AutoImportPlaylists { + log.Info(p.ctx, "Playlists will not be imported, AutoImportPlaylists is set to false") + return nil + } u, _ := request.UserFrom(p.ctx) - if !conf.Server.AutoImportPlaylists || !u.IsAdmin { + if !u.IsAdmin { log.Warn(p.ctx, "Playlists will not be imported, as there are no admin users yet, "+ "Please create an admin user first, and then update the playlists for them to be imported") return nil From 3f9d17349594042997dd33835bf51552680b29ce Mon Sep 17 00:00:00 2001 From: Deluan Date: Sat, 22 Mar 2025 15:48:07 -0400 Subject: [PATCH 32/51] fix(scanner): support ID3v2 embedded images in WAV files Fix #3867 Signed-off-by: Deluan --- adapters/taglib/taglib_wrapper.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/adapters/taglib/taglib_wrapper.cpp b/adapters/taglib/taglib_wrapper.cpp index 188a8b7d7..4c5a9fa1e 100644 --- a/adapters/taglib/taglib_wrapper.cpp +++ b/adapters/taglib/taglib_wrapper.cpp @@ -201,41 +201,42 @@ int taglib_read(const FILENAME_CHAR_T *filename, unsigned long id) { char has_cover(const TagLib::FileRef f) { char hasCover = 0; // ----- MP3 - if (TagLib::MPEG::File * - mp3File{dynamic_cast(f.file())}) { + if (TagLib::MPEG::File * mp3File{dynamic_cast(f.file())}) { if (mp3File->ID3v2Tag()) { const auto &frameListMap{mp3File->ID3v2Tag()->frameListMap()}; hasCover = !frameListMap["APIC"].isEmpty(); } } // ----- FLAC - else if (TagLib::FLAC::File * - flacFile{dynamic_cast(f.file())}) { + else if (TagLib::FLAC::File * flacFile{dynamic_cast(f.file())}) { hasCover = !flacFile->pictureList().isEmpty(); } // ----- MP4 - else if (TagLib::MP4::File * - mp4File{dynamic_cast(f.file())}) { + else if (TagLib::MP4::File * mp4File{dynamic_cast(f.file())}) { auto &coverItem{mp4File->tag()->itemMap()["covr"]}; TagLib::MP4::CoverArtList coverArtList{coverItem.toCoverArtList()}; hasCover = !coverArtList.isEmpty(); } // ----- Ogg - else if (TagLib::Ogg::Vorbis::File * - vorbisFile{dynamic_cast(f.file())}) { + else if (TagLib::Ogg::Vorbis::File * vorbisFile{dynamic_cast(f.file())}) { hasCover = !vorbisFile->tag()->pictureList().isEmpty(); } // ----- Opus - else if (TagLib::Ogg::Opus::File * - opusFile{dynamic_cast(f.file())}) { + else if (TagLib::Ogg::Opus::File * opusFile{dynamic_cast(f.file())}) { hasCover = !opusFile->tag()->pictureList().isEmpty(); } // ----- WMA - if (TagLib::ASF::File * - asfFile{dynamic_cast(f.file())}) { + else if (TagLib::ASF::File * asfFile{dynamic_cast(f.file())}) { const TagLib::ASF::Tag *tag{asfFile->tag()}; hasCover = tag && tag->attributeListMap().contains("WM/Picture"); } + // ----- WAV + else if (TagLib::RIFF::WAV::File * wavFile{ dynamic_cast(f.file()) }) { + if (wavFile->hasID3v2Tag()) { + const auto& frameListMap{ wavFile->ID3v2Tag()->frameListMap() }; + hasCover = !frameListMap["APIC"].isEmpty(); + } + } return hasCover; } From 296259d781ff2ff12b9dbed3231164ad19fe4004 Mon Sep 17 00:00:00 2001 From: Deluan Date: Sat, 22 Mar 2025 15:48:29 -0400 Subject: [PATCH 33/51] feat(ui): show bitDepth in song info dialog Signed-off-by: Deluan --- resources/i18n/pt.json | 1 + ui/src/common/SongInfo.jsx | 3 ++- ui/src/i18n/en.json | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/resources/i18n/pt.json b/resources/i18n/pt.json index c3c65ca57..d856391ff 100644 --- a/resources/i18n/pt.json +++ b/resources/i18n/pt.json @@ -18,6 +18,7 @@ "size": "Tamanho", "updatedAt": "Últ. Atualização", "bitRate": "Bitrate", + "bitDepth": "Profundidade de bits", "discSubtitle": "Sub-título do disco", "starred": "Favorita", "comment": "Comentário", diff --git a/ui/src/common/SongInfo.jsx b/ui/src/common/SongInfo.jsx index d94685633..5adc1ebf0 100644 --- a/ui/src/common/SongInfo.jsx +++ b/ui/src/common/SongInfo.jsx @@ -74,6 +74,7 @@ export const SongInfo = (props) => { ), compilation: , bitRate: , + bitDepth: , channels: , size: , updatedAt: , @@ -91,7 +92,7 @@ export const SongInfo = (props) => { roles.push([name, record.participants[name].length]) } - const optionalFields = ['discSubtitle', 'comment', 'bpm', 'genre'] + const optionalFields = ['discSubtitle', 'comment', 'bpm', 'genre', 'bitDepth'] optionalFields.forEach((field) => { !record[field] && delete data[field] }) diff --git a/ui/src/i18n/en.json b/ui/src/i18n/en.json index cd377932c..678e42cd4 100644 --- a/ui/src/i18n/en.json +++ b/ui/src/i18n/en.json @@ -18,6 +18,7 @@ "size": "File size", "updatedAt": "Updated at", "bitRate": "Bit rate", + "bitDepth": "Bit depth", "channels": "Channels", "discSubtitle": "Disc Subtitle", "starred": "Favourite", From 264d73d73e2169b2e865e123ec52997593ce6492 Mon Sep 17 00:00:00 2001 From: Deluan Date: Sat, 22 Mar 2025 17:08:03 -0400 Subject: [PATCH 34/51] fix(server): don't break if the ND_CONFIGFILE does not exist Signed-off-by: Deluan --- conf/configuration.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/conf/configuration.go b/conf/configuration.go index 9abb7e163..6f4b2d594 100644 --- a/conf/configuration.go +++ b/conf/configuration.go @@ -577,9 +577,17 @@ func InitConfig(cfgFile string) { } } +// getConfigFile returns the path to the config file, either from the flag or from the environment variable. +// If it is defined in the environment variable, it will check if the file exists. func getConfigFile(cfgFile string) string { if cfgFile != "" { return cfgFile } - return os.Getenv("ND_CONFIGFILE") + cfgFile = os.Getenv("ND_CONFIGFILE") + if cfgFile != "" { + if _, err := os.Stat(cfgFile); err == nil { + return cfgFile + } + } + return "" } From 1c691ac0e6d4b30feb0e491d1268988180877558 Mon Sep 17 00:00:00 2001 From: Deluan Date: Sat, 22 Mar 2025 17:33:56 -0400 Subject: [PATCH 35/51] feat(docker): automatically loads a navidrome.toml file from /data, if available Signed-off-by: Deluan --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 0ec64f769..4b4c3d18c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -133,6 +133,7 @@ COPY --from=build /out/navidrome /app/ VOLUME ["/data", "/music"] ENV ND_MUSICFOLDER=/music ENV ND_DATAFOLDER=/data +ENV ND_CONFIGFILE=/data/navidrome.toml ENV ND_PORT=4533 ENV GODEBUG="asyncpreemptoff=1" RUN touch /.nddockerenv From 57e0f6d3ea2212650c4716836d06fbc29d26405e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Deluan=20Quint=C3=A3o?= Date: Sun, 23 Mar 2025 10:53:21 -0400 Subject: [PATCH 36/51] feat(server): custom ArtistJoiner config (#3873) * feat(server): custom ArtistJoiner config Signed-off-by: Deluan * refactor(ui): organize ArtistLinkField, add tests Signed-off-by: Deluan * feat(ui): use display artist * feat(ui): use display artist Signed-off-by: Deluan --------- Signed-off-by: Deluan --- conf/configuration.go | 2 + model/metadata/map_participants.go | 5 +- ui/src/common/ArtistLinkField.jsx | 78 +++++--- ui/src/common/ArtistLinkField.test.jsx | 238 +++++++++++++++++++++++++ 4 files changed, 297 insertions(+), 26 deletions(-) create mode 100644 ui/src/common/ArtistLinkField.test.jsx diff --git a/conf/configuration.go b/conf/configuration.go index 6f4b2d594..a75581fca 100644 --- a/conf/configuration.go +++ b/conf/configuration.go @@ -129,6 +129,7 @@ type scannerOptions struct { WatcherWait time.Duration ScanOnStartup bool Extractor string + ArtistJoiner string GenreSeparators string // Deprecated: Use Tags.genre.Split instead GroupAlbumReleases bool // Deprecated: Use PID.Album instead } @@ -495,6 +496,7 @@ func init() { viper.SetDefault("scanner.extractor", consts.DefaultScannerExtractor) viper.SetDefault("scanner.watcherwait", consts.DefaultWatcherWait) viper.SetDefault("scanner.scanonstartup", true) + viper.SetDefault("scanner.artistjoiner", consts.ArtistJoiner) viper.SetDefault("scanner.genreseparators", "") viper.SetDefault("scanner.groupalbumreleases", false) diff --git a/model/metadata/map_participants.go b/model/metadata/map_participants.go index a871f64fa..e8be6aaab 100644 --- a/model/metadata/map_participants.go +++ b/model/metadata/map_participants.go @@ -4,6 +4,7 @@ import ( "cmp" "strings" + "github.com/navidrome/navidrome/conf" "github.com/navidrome/navidrome/consts" "github.com/navidrome/navidrome/model" "github.com/navidrome/navidrome/utils/str" @@ -210,8 +211,8 @@ func (md Metadata) getArtistValues(single, multi model.TagName) []string { func (md Metadata) mapDisplayName(singularTagName, pluralTagName model.TagName) string { return cmp.Or( - strings.Join(md.tags[singularTagName], consts.ArtistJoiner), - strings.Join(md.tags[pluralTagName], consts.ArtistJoiner), + strings.Join(md.tags[singularTagName], conf.Server.Scanner.ArtistJoiner), + strings.Join(md.tags[pluralTagName], conf.Server.Scanner.ArtistJoiner), ) } diff --git a/ui/src/common/ArtistLinkField.jsx b/ui/src/common/ArtistLinkField.jsx index 053cd25aa..60832eb40 100644 --- a/ui/src/common/ArtistLinkField.jsx +++ b/ui/src/common/ArtistLinkField.jsx @@ -63,38 +63,70 @@ const parseAndReplaceArtists = ( export const ArtistLinkField = ({ record, className, limit, source }) => { const role = source.toLowerCase() - const artists = record['participants'] - ? record['participants'][role] - : [{ name: record[source], id: record[source + 'Id'] }] - // When showing artists for a track, add any remixers to the list of artists - if ( - role === 'artist' && - record['participants'] && - record['participants']['remixer'] - ) { - record['participants']['remixer'].forEach((remixer) => { - artists.push(remixer) - }) - } + // Get artists array with fallback + let artists = record?.participants?.[role] || [] + const remixers = + role === 'artist' && record?.participants?.remixer + ? record.participants.remixer.slice(0, 2) + : [] - if (role === 'albumartist') { + // Use parseAndReplaceArtists for artist and albumartist roles + if ((role === 'artist' || role === 'albumartist') && record[source]) { const artistsLinks = parseAndReplaceArtists( record[source], artists, className, ) + if (artistsLinks.length > 0) { + // For artist role, append remixers if available, avoiding duplicates + if (role === 'artist' && remixers.length > 0) { + // Track which artists are already displayed to avoid duplicates + const displayedArtistIds = new Set( + artists.map((artist) => artist.id).filter(Boolean), + ) + + // Only add remixers that aren't already in the artists list + const uniqueRemixers = remixers.filter( + (remixer) => remixer.id && !displayedArtistIds.has(remixer.id), + ) + + if (uniqueRemixers.length > 0) { + artistsLinks.push(' • ') + uniqueRemixers.forEach((remixer, index) => { + if (index > 0) artistsLinks.push(' • ') + artistsLinks.push( + , + ) + }) + } + } + return
{artistsLinks}
} } - // Dedupe artists, only shows the first 3 + // Fall back to regular handling + if (artists.length === 0 && record[source]) { + artists = [{ name: record[source], id: record[source + 'Id'] }] + } + + // For artist role, combine artists and remixers before deduplication + const allArtists = role === 'artist' ? [...artists, ...remixers] : artists + + // Dedupe artists and collect subroles const seen = new Map() const dedupedArtists = [] let limitedShow = false - for (const artist of artists ?? []) { + for (const artist of allArtists) { + if (!artist?.id) continue + if (!seen.has(artist.id)) { if (dedupedArtists.length < limit) { seen.set(artist.id, dedupedArtists.length) @@ -107,22 +139,20 @@ export const ArtistLinkField = ({ record, className, limit, source }) => { } } else { const position = seen.get(artist.id) - - if (position !== -1) { - const existing = dedupedArtists[position] - if (artist.subRole && !existing.subroles.includes(artist.subRole)) { - existing.subroles.push(artist.subRole) - } + const existing = dedupedArtists[position] + if (artist.subRole && !existing.subroles.includes(artist.subRole)) { + existing.subroles.push(artist.subRole) } } } + // Create artist links const artistsList = dedupedArtists.map((artist) => ( - + )) if (limitedShow) { - artistsList.push(...) + artistsList.push(...) } return <>{intersperse(artistsList, ' • ')} diff --git a/ui/src/common/ArtistLinkField.test.jsx b/ui/src/common/ArtistLinkField.test.jsx new file mode 100644 index 000000000..09fdf64a4 --- /dev/null +++ b/ui/src/common/ArtistLinkField.test.jsx @@ -0,0 +1,238 @@ +import React from 'react' +import { render, screen } from '@testing-library/react' +import { describe, it, expect, beforeEach, vi } from 'vitest' +import { ArtistLinkField } from './ArtistLinkField' +import { intersperse } from '../utils/index.js' + +// Mock dependencies +vi.mock('react-redux', () => ({ + useDispatch: vi.fn(() => vi.fn()), +})) + +vi.mock('./useGetHandleArtistClick', () => ({ + useGetHandleArtistClick: vi.fn(() => (id) => `/artist/${id}`), +})) + +vi.mock('../utils/index.js', () => ({ + intersperse: vi.fn((arr) => arr), +})) + +vi.mock('@material-ui/core', () => ({ + withWidth: () => (Component) => { + const WithWidthComponent = (props) => + WithWidthComponent.displayName = `WithWidth(${Component.displayName || Component.name || 'Component'})` + return WithWidthComponent + }, +})) + +vi.mock('react-admin', () => ({ + Link: ({ children, to, ...props }) => ( + + {children} + + ), +})) + +describe('ArtistLinkField', () => { + beforeEach(() => { + vi.clearAllMocks() + }) + + describe('when rendering artists', () => { + it('renders artists from participants when available', () => { + const record = { + participants: { + artist: [ + { id: '1', name: 'Artist 1' }, + { id: '2', name: 'Artist 2' }, + ], + }, + } + + render() + + expect(screen.getByText('Artist 1')).toBeInTheDocument() + expect(screen.getByText('Artist 2')).toBeInTheDocument() + }) + + it('falls back to record[source] when participants not available', () => { + const record = { + artist: 'Fallback Artist', + artistId: '123', + } + + render() + + expect(screen.getByText('Fallback Artist')).toBeInTheDocument() + }) + + it('handles empty artists array', () => { + const record = { + participants: { + artist: [], + }, + } + + render() + + expect(intersperse).toHaveBeenCalledWith([], ' • ') + }) + }) + + describe('when handling remixers', () => { + it('adds remixers when showing artist role', () => { + const record = { + participants: { + artist: [{ id: '1', name: 'Artist 1' }], + remixer: [{ id: '2', name: 'Remixer 1' }], + }, + } + + render() + + expect(screen.getByText('Artist 1')).toBeInTheDocument() + expect(screen.getByText('Remixer 1')).toBeInTheDocument() + }) + + it('limits remixers to maximum of 2', () => { + const record = { + participants: { + artist: [{ id: '1', name: 'Artist 1' }], + remixer: [ + { id: '2', name: 'Remixer 1' }, + { id: '3', name: 'Remixer 2' }, + { id: '4', name: 'Remixer 3' }, + ], + }, + } + + render() + + expect(screen.getByText('Artist 1')).toBeInTheDocument() + expect(screen.getByText('Remixer 1')).toBeInTheDocument() + expect(screen.getByText('Remixer 2')).toBeInTheDocument() + expect(screen.queryByText('Remixer 3')).not.toBeInTheDocument() + }) + + it('deduplicates artists and remixers', () => { + const record = { + participants: { + artist: [{ id: '1', name: 'Duplicate Person' }], + remixer: [{ id: '1', name: 'Duplicate Person' }], + }, + } + + render() + + const links = screen.getAllByRole('link') + expect(links).toHaveLength(1) + expect(links[0]).toHaveTextContent('Duplicate Person') + }) + }) + + describe('when using parseAndReplaceArtists', () => { + it('uses parseAndReplaceArtists when role is albumartist', () => { + const record = { + albumArtist: 'Group Artist', + participants: { + albumartist: [{ id: '1', name: 'Group Artist' }], + }, + } + + render() + + expect(screen.getByText('Group Artist')).toBeInTheDocument() + expect(screen.getByRole('link')).toHaveAttribute('href', '/artist/1') + }) + + it('uses parseAndReplaceArtists when role is artist', () => { + const record = { + artist: 'Main Artist', + participants: { + artist: [{ id: '1', name: 'Main Artist' }], + }, + } + + render() + + expect(screen.getByText('Main Artist')).toBeInTheDocument() + expect(screen.getByRole('link')).toHaveAttribute('href', '/artist/1') + }) + + it('adds remixers after parseAndReplaceArtists for artist role', () => { + const record = { + artist: 'Main Artist', + participants: { + artist: [{ id: '1', name: 'Main Artist' }], + remixer: [{ id: '2', name: 'Remixer 1' }], + }, + } + + render() + + const links = screen.getAllByRole('link') + expect(links).toHaveLength(2) + expect(links[0]).toHaveAttribute('href', '/artist/1') + expect(links[1]).toHaveAttribute('href', '/artist/2') + }) + }) + + describe('when handling artist deduplication', () => { + it('deduplicates artists with the same id', () => { + const record = { + participants: { + artist: [ + { id: '1', name: 'Duplicate Artist' }, + { id: '1', name: 'Duplicate Artist', subRole: 'Vocals' }, + ], + }, + } + + render() + + const links = screen.getAllByRole('link') + expect(links).toHaveLength(1) + expect(links[0]).toHaveTextContent('Duplicate Artist (Vocals)') + }) + + it('aggregates subroles for the same artist', () => { + const record = { + participants: { + artist: [ + { id: '1', name: 'Multi-Role Artist', subRole: 'Vocals' }, + { id: '1', name: 'Multi-Role Artist', subRole: 'Guitar' }, + ], + }, + } + + render() + + expect( + screen.getByText('Multi-Role Artist (Vocals, Guitar)'), + ).toBeInTheDocument() + }) + }) + + describe('when limiting displayed artists', () => { + it('limits the number of artists displayed', () => { + const record = { + participants: { + artist: [ + { id: '1', name: 'Artist 1' }, + { id: '2', name: 'Artist 2' }, + { id: '3', name: 'Artist 3' }, + { id: '4', name: 'Artist 4' }, + ], + }, + } + + render() + + expect(screen.getByText('Artist 1')).toBeInTheDocument() + expect(screen.getByText('Artist 2')).toBeInTheDocument() + expect(screen.getByText('Artist 3')).toBeInTheDocument() + expect(screen.queryByText('Artist 4')).not.toBeInTheDocument() + expect(screen.getByText('...')).toBeInTheDocument() + }) + }) +}) From 223e88d481b4b302b15bdccc464bf5615600e54f Mon Sep 17 00:00:00 2001 From: Deluan Date: Sun, 23 Mar 2025 11:37:20 -0400 Subject: [PATCH 37/51] chore: remove some BFR-related TODOs that are not valid anymore Signed-off-by: Deluan --- conf/configuration.go | 1 - core/artwork/artwork_internal_test.go | 2 +- core/scrobbler/play_tracker_test.go | 1 - model/album.go | 2 +- model/mediafile.go | 4 ++-- persistence/album_repository.go | 1 - persistence/artist_repository.go | 3 +-- persistence/mediafile_repository.go | 1 - persistence/persistence_suite_test.go | 7 ------- persistence/playlist_repository_test.go | 2 +- scanner/controller.go | 1 - server/subsonic/helpers.go | 1 - 12 files changed, 6 insertions(+), 20 deletions(-) diff --git a/conf/configuration.go b/conf/configuration.go index a75581fca..08008105d 100644 --- a/conf/configuration.go +++ b/conf/configuration.go @@ -306,7 +306,6 @@ func Load(noConfigDump bool) { disableExternalServices() } - // BFR Remove before release if Server.Scanner.Extractor != consts.DefaultScannerExtractor { log.Warn(fmt.Sprintf("Extractor '%s' is not implemented, using 'taglib'", Server.Scanner.Extractor)) Server.Scanner.Extractor = consts.DefaultScannerExtractor diff --git a/core/artwork/artwork_internal_test.go b/core/artwork/artwork_internal_test.go index 65228ace5..462027082 100644 --- a/core/artwork/artwork_internal_test.go +++ b/core/artwork/artwork_internal_test.go @@ -15,7 +15,7 @@ import ( . "github.com/onsi/gomega" ) -// BFR Fix tests +// TODO Fix tests var _ = XDescribe("Artwork", func() { var aw *artwork var ds model.DataStore diff --git a/core/scrobbler/play_tracker_test.go b/core/scrobbler/play_tracker_test.go index a4bd7cec2..da1f96864 100644 --- a/core/scrobbler/play_tracker_test.go +++ b/core/scrobbler/play_tracker_test.go @@ -239,7 +239,6 @@ func (f *fakeScrobbler) Scrobble(ctx context.Context, userId string, s Scrobble) return nil } -// BFR This is duplicated in a few places func _p(id, name string, sortName ...string) model.Participant { p := model.Participant{Artist: model.Artist{ID: id, Name: name}} if len(sortName) > 0 { diff --git a/model/album.go b/model/album.go index 4ac976e24..c9dc022cb 100644 --- a/model/album.go +++ b/model/album.go @@ -17,7 +17,7 @@ type Album struct { Name string `structs:"name" json:"name"` EmbedArtPath string `structs:"embed_art_path" json:"-"` AlbumArtistID string `structs:"album_artist_id" json:"albumArtistId"` // Deprecated, use Participants - // BFR Rename to AlbumArtistDisplayName + // AlbumArtist is the display name used for the album artist. AlbumArtist string `structs:"album_artist" json:"albumArtist"` MaxYear int `structs:"max_year" json:"maxYear"` MinYear int `structs:"min_year" json:"minYear"` diff --git a/model/mediafile.go b/model/mediafile.go index 795657466..896442436 100644 --- a/model/mediafile.go +++ b/model/mediafile.go @@ -31,10 +31,10 @@ type MediaFile struct { Title string `structs:"title" json:"title"` Album string `structs:"album" json:"album"` ArtistID string `structs:"artist_id" json:"artistId"` // Deprecated: Use Participants instead - // BFR Rename to ArtistDisplayName + // Artist is the display name used for the artist. Artist string `structs:"artist" json:"artist"` AlbumArtistID string `structs:"album_artist_id" json:"albumArtistId"` // Deprecated: Use Participants instead - // BFR Rename to AlbumArtistDisplayName + // AlbumArtist is the display name used for the album artist. AlbumArtist string `structs:"album_artist" json:"albumArtist"` AlbumID string `structs:"album_id" json:"albumId"` HasCoverArt bool `structs:"has_cover_art" json:"hasCoverArt"` diff --git a/persistence/album_repository.go b/persistence/album_repository.go index b29a44701..0f2a46dec 100644 --- a/persistence/album_repository.go +++ b/persistence/album_repository.go @@ -184,7 +184,6 @@ func allRolesFilter(_ string, value interface{}) Sqlizer { func (r *albumRepository) CountAll(options ...model.QueryOptions) (int64, error) { sql := r.newSelect() sql = r.withAnnotation(sql, "album.id") - // BFR WithParticipants (for filtering by name)? return r.count(sql, options...) } diff --git a/persistence/artist_repository.go b/persistence/artist_repository.go index dd3f31b00..7602be381 100644 --- a/persistence/artist_repository.go +++ b/persistence/artist_repository.go @@ -85,7 +85,7 @@ func (a *dbArtist) PostMapArgs(m map[string]any) error { m["full_text"] = formatFullText(a.Name, a.SortArtistName) // Do not override the sort_artist_name and mbz_artist_id fields if they are empty - // BFR: Better way to handle this? + // TODO: Better way to handle this? if v, ok := m["sort_artist_name"]; !ok || v.(string) == "" { delete(m, "sort_artist_name") } @@ -134,7 +134,6 @@ func roleFilter(_ string, role any) Sqlizer { func (r *artistRepository) selectArtist(options ...model.QueryOptions) SelectBuilder { query := r.newSelect(options...).Columns("artist.*") query = r.withAnnotation(query, "artist.id") - // BFR How to handle counts and sizes (per role)? return query } diff --git a/persistence/mediafile_repository.go b/persistence/mediafile_repository.go index ef4507877..ebf07ce17 100644 --- a/persistence/mediafile_repository.go +++ b/persistence/mediafile_repository.go @@ -105,7 +105,6 @@ var mediaFileFilter = sync.OnceValue(func() map[string]filterFunc { func (r *mediaFileRepository) CountAll(options ...model.QueryOptions) (int64, error) { query := r.newSelect() query = r.withAnnotation(query, "media_file.id") - // BFR WithParticipants (for filtering by name)? return r.count(query, options...) } diff --git a/persistence/persistence_suite_test.go b/persistence/persistence_suite_test.go index 609904b49..43e4c292b 100644 --- a/persistence/persistence_suite_test.go +++ b/persistence/persistence_suite_test.go @@ -29,13 +29,6 @@ func TestPersistence(t *testing.T) { RunSpecs(t, "Persistence Suite") } -// BFR Test tags -//var ( -// genreElectronic = model.Genre{ID: "gn-1", Name: "Electronic"} -// genreRock = model.Genre{ID: "gn-2", Name: "Rock"} -// testGenres = model.Genres{genreElectronic, genreRock} -//) - func mf(mf model.MediaFile) model.MediaFile { mf.Tags = model.Tags{} mf.LibraryID = 1 diff --git a/persistence/playlist_repository_test.go b/persistence/playlist_repository_test.go index 85a87ece7..5a82964c9 100644 --- a/persistence/playlist_repository_test.go +++ b/persistence/playlist_repository_test.go @@ -145,7 +145,7 @@ var _ = Describe("PlaylistRepository", func() { }) }) - // BFR Validate these tests + // TODO Validate these tests XContext("child smart playlists", func() { When("refresh day has expired", func() { It("should refresh tracks for smart playlist referenced in parent smart playlist criteria", func() { diff --git a/scanner/controller.go b/scanner/controller.go index 84ea8e606..e3e008483 100644 --- a/scanner/controller.go +++ b/scanner/controller.go @@ -98,7 +98,6 @@ type ProgressInfo struct { type scanner interface { scanAll(ctx context.Context, fullScan bool, progress chan<- *ProgressInfo) - // BFR: scanFolders(ctx context.Context, lib model.Lib, folders []string, progress chan<- *ScannerStatus) } type controller struct { diff --git a/server/subsonic/helpers.go b/server/subsonic/helpers.go index fa98a985b..56b65f894 100644 --- a/server/subsonic/helpers.go +++ b/server/subsonic/helpers.go @@ -235,7 +235,6 @@ func osChildFromMediaFile(ctx context.Context, mf model.MediaFile) *responses.Op child.BitDepth = int32(mf.BitDepth) child.Genres = toItemGenres(mf.Genres) child.Moods = mf.Tags.Values(model.TagMood) - // BFR What if Child is an Album and not a Song? child.DisplayArtist = mf.Artist child.Artists = artistRefs(mf.Participants[model.RoleArtist]) child.DisplayAlbumArtist = mf.AlbumArtist From 1806552ef67994ddbf79ca35c223a1739bfb3a81 Mon Sep 17 00:00:00 2001 From: Deluan Date: Sun, 23 Mar 2025 11:53:43 -0400 Subject: [PATCH 38/51] chore: remove more outdated TODOs Signed-off-by: Deluan --- model/criteria/operators_test.go | 1 - model/player.go | 1 - server/subsonic/browsing.go | 4 +--- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/model/criteria/operators_test.go b/model/criteria/operators_test.go index 575b9c3f8..e6082de44 100644 --- a/model/criteria/operators_test.go +++ b/model/criteria/operators_test.go @@ -46,7 +46,6 @@ var _ = Describe("Operators", func() { Entry("notInPlaylist", NotInPlaylist{"id": "deadbeef-dead-beef"}, "media_file.id NOT IN "+ "(SELECT media_file_id FROM playlist_tracks pl LEFT JOIN playlist on pl.playlist_id = playlist.id WHERE (pl.playlist_id = ? AND playlist.public = ?))", "deadbeef-dead-beef", 1), - // TODO These may be flaky Entry("inTheLast", InTheLast{"lastPlayed": 30}, "annotation.play_date > ?", StartOfPeriod(30, time.Now())), Entry("notInTheLast", NotInTheLast{"lastPlayed": 30}, "(annotation.play_date < ? OR annotation.play_date IS NULL)", StartOfPeriod(30, time.Now())), diff --git a/model/player.go b/model/player.go index ee7346b66..39ea99d1a 100644 --- a/model/player.go +++ b/model/player.go @@ -28,5 +28,4 @@ type PlayerRepository interface { Put(p *Player) error CountAll(...QueryOptions) (int64, error) CountByClient(...QueryOptions) (map[string]int64, error) - // TODO: Add CountAll method. Useful at least for metrics. } diff --git a/server/subsonic/browsing.go b/server/subsonic/browsing.go index d46c7937d..edc45a7c7 100644 --- a/server/subsonic/browsing.go +++ b/server/subsonic/browsing.go @@ -252,9 +252,7 @@ func (api *Router) GetSong(r *http.Request) (*responses.Subsonic, error) { func (api *Router) GetGenres(r *http.Request) (*responses.Subsonic, error) { ctx := r.Context() - // TODO Put back when album_count is available - //genres, err := api.ds.Genre(ctx).GetAll(model.QueryOptions{Sort: "song_count, album_count, name desc", Order: "desc"}) - genres, err := api.ds.Genre(ctx).GetAll(model.QueryOptions{Sort: "song_count, name desc", Order: "desc"}) + genres, err := api.ds.Genre(ctx).GetAll(model.QueryOptions{Sort: "song_count, album_count, name desc", Order: "desc"}) if err != nil { log.Error(r, err) return nil, err From 3a0ce6aafa53f87b29e82ff526785215e41c86d8 Mon Sep 17 00:00:00 2001 From: Deluan Date: Sun, 23 Mar 2025 12:36:38 -0400 Subject: [PATCH 39/51] fix(scanner): elapsed time for folder processing is wrong in the logs Signed-off-by: Deluan --- scanner/walk_dir_tree.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scanner/walk_dir_tree.go b/scanner/walk_dir_tree.go index 323ba0392..ba87f2628 100644 --- a/scanner/walk_dir_tree.go +++ b/scanner/walk_dir_tree.go @@ -70,7 +70,6 @@ func newFolderEntry(job *scanJob, path string) *folderEntry { albumIDMap: make(map[string]string), updTime: job.popLastUpdate(id), } - f.elapsed.Start() return f } @@ -115,6 +114,8 @@ func walkFolder(ctx context.Context, job *scanJob, currentFolder string, ignoreP "images", maps.Keys(folder.imageFiles), "playlists", folder.numPlaylists, "imagesUpdatedAt", folder.imagesUpdatedAt, "updTime", folder.updTime, "modTime", folder.modTime, "numChildren", len(children)) folder.path = dir + folder.elapsed.Start() + results <- folder return nil From d331ee904b06fbc7ef4ecc54044f0f2ad3a61c9d Mon Sep 17 00:00:00 2001 From: Deluan Date: Mon, 24 Mar 2025 15:08:17 -0400 Subject: [PATCH 40/51] fix(ui): sort playlist by `year` fix #3878 Signed-off-by: Deluan --- persistence/playlist_track_repository.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/persistence/playlist_track_repository.go b/persistence/playlist_track_repository.go index 69a2449c6..ea1977f3d 100644 --- a/persistence/playlist_track_repository.go +++ b/persistence/playlist_track_repository.go @@ -51,11 +51,13 @@ func (r *playlistRepository) Tracks(playlistId string, refreshSmartPlaylist bool }) p.setSortMappings( map[string]string{ - "id": "playlist_tracks.id", - "artist": "order_artist_name", - "album": "order_album_name, order_album_artist_name", - "title": "order_title", - "duration": "duration", // To make sure the field will be whitelisted + "id": "playlist_tracks.id", + "artist": "order_artist_name", + "album": "order_album_name, order_album_artist_name", + "title": "order_title", + // To make sure these fields will be whitelisted + "duration": "duration", + "year": "year", }, "f") // TODO I don't like this solution, but I won't change it now as it's not the focus of BFR. From 55ce28b2c63599c38bd0eae066caa457b6605129 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Deluan=20Quint=C3=A3o?= Date: Mon, 24 Mar 2025 15:22:59 -0400 Subject: [PATCH 41/51] fix(bfr): force upgrade to read all folders. (#3871) * chore(scanner): add trace logs Signed-off-by: Deluan * fix(bfr): force upgrade to read all folders. It was skipping folders for certain timezones Signed-off-by: Deluan --------- Signed-off-by: Deluan --- db/migrations/20241026183640_support_new_scanner.go | 4 +++- scanner/phase_1_folders.go | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/db/migrations/20241026183640_support_new_scanner.go b/db/migrations/20241026183640_support_new_scanner.go index 3e7c47f54..251b27f63 100644 --- a/db/migrations/20241026183640_support_new_scanner.go +++ b/db/migrations/20241026183640_support_new_scanner.go @@ -164,7 +164,9 @@ join library on media_file.library_id = library.id`, string(os.PathSeparator))) return nil } - stmt, err := tx.PrepareContext(ctx, "insert into folder (id, library_id, path, name, parent_id) values (?, ?, ?, ?, ?)") + stmt, err := tx.PrepareContext(ctx, + "insert into folder (id, library_id, path, name, parent_id, updated_at) values (?, ?, ?, ?, ?, '0000-00-00 00:00:00')", + ) if err != nil { return err } diff --git a/scanner/phase_1_folders.go b/scanner/phase_1_folders.go index ca7851f17..ae0d906de 100644 --- a/scanner/phase_1_folders.go +++ b/scanner/phase_1_folders.go @@ -150,6 +150,14 @@ func (p *phaseFolders) producer() ppl.Producer[*folderEntry] { Path: folder.path, Phase: "1", }) + + // Log folder info + log.Trace(p.ctx, "Scanner: Checking folder state", " folder", folder.path, "_updTime", folder.updTime, + "_modTime", folder.modTime, "_lastScanStartedAt", folder.job.lib.LastScanStartedAt, + "numAudioFiles", len(folder.audioFiles), "numImageFiles", len(folder.imageFiles), + "numPlaylists", folder.numPlaylists, "numSubfolders", folder.numSubFolders) + + // Check if folder is outdated if folder.isOutdated() { if !p.state.fullScan { if folder.hasNoFiles() && folder.isNew() { @@ -161,6 +169,8 @@ func (p *phaseFolders) producer() ppl.Producer[*folderEntry] { totalChanged++ folder.elapsed.Stop() put(folder) + } else { + log.Trace(p.ctx, "Scanner: Skipping up-to-date folder", "folder", folder.path, "lastUpdate", folder.modTime, "lib", job.lib.Name) } } total += job.numFolders.Load() From 651ce163c70fee1141b3d75aea289ca54655bb3e Mon Sep 17 00:00:00 2001 From: Deluan Date: Mon, 24 Mar 2025 16:41:54 -0400 Subject: [PATCH 42/51] fix(ui): sort playlist by `album_artist`, `bpm` and `channels` fix #3878 Signed-off-by: Deluan --- persistence/playlist_track_repository.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/persistence/playlist_track_repository.go b/persistence/playlist_track_repository.go index ea1977f3d..d33bd5113 100644 --- a/persistence/playlist_track_repository.go +++ b/persistence/playlist_track_repository.go @@ -51,13 +51,16 @@ func (r *playlistRepository) Tracks(playlistId string, refreshSmartPlaylist bool }) p.setSortMappings( map[string]string{ - "id": "playlist_tracks.id", - "artist": "order_artist_name", - "album": "order_album_name, order_album_artist_name", - "title": "order_title", + "id": "playlist_tracks.id", + "artist": "order_artist_name", + "album_artist": "order_album_artist_name", + "album": "order_album_name, order_album_artist_name", + "title": "order_title", // To make sure these fields will be whitelisted "duration": "duration", "year": "year", + "bpm": "bpm", + "channels": "channels", }, "f") // TODO I don't like this solution, but I won't change it now as it's not the focus of BFR. From 9e9465567d4e4cd1e18a09d99786e1c91ee64178 Mon Sep 17 00:00:00 2001 From: matteo00gm <76428629+matteo00gm@users.noreply.github.com> Date: Mon, 24 Mar 2025 22:49:23 +0100 Subject: [PATCH 43/51] fix(ui): update Italian translations (#3885) --- resources/i18n/it.json | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/resources/i18n/it.json b/resources/i18n/it.json index edc3cc69e..aaaa2f8c2 100644 --- a/resources/i18n/it.json +++ b/resources/i18n/it.json @@ -53,12 +53,12 @@ "updatedAt": "Ultimo aggiornamento", "comment": "Commento", "rating": "Valutazione", - "createdAt": "", - "size": "", + "createdAt": "Data di creazione", + "size": "Dimensione", "originalDate": "", - "releaseDate": "", - "releases": "", - "released": "" + "releaseDate": "Data di pubblicazione", + "releases": "Pubblicazione |||| Pubblicazioni", + "released": "Pubblicato" }, "actions": { "playAll": "Riproduci", @@ -68,7 +68,7 @@ "addToPlaylist": "Aggiungi alla Playlist", "download": "Scarica", "info": "Informazioni", - "share": "" + "share": "Condividi" }, "lists": { "all": "Tutti", @@ -89,7 +89,7 @@ "playCount": "Riproduzioni", "rating": "Valutazione", "genre": "Genere", - "size": "" + "size": "Dimensione" } }, "user": { @@ -160,8 +160,8 @@ "selectPlaylist": "Aggiungi tracce alla playlist:", "addNewPlaylist": "Aggiungi \"%{name}\"", "export": "Esporta", - "makePublic": "", - "makePrivate": "" + "makePublic": "Rendi Pubblica", + "makePrivate": "Rendi Privata" }, "message": { "duplicate_song": "Aggiungere i duplicati", @@ -169,9 +169,9 @@ } }, "radio": { - "name": "", + "name": "Radio |||| Radio", "fields": { - "name": "", + "name": "Nome", "streamUrl": "", "homePageUrl": "", "updatedAt": "", From c837838d58c03e7dc0ed6e24736623d7b3b277d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Deluan=20Quint=C3=A3o?= Date: Mon, 24 Mar 2025 17:52:03 -0400 Subject: [PATCH 44/51] fix(ui): update French, Polish, Turkish translations from POEditor (#3834) Co-authored-by: navidrome-bot --- resources/i18n/fr.json | 68 +++++++++++++++++++++--------------------- resources/i18n/pl.json | 54 ++++++++++++++++++++++++++++++--- resources/i18n/tr.json | 6 ++-- 3 files changed, 88 insertions(+), 40 deletions(-) diff --git a/resources/i18n/fr.json b/resources/i18n/fr.json index 50bc0d449..4060a789d 100644 --- a/resources/i18n/fr.json +++ b/resources/i18n/fr.json @@ -25,13 +25,15 @@ "quality": "Qualité", "bpm": "BPM", "playDate": "Derniers joués", + "channels": "Canaux", "createdAt": "Date d'ajout", "grouping": "Regroupement", "mood": "Humeur", "participants": "Participants supplémentaires", "tags": "Étiquettes supplémentaires", "mappedTags": "Étiquettes correspondantes", - "rawTags": "Étiquettes brutes" + "rawTags": "Étiquettes brutes", + "bitDepth": "Profondeur de bit" }, "actions": { "addToQueue": "Ajouter à la file", @@ -51,19 +53,19 @@ "duration": "Durée", "songCount": "Nombre de pistes", "playCount": "Nombre d'écoutes", - "size": "Taille", "name": "Nom", "genre": "Genre", "compilation": "Compilation", "year": "Année", - "originalDate": "Original", - "releaseDate": "Sortie", - "releases": "Sortie |||| Sorties", - "released": "Sortie", "updatedAt": "Mis à jour le", "comment": "Commentaire", "rating": "Classement", "createdAt": "Date d'ajout", + "size": "Taille", + "originalDate": "Original", + "releaseDate": "Sortie", + "releases": "Sortie |||| Sorties", + "released": "Sortie", "recordLabel": "Label", "catalogNum": "Numéro de catalogue", "releaseType": "Type", @@ -75,11 +77,11 @@ "playAll": "Lire", "playNext": "Lire ensuite", "addToQueue": "Ajouter à la file", - "share": "Partager", "shuffle": "Mélanger", "addToPlaylist": "Ajouter à la playlist", "download": "Télécharger", - "info": "Plus d'informations" + "info": "Plus d'informations", + "share": "Partager" }, "lists": { "all": "Tous", @@ -97,10 +99,10 @@ "name": "Nom", "albumCount": "Nombre d'albums", "songCount": "Nombre de pistes", - "size": "Taille", "playCount": "Lectures", "rating": "Classement", "genre": "Genre", + "size": "Taille", "role": "Rôle" }, "roles": { @@ -125,7 +127,6 @@ "userName": "Nom d'utilisateur", "isAdmin": "Administrateur", "lastLoginAt": "Dernière connexion", - "lastAccessAt": "Dernier accès", "updatedAt": "Dernière mise à jour", "name": "Nom", "password": "Mot de passe", @@ -133,7 +134,8 @@ "changePassword": "Changer le mot de passe ?", "currentPassword": "Mot de passe actuel", "newPassword": "Nouveau mot de passe", - "token": "Token" + "token": "Token", + "lastAccessAt": "Dernier accès" }, "helperTexts": { "name": "Les changements liés à votre nom ne seront reflétés qu'à la prochaine connexion" @@ -215,7 +217,6 @@ "username": "Partagé(e) par", "url": "Lien URL", "description": "Description", - "downloadable": "Autoriser les téléchargements ?", "contents": "Contenu", "expiresAt": "Expire le", "lastVisitedAt": "Visité pour la dernière fois", @@ -223,14 +224,12 @@ "format": "Format", "maxBitRate": "Bitrate maximum", "updatedAt": "Mis à jour le", - "createdAt": "Créé le" - }, - "notifications": {}, - "actions": {} + "createdAt": "Créé le", + "downloadable": "Autoriser les téléchargements ?" + } }, "missing": { "name": "Fichier manquant|||| Fichiers manquants", - "empty": "Aucun fichier manquant", "fields": { "path": "Chemin", "size": "Taille", @@ -241,7 +240,8 @@ }, "notifications": { "removed": "Fichier(s) manquant(s) supprimé(s)" - } + }, + "empty": "Aucun fichier manquant" } }, "ra": { @@ -279,7 +279,6 @@ "add": "Ajouter", "back": "Retour", "bulk_actions": "%{smart_count} sélectionné |||| %{smart_count} sélectionnés", - "bulk_actions_mobile": "1 |||| %{smart_count}", "cancel": "Annuler", "clear_input_value": "Vider le champ", "clone": "Dupliquer", @@ -303,6 +302,7 @@ "close_menu": "Fermer le menu", "unselect": "Désélectionner", "skip": "Ignorer", + "bulk_actions_mobile": "1 |||| %{smart_count}", "share": "Partager", "download": "Télécharger" }, @@ -397,31 +397,31 @@ "noPlaylistsAvailable": "Aucune playlist", "delete_user_title": "Supprimer l'utilisateur '%{name}'", "delete_user_content": "Êtes-vous sûr(e) de vouloir supprimer cet utilisateur et ses données associées (y compris ses playlists et préférences) ?", - "remove_missing_title": "Supprimer les fichiers manquants", - "remove_missing_content": "Êtes-vous sûr(e) de vouloir supprimer les fichiers manquants sélectionnés de la base de données ? Ceci supprimera définiviement toute référence à ceux-ci, y compris leurs nombres d'écoutes et leurs notations.", "notifications_blocked": "Votre navigateur bloque les notifications de ce site", "notifications_not_available": "Votre navigateur ne permet pas d'afficher les notifications sur le bureau ou vous n'accédez pas à Navidrome via HTTPS", "lastfmLinkSuccess": "Last.fm a été correctement relié et le scrobble a été activé", "lastfmLinkFailure": "Last.fm n'a pas pu être correctement relié", "lastfmUnlinkSuccess": "Last.fm n'est plus relié et le scrobble a été désactivé", "lastfmUnlinkFailure": "Erreur pendant la suppression du lien avec Last.fm", - "listenBrainzLinkSuccess": "La liaison et le scrobble avec ListenBrainz sont maintenant activés pour l'utilisateur : %{user}", - "listenBrainzLinkFailure": "Échec lors de la liaison avec ListenBrainz : %{error}", - "listenBrainzUnlinkSuccess": "La liaison et le scrobble avec ListenBrainz sont maintenant désactivés", - "listenBrainzUnlinkFailure": "Échec lors de la désactivation de la liaison avec ListenBrainz", "openIn": { "lastfm": "Ouvrir dans Last.fm", "musicbrainz": "Ouvrir dans MusicBrainz" }, "lastfmLink": "Lire plus...", + "listenBrainzLinkSuccess": "La liaison et le scrobble avec ListenBrainz sont maintenant activés pour l'utilisateur : %{user}", + "listenBrainzLinkFailure": "Échec lors de la liaison avec ListenBrainz : %{error}", + "listenBrainzUnlinkSuccess": "La liaison et le scrobble avec ListenBrainz sont maintenant désactivés", + "listenBrainzUnlinkFailure": "Échec lors de la désactivation de la liaison avec ListenBrainz", + "downloadOriginalFormat": "Télécharger au format original", "shareOriginalFormat": "Partager avec le format original", "shareDialogTitle": "Partager %{resource} '%{name}'", "shareBatchDialogTitle": "Partager 1 %{resource} |||| Partager %{smart_count} %{resource}", - "shareCopyToClipboard": "Copier vers le presse-papier : Ctrl+C, Enter", "shareSuccess": "Lien copié vers le presse-papier : %{url}", "shareFailure": "Erreur en copiant le lien %{url} vers le presse-papier", "downloadDialogTitle": "Télécharger %{resource} '%{name}' (%{size})", - "downloadOriginalFormat": "Télécharger au format original" + "shareCopyToClipboard": "Copier vers le presse-papier : Ctrl+C, Enter", + "remove_missing_title": "Supprimer les fichiers manquants", + "remove_missing_content": "Êtes-vous sûr(e) de vouloir supprimer les fichiers manquants sélectionnés de la base de données ? Ceci supprimera définitivement toute référence à ceux-ci, y compris leurs nombres d'écoutes et leurs notations" }, "menu": { "library": "Bibliothèque", @@ -435,7 +435,6 @@ "language": "Langue", "defaultView": "Vue par défaut", "desktop_notifications": "Notifications de bureau", - "lastfmNotConfigured": "La clef API de Last.fm n'est pas configurée", "lastfmScrobbling": "Scrobbler vers Last.fm", "listenBrainzScrobbling": "Scrobbler vers ListenBrainz", "replaygain": "Mode ReplayGain", @@ -444,13 +443,14 @@ "none": "Désactivé", "album": "Utiliser le gain de l'album", "track": "Utiliser le gain des pistes" - } + }, + "lastfmNotConfigured": "La clef API de Last.fm n'est pas configurée" } }, "albumList": "Albums", + "about": "À propos", "playlists": "Playlists", - "sharedPlaylists": "Playlists partagées", - "about": "À propos" + "sharedPlaylists": "Playlists partagées" }, "player": { "playListsText": "File de lecture", @@ -505,10 +505,10 @@ "toggle_play": "Lecture/Pause", "prev_song": "Morceau précédent", "next_song": "Morceau suivant", - "current_song": "Aller à la chanson en cours", "vol_up": "Augmenter le volume", "vol_down": "Baisser le volume", - "toggle_love": "Ajouter/Enlever le morceau des favoris" + "toggle_love": "Ajouter/Enlever le morceau des favoris", + "current_song": "Aller à la chanson en cours" } } -} +} \ No newline at end of file diff --git a/resources/i18n/pl.json b/resources/i18n/pl.json index fe29f0e08..a9a128abc 100644 --- a/resources/i18n/pl.json +++ b/resources/i18n/pl.json @@ -26,7 +26,14 @@ "bpm": "BPM", "playDate": "Ostatnio Odtwarzane", "channels": "Kanały", - "createdAt": "Data dodania" + "createdAt": "Data dodania", + "grouping": "", + "mood": "", + "participants": "", + "tags": "", + "mappedTags": "", + "rawTags": "", + "bitDepth": "" }, "actions": { "addToQueue": "Odtwarzaj Później", @@ -58,7 +65,13 @@ "originalDate": "Pierwotna Data", "releaseDate": "Data Wydania", "releases": "Wydanie |||| Wydania", - "released": "Wydany" + "released": "Wydany", + "recordLabel": "", + "catalogNum": "", + "releaseType": "", + "grouping": "", + "media": "", + "mood": "" }, "actions": { "playAll": "Odtwarzaj", @@ -89,7 +102,23 @@ "playCount": "Liczba Odtworzeń", "rating": "Ocena", "genre": "Gatunek", - "size": "Rozmiar" + "size": "Rozmiar", + "role": "" + }, + "roles": { + "albumartist": "", + "artist": "", + "composer": "", + "conductor": "", + "lyricist": "", + "arranger": "", + "producer": "Producent |||| Producenci", + "director": "Reżyser |||| Reżyserzy", + "engineer": "Inżynier |||| Inżynierowie", + "mixer": "Mikser |||| Mikserzy", + "remixer": "Remixer |||| Remixerzy", + "djmixer": "Didżej |||| Didżerzy", + "performer": "Wykonawca |||| Wykonawcy" } }, "user": { @@ -198,6 +227,21 @@ "createdAt": "Stworzono", "downloadable": "Zezwolić Na Pobieranie?" } + }, + "missing": { + "name": "Brakujący Plik|||| Brakujące Pliki", + "fields": { + "path": "Ścieżka", + "size": "Rozmiar", + "updatedAt": "Zniknął na" + }, + "actions": { + "remove": "Usuń" + }, + "notifications": { + "removed": "Usunięto brakujące pliki" + }, + "empty": "" } }, "ra": { @@ -375,7 +419,9 @@ "shareSuccess": "Adres URL skopiowany do schowka: %{url}", "shareFailure": "Błąd podczas kopiowania URL %{url} do schowka", "downloadDialogTitle": "Pobierz %{resource} '%{name}' (%{size})", - "shareCopyToClipboard": "Skopiuj do schowka: Ctrl+C, Enter" + "shareCopyToClipboard": "Skopiuj do schowka: Ctrl+C, Enter", + "remove_missing_title": "Usuń brakujące dane", + "remove_missing_content": "Czy na pewno chcesz usunąć wybrane brakujące pliki z bazy danych? Spowoduje to trwałe usunięcie wszystkich powiązań, takich jak liczba odtworzeń i oceny." }, "menu": { "library": "Biblioteka", diff --git a/resources/i18n/tr.json b/resources/i18n/tr.json index f138f6730..2ae07b614 100644 --- a/resources/i18n/tr.json +++ b/resources/i18n/tr.json @@ -32,7 +32,8 @@ "participants": "Ek katılımcılar", "tags": "Ek Etiketler", "mappedTags": "Eşlenen etiketler", - "rawTags": "Ham etiketler" + "rawTags": "Ham etiketler", + "bitDepth": "" }, "actions": { "addToQueue": "Oynatma Sırasına Ekle", @@ -239,7 +240,8 @@ }, "notifications": { "removed": "Eksik dosya(lar) kaldırıldı" - } + }, + "empty": "Eksik Dosya Yok" } }, "ra": { From 112ea281d94d75036f82a2e75d95e4f21da864a4 Mon Sep 17 00:00:00 2001 From: Michachatz <121869403+michatec@users.noreply.github.com> Date: Tue, 25 Mar 2025 22:33:33 +0100 Subject: [PATCH 45/51] feat(ui): add Greek translation (#3892) Signed-off-by: Deluan --- resources/i18n/el.json | 514 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 514 insertions(+) create mode 100644 resources/i18n/el.json diff --git a/resources/i18n/el.json b/resources/i18n/el.json new file mode 100644 index 000000000..86ccf7c06 --- /dev/null +++ b/resources/i18n/el.json @@ -0,0 +1,514 @@ +{ + "languageName": "Ελληνικά", + "resources": { + "song": { + "name": "Τραγούδι |||| Τραγούδια", + "fields": { + "albumArtist": "Καλλιτεχνης Αλμπουμ", + "duration": "Διαρκεια", + "trackNumber": "#", + "playCount": "Αναπαραγωγες", + "title": "Τιτλος", + "artist": "Καλλιτεχνης", + "album": "Αλμπουμ", + "path": "Διαδρομη αρχειου", + "genre": "Ειδος", + "compilation": "Συλλογή", + "year": "Ετος", + "size": "Μεγεθος αρχειου", + "updatedAt": "Ενημερωθηκε", + "bitRate": "Ρυθμός Bit", + "discSubtitle": "Υπότιτλοι Δίσκου", + "starred": "Αγαπημένο", + "comment": "Σχόλιο", + "rating": "Βαθμολογια", + "quality": "Ποιοτητα", + "bpm": "BPM", + "playDate": "Παίχτηκε Τελευταία", + "channels": "Κανάλια", + "createdAt": "Ημερομηνία προσθήκης", + "grouping": "Ομαδοποίηση", + "mood": "Διάθεση", + "participants": "Πρόσθετοι συμμετέχοντες", + "tags": "Πρόσθετες Ετικέτες", + "mappedTags": "Χαρτογραφημένες ετικέτες", + "rawTags": "Ακατέργαστες ετικέτες", + "bitDepth": "Λίγο βάθος" + }, + "actions": { + "addToQueue": "Αναπαραγωγη Μετα", + "playNow": "Αναπαραγωγή Τώρα", + "addToPlaylist": "Προσθήκη στη λίστα αναπαραγωγής", + "shuffleAll": "Ανακατεμα ολων", + "download": "Ληψη", + "playNext": "Επόμενη Αναπαραγωγή", + "info": "Εμφάνιση Πληροφοριών" + } + }, + "album": { + "name": "Άλμπουμ |||| Άλμπουμ", + "fields": { + "albumArtist": "Καλλιτεχνης Αλμπουμ", + "artist": "Καλλιτεχνης", + "duration": "Διαρκεια", + "songCount": "Τραγουδια", + "playCount": "Αναπαραγωγες", + "name": "Ονομα", + "genre": "Ειδος", + "compilation": "Συλλογη", + "year": "Ετος", + "updatedAt": "Ενημερωθηκε", + "comment": "Σχόλιο", + "rating": "Βαθμολογια", + "createdAt": "Ημερομηνία προσθήκης", + "size": "Μέγεθος", + "originalDate": "Πρωτότυπο", + "releaseDate": "Κυκλοφόρησε", + "releases": "Έκδοση |||| Εκδόσεις", + "released": "Κυκλοφόρησε", + "recordLabel": "Επιγραφή", + "catalogNum": "Αριθμός καταλόγου", + "releaseType": "Τύπος", + "grouping": "Ομαδοποίηση", + "media": "Μέσα", + "mood": "Διάθεση" + }, + "actions": { + "playAll": "Αναπαραγωγή", + "playNext": "Αναπαραγωγη Μετα", + "addToQueue": "Αναπαραγωγη Αργοτερα", + "shuffle": "Ανακατεμα", + "addToPlaylist": "Προσθηκη στη λιστα αναπαραγωγης", + "download": "Ληψη", + "info": "Εμφάνιση Πληροφοριών", + "share": "Μερίδιο" + }, + "lists": { + "all": "Όλα", + "random": "Τυχαία", + "recentlyAdded": "Νέες Προσθήκες", + "recentlyPlayed": "Παίχτηκαν Πρόσφατα", + "mostPlayed": "Παίζονται Συχνά", + "starred": "Αγαπημένα", + "topRated": "Κορυφαία" + } + }, + "artist": { + "name": "Καλλιτέχνης |||| Καλλιτέχνες", + "fields": { + "name": "Ονομα", + "albumCount": "Αναπαραγωγές Αλμπουμ", + "songCount": "Αναπαραγωγες Τραγουδιου", + "playCount": "Αναπαραγωγες", + "rating": "Βαθμολογια", + "genre": "Είδος", + "size": "Μέγεθος", + "role": "Ρόλος" + }, + "roles": { + "albumartist": "Καλλιτέχνης Άλμπουμ |||| Καλλιτέχνες άλμπουμ", + "artist": "Καλλιτέχνης |||| Καλλιτέχνες", + "composer": "Συνθέτης |||| Συνθέτες", + "conductor": "Μαέστρος |||| Μαέστροι", + "lyricist": "Στιχουργός |||| Στιχουργοί", + "arranger": "Τακτοποιητής |||| Τακτοποιητές", + "producer": "Παραγωγός |||| Παραγωγοί", + "director": "Διευθυντής |||| Διευθυντές", + "engineer": "Μηχανικός |||| Μηχανικοί", + "mixer": "Μίξερ |||| Μίξερ", + "remixer": "Ρεμίξερ |||| Ρεμίξερ", + "djmixer": "Dj Μίξερ |||| Dj Μίξερ", + "performer": "Εκτελεστής |||| Ερμηνευτές" + } + }, + "user": { + "name": "Χρήστης |||| Χρήστες", + "fields": { + "userName": "Ονομα Χρηστη", + "isAdmin": "Ειναι Διαχειριστης", + "lastLoginAt": "Τελευταια συνδεση στις", + "updatedAt": "Ενημερωθηκε", + "name": "Όνομα", + "password": "Κωδικός Πρόσβασης", + "createdAt": "Δημιουργήθηκε στις", + "changePassword": "Αλλαγή Κωδικού Πρόσβασης;", + "currentPassword": "Υπάρχων Κωδικός Πρόσβασης", + "newPassword": "Νέος Κωδικός Πρόσβασης", + "token": "Token", + "lastAccessAt": "Τελευταία Πρόσβαση" + }, + "helperTexts": { + "name": "Αλλαγές στο όνομα σας θα εφαρμοστούν στην επόμενη σύνδεση" + }, + "notifications": { + "created": "Ο χρήστης δημιουργήθηκε", + "updated": "Ο χρήστης ενημερώθηκε", + "deleted": "Ο χρήστης διαγράφηκε" + }, + "message": { + "listenBrainzToken": "Εισάγετε το token του χρήστη σας στο ListenBrainz.", + "clickHereForToken": "Κάντε κλικ εδώ για να αποκτήσετε το token σας" + } + }, + "player": { + "name": "Συσκευή Αναπαραγωγής |||| Συσκευές Αναπαραγωγής", + "fields": { + "name": "Όνομα", + "transcodingId": "Διακωδικοποίηση", + "maxBitRate": "Μεγ. Ρυθμός Bit", + "client": "Πελάτης", + "userName": "Ονομα Χρηστη", + "lastSeen": "Τελευταια προβολη στις", + "reportRealPath": "Αναφορά Πραγματικής Διαδρομής", + "scrobbleEnabled": "Αποστολή scrobbles σε εξωτερικές συσκευές" + } + }, + "transcoding": { + "name": "Διακωδικοποίηση |||| Διακωδικοποιήσεις", + "fields": { + "name": "Όνομα", + "targetFormat": "Μορφη Προορισμου", + "defaultBitRate": "Προκαθορισμένος Ρυθμός Bit", + "command": "Εντολή" + } + }, + "playlist": { + "name": "Λίστα αναπαραγωγής |||| Λίστες αναπαραγωγής", + "fields": { + "name": "Όνομα", + "duration": "Διάρκεια", + "ownerName": "Ιδιοκτήτης", + "public": "Δημόσιο", + "updatedAt": "Ενημερωθηκε", + "createdAt": "Δημιουργήθηκε στις", + "songCount": "Τραγούδια", + "comment": "Σχόλιο", + "sync": "Αυτόματη εισαγωγή", + "path": "Εισαγωγή από" + }, + "actions": { + "selectPlaylist": "Επιλέξτε μια λίστα αναπαραγωγής:", + "addNewPlaylist": "Δημιουργία \"%{name}\"", + "export": "Εξαγωγη", + "makePublic": "Να γίνει δημόσιο", + "makePrivate": "Να γίνει ιδιωτικό" + }, + "message": { + "duplicate_song": "Προσθήκη διπλοεγγραφών τραγουδιών", + "song_exist": "Υπάρχουν διπλοεγγραφές στην λίστα αναπαραγωγής. Θέλετε να προστεθούν οι διπλοεγγραφές ή να τις παραβλέψετε;" + } + }, + "radio": { + "name": "Ραδιόφωνο ||| Ραδιόφωνο", + "fields": { + "name": "Όνομα", + "streamUrl": "Ρεύμα URL", + "homePageUrl": "Αρχική σελίδα URL", + "updatedAt": "Ενημερώθηκε στις", + "createdAt": "Δημιουργήθηκε στις" + }, + "actions": { + "playNow": "Αναπαραγωγή" + } + }, + "share": { + "name": "Μοιραστείτε |||| Μερίδια", + "fields": { + "username": "Κοινή χρήση από", + "url": "URL", + "description": "Περιγραφή", + "contents": "Περιεχόμενα", + "expiresAt": "Λήγει", + "lastVisitedAt": "Τελευταία Επίσκεψη", + "visitCount": "Επισκέψεις", + "format": "Μορφή", + "maxBitRate": "Μέγ. Ρυθμός Bit", + "updatedAt": "Ενημερώθηκε στις", + "createdAt": "Δημιουργήθηκε στις", + "downloadable": "Επιτρέπονται οι λήψεις?" + } + }, + "missing": { + "name": "Λείπει αρχείο |||| Λείπουν αρχεία", + "fields": { + "path": "Διαδρομή", + "size": "Μέγεθος", + "updatedAt": "Εξαφανίστηκε" + }, + "actions": { + "remove": "Αφαίρεση" + }, + "notifications": { + "removed": "Λείπει αρχείο(α) αφαιρέθηκε" + }, + "empty": "Δεν λείπουν αρχεία" + } + }, + "ra": { + "auth": { + "welcome1": "Σας ευχαριστούμε που εγκαταστήσατε το Navidrome!", + "welcome2": "Για να ξεκινήσετε, δημιουργήστε έναν χρήστη ως διαχειριστή", + "confirmPassword": "Επιβεβαίωση κωδικού πρόσβασης", + "buttonCreateAdmin": "Δημιουργία Διαχειριστή", + "auth_check_error": "Παρακαλούμε συνδεθείτε για να συννεχίσετε", + "user_menu": "Προφίλ", + "username": "Ονομα Χρηστη", + "password": "Κωδικός Πρόσβασης", + "sign_in": "Σύνδεση", + "sign_in_error": "Η αυθεντικοποίηση απέτυχε, παρακαλούμε προσπαθήστε ξανά", + "logout": "Αποσύνδεση", + "insightsCollectionNote": "Το Navidrome συλλέγει ανώνυμα δεδομένα χρήσης σε\nβοηθήσουν στη βελτίωση του έργου. Κάντε κλικ [εδώ] για να μάθετε\nπερισσότερα και να εξαιρεθείτε αν θέλετε" + }, + "validation": { + "invalidChars": "Παρακαλούμε χρησημοποιήστε μόνο γράμματα και αριθμούς", + "passwordDoesNotMatch": "Ο κωδικός πρόσβασης δεν ταιριάζει", + "required": "Υποχρεωτικό", + "minLength": "Πρέπει να είναι %{min} χαρακτήρες τουλάχιστον", + "maxLength": "Πρέπει να είναι %{max} χαρακτήρες ή λιγότερο", + "minValue": "Πρέπει να είναι τουλάχιστον %{min}", + "maxValue": "Πρέπει να είναι %{max} ή λιγότερο", + "number": "Πρέπει να είναι αριθμός", + "email": "Πρέπει να είναι ένα έγκυρο email", + "oneOf": "Πρέπει να είναι ένα από τα ακόλουθα: %{options}", + "regex": "Πρέπει να ταιριάζει με ένα συγκεκριμένο τύπο (κανονική έκφραση): %{pattern}", + "unique": "Πρέπει να είναι μοναδικό", + "url": "Πρέπει να είναι έγκυρη διεύθυνση URL" + }, + "action": { + "add_filter": "Προσθηκη φιλτρου", + "add": "Προσθήκη", + "back": "Πίσω", + "bulk_actions": "1 αντικείμενο επιλέχθηκε |||| %{smart_count} αντικείμενα επιλέχθηκαν", + "cancel": "Ακύρωση", + "clear_input_value": "Καθαρισμός τιμής", + "clone": "Κλωνοποίηση", + "confirm": "Επιβεβαίωση", + "create": "Δημιουργία", + "delete": "Διαγραφή", + "edit": "Επεξεργασία", + "export": "Εξαγωγη", + "list": "Λίστα", + "refresh": "Ανανέωση", + "remove_filter": "Αφαίρεση αυτού του φίλτρου", + "remove": "Αφαίρεση", + "save": "Αποθηκευση", + "search": "Αναζήτηση", + "show": "Προβολή", + "sort": "Ταξινόμιση", + "undo": "Αναίρεση", + "expand": "Επέκταση", + "close": "Κλείσιμο", + "open_menu": "Άνοιγμα μενού", + "close_menu": "Κλείσιμο μενού", + "unselect": "Αποεπιλογή", + "skip": "Παράβλεψη", + "bulk_actions_mobile": "1 |||| %{smart_count}", + "share": "Κοινοποίηση", + "download": "Λήψη " + }, + "boolean": { + "true": "Ναι", + "false": "Όχι" + }, + "page": { + "create": "Δημιουργία %{name}", + "dashboard": "Πίνακας Ελέγχου", + "edit": "%{name} #%{id}", + "error": "Κάτι πήγε στραβά", + "list": "%{name}", + "loading": "Φόρτωση", + "not_found": "Δεν βρέθηκε", + "show": "%{name} #%{id}", + "empty": "Δεν υπάρχει %{name} ακόμη.", + "invite": "Θέλετε να προσθέσετε ένα?" + }, + "input": { + "file": { + "upload_several": "Ρίξτε μερικά αρχεία για να τα ανεβάσετε, ή κάντε κλικ για να επιλέξετε ένα.", + "upload_single": "Ρίξτε ένα αρχείο για να τα ανεβάσετε, ή κάντε κλικ για να το επιλέξετε." + }, + "image": { + "upload_several": "Ρίξτε μερικές φωτογραφίες για να τις ανεβάσετε, ή κάντε κλικ για να επιλέξετε μια.", + "upload_single": "Ρίξτε μια φωτογραφία για να την ανεβάσετε, ή κάντε κλικ για να την επιλέξετε." + }, + "references": { + "all_missing": "Αδυναμία εύρεσης δεδομένων αναφοράς.", + "many_missing": "Τουλάχιστον μια από τις συσχετιζόμενες αναφορές φαίνεται δεν είναι διαθέσιμη.", + "single_missing": "Η συσχετιζόμενη αναφορά φαίνεται δεν είναι διαθέσιμη." + }, + "password": { + "toggle_visible": "Απόκρυψη κωδικού πρόσβασης", + "toggle_hidden": "Εμφάνιση κωδικού πρόσβασης" + } + }, + "message": { + "about": "Σχετικά", + "are_you_sure": "Είστε σίγουροι;", + "bulk_delete_content": "Είστε σίγουροι πως θέλετε να διαγράψετε το %{name}; |||| Είστε σίγουροι πως θέλετε να διαγράψετε τα %{smart_count};", + "bulk_delete_title": "Διαγραφή του %{name} |||| Διαγραφή του %{smart_count} %{name}", + "delete_content": "Είστε σίγουροι πως θέλετε να διαγράψετε αυτό το αντικείμενο;", + "delete_title": "Διαγραφή του %{name} #%{id}", + "details": "Λεπτομέρειες", + "error": "Παρουσιάστηκε ένα πρόβλημα από τη μεριά του πελάτη και το αίτημα σας δεν μπορεί να ολοκληρωθεί.", + "invalid_form": "Η φόρμα δεν είναι έγκυρη. Ελέγξτε για σφάλματα", + "loading": "Η σελίδα φορτώνει, περιμένετε λίγο", + "no": "Όχι", + "not_found": "Είτε έχετε εισάγει λανθασμένο URL, είτε ακολουθήσατε έναν υπερσύνδεσμο που δεν ισχύει.", + "yes": "Ναι", + "unsaved_changes": "Μερικές από τις αλλαγές σας δεν έχουν αποθηκευτεί. Είστε σίγουροι πως θέλετε να τις αγνοήσετε;" + }, + "navigation": { + "no_results": "Δεν βρέθηκαν αποτελέσματα", + "no_more_results": "Η σελίδα %{page} είναι εκτός ορίων. Δοκιμάστε την προηγούμενη σελίδα.", + "page_out_of_boundaries": "Η σελίδα {page} είναι εκτός ορίων", + "page_out_from_end": "Δεν είναι δυνατή η πλοήγηση πέραν της τελευταίας σελίδας", + "page_out_from_begin": "Δεν είναι δυνατή η πλοήγηση πριν τη σελίδα 1", + "page_range_info": "%{offsetBegin}-%{offsetEnd} από %{total}", + "page_rows_per_page": "Αντικείμενα ανά σελίδα:", + "next": "Επόμενο", + "prev": "Προηγούμενο", + "skip_nav": "Παράβλεψη στο περιεχόμενο" + }, + "notification": { + "updated": "Το στοιχείο ενημερώθηκε |||| %{smart_count} στοιχεία ενημερώθηκαν", + "created": "Το στοιχείο δημιουργήθηκε", + "deleted": "Το στοιχείο διαγράφηκε |||| %{smart_count} στοιχεία διαγράφηκαν", + "bad_item": "Λανθασμένο στοιχείο", + "item_doesnt_exist": "Το παρόν στοιχείο δεν υπάρχει", + "http_error": "Σφάλμα κατά την επικοινωνία με το διακομιστή", + "data_provider_error": "Σφάλμα παρόχου δεδομένων. Παρακαλούμε συμβουλευτείτε την κονσόλα για περισσότερες πληροφορίες.", + "i18n_error": "Αδυναμία ανάκτησης των μεταφράσεων για την συγκεκριμένη γλώσσα", + "canceled": "Η συγκεκριμένη δράση ακυρώθηκε", + "logged_out": "Η συνεδρία σας έχει λήξει, παρακαλούμε ξανασυνδεθείτε.", + "new_version": "Υπάρχει νέα έκδοση διαθέσιμη! Παρακαλούμε ανανεώστε το παράθυρο." + }, + "toggleFieldsMenu": { + "columnsToDisplay": "Στήλες προς εμφάνιση", + "layout": "Διάταξη", + "grid": "Πλεγμα", + "table": "Πινακας" + } + }, + "message": { + "note": "ΣΗΜΕΙΩΣΗ", + "transcodingDisabled": "Η αλλαγή της διαμόρφωσης της διακωδικοποίησης μέσω της διεπαφής του περιηγητή ιστού είναι απενεργοποιημένη για λόγους ασφαλείας. Εαν επιθυμείτε να αλλάξετε (τροποποίηση ή δημιουργία) των επιλογών διακωδικοποίησης, επανεκκινήστε το διακομιστή με την επιλογή %{config}.", + "transcodingEnabled": "Το Navidrome λειτουργεί με %{config}, καθιστόντας δυνατή την εκτέλεση εντολών συστήματος μέσω των ρυθμίσεων διακωδικοποίησης χρησιμοποιώντας την διεπαφή ιστού. Προτείνουμε να το απενεργοποιήσετε για λόγους ασφαλείας και να το ενεργοποιήσετε μόνο όταν παραμετροποιείτε τις επιλογές διακωδικοποίησης.", + "songsAddedToPlaylist": "Προστέθηκε 1 τραγούδι στη λίστα αναπαραγωγής |||| Προστέθηκαν %{smart_count} τραγούδια στη λίστα αναπαραγωγής", + "noPlaylistsAvailable": "Κανένα διαθέσιμο", + "delete_user_title": "Διαγραφή του χρήστη '%{name}'", + "delete_user_content": "Είστε σίγουροι πως θέλετε να διαγράψετε αυτό το χρήστη και όλα τα δεδομένα του (συμπεριλαμβανομένων των λιστών αναπαραγωγής και προτιμήσεων);", + "notifications_blocked": "Έχετε μπλοκάρει τις Ειδοποιήσεις από τη σελίδα, μέσω των ρυθμίσεων του περιηγητή ιστού σας", + "notifications_not_available": "Αυτός ο περιηγητής ιστού δεν υποστηρίζει ειδοποιήσεις στην επιφάνεια εργασίας ή δεν έχετε πρόσβαση στο Navidrome μέσω https", + "lastfmLinkSuccess": "Το Last.fm έχει διασυνδεθεί επιτυχώς και η λειτουργία scrobbling ενεργοποιήθηκε", + "lastfmLinkFailure": "Δεν μπορεί να πραγματοποιηθεί διασύνδεση με το Last.fm", + "lastfmUnlinkSuccess": "Το Last.fm αποσυνδέθηκε και η λειτουργία scrobbling έχει απενεργοποιηθεί", + "lastfmUnlinkFailure": "Το Last.fm δεν μπορεί να αποσυνδεθεί", + "openIn": { + "lastfm": "Άνοιγμα στο Last.fm", + "musicbrainz": "Άνοιγμα στο MusicBrainz" + }, + "lastfmLink": "Διαβάστε περισσότερα...", + "listenBrainzLinkSuccess": "Το ListenBrainz έχει διασυνδεθεί επιτυχώς και η λειτουργία scrobbling έχει ενεργοποιηθεί για το χρήστη: %{user}", + "listenBrainzLinkFailure": "Το ListenBrainz δεν μπορεί να διασυνδεθεί: %{error}", + "listenBrainzUnlinkSuccess": "Το ListenBrainz έχει αποσυνδεθεί και το scrobbling έχει απενεργοποιηθεί", + "listenBrainzUnlinkFailure": "Το ListenBrainz δεν μπορεί να διασυνδεθεί", + "downloadOriginalFormat": "Λήψη σε αρχική μορφή", + "shareOriginalFormat": "Κοινή χρήση σε αρχική μορφή", + "shareDialogTitle": "Κοινή χρήση %{resource} '%{name}'", + "shareBatchDialogTitle": "Κοινή χρήση 1 %{resource} |||| Κοινή χρήση %{smart_count} %{resource}", + "shareSuccess": "Το URL αντιγράφτηκε στο πρόχειρο: %{url}", + "shareFailure": "Σφάλμα κατά την αντιγραφή της διεύθυνσης URL %{url} στο πρόχειρο", + "downloadDialogTitle": "Λήψη %{resource} '%{name}'(%{size})", + "shareCopyToClipboard": "Αντιγραφή στο πρόχειρο: Ctrl+C, Enter", + "remove_missing_title": "Αφαιρέστε τα αρχεία που λείπουν", + "remove_missing_content": "Είστε βέβαιοι ότι θέλετε να αφαιρέσετε τα επιλεγμένα αρχεία που λείπουν από τη βάση δεδομένων; Αυτό θα καταργήσει οριστικά τυχόν αναφορές σε αυτά, συμπεριλαμβανομένων των αριθμών παιχνιδιών και των αξιολογήσεών τους." + }, + "menu": { + "library": "Βιβλιοθήκη", + "settings": "Ρυθμίσεις", + "version": "Έκδοση", + "theme": "Θέμα", + "personal": { + "name": "Προσωπικές", + "options": { + "theme": "Θέμα", + "language": "Γλώσσα", + "defaultView": "Προκαθορισμένη προβολή", + "desktop_notifications": "Ειδοποιήσεις στην Επιφάνεια Εργασίας", + "lastfmScrobbling": "Λειτουργία Scrobble στο Last.fm", + "listenBrainzScrobbling": "Λειτουργία scrobble με το ListenBrainz", + "replaygain": "Λειτουργία ReplayGain", + "preAmp": "ReplayGain PreAmp (dB)", + "gain": { + "none": "Ανενεργό", + "album": "Χρησιμοποιήστε το Album Gain", + "track": "Χρησιμοποιήστε το Track Gain" + }, + "lastfmNotConfigured": "Το Last.fm API-Key δεν έχει ρυθμιστεί" + } + }, + "albumList": "Άλμπουμ", + "about": "Σχετικά", + "playlists": "Λίστες Αναπαραγωγής", + "sharedPlaylists": "Κοινοποιημένες Λίστες Αναπαραγωγής" + }, + "player": { + "playListsText": "Ουρά Αναπαραγωγής", + "openText": "Άνοιγμα", + "closeText": "Κλείσιμο", + "notContentText": "Δεν υπάρχει μουσική", + "clickToPlayText": "Κλίκ για αναπαραγωγή", + "clickToPauseText": "Κλίκ για παύση", + "nextTrackText": "Επόμενο κομμάτι", + "previousTrackText": "Προηγούμενο κομμάτι", + "reloadText": "Επαναφόρτωση", + "volumeText": "Ένταση", + "toggleLyricText": "Εναλλαγή στίχων", + "toggleMiniModeText": "Ελαχιστοποίηση", + "destroyText": "Κλέισιμο", + "downloadText": "Ληψη", + "removeAudioListsText": "Διαγραφή λιστών ήχου", + "clickToDeleteText": "Κάντε κλικ για να διαγράψετε %{name}", + "emptyLyricText": "Δεν υπάρχουν στίχοι", + "playModeText": { + "order": "Στη σειρά", + "orderLoop": "Επανάληψη", + "singleLoop": "Επανάληψη μια φορά", + "shufflePlay": "Ανακατεμα" + } + }, + "about": { + "links": { + "homepage": "Αρχική σελίδα", + "source": "Πηγαίος κώδικας", + "featureRequests": "Αιτήματα χαρακτηριστικών", + "lastInsightsCollection": "Τελευταία συλλογή πληροφοριών", + "insights": { + "disabled": "Απενεργοποιημένο", + "waiting": "Αναμονή" + } + } + }, + "activity": { + "title": "Δραστηριότητα", + "totalScanned": "Σαρώμένοι Φάκελοι", + "quickScan": "Γρήγορη Σάρωση", + "fullScan": "Πλήρης Σάρωση", + "serverUptime": "Λειτουργία Διακομιστή", + "serverDown": "ΕΚΤΟΣ ΣΥΝΔΕΣΗΣ" + }, + "help": { + "title": "Συντομεύσεις του Navidrome", + "hotkeys": { + "show_help": "Προβολή αυτής της Βοήθειας", + "toggle_menu": "Εναλλαγή Μπάρας Μενού", + "toggle_play": "Αναπαραγωγή / Παύση", + "prev_song": "Προηγούμενο Τραγούδι", + "next_song": "Επόμενο Τραγούδι", + "vol_up": "Αύξηση Έντασης", + "vol_down": "Μείωση Έντασης", + "toggle_love": "Προσθήκη αυτού του κομματιού στα αγαπημένα", + "current_song": "Μεταβείτε στο Τρέχον τραγούδι" + } + } +} \ No newline at end of file From 339458041389219279f2519205c25d4dcc0e0940 Mon Sep 17 00:00:00 2001 From: Deluan Date: Tue, 25 Mar 2025 17:43:25 -0400 Subject: [PATCH 46/51] feat(ui): add Norwegian translation Signed-off-by: Deluan --- resources/i18n/no.json | 514 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 514 insertions(+) create mode 100644 resources/i18n/no.json diff --git a/resources/i18n/no.json b/resources/i18n/no.json new file mode 100644 index 000000000..bd4c37d0b --- /dev/null +++ b/resources/i18n/no.json @@ -0,0 +1,514 @@ +{ + "languageName": "Engelsk", + "resources": { + "song": { + "name": "Låt |||| Låter", + "fields": { + "albumArtist": "Album Artist", + "duration": "Tid", + "trackNumber": "#", + "playCount": "Avspillinger", + "title": "Tittel", + "artist": "Artist", + "album": "Album", + "path": "Filbane", + "genre": "Sjanger", + "compilation": "Samling", + "year": "År", + "size": "Filstørrelse", + "updatedAt": "Oppdatert kl", + "bitRate": "Bithastighet", + "discSubtitle": "Diskundertekst", + "starred": "Favoritt", + "comment": "Kommentar", + "rating": "Vurdering", + "quality": "Kvalitet", + "bpm": "BPM", + "playDate": "Sist spilt", + "channels": "Kanaler", + "createdAt": "", + "grouping": "", + "mood": "", + "participants": "", + "tags": "", + "mappedTags": "", + "rawTags": "", + "bitDepth": "" + }, + "actions": { + "addToQueue": "Spill Senere", + "playNow": "Leke nå", + "addToPlaylist": "Legg til i spilleliste", + "shuffleAll": "Bland alle", + "download": "nedlasting", + "playNext": "Spill Neste", + "info": "Få informasjon" + } + }, + "album": { + "name": "Album", + "fields": { + "albumArtist": "Album Artist", + "artist": "Artist", + "duration": "Tid", + "songCount": "Sanger", + "playCount": "Avspillinger", + "name": "Navn", + "genre": "Sjanger", + "compilation": "Samling", + "year": "År", + "updatedAt": "Oppdatert kl", + "comment": "Kommentar", + "rating": "Vurdering", + "createdAt": "", + "size": "", + "originalDate": "", + "releaseDate": "", + "releases": "", + "released": "", + "recordLabel": "", + "catalogNum": "", + "releaseType": "", + "grouping": "", + "media": "", + "mood": "" + }, + "actions": { + "playAll": "Spill", + "playNext": "Spill neste", + "addToQueue": "Spille senere", + "shuffle": "Bland", + "addToPlaylist": "Legg til i spilleliste", + "download": "nedlasting", + "info": "Få informasjon", + "share": "" + }, + "lists": { + "all": "Alle", + "random": "Tilfeldig", + "recentlyAdded": "Nylig lagt til", + "recentlyPlayed": "Nylig spilt", + "mostPlayed": "Mest spilte", + "starred": "Favoritter", + "topRated": "Topp rangert" + } + }, + "artist": { + "name": "Artist |||| Artister", + "fields": { + "name": "Navn", + "albumCount": "Antall album", + "songCount": "Antall sanger", + "playCount": "Spiller", + "rating": "Vurdering", + "genre": "Sjanger", + "size": "", + "role": "" + }, + "roles": { + "albumartist": "", + "artist": "", + "composer": "", + "conductor": "", + "lyricist": "", + "arranger": "", + "producer": "", + "director": "", + "engineer": "", + "mixer": "", + "remixer": "", + "djmixer": "", + "performer": "" + } + }, + "user": { + "name": "Bruker |||| Brukere", + "fields": { + "userName": "Brukernavn", + "isAdmin": "er admin", + "lastLoginAt": "Siste pålogging kl", + "updatedAt": "Oppdatert kl", + "name": "Navn", + "password": "Passord", + "createdAt": "Opprettet kl", + "changePassword": "Bytte Passord", + "currentPassword": "Nåværende Passord", + "newPassword": "Nytt Passord", + "token": "Token", + "lastAccessAt": "" + }, + "helperTexts": { + "name": "Endringer i navnet ditt vil kun gjenspeiles ved neste pålogging" + }, + "notifications": { + "created": "Bruker opprettet", + "updated": "Bruker oppdatert", + "deleted": "Bruker fjernet" + }, + "message": { + "listenBrainzToken": "Skriv inn ListenBrainz-brukertokenet ditt.", + "clickHereForToken": "Klikk her for å få tokenet ditt" + } + }, + "player": { + "name": "Avspiller |||| Avspillere", + "fields": { + "name": "Navn", + "transcodingId": "Omkoding", + "maxBitRate": "Maks. Bithastighet", + "client": "Klient", + "userName": "Brukernavn", + "lastSeen": "Sist sett kl", + "reportRealPath": "Rapporter ekte sti", + "scrobbleEnabled": "Send Scrobbles til eksterne tjenester" + } + }, + "transcoding": { + "name": "Omkoding |||| Omkodinger", + "fields": { + "name": "Navn", + "targetFormat": "Målformat", + "defaultBitRate": "Standard bithastighet", + "command": "Kommando" + } + }, + "playlist": { + "name": "Spilleliste |||| Spillelister", + "fields": { + "name": "Navn", + "duration": "Varighet", + "ownerName": "Eieren", + "public": "Offentlig", + "updatedAt": "Oppdatert kl", + "createdAt": "Opprettet kl", + "songCount": "Sanger", + "comment": "Kommentar", + "sync": "Autoimport", + "path": "Import fra" + }, + "actions": { + "selectPlaylist": "Velg en spilleliste:", + "addNewPlaylist": "Opprett \"%{name}\"", + "export": "Eksport", + "makePublic": "Gjør offentlig", + "makePrivate": "Gjør privat" + }, + "message": { + "duplicate_song": "Legg til dupliserte sanger", + "song_exist": "Det legges til duplikater i spillelisten. Vil du legge til duplikatene eller hoppe over dem?" + } + }, + "radio": { + "name": "", + "fields": { + "name": "", + "streamUrl": "", + "homePageUrl": "", + "updatedAt": "", + "createdAt": "" + }, + "actions": { + "playNow": "" + } + }, + "share": { + "name": "", + "fields": { + "username": "", + "url": "", + "description": "", + "contents": "", + "expiresAt": "", + "lastVisitedAt": "", + "visitCount": "", + "format": "", + "maxBitRate": "", + "updatedAt": "", + "createdAt": "", + "downloadable": "" + } + }, + "missing": { + "name": "", + "fields": { + "path": "", + "size": "", + "updatedAt": "" + }, + "actions": { + "remove": "" + }, + "notifications": { + "removed": "" + }, + "empty": "" + } + }, + "ra": { + "auth": { + "welcome1": "Takk for at du installerte Navidrome!", + "welcome2": "Opprett en admin -bruker for å starte", + "confirmPassword": "Bekreft Passord", + "buttonCreateAdmin": "Opprett Admin", + "auth_check_error": "Vennligst Logg inn for å fortsette", + "user_menu": "Profil", + "username": "Brukernavn", + "password": "Passord", + "sign_in": "Logg inn", + "sign_in_error": "Autentisering mislyktes. Prøv på nytt", + "logout": "Logg ut", + "insightsCollectionNote": "" + }, + "validation": { + "invalidChars": "Bruk bare bokstaver og tall", + "passwordDoesNotMatch": "Passordet er ikke like", + "required": "Obligatorisk", + "minLength": "Må være minst %{min} tegn", + "maxLength": "Må være %{max} tegn eller færre", + "minValue": "Må være minst %{min}", + "maxValue": "Må være %{max} eller mindre", + "number": "Må være et tall", + "email": "Må være en gyldig e-post", + "oneOf": "Må være en av: %{options}", + "regex": "Må samsvare med et spesifikt format (regexp): %{pattern}", + "unique": "Må være unik", + "url": "" + }, + "action": { + "add_filter": "Legg til filter", + "add": "Legge til", + "back": "Gå tilbake", + "bulk_actions": "1 element valgt |||| %{smart_count} elementer er valgt", + "cancel": "Avbryt", + "clear_input_value": "Klar verdi", + "clone": "Klone", + "confirm": "Bekrefte", + "create": "Skape", + "delete": "Slett", + "edit": "Redigere", + "export": "Eksport", + "list": "Liste", + "refresh": "oppdater", + "remove_filter": "Fjern dette filteret", + "remove": "Fjerne", + "save": "Lagre", + "search": "Søk", + "show": "Vis", + "sort": "Sortere", + "undo": "Angre", + "expand": "Utvide", + "close": "Lukk", + "open_menu": "Åpne menyen", + "close_menu": "Lukk menyen", + "unselect": "Fjern valget", + "skip": "Hopp over", + "bulk_actions_mobile": "", + "share": "", + "download": "" + }, + "boolean": { + "true": "Ja", + "false": "Nei" + }, + "page": { + "create": "Opprett %{name}", + "dashboard": "Dashbord", + "edit": "%{name} #%{id}", + "error": "Noe gikk galt", + "list": "%{Navn}", + "loading": "Laster", + "not_found": "Ikke funnet", + "show": "%{name} #%{id}", + "empty": "Ingen %{name} ennå.", + "invite": "Vil du legge til en?" + }, + "input": { + "file": { + "upload_several": "Slipp noen filer for å laste opp, eller klikk for å velge en.", + "upload_single": "Slipp en fil for å laste opp, eller klikk for å velge den." + }, + "image": { + "upload_several": "Slipp noen bilder for å laste opp, eller klikk for å velge ett.", + "upload_single": "Slipp et bilde for å laste opp, eller klikk for å velge det." + }, + "references": { + "all_missing": "Kan ikke finne referansedata.", + "many_missing": "Minst én av de tilknyttede referansene ser ikke ut til å være tilgjengelig lenger.", + "single_missing": "Tilknyttet referanse ser ikke lenger ut til å være tilgjengelig." + }, + "password": { + "toggle_visible": "Skjul passord", + "toggle_hidden": "Vis passord" + } + }, + "message": { + "about": "Om", + "are_you_sure": "Er du sikker?", + "bulk_delete_content": "Er du sikker på at du vil slette denne %{name}? |||| Er du sikker på at du vil slette disse %{smart_count} elementene?", + "bulk_delete_title": "Slett %{name} |||| Slett %{smart_count} %{name}", + "delete_content": "Er du sikker på at du vil slette dette elementet?", + "delete_title": "Slett %{name} #%{id}", + "details": "Detaljer", + "error": "Det oppstod en klientfeil og forespørselen din kunne ikke fullføres.", + "invalid_form": "Skjemaet er ikke gyldig. Vennligst se etter feil", + "loading": "Siden lastes, bare et øyeblikk", + "no": "Nei", + "not_found": "Enten skrev du inn feil URL, eller så fulgte du en dårlig lenke.", + "yes": "Ja", + "unsaved_changes": "Noen av endringene dine ble ikke lagret. Er du sikker på at du vil ignorere dem?" + }, + "navigation": { + "no_results": "Ingen resultater", + "no_more_results": "Sidetallet %{page} er utenfor grensene. Prøv forrige side.", + "page_out_of_boundaries": "Sidetall %{page} utenfor grensene", + "page_out_from_end": "Kan ikke gå etter siste side", + "page_out_from_begin": "Kan ikke gå før side 1", + "page_range_info": "%{offsetBegin}-%{offsetEnd} av %{total}", + "page_rows_per_page": "Elementer per side:", + "next": "Neste", + "prev": "Forrige", + "skip_nav": "Hopp til innholdet" + }, + "notification": { + "updated": "Element oppdatert |||| %{smart_count} elementer er oppdatert", + "created": "Element opprettet", + "deleted": "Element slettet |||| %{smart_count} elementer slettet", + "bad_item": "Feil element", + "item_doesnt_exist": "Elementet eksisterer ikke", + "http_error": "Serverkommunikasjonsfeil", + "data_provider_error": "dataleverandørfeil. Sjekk konsollen for detaljer.", + "i18n_error": "Kan ikke laste oversettelsene for det angitte språket", + "canceled": "Handlingen avbrutt", + "logged_out": "Økten din er avsluttet. Koble til på nytt.", + "new_version": "Ny versjon tilgjengelig! Trykk Oppdater " + }, + "toggleFieldsMenu": { + "columnsToDisplay": "Kolonner som skal vises", + "layout": "Oppsett", + "grid": "Nett", + "table": "Bord" + } + }, + "message": { + "note": "Info", + "transcodingDisabled": "Endring av transkodingskonfigurasjonen gjennom webgrensesnittet er deaktivert av sikkerhetsgrunner. Hvis du ønsker å endre (redigere eller legge til) transkodingsalternativer, start serveren på nytt med %{config}-konfigurasjonsalternativet.", + "transcodingEnabled": "Navidrome kjører for øyeblikket med %{config}, noe som gjør det mulig å kjøre systemkommandoer fra transkodingsinnstillingene ved å bruke nettgrensesnittet. Vi anbefaler å deaktivere den av sikkerhetsgrunner og bare aktivere den når du konfigurerer alternativer for omkoding.", + "songsAddedToPlaylist": "Lagt til 1 sang i spillelisten |||| Lagt til %{smart_count} sanger i spillelisten", + "noPlaylistsAvailable": "Ingen tilgjengelig", + "delete_user_title": "Slett bruker «%{name}»", + "delete_user_content": "Er du sikker på at du vil slette denne brukeren og alle dataene deres (inkludert spillelister og preferanser)?", + "notifications_blocked": "Du har blokkert varsler for dette nettstedet i nettleserens innstillinger", + "notifications_not_available": "Denne nettleseren støtter ikke skrivebordsvarsler, eller du har ikke tilgang til Navidrome over https", + "lastfmLinkSuccess": "Last.fm er vellykket koblet og scrobbling aktivert", + "lastfmLinkFailure": "Last.fm kunne ikke kobles til", + "lastfmUnlinkSuccess": "Last.fm koblet fra og scrobbling deaktivert", + "lastfmUnlinkFailure": "Last.fm kunne ikke kobles fra", + "openIn": { + "lastfm": "Åpne i Last.fm", + "musicbrainz": "Åpne i MusicBrainz" + }, + "lastfmLink": "Les mer...", + "listenBrainzLinkSuccess": "ListenBrainz er vellykket koblet og scrobbling aktivert som bruker: %{user}", + "listenBrainzLinkFailure": "ListenBrainz kunne ikke kobles: %{error}", + "listenBrainzUnlinkSuccess": "ListenBrainz koblet fra og scrobbling deaktivert", + "listenBrainzUnlinkFailure": "ListenBrainz kunne ikke fjernes", + "downloadOriginalFormat": "", + "shareOriginalFormat": "", + "shareDialogTitle": "", + "shareBatchDialogTitle": "", + "shareSuccess": "", + "shareFailure": "", + "downloadDialogTitle": "", + "shareCopyToClipboard": "", + "remove_missing_title": "", + "remove_missing_content": "" + }, + "menu": { + "library": "Bibliotek", + "settings": "Innstillinger", + "version": "Versjon", + "theme": "Tema", + "personal": { + "name": "Personlig", + "options": { + "theme": "Tema", + "language": "Språk", + "defaultView": "Standardvisning", + "desktop_notifications": "Skrivebordsvarsler", + "lastfmScrobbling": "Scrobble til Last.fm", + "listenBrainzScrobbling": "Scrobble til ListenBrainz", + "replaygain": "", + "preAmp": "", + "gain": { + "none": "", + "album": "", + "track": "" + }, + "lastfmNotConfigured": "" + } + }, + "albumList": "Album", + "about": "Om", + "playlists": "Spilleliste", + "sharedPlaylists": "Delte spillelister" + }, + "player": { + "playListsText": "Spillekø", + "openText": "Åpne", + "closeText": "Lukk", + "notContentText": "Ingen musikk", + "clickToPlayText": "Klikk for å spille", + "clickToPauseText": "Klikk for å sette på pause", + "nextTrackText": "Neste spor", + "previousTrackText": "Forrige spor", + "reloadText": "Last inn på nytt", + "volumeText": "Volum", + "toggleLyricText": "Veksle mellom tekster", + "toggleMiniModeText": "Minimer", + "destroyText": "Ødelegge", + "downloadText": "nedlasting", + "removeAudioListsText": "Slett lydlister", + "clickToDeleteText": "Klikk for å slette %{name}", + "emptyLyricText": "Ingen sangtekster", + "playModeText": { + "order": "I rekkefølge", + "orderLoop": "Gjenta", + "singleLoop": "Gjenta engang", + "shufflePlay": "Tilfeldig rekkefølge" + } + }, + "about": { + "links": { + "homepage": "Hjemmeside", + "source": "Kildekode", + "featureRequests": "Funksjonsforespørsler", + "lastInsightsCollection": "", + "insights": { + "disabled": "", + "waiting": "" + } + } + }, + "activity": { + "title": "Aktivitet", + "totalScanned": "Totalt skannede mapper", + "quickScan": "Rask skanning", + "fullScan": "Full skanning", + "serverUptime": "Serveroppetid", + "serverDown": "OFFLINE" + }, + "help": { + "title": "Navidrome hurtigtaster", + "hotkeys": { + "show_help": "Vis denne hjelpen", + "toggle_menu": "Bytt menysidelinje", + "toggle_play": "Spill / Pause", + "prev_song": "Forrige sang", + "next_song": "Neste sang", + "vol_up": "Volum opp", + "vol_down": "Volum ned", + "toggle_love": "Legg til dette sporet i favoritter", + "current_song": "" + } + } +} \ No newline at end of file From 46a2ec0ba195183419e3836de7d2f41f96061d92 Mon Sep 17 00:00:00 2001 From: Deluan Date: Tue, 25 Mar 2025 20:05:24 -0400 Subject: [PATCH 47/51] feat(ui): hide absolute paths from regular users Signed-off-by: Deluan --- ui/src/common/PathField.jsx | 24 ++++----- ui/src/common/PathField.test.jsx | 86 ++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 13 deletions(-) create mode 100644 ui/src/common/PathField.test.jsx diff --git a/ui/src/common/PathField.jsx b/ui/src/common/PathField.jsx index 115a2ee49..21822878a 100644 --- a/ui/src/common/PathField.jsx +++ b/ui/src/common/PathField.jsx @@ -1,24 +1,22 @@ import PropTypes from 'prop-types' import React from 'react' -import { useRecordContext } from 'react-admin' +import { usePermissions, useRecordContext } from 'react-admin' import config from '../config' export const PathField = (props) => { const record = useRecordContext(props) - return ( - - {record.libraryPath} - {config.separator} - {record.path} - - ) + const { permissions } = usePermissions() + let path = permissions === 'admin' ? record.libraryPath : '' + + if (path && path.endsWith(config.separator)) { + path = `${path}${record.path}` + } else { + path = path ? `${path}${config.separator}${record.path}` : record.path + } + + return {path} } PathField.propTypes = { - label: PropTypes.string, record: PropTypes.object, } - -PathField.defaultProps = { - addLabel: true, -} diff --git a/ui/src/common/PathField.test.jsx b/ui/src/common/PathField.test.jsx new file mode 100644 index 000000000..de8b90899 --- /dev/null +++ b/ui/src/common/PathField.test.jsx @@ -0,0 +1,86 @@ +import React from 'react' +import { render } from '@testing-library/react' +import { PathField } from './PathField' +import { usePermissions, useRecordContext } from 'react-admin' +import config from '../config' + +// Mock react-admin hooks +vi.mock('react-admin', () => ({ + usePermissions: vi.fn(), + useRecordContext: vi.fn(), +})) + +// Mock config +vi.mock('../config', () => ({ + default: { + separator: '/', + }, +})) + +describe('PathField', () => { + beforeEach(() => { + vi.clearAllMocks() + }) + + it('renders path without libraryPath for non-admin users', () => { + // Setup + usePermissions.mockReturnValue({ permissions: 'user' }) + useRecordContext.mockReturnValue({ + path: 'music/song.mp3', + libraryPath: '/data/media', + }) + + // Act + const { container } = render() + + // Assert + expect(container.textContent).toBe('music/song.mp3') + expect(container.textContent).not.toContain('/data/media') + }) + + it('renders combined path for admin users when libraryPath does not end with separator', () => { + // Setup + usePermissions.mockReturnValue({ permissions: 'admin' }) + useRecordContext.mockReturnValue({ + path: 'music/song.mp3', + libraryPath: '/data/media', + }) + + // Act + const { container } = render() + + // Assert + expect(container.textContent).toBe('/data/media/music/song.mp3') + }) + + it('renders combined path for admin users when libraryPath ends with separator', () => { + // Setup + usePermissions.mockReturnValue({ permissions: 'admin' }) + useRecordContext.mockReturnValue({ + path: 'music/song.mp3', + libraryPath: '/data/media/', + }) + + // Act + const { container } = render() + + // Assert + expect(container.textContent).toBe('/data/media/music/song.mp3') + }) + + it('works with a different separator from config', () => { + // Setup + config.separator = '\\' + usePermissions.mockReturnValue({ permissions: 'admin' }) + useRecordContext.mockReturnValue({ + path: 'music\\song.mp3', + libraryPath: 'C:\\data', + }) + + // Act + const { container } = render() + + // Assert + expect(container.textContent).toBe('C:\\data\\music\\song.mp3') + }) +}) From 5ab345c83ed8af92f95e4131299d879b18a1f37f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Deluan=20Quint=C3=A3o?= Date: Thu, 27 Mar 2025 18:57:06 -0400 Subject: [PATCH 48/51] chore(server): add more info to scrobble errors logs (#3889) * chore(server): add more info to scrobble errors Signed-off-by: Deluan * chore(server): add more info to scrobble errors Signed-off-by: Deluan * chore(server): add more info to scrobble errors Signed-off-by: Deluan --------- Signed-off-by: Deluan --- core/agents/lastfm/agent.go | 10 +++++----- core/agents/listenbrainz/agent.go | 12 ++++++------ utils/cache/cached_http_client.go | 4 +++- utils/cache/simple_cache.go | 9 ++++++++- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/core/agents/lastfm/agent.go b/core/agents/lastfm/agent.go index 01ffa677e..0c8d290d4 100644 --- a/core/agents/lastfm/agent.go +++ b/core/agents/lastfm/agent.go @@ -296,7 +296,7 @@ func (l *lastfmAgent) NowPlaying(ctx context.Context, userId string, track *mode }) if err != nil { log.Warn(ctx, "Last.fm client.updateNowPlaying returned error", "track", track.Title, err) - return scrobbler.ErrUnrecoverable + return errors.Join(err, scrobbler.ErrUnrecoverable) } return nil } @@ -304,7 +304,7 @@ func (l *lastfmAgent) NowPlaying(ctx context.Context, userId string, track *mode func (l *lastfmAgent) Scrobble(ctx context.Context, userId string, s scrobbler.Scrobble) error { sk, err := l.sessionKeys.Get(ctx, userId) if err != nil || sk == "" { - return scrobbler.ErrNotAuthorized + return errors.Join(err, scrobbler.ErrNotAuthorized) } if s.Duration <= 30 { @@ -328,12 +328,12 @@ func (l *lastfmAgent) Scrobble(ctx context.Context, userId string, s scrobbler.S isLastFMError := errors.As(err, &lfErr) if !isLastFMError { log.Warn(ctx, "Last.fm client.scrobble returned error", "track", s.Title, err) - return scrobbler.ErrRetryLater + return errors.Join(err, scrobbler.ErrRetryLater) } if lfErr.Code == 11 || lfErr.Code == 16 { - return scrobbler.ErrRetryLater + return errors.Join(err, scrobbler.ErrRetryLater) } - return scrobbler.ErrUnrecoverable + return errors.Join(err, scrobbler.ErrUnrecoverable) } func (l *lastfmAgent) IsAuthorized(ctx context.Context, userId string) bool { diff --git a/core/agents/listenbrainz/agent.go b/core/agents/listenbrainz/agent.go index e808f025e..200e9f63c 100644 --- a/core/agents/listenbrainz/agent.go +++ b/core/agents/listenbrainz/agent.go @@ -76,14 +76,14 @@ func (l *listenBrainzAgent) formatListen(track *model.MediaFile) listenInfo { func (l *listenBrainzAgent) NowPlaying(ctx context.Context, userId string, track *model.MediaFile) error { sk, err := l.sessionKeys.Get(ctx, userId) if err != nil || sk == "" { - return scrobbler.ErrNotAuthorized + return errors.Join(err, scrobbler.ErrNotAuthorized) } li := l.formatListen(track) err = l.client.updateNowPlaying(ctx, sk, li) if err != nil { log.Warn(ctx, "ListenBrainz updateNowPlaying returned error", "track", track.Title, err) - return scrobbler.ErrUnrecoverable + return errors.Join(err, scrobbler.ErrUnrecoverable) } return nil } @@ -91,7 +91,7 @@ func (l *listenBrainzAgent) NowPlaying(ctx context.Context, userId string, track func (l *listenBrainzAgent) Scrobble(ctx context.Context, userId string, s scrobbler.Scrobble) error { sk, err := l.sessionKeys.Get(ctx, userId) if err != nil || sk == "" { - return scrobbler.ErrNotAuthorized + return errors.Join(err, scrobbler.ErrNotAuthorized) } li := l.formatListen(&s.MediaFile) @@ -105,12 +105,12 @@ func (l *listenBrainzAgent) Scrobble(ctx context.Context, userId string, s scrob isListenBrainzError := errors.As(err, &lbErr) if !isListenBrainzError { log.Warn(ctx, "ListenBrainz Scrobble returned HTTP error", "track", s.Title, err) - return scrobbler.ErrRetryLater + return errors.Join(err, scrobbler.ErrRetryLater) } if lbErr.Code == 500 || lbErr.Code == 503 { - return scrobbler.ErrRetryLater + return errors.Join(err, scrobbler.ErrRetryLater) } - return scrobbler.ErrUnrecoverable + return errors.Join(err, scrobbler.ErrUnrecoverable) } func (l *listenBrainzAgent) IsAuthorized(ctx context.Context, userId string) bool { diff --git a/utils/cache/cached_http_client.go b/utils/cache/cached_http_client.go index d570cb062..94d33100b 100644 --- a/utils/cache/cached_http_client.go +++ b/utils/cache/cached_http_client.go @@ -49,16 +49,18 @@ func (c *HTTPClient) Do(req *http.Request) (*http.Response, error) { cached = false req, err := c.deserializeReq(key) if err != nil { + log.Trace(req.Context(), "CachedHTTPClient.Do", "key", key, err) return "", 0, err } resp, err := c.hc.Do(req) if err != nil { + log.Trace(req.Context(), "CachedHTTPClient.Do", "req", req, err) return "", 0, err } defer resp.Body.Close() return c.serializeResponse(resp), c.ttl, nil }) - log.Trace(req.Context(), "CachedHTTPClient.Do", "key", key, "cached", cached, "elapsed", time.Since(start)) + log.Trace(req.Context(), "CachedHTTPClient.Do", "key", key, "cached", cached, "elapsed", time.Since(start), err) if err != nil { return nil, err } diff --git a/utils/cache/simple_cache.go b/utils/cache/simple_cache.go index 595a26637..182d1d12a 100644 --- a/utils/cache/simple_cache.go +++ b/utils/cache/simple_cache.go @@ -2,6 +2,7 @@ package cache import ( "errors" + "fmt" "sync/atomic" "time" @@ -74,10 +75,13 @@ func (c *simpleCache[K, V]) Get(key K) (V, error) { } func (c *simpleCache[K, V]) GetWithLoader(key K, loader func(key K) (V, time.Duration, error)) (V, error) { + var err error loaderWrapper := ttlcache.LoaderFunc[K, V]( func(t *ttlcache.Cache[K, V], key K) *ttlcache.Item[K, V] { c.evictExpired() - value, ttl, err := loader(key) + var value V + var ttl time.Duration + value, ttl, err = loader(key) if err != nil { return nil } @@ -87,6 +91,9 @@ func (c *simpleCache[K, V]) GetWithLoader(key K, loader func(key K) (V, time.Dur item := c.data.Get(key, ttlcache.WithLoader[K, V](loaderWrapper)) if item == nil { var zero V + if err != nil { + return zero, fmt.Errorf("cache error: loader returned %w", err) + } return zero, errors.New("item not found") } return item.Value(), nil From cf100c4eb422c63aca3121d541263c811bced527 Mon Sep 17 00:00:00 2001 From: Deluan Date: Thu, 27 Mar 2025 22:50:22 -0400 Subject: [PATCH 49/51] chore(subsonic): update snapshot tests to use version 1.16.1 --- .../Responses AlbumInfo with data should match .JSON | 4 ++-- .../Responses AlbumInfo with data should match .XML | 2 +- .../Responses AlbumInfo without data should match .JSON | 4 ++-- .../Responses AlbumInfo without data should match .XML | 2 +- .../Responses AlbumList with OS data should match .JSON | 4 ++-- .../Responses AlbumList with OS data should match .XML | 2 +- .../Responses AlbumList with data should match .JSON | 4 ++-- .../Responses AlbumList with data should match .XML | 2 +- .../Responses AlbumList without data should match .JSON | 4 ++-- .../Responses AlbumList without data should match .XML | 2 +- .../Responses AlbumWithSongsID3 with data should match .JSON | 4 ++-- .../Responses AlbumWithSongsID3 with data should match .XML | 2 +- ...esponses AlbumWithSongsID3 without data should match .JSON | 4 ++-- ...Responses AlbumWithSongsID3 without data should match .XML | 2 +- ...mWithSongsID3 without data should match OpenSubsonic .JSON | 4 ++-- ...umWithSongsID3 without data should match OpenSubsonic .XML | 2 +- ...Responses Artist with OpenSubsonic data should match .JSON | 4 ++-- .../Responses Artist with OpenSubsonic data should match .XML | 2 +- .../.snapshots/Responses Artist with data should match .JSON | 4 ++-- .../.snapshots/Responses Artist with data should match .XML | 2 +- .../Responses Artist without data should match .JSON | 4 ++-- .../Responses Artist without data should match .XML | 2 +- .../Responses ArtistInfo with data should match .JSON | 4 ++-- .../Responses ArtistInfo with data should match .XML | 2 +- .../Responses ArtistInfo without data should match .JSON | 4 ++-- .../Responses ArtistInfo without data should match .XML | 2 +- .../Responses Bookmarks with data should match .JSON | 4 ++-- .../Responses Bookmarks with data should match .XML | 2 +- .../Responses Bookmarks without data should match .JSON | 4 ++-- .../Responses Bookmarks without data should match .XML | 2 +- .../.snapshots/Responses Child with data should match .JSON | 4 ++-- .../.snapshots/Responses Child with data should match .XML | 2 +- .../Responses Child without data should match .JSON | 4 ++-- .../.snapshots/Responses Child without data should match .XML | 2 +- ...sponses Child without data should match OpenSubsonic .JSON | 4 ++-- ...esponses Child without data should match OpenSubsonic .XML | 2 +- .../Responses Directory with data should match .JSON | 4 ++-- .../Responses Directory with data should match .XML | 2 +- .../Responses Directory without data should match .JSON | 4 ++-- .../Responses Directory without data should match .XML | 2 +- .../.snapshots/Responses EmptyResponse should match .JSON | 4 ++-- .../.snapshots/Responses EmptyResponse should match .XML | 2 +- .../.snapshots/Responses Genres with data should match .JSON | 4 ++-- .../.snapshots/Responses Genres with data should match .XML | 2 +- .../Responses Genres without data should match .JSON | 4 ++-- .../Responses Genres without data should match .XML | 2 +- .../.snapshots/Responses Indexes with data should match .JSON | 4 ++-- .../.snapshots/Responses Indexes with data should match .XML | 2 +- .../Responses Indexes without data should match .JSON | 4 ++-- .../Responses Indexes without data should match .XML | 2 +- ...sponses InternetRadioStations with data should match .JSON | 4 ++-- ...esponses InternetRadioStations with data should match .XML | 2 +- ...nses InternetRadioStations without data should match .JSON | 4 ++-- ...onses InternetRadioStations without data should match .XML | 2 +- .../responses/.snapshots/Responses License should match .JSON | 4 ++-- .../responses/.snapshots/Responses License should match .XML | 2 +- .../.snapshots/Responses Lyrics with data should match .JSON | 4 ++-- .../.snapshots/Responses Lyrics with data should match .XML | 2 +- .../Responses Lyrics without data should match .JSON | 4 ++-- .../Responses Lyrics without data should match .XML | 2 +- .../Responses LyricsList with data should match .JSON | 4 ++-- .../Responses LyricsList with data should match .XML | 2 +- .../Responses LyricsList without data should match .JSON | 4 ++-- .../Responses LyricsList without data should match .XML | 2 +- .../Responses MusicFolders with data should match .JSON | 4 ++-- .../Responses MusicFolders with data should match .XML | 2 +- .../Responses MusicFolders without data should match .JSON | 4 ++-- .../Responses MusicFolders without data should match .XML | 2 +- ...ponses OpenSubsonicExtensions with data should match .JSON | 4 ++-- ...sponses OpenSubsonicExtensions with data should match .XML | 2 +- ...ses OpenSubsonicExtensions without data should match .JSON | 4 ++-- ...nses OpenSubsonicExtensions without data should match .XML | 2 +- .../Responses PlayQueue with data should match .JSON | 4 ++-- .../Responses PlayQueue with data should match .XML | 2 +- .../Responses PlayQueue without data should match .JSON | 4 ++-- .../Responses PlayQueue without data should match .XML | 2 +- .../Responses Playlists with data should match .JSON | 4 ++-- .../Responses Playlists with data should match .XML | 2 +- .../Responses Playlists without data should match .JSON | 4 ++-- .../Responses Playlists without data should match .XML | 2 +- .../Responses ScanStatus with data should match .JSON | 4 ++-- .../Responses ScanStatus with data should match .XML | 2 +- .../Responses ScanStatus without data should match .JSON | 4 ++-- .../Responses ScanStatus without data should match .XML | 2 +- .../.snapshots/Responses Shares with data should match .JSON | 4 ++-- .../.snapshots/Responses Shares with data should match .XML | 2 +- ...ponses Shares with only required fields should match .JSON | 4 ++-- ...sponses Shares with only required fields should match .XML | 2 +- .../Responses Shares without data should match .JSON | 4 ++-- .../Responses Shares without data should match .XML | 2 +- .../Responses SimilarSongs with data should match .JSON | 4 ++-- .../Responses SimilarSongs with data should match .XML | 2 +- .../Responses SimilarSongs without data should match .JSON | 4 ++-- .../Responses SimilarSongs without data should match .XML | 2 +- .../Responses SimilarSongs2 with data should match .JSON | 4 ++-- .../Responses SimilarSongs2 with data should match .XML | 2 +- .../Responses SimilarSongs2 without data should match .JSON | 4 ++-- .../Responses SimilarSongs2 without data should match .XML | 2 +- .../Responses TopSongs with data should match .JSON | 4 ++-- .../.snapshots/Responses TopSongs with data should match .XML | 2 +- .../Responses TopSongs without data should match .JSON | 4 ++-- .../Responses TopSongs without data should match .XML | 2 +- .../.snapshots/Responses User with data should match .JSON | 4 ++-- .../.snapshots/Responses User with data should match .XML | 2 +- .../.snapshots/Responses User without data should match .JSON | 4 ++-- .../.snapshots/Responses User without data should match .XML | 2 +- .../.snapshots/Responses Users with data should match .JSON | 4 ++-- .../.snapshots/Responses Users with data should match .XML | 2 +- .../Responses Users without data should match .JSON | 4 ++-- .../.snapshots/Responses Users without data should match .XML | 2 +- server/subsonic/responses/responses_test.go | 4 ++-- 111 files changed, 167 insertions(+), 167 deletions(-) diff --git a/server/subsonic/responses/.snapshots/Responses AlbumInfo with data should match .JSON b/server/subsonic/responses/.snapshots/Responses AlbumInfo with data should match .JSON index 329f03ee9..597737fde 100644 --- a/server/subsonic/responses/.snapshots/Responses AlbumInfo with data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses AlbumInfo with data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "albumInfo": { "notes": "Believe is the twenty-third studio album by American singer-actress Cher...", diff --git a/server/subsonic/responses/.snapshots/Responses AlbumInfo with data should match .XML b/server/subsonic/responses/.snapshots/Responses AlbumInfo with data should match .XML index e06da821f..be7651c14 100644 --- a/server/subsonic/responses/.snapshots/Responses AlbumInfo with data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses AlbumInfo with data should match .XML @@ -1,4 +1,4 @@ - + Believe is the twenty-third studio album by American singer-actress Cher... 03c91c40-49a6-44a7-90e7-a700edf97a62 diff --git a/server/subsonic/responses/.snapshots/Responses AlbumInfo without data should match .JSON b/server/subsonic/responses/.snapshots/Responses AlbumInfo without data should match .JSON index b67514b7e..27f0b26fa 100644 --- a/server/subsonic/responses/.snapshots/Responses AlbumInfo without data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses AlbumInfo without data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "albumInfo": {} } diff --git a/server/subsonic/responses/.snapshots/Responses AlbumInfo without data should match .XML b/server/subsonic/responses/.snapshots/Responses AlbumInfo without data should match .XML index fa8d0cedd..80aff1358 100644 --- a/server/subsonic/responses/.snapshots/Responses AlbumInfo without data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses AlbumInfo without data should match .XML @@ -1,3 +1,3 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses AlbumList with OS data should match .JSON b/server/subsonic/responses/.snapshots/Responses AlbumList with OS data should match .JSON index c7bddc312..0db35c37c 100644 --- a/server/subsonic/responses/.snapshots/Responses AlbumList with OS data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses AlbumList with OS data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "albumList": { "album": [ diff --git a/server/subsonic/responses/.snapshots/Responses AlbumList with OS data should match .XML b/server/subsonic/responses/.snapshots/Responses AlbumList with OS data should match .XML index 33aef53be..07200c0c5 100644 --- a/server/subsonic/responses/.snapshots/Responses AlbumList with OS data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses AlbumList with OS data should match .XML @@ -1,4 +1,4 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses AlbumList with data should match .JSON b/server/subsonic/responses/.snapshots/Responses AlbumList with data should match .JSON index 80a709997..946378755 100644 --- a/server/subsonic/responses/.snapshots/Responses AlbumList with data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses AlbumList with data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "albumList": { "album": [ diff --git a/server/subsonic/responses/.snapshots/Responses AlbumList with data should match .XML b/server/subsonic/responses/.snapshots/Responses AlbumList with data should match .XML index 5f171e72a..000b8c00c 100644 --- a/server/subsonic/responses/.snapshots/Responses AlbumList with data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses AlbumList with data should match .XML @@ -1,4 +1,4 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses AlbumList without data should match .JSON b/server/subsonic/responses/.snapshots/Responses AlbumList without data should match .JSON index 4a668e5a1..706eefc08 100644 --- a/server/subsonic/responses/.snapshots/Responses AlbumList without data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses AlbumList without data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "albumList": {} } diff --git a/server/subsonic/responses/.snapshots/Responses AlbumList without data should match .XML b/server/subsonic/responses/.snapshots/Responses AlbumList without data should match .XML index 54a9a774e..d3012157e 100644 --- a/server/subsonic/responses/.snapshots/Responses AlbumList without data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses AlbumList without data should match .XML @@ -1,3 +1,3 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses AlbumWithSongsID3 with data should match .JSON b/server/subsonic/responses/.snapshots/Responses AlbumWithSongsID3 with data should match .JSON index 9f7d8c6b8..c3ae3ee20 100644 --- a/server/subsonic/responses/.snapshots/Responses AlbumWithSongsID3 with data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses AlbumWithSongsID3 with data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "album": { "id": "1", diff --git a/server/subsonic/responses/.snapshots/Responses AlbumWithSongsID3 with data should match .XML b/server/subsonic/responses/.snapshots/Responses AlbumWithSongsID3 with data should match .XML index 98545905a..a02c0feee 100644 --- a/server/subsonic/responses/.snapshots/Responses AlbumWithSongsID3 with data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses AlbumWithSongsID3 with data should match .XML @@ -1,4 +1,4 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses AlbumWithSongsID3 without data should match .JSON b/server/subsonic/responses/.snapshots/Responses AlbumWithSongsID3 without data should match .JSON index a9e38c9be..fbeded48a 100644 --- a/server/subsonic/responses/.snapshots/Responses AlbumWithSongsID3 without data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses AlbumWithSongsID3 without data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "album": { "id": "", diff --git a/server/subsonic/responses/.snapshots/Responses AlbumWithSongsID3 without data should match .XML b/server/subsonic/responses/.snapshots/Responses AlbumWithSongsID3 without data should match .XML index 43189f2a3..159967c1d 100644 --- a/server/subsonic/responses/.snapshots/Responses AlbumWithSongsID3 without data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses AlbumWithSongsID3 without data should match .XML @@ -1,3 +1,3 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses AlbumWithSongsID3 without data should match OpenSubsonic .JSON b/server/subsonic/responses/.snapshots/Responses AlbumWithSongsID3 without data should match OpenSubsonic .JSON index d179e628a..758aef0cb 100644 --- a/server/subsonic/responses/.snapshots/Responses AlbumWithSongsID3 without data should match OpenSubsonic .JSON +++ b/server/subsonic/responses/.snapshots/Responses AlbumWithSongsID3 without data should match OpenSubsonic .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "album": { "id": "", diff --git a/server/subsonic/responses/.snapshots/Responses AlbumWithSongsID3 without data should match OpenSubsonic .XML b/server/subsonic/responses/.snapshots/Responses AlbumWithSongsID3 without data should match OpenSubsonic .XML index 43189f2a3..159967c1d 100644 --- a/server/subsonic/responses/.snapshots/Responses AlbumWithSongsID3 without data should match OpenSubsonic .XML +++ b/server/subsonic/responses/.snapshots/Responses AlbumWithSongsID3 without data should match OpenSubsonic .XML @@ -1,3 +1,3 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses Artist with OpenSubsonic data should match .JSON b/server/subsonic/responses/.snapshots/Responses Artist with OpenSubsonic data should match .JSON index f7d701d03..71d365dda 100644 --- a/server/subsonic/responses/.snapshots/Responses Artist with OpenSubsonic data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses Artist with OpenSubsonic data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "artists": { "index": [ diff --git a/server/subsonic/responses/.snapshots/Responses Artist with OpenSubsonic data should match .XML b/server/subsonic/responses/.snapshots/Responses Artist with OpenSubsonic data should match .XML index 630ef919b..799d21054 100644 --- a/server/subsonic/responses/.snapshots/Responses Artist with OpenSubsonic data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses Artist with OpenSubsonic data should match .XML @@ -1,4 +1,4 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses Artist with data should match .JSON b/server/subsonic/responses/.snapshots/Responses Artist with data should match .JSON index e6c74332c..f60df3ebf 100644 --- a/server/subsonic/responses/.snapshots/Responses Artist with data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses Artist with data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "artists": { "index": [ diff --git a/server/subsonic/responses/.snapshots/Responses Artist with data should match .XML b/server/subsonic/responses/.snapshots/Responses Artist with data should match .XML index 1e3aaba16..21bea828c 100644 --- a/server/subsonic/responses/.snapshots/Responses Artist with data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses Artist with data should match .XML @@ -1,4 +1,4 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses Artist without data should match .JSON b/server/subsonic/responses/.snapshots/Responses Artist without data should match .JSON index b4b504f6e..74bb5683b 100644 --- a/server/subsonic/responses/.snapshots/Responses Artist without data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses Artist without data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "artists": { "lastModified": 1, diff --git a/server/subsonic/responses/.snapshots/Responses Artist without data should match .XML b/server/subsonic/responses/.snapshots/Responses Artist without data should match .XML index 01fda5620..781599731 100644 --- a/server/subsonic/responses/.snapshots/Responses Artist without data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses Artist without data should match .XML @@ -1,3 +1,3 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses ArtistInfo with data should match .JSON b/server/subsonic/responses/.snapshots/Responses ArtistInfo with data should match .JSON index d062e9c20..2edaa7edc 100644 --- a/server/subsonic/responses/.snapshots/Responses ArtistInfo with data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses ArtistInfo with data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "artistInfo": { "biography": "Black Sabbath is an English \u003ca target='_blank' href=\"https://www.last.fm/tag/heavy%20metal\" class=\"bbcode_tag\" rel=\"tag\"\u003eheavy metal\u003c/a\u003e band", diff --git a/server/subsonic/responses/.snapshots/Responses ArtistInfo with data should match .XML b/server/subsonic/responses/.snapshots/Responses ArtistInfo with data should match .XML index ce0dda0d8..16c6c5fe0 100644 --- a/server/subsonic/responses/.snapshots/Responses ArtistInfo with data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses ArtistInfo with data should match .XML @@ -1,4 +1,4 @@ - + Black Sabbath is an English <a target='_blank' href="https://www.last.fm/tag/heavy%20metal" class="bbcode_tag" rel="tag">heavy metal</a> band 5182c1d9-c7d2-4dad-afa0-ccfeada921a8 diff --git a/server/subsonic/responses/.snapshots/Responses ArtistInfo without data should match .JSON b/server/subsonic/responses/.snapshots/Responses ArtistInfo without data should match .JSON index 215bd61b5..8e2807982 100644 --- a/server/subsonic/responses/.snapshots/Responses ArtistInfo without data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses ArtistInfo without data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "artistInfo": {} } diff --git a/server/subsonic/responses/.snapshots/Responses ArtistInfo without data should match .XML b/server/subsonic/responses/.snapshots/Responses ArtistInfo without data should match .XML index cc4fe25be..16f0ad2c5 100644 --- a/server/subsonic/responses/.snapshots/Responses ArtistInfo without data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses ArtistInfo without data should match .XML @@ -1,3 +1,3 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses Bookmarks with data should match .JSON b/server/subsonic/responses/.snapshots/Responses Bookmarks with data should match .JSON index 0cf51c8d5..7ca38d4db 100644 --- a/server/subsonic/responses/.snapshots/Responses Bookmarks with data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses Bookmarks with data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "bookmarks": { "bookmark": [ diff --git a/server/subsonic/responses/.snapshots/Responses Bookmarks with data should match .XML b/server/subsonic/responses/.snapshots/Responses Bookmarks with data should match .XML index ef2443428..66c57820e 100644 --- a/server/subsonic/responses/.snapshots/Responses Bookmarks with data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses Bookmarks with data should match .XML @@ -1,4 +1,4 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses Bookmarks without data should match .JSON b/server/subsonic/responses/.snapshots/Responses Bookmarks without data should match .JSON index 693beb1bc..267b06eea 100644 --- a/server/subsonic/responses/.snapshots/Responses Bookmarks without data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses Bookmarks without data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "bookmarks": {} } diff --git a/server/subsonic/responses/.snapshots/Responses Bookmarks without data should match .XML b/server/subsonic/responses/.snapshots/Responses Bookmarks without data should match .XML index f1365599c..c0f16179a 100644 --- a/server/subsonic/responses/.snapshots/Responses Bookmarks without data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses Bookmarks without data should match .XML @@ -1,3 +1,3 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses Child with data should match .JSON b/server/subsonic/responses/.snapshots/Responses Child with data should match .JSON index c3290868b..13aa1f187 100644 --- a/server/subsonic/responses/.snapshots/Responses Child with data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses Child with data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "directory": { "child": [ diff --git a/server/subsonic/responses/.snapshots/Responses Child with data should match .XML b/server/subsonic/responses/.snapshots/Responses Child with data should match .XML index a565f279c..477892ac7 100644 --- a/server/subsonic/responses/.snapshots/Responses Child with data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses Child with data should match .XML @@ -1,4 +1,4 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses Child without data should match .JSON b/server/subsonic/responses/.snapshots/Responses Child without data should match .JSON index ddcc45bd8..66b49830f 100644 --- a/server/subsonic/responses/.snapshots/Responses Child without data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses Child without data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "directory": { "child": [ diff --git a/server/subsonic/responses/.snapshots/Responses Child without data should match .XML b/server/subsonic/responses/.snapshots/Responses Child without data should match .XML index fc33a139c..d43b9d3ef 100644 --- a/server/subsonic/responses/.snapshots/Responses Child without data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses Child without data should match .XML @@ -1,4 +1,4 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses Child without data should match OpenSubsonic .JSON b/server/subsonic/responses/.snapshots/Responses Child without data should match OpenSubsonic .JSON index 4b8ac19ba..5dc0e8eb8 100644 --- a/server/subsonic/responses/.snapshots/Responses Child without data should match OpenSubsonic .JSON +++ b/server/subsonic/responses/.snapshots/Responses Child without data should match OpenSubsonic .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "directory": { "child": [ diff --git a/server/subsonic/responses/.snapshots/Responses Child without data should match OpenSubsonic .XML b/server/subsonic/responses/.snapshots/Responses Child without data should match OpenSubsonic .XML index fc33a139c..d43b9d3ef 100644 --- a/server/subsonic/responses/.snapshots/Responses Child without data should match OpenSubsonic .XML +++ b/server/subsonic/responses/.snapshots/Responses Child without data should match OpenSubsonic .XML @@ -1,4 +1,4 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses Directory with data should match .JSON b/server/subsonic/responses/.snapshots/Responses Directory with data should match .JSON index 6138cbb00..daa7b9c7e 100644 --- a/server/subsonic/responses/.snapshots/Responses Directory with data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses Directory with data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "directory": { "child": [ diff --git a/server/subsonic/responses/.snapshots/Responses Directory with data should match .XML b/server/subsonic/responses/.snapshots/Responses Directory with data should match .XML index 8b256a111..2ac4f9529 100644 --- a/server/subsonic/responses/.snapshots/Responses Directory with data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses Directory with data should match .XML @@ -1,4 +1,4 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses Directory without data should match .JSON b/server/subsonic/responses/.snapshots/Responses Directory without data should match .JSON index 9636d1b7a..c76abb908 100644 --- a/server/subsonic/responses/.snapshots/Responses Directory without data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses Directory without data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "directory": { "id": "1", diff --git a/server/subsonic/responses/.snapshots/Responses Directory without data should match .XML b/server/subsonic/responses/.snapshots/Responses Directory without data should match .XML index 44b989908..1c1f1d2ad 100644 --- a/server/subsonic/responses/.snapshots/Responses Directory without data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses Directory without data should match .XML @@ -1,3 +1,3 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses EmptyResponse should match .JSON b/server/subsonic/responses/.snapshots/Responses EmptyResponse should match .JSON index 0972d329e..d53ba841f 100644 --- a/server/subsonic/responses/.snapshots/Responses EmptyResponse should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses EmptyResponse should match .JSON @@ -1,7 +1,7 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true } diff --git a/server/subsonic/responses/.snapshots/Responses EmptyResponse should match .XML b/server/subsonic/responses/.snapshots/Responses EmptyResponse should match .XML index 651d6df0d..184228a0e 100644 --- a/server/subsonic/responses/.snapshots/Responses EmptyResponse should match .XML +++ b/server/subsonic/responses/.snapshots/Responses EmptyResponse should match .XML @@ -1 +1 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses Genres with data should match .JSON b/server/subsonic/responses/.snapshots/Responses Genres with data should match .JSON index b38c97361..90d86535a 100644 --- a/server/subsonic/responses/.snapshots/Responses Genres with data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses Genres with data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "genres": { "genre": [ diff --git a/server/subsonic/responses/.snapshots/Responses Genres with data should match .XML b/server/subsonic/responses/.snapshots/Responses Genres with data should match .XML index 02034e7af..75497c403 100644 --- a/server/subsonic/responses/.snapshots/Responses Genres with data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses Genres with data should match .XML @@ -1,4 +1,4 @@ - + Rock Reggae diff --git a/server/subsonic/responses/.snapshots/Responses Genres without data should match .JSON b/server/subsonic/responses/.snapshots/Responses Genres without data should match .JSON index 45c5a7bca..0e473a617 100644 --- a/server/subsonic/responses/.snapshots/Responses Genres without data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses Genres without data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "genres": {} } diff --git a/server/subsonic/responses/.snapshots/Responses Genres without data should match .XML b/server/subsonic/responses/.snapshots/Responses Genres without data should match .XML index d0a66c3e0..4f4217d43 100644 --- a/server/subsonic/responses/.snapshots/Responses Genres without data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses Genres without data should match .XML @@ -1,3 +1,3 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses Indexes with data should match .JSON b/server/subsonic/responses/.snapshots/Responses Indexes with data should match .JSON index 9f835da1a..9704eab58 100644 --- a/server/subsonic/responses/.snapshots/Responses Indexes with data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses Indexes with data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "indexes": { "index": [ diff --git a/server/subsonic/responses/.snapshots/Responses Indexes with data should match .XML b/server/subsonic/responses/.snapshots/Responses Indexes with data should match .XML index 595f2ff03..6fc70b498 100644 --- a/server/subsonic/responses/.snapshots/Responses Indexes with data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses Indexes with data should match .XML @@ -1,4 +1,4 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses Indexes without data should match .JSON b/server/subsonic/responses/.snapshots/Responses Indexes without data should match .JSON index 4dbdc3617..e267fcc01 100644 --- a/server/subsonic/responses/.snapshots/Responses Indexes without data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses Indexes without data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "indexes": { "lastModified": 1, diff --git a/server/subsonic/responses/.snapshots/Responses Indexes without data should match .XML b/server/subsonic/responses/.snapshots/Responses Indexes without data should match .XML index fad3a53e4..f433b62bc 100644 --- a/server/subsonic/responses/.snapshots/Responses Indexes without data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses Indexes without data should match .XML @@ -1,3 +1,3 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses InternetRadioStations with data should match .JSON b/server/subsonic/responses/.snapshots/Responses InternetRadioStations with data should match .JSON index 355523605..5762011ae 100644 --- a/server/subsonic/responses/.snapshots/Responses InternetRadioStations with data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses InternetRadioStations with data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "internetRadioStations": { "internetRadioStation": [ diff --git a/server/subsonic/responses/.snapshots/Responses InternetRadioStations with data should match .XML b/server/subsonic/responses/.snapshots/Responses InternetRadioStations with data should match .XML index bf65d41d2..24cd687c5 100644 --- a/server/subsonic/responses/.snapshots/Responses InternetRadioStations with data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses InternetRadioStations with data should match .XML @@ -1,4 +1,4 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses InternetRadioStations without data should match .JSON b/server/subsonic/responses/.snapshots/Responses InternetRadioStations without data should match .JSON index f4cee5c84..30d81f29d 100644 --- a/server/subsonic/responses/.snapshots/Responses InternetRadioStations without data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses InternetRadioStations without data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "internetRadioStations": {} } diff --git a/server/subsonic/responses/.snapshots/Responses InternetRadioStations without data should match .XML b/server/subsonic/responses/.snapshots/Responses InternetRadioStations without data should match .XML index 1c5ae82a9..ba81e4215 100644 --- a/server/subsonic/responses/.snapshots/Responses InternetRadioStations without data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses InternetRadioStations without data should match .XML @@ -1,3 +1,3 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses License should match .JSON b/server/subsonic/responses/.snapshots/Responses License should match .JSON index 4052c5491..00f3ab7cb 100644 --- a/server/subsonic/responses/.snapshots/Responses License should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses License should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "license": { "valid": true diff --git a/server/subsonic/responses/.snapshots/Responses License should match .XML b/server/subsonic/responses/.snapshots/Responses License should match .XML index dc56efabc..f892e6f95 100644 --- a/server/subsonic/responses/.snapshots/Responses License should match .XML +++ b/server/subsonic/responses/.snapshots/Responses License should match .XML @@ -1,3 +1,3 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses Lyrics with data should match .JSON b/server/subsonic/responses/.snapshots/Responses Lyrics with data should match .JSON index 35833e00a..e2c2b4dbf 100644 --- a/server/subsonic/responses/.snapshots/Responses Lyrics with data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses Lyrics with data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "lyrics": { "artist": "Rick Astley", diff --git a/server/subsonic/responses/.snapshots/Responses Lyrics with data should match .XML b/server/subsonic/responses/.snapshots/Responses Lyrics with data should match .XML index 51f0032d4..52c0ff39b 100644 --- a/server/subsonic/responses/.snapshots/Responses Lyrics with data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses Lyrics with data should match .XML @@ -1,3 +1,3 @@ - + Never gonna give you up Never gonna let you down Never gonna run around and desert you Never gonna say goodbye diff --git a/server/subsonic/responses/.snapshots/Responses Lyrics without data should match .JSON b/server/subsonic/responses/.snapshots/Responses Lyrics without data should match .JSON index 1094e9e1f..d6d40298a 100644 --- a/server/subsonic/responses/.snapshots/Responses Lyrics without data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses Lyrics without data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "lyrics": { "value": "" diff --git a/server/subsonic/responses/.snapshots/Responses Lyrics without data should match .XML b/server/subsonic/responses/.snapshots/Responses Lyrics without data should match .XML index cc1821d78..d7fcb284e 100644 --- a/server/subsonic/responses/.snapshots/Responses Lyrics without data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses Lyrics without data should match .XML @@ -1,3 +1,3 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses LyricsList with data should match .JSON b/server/subsonic/responses/.snapshots/Responses LyricsList with data should match .JSON index c855a660e..e027d62e6 100644 --- a/server/subsonic/responses/.snapshots/Responses LyricsList with data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses LyricsList with data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "lyricsList": { "structuredLyrics": [ diff --git a/server/subsonic/responses/.snapshots/Responses LyricsList with data should match .XML b/server/subsonic/responses/.snapshots/Responses LyricsList with data should match .XML index 262b1d390..0f1c6c565 100644 --- a/server/subsonic/responses/.snapshots/Responses LyricsList with data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses LyricsList with data should match .XML @@ -1,4 +1,4 @@ - + We're no strangers to love diff --git a/server/subsonic/responses/.snapshots/Responses LyricsList without data should match .JSON b/server/subsonic/responses/.snapshots/Responses LyricsList without data should match .JSON index 876cc71ce..c552df1b0 100644 --- a/server/subsonic/responses/.snapshots/Responses LyricsList without data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses LyricsList without data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "lyricsList": {} } diff --git a/server/subsonic/responses/.snapshots/Responses LyricsList without data should match .XML b/server/subsonic/responses/.snapshots/Responses LyricsList without data should match .XML index 040cf6b9e..3cc86c32a 100644 --- a/server/subsonic/responses/.snapshots/Responses LyricsList without data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses LyricsList without data should match .XML @@ -1,3 +1,3 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses MusicFolders with data should match .JSON b/server/subsonic/responses/.snapshots/Responses MusicFolders with data should match .JSON index 016310833..84555b7a2 100644 --- a/server/subsonic/responses/.snapshots/Responses MusicFolders with data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses MusicFolders with data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "musicFolders": { "musicFolder": [ diff --git a/server/subsonic/responses/.snapshots/Responses MusicFolders with data should match .XML b/server/subsonic/responses/.snapshots/Responses MusicFolders with data should match .XML index 3171c6f23..a9517ea2f 100644 --- a/server/subsonic/responses/.snapshots/Responses MusicFolders with data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses MusicFolders with data should match .XML @@ -1,4 +1,4 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses MusicFolders without data should match .JSON b/server/subsonic/responses/.snapshots/Responses MusicFolders without data should match .JSON index b2fdd22a1..5c0fb8be8 100644 --- a/server/subsonic/responses/.snapshots/Responses MusicFolders without data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses MusicFolders without data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "musicFolders": {} } diff --git a/server/subsonic/responses/.snapshots/Responses MusicFolders without data should match .XML b/server/subsonic/responses/.snapshots/Responses MusicFolders without data should match .XML index 12b4ff9ce..5237139a6 100644 --- a/server/subsonic/responses/.snapshots/Responses MusicFolders without data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses MusicFolders without data should match .XML @@ -1,3 +1,3 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses OpenSubsonicExtensions with data should match .JSON b/server/subsonic/responses/.snapshots/Responses OpenSubsonicExtensions with data should match .JSON index 5e8b33ae3..d3972e7ba 100644 --- a/server/subsonic/responses/.snapshots/Responses OpenSubsonicExtensions with data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses OpenSubsonicExtensions with data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "openSubsonicExtensions": [ { diff --git a/server/subsonic/responses/.snapshots/Responses OpenSubsonicExtensions with data should match .XML b/server/subsonic/responses/.snapshots/Responses OpenSubsonicExtensions with data should match .XML index 587eda70d..adcb0086b 100644 --- a/server/subsonic/responses/.snapshots/Responses OpenSubsonicExtensions with data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses OpenSubsonicExtensions with data should match .XML @@ -1,4 +1,4 @@ - + 1 2 diff --git a/server/subsonic/responses/.snapshots/Responses OpenSubsonicExtensions without data should match .JSON b/server/subsonic/responses/.snapshots/Responses OpenSubsonicExtensions without data should match .JSON index 143bd1f80..b81ecd039 100644 --- a/server/subsonic/responses/.snapshots/Responses OpenSubsonicExtensions without data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses OpenSubsonicExtensions without data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "openSubsonicExtensions": [] } diff --git a/server/subsonic/responses/.snapshots/Responses OpenSubsonicExtensions without data should match .XML b/server/subsonic/responses/.snapshots/Responses OpenSubsonicExtensions without data should match .XML index 651d6df0d..184228a0e 100644 --- a/server/subsonic/responses/.snapshots/Responses OpenSubsonicExtensions without data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses OpenSubsonicExtensions without data should match .XML @@ -1 +1 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses PlayQueue with data should match .JSON b/server/subsonic/responses/.snapshots/Responses PlayQueue with data should match .JSON index 0af76f118..eb771692b 100644 --- a/server/subsonic/responses/.snapshots/Responses PlayQueue with data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses PlayQueue with data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "playQueue": { "entry": [ diff --git a/server/subsonic/responses/.snapshots/Responses PlayQueue with data should match .XML b/server/subsonic/responses/.snapshots/Responses PlayQueue with data should match .XML index bd9f84979..1156af0a8 100644 --- a/server/subsonic/responses/.snapshots/Responses PlayQueue with data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses PlayQueue with data should match .XML @@ -1,4 +1,4 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses PlayQueue without data should match .JSON b/server/subsonic/responses/.snapshots/Responses PlayQueue without data should match .JSON index 7af12aeed..88eebb276 100644 --- a/server/subsonic/responses/.snapshots/Responses PlayQueue without data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses PlayQueue without data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "playQueue": { "username": "", diff --git a/server/subsonic/responses/.snapshots/Responses PlayQueue without data should match .XML b/server/subsonic/responses/.snapshots/Responses PlayQueue without data should match .XML index 1a3e0b527..5af3d9157 100644 --- a/server/subsonic/responses/.snapshots/Responses PlayQueue without data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses PlayQueue without data should match .XML @@ -1,3 +1,3 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses Playlists with data should match .JSON b/server/subsonic/responses/.snapshots/Responses Playlists with data should match .JSON index 3c87c80bf..b6e996d6e 100644 --- a/server/subsonic/responses/.snapshots/Responses Playlists with data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses Playlists with data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "playlists": { "playlist": [ diff --git a/server/subsonic/responses/.snapshots/Responses Playlists with data should match .XML b/server/subsonic/responses/.snapshots/Responses Playlists with data should match .XML index 91a71d281..100301afe 100644 --- a/server/subsonic/responses/.snapshots/Responses Playlists with data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses Playlists with data should match .XML @@ -1,4 +1,4 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses Playlists without data should match .JSON b/server/subsonic/responses/.snapshots/Responses Playlists without data should match .JSON index 4a55658d8..c4510a7eb 100644 --- a/server/subsonic/responses/.snapshots/Responses Playlists without data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses Playlists without data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "playlists": {} } diff --git a/server/subsonic/responses/.snapshots/Responses Playlists without data should match .XML b/server/subsonic/responses/.snapshots/Responses Playlists without data should match .XML index 0c091fe9f..acdb6732e 100644 --- a/server/subsonic/responses/.snapshots/Responses Playlists without data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses Playlists without data should match .XML @@ -1,3 +1,3 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses ScanStatus with data should match .JSON b/server/subsonic/responses/.snapshots/Responses ScanStatus with data should match .JSON index 576c59051..af26f09e6 100644 --- a/server/subsonic/responses/.snapshots/Responses ScanStatus with data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses ScanStatus with data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "scanStatus": { "scanning": true, diff --git a/server/subsonic/responses/.snapshots/Responses ScanStatus with data should match .XML b/server/subsonic/responses/.snapshots/Responses ScanStatus with data should match .XML index fb6432bb8..6ce0dac7b 100644 --- a/server/subsonic/responses/.snapshots/Responses ScanStatus with data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses ScanStatus with data should match .XML @@ -1,3 +1,3 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses ScanStatus without data should match .JSON b/server/subsonic/responses/.snapshots/Responses ScanStatus without data should match .JSON index d880a2dea..fed45c51c 100644 --- a/server/subsonic/responses/.snapshots/Responses ScanStatus without data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses ScanStatus without data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "scanStatus": { "scanning": false, diff --git a/server/subsonic/responses/.snapshots/Responses ScanStatus without data should match .XML b/server/subsonic/responses/.snapshots/Responses ScanStatus without data should match .XML index 6e9156eab..8e622d813 100644 --- a/server/subsonic/responses/.snapshots/Responses ScanStatus without data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses ScanStatus without data should match .XML @@ -1,3 +1,3 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses Shares with data should match .JSON b/server/subsonic/responses/.snapshots/Responses Shares with data should match .JSON index d6103f59e..0c08be37a 100644 --- a/server/subsonic/responses/.snapshots/Responses Shares with data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses Shares with data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "shares": { "share": [ diff --git a/server/subsonic/responses/.snapshots/Responses Shares with data should match .XML b/server/subsonic/responses/.snapshots/Responses Shares with data should match .XML index d1770496e..36cfc25fe 100644 --- a/server/subsonic/responses/.snapshots/Responses Shares with data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses Shares with data should match .XML @@ -1,4 +1,4 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses Shares with only required fields should match .JSON b/server/subsonic/responses/.snapshots/Responses Shares with only required fields should match .JSON index cc1e48667..2856ac7f6 100644 --- a/server/subsonic/responses/.snapshots/Responses Shares with only required fields should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses Shares with only required fields should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "shares": { "share": [ diff --git a/server/subsonic/responses/.snapshots/Responses Shares with only required fields should match .XML b/server/subsonic/responses/.snapshots/Responses Shares with only required fields should match .XML index e59372b26..12e8f6bea 100644 --- a/server/subsonic/responses/.snapshots/Responses Shares with only required fields should match .XML +++ b/server/subsonic/responses/.snapshots/Responses Shares with only required fields should match .XML @@ -1,4 +1,4 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses Shares without data should match .JSON b/server/subsonic/responses/.snapshots/Responses Shares without data should match .JSON index 393e1ab32..d05e1407e 100644 --- a/server/subsonic/responses/.snapshots/Responses Shares without data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses Shares without data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "shares": {} } diff --git a/server/subsonic/responses/.snapshots/Responses Shares without data should match .XML b/server/subsonic/responses/.snapshots/Responses Shares without data should match .XML index 4b9dde4e6..9217c7850 100644 --- a/server/subsonic/responses/.snapshots/Responses Shares without data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses Shares without data should match .XML @@ -1,3 +1,3 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses SimilarSongs with data should match .JSON b/server/subsonic/responses/.snapshots/Responses SimilarSongs with data should match .JSON index 2fad6fe29..7df08ded1 100644 --- a/server/subsonic/responses/.snapshots/Responses SimilarSongs with data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses SimilarSongs with data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "similarSongs": { "song": [ diff --git a/server/subsonic/responses/.snapshots/Responses SimilarSongs with data should match .XML b/server/subsonic/responses/.snapshots/Responses SimilarSongs with data should match .XML index 7119e899d..b05443a91 100644 --- a/server/subsonic/responses/.snapshots/Responses SimilarSongs with data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses SimilarSongs with data should match .XML @@ -1,4 +1,4 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses SimilarSongs without data should match .JSON b/server/subsonic/responses/.snapshots/Responses SimilarSongs without data should match .JSON index 37092e67b..2436e38cf 100644 --- a/server/subsonic/responses/.snapshots/Responses SimilarSongs without data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses SimilarSongs without data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "similarSongs": {} } diff --git a/server/subsonic/responses/.snapshots/Responses SimilarSongs without data should match .XML b/server/subsonic/responses/.snapshots/Responses SimilarSongs without data should match .XML index 49ffa3ebd..c3e020af0 100644 --- a/server/subsonic/responses/.snapshots/Responses SimilarSongs without data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses SimilarSongs without data should match .XML @@ -1,3 +1,3 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses SimilarSongs2 with data should match .JSON b/server/subsonic/responses/.snapshots/Responses SimilarSongs2 with data should match .JSON index 9340bb5ee..73eda015e 100644 --- a/server/subsonic/responses/.snapshots/Responses SimilarSongs2 with data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses SimilarSongs2 with data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "similarSongs2": { "song": [ diff --git a/server/subsonic/responses/.snapshots/Responses SimilarSongs2 with data should match .XML b/server/subsonic/responses/.snapshots/Responses SimilarSongs2 with data should match .XML index c895a03f7..0402f031e 100644 --- a/server/subsonic/responses/.snapshots/Responses SimilarSongs2 with data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses SimilarSongs2 with data should match .XML @@ -1,4 +1,4 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses SimilarSongs2 without data should match .JSON b/server/subsonic/responses/.snapshots/Responses SimilarSongs2 without data should match .JSON index 24d873e84..1d86c944a 100644 --- a/server/subsonic/responses/.snapshots/Responses SimilarSongs2 without data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses SimilarSongs2 without data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "similarSongs2": {} } diff --git a/server/subsonic/responses/.snapshots/Responses SimilarSongs2 without data should match .XML b/server/subsonic/responses/.snapshots/Responses SimilarSongs2 without data should match .XML index ef8535e1a..aa301249e 100644 --- a/server/subsonic/responses/.snapshots/Responses SimilarSongs2 without data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses SimilarSongs2 without data should match .XML @@ -1,3 +1,3 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses TopSongs with data should match .JSON b/server/subsonic/responses/.snapshots/Responses TopSongs with data should match .JSON index 62cf30226..575c9b7fd 100644 --- a/server/subsonic/responses/.snapshots/Responses TopSongs with data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses TopSongs with data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "topSongs": { "song": [ diff --git a/server/subsonic/responses/.snapshots/Responses TopSongs with data should match .XML b/server/subsonic/responses/.snapshots/Responses TopSongs with data should match .XML index 284de9a2e..35a77cb6c 100644 --- a/server/subsonic/responses/.snapshots/Responses TopSongs with data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses TopSongs with data should match .XML @@ -1,4 +1,4 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses TopSongs without data should match .JSON b/server/subsonic/responses/.snapshots/Responses TopSongs without data should match .JSON index 1dc04ae36..68ef26569 100644 --- a/server/subsonic/responses/.snapshots/Responses TopSongs without data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses TopSongs without data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "topSongs": {} } diff --git a/server/subsonic/responses/.snapshots/Responses TopSongs without data should match .XML b/server/subsonic/responses/.snapshots/Responses TopSongs without data should match .XML index 28429110c..74f5d1cb1 100644 --- a/server/subsonic/responses/.snapshots/Responses TopSongs without data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses TopSongs without data should match .XML @@ -1,3 +1,3 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses User with data should match .JSON b/server/subsonic/responses/.snapshots/Responses User with data should match .JSON index 9581a7f11..94ca289a2 100644 --- a/server/subsonic/responses/.snapshots/Responses User with data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses User with data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "user": { "username": "deluan", diff --git a/server/subsonic/responses/.snapshots/Responses User with data should match .XML b/server/subsonic/responses/.snapshots/Responses User with data should match .XML index e3dafa529..18fae22f3 100644 --- a/server/subsonic/responses/.snapshots/Responses User with data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses User with data should match .XML @@ -1,4 +1,4 @@ - + 1 diff --git a/server/subsonic/responses/.snapshots/Responses User without data should match .JSON b/server/subsonic/responses/.snapshots/Responses User without data should match .JSON index 8da9efca8..fb7881974 100644 --- a/server/subsonic/responses/.snapshots/Responses User without data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses User without data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "user": { "username": "deluan", diff --git a/server/subsonic/responses/.snapshots/Responses User without data should match .XML b/server/subsonic/responses/.snapshots/Responses User without data should match .XML index 3ad33d7ed..16ebce7ba 100644 --- a/server/subsonic/responses/.snapshots/Responses User without data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses User without data should match .XML @@ -1,3 +1,3 @@ - + diff --git a/server/subsonic/responses/.snapshots/Responses Users with data should match .JSON b/server/subsonic/responses/.snapshots/Responses Users with data should match .JSON index ba29ba2ef..4688feb9e 100644 --- a/server/subsonic/responses/.snapshots/Responses Users with data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses Users with data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "users": { "user": [ diff --git a/server/subsonic/responses/.snapshots/Responses Users with data should match .XML b/server/subsonic/responses/.snapshots/Responses Users with data should match .XML index d31105924..f40d32379 100644 --- a/server/subsonic/responses/.snapshots/Responses Users with data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses Users with data should match .XML @@ -1,4 +1,4 @@ - + 1 diff --git a/server/subsonic/responses/.snapshots/Responses Users without data should match .JSON b/server/subsonic/responses/.snapshots/Responses Users without data should match .JSON index 41ecdd67a..96b697300 100644 --- a/server/subsonic/responses/.snapshots/Responses Users without data should match .JSON +++ b/server/subsonic/responses/.snapshots/Responses Users without data should match .JSON @@ -1,8 +1,8 @@ { "status": "ok", - "version": "1.8.0", + "version": "1.16.1", "type": "navidrome", - "serverVersion": "v0.0.0", + "serverVersion": "v0.55.0", "openSubsonic": true, "users": { "user": [ diff --git a/server/subsonic/responses/.snapshots/Responses Users without data should match .XML b/server/subsonic/responses/.snapshots/Responses Users without data should match .XML index fad50ed40..3033ad9bc 100644 --- a/server/subsonic/responses/.snapshots/Responses Users without data should match .XML +++ b/server/subsonic/responses/.snapshots/Responses Users without data should match .XML @@ -1,4 +1,4 @@ - + diff --git a/server/subsonic/responses/responses_test.go b/server/subsonic/responses/responses_test.go index f3796f10a..e484ab2c2 100644 --- a/server/subsonic/responses/responses_test.go +++ b/server/subsonic/responses/responses_test.go @@ -21,9 +21,9 @@ var _ = Describe("Responses", func() { BeforeEach(func() { response = &Subsonic{ Status: StatusOK, - Version: "1.8.0", + Version: "1.16.1", Type: consts.AppName, - ServerVersion: "v0.0.0", + ServerVersion: "v0.55.0", OpenSubsonic: true, } }) From 88f87e6c4fb7ae805908fc39b62c0c3169e61416 Mon Sep 17 00:00:00 2001 From: Deluan Date: Sun, 30 Mar 2025 13:41:32 -0400 Subject: [PATCH 50/51] chore: replace album placeholder Signed-off-by: Deluan --- resources/album-placeholder.webp | Bin 17464 -> 69228 bytes resources/placeholder.png | Bin 300162 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 resources/placeholder.png diff --git a/resources/album-placeholder.webp b/resources/album-placeholder.webp index 864f35f6747804052751b3be5d14906a46e9b3c3..ced0ade239e261d76ccc7701504ea8d9103e97d0 100644 GIT binary patch literal 69228 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 z zMpuo6uW&jX%Y zxLuR)x=!s96zLfh!59|7YNO?_XjU!Indq^QeZVmuxOF(*buUlJ(}-gRu0|x06CEG* zxq;%HNgTs#Z&}04_ug(%=Y{|>@qb&WP*td=z=lQRlXg(kmkabDE$YnIcMk2J$vL{B zHLoOHX9O}MVonMe4Oh=GZkmsm8z#F1!F^H*|F`A1KTJ}jk~SsDscj9FG} zG3c8fDOMc0h>?zqx7>vbYJLxHEDScK_!{?RjQl4UroR&;pf1@8`^`icI{;aFETsJT z_&kY}3#O=Y+#lLeqjWxVB@W3GtpeBwEF*ZJ%Q)L}3^SqP7>aT13NN-7@)h9p0W^&rM~;^8TklqTj?-6RO+xsKZ5 zp*e!W;~na82%Ih`0Y3{ol;^&u3zx)w|Fc4s6Hf`(hvzH27={lEf_|SkcECT|&%^&8 zCr@E44uSDe1e8Q5*};h+G#_qbDp)LaZyl6#GGY!k52i4wvoC_VyO#0%$rfzzPRCiu zxEOT`2Zw_l?h0b|>aJju;$J>T!^bJYB~BE!1KbAUm!PDE2s9Krmr005SRdbhyw{*< zQn?IZTc|uo;aiS|3k4W&Fh{;veX+m&`jI*7A%ppp0zTxTz}xz^Z;eFmW@v8VzTQty zYgIB}MuCEc;xY4?JQ^?JfMGOl<3DjAdvkKAAjsSgqmRMIn5)34dOpa782Jy7pC*Sn zJ|t`ejcPzfy`CGzyB=oxD&zj3&=`Dg%q z@Jui`{MatMWylb~^LgN4qG87J<=WrNs-FOCWWMMBRs?g1z7VcPmRiO~=Y*m8_?92L zeQbjh$&hPCZjPVaTC*rjmbZ4-i?=;VHGxDlx5V3vi2H7@I2qs%c#eq4 z$@2%iSQL52Za!ad6k8iFB1glCba}pf-?s;V2JDsXFL=rAR^y|tm-{aZ2X&GIWd??^ z>0LT<3uY7dNc9Mm0xhC{30(5s`c7ry@u#=pe`fxR7Y$mDlVaw2ZyQ2Sh=Nv(pyI6{1LdBdPd|!iTtz7nnmJ3;)M8QOy-Qmg6G>hvR0=dBbn>En-O(|1Yh~X z186qo=i$AXnIMiqaZ5wuC@@abK)4$L-VRvxO4ke0=sd$AJ;6^rKNLxPUNWoK>0+AS zTW@}S7d#k0_A(A*?{h{q-6NdO9mhKyC|2CS<#^aQx#5}-;aP{pVk#S7*Wjx2N!FKZ z51*VKYbDKiBOkAIiSwGDtnwwPyv~C^^P78F2jy#j5A`6s%CAU@v1iV<0>5d)aeN+; zn22rc9aep=w=FEhqOY6_U-`!(h^Qzw_wUPtfYw(f=U4h5V8$bGF&uA~7!4{CLL7{g zLaufWjfsZyDb@1hM3?#!C;za6RO%zk#2;HlXueX7-b@s!2Eh>X+fN52zmd^aF<`yR zyLd-+NEi|5YDD&sgU5)BL2CXV6hscL()>|)tLI=s{eT{Ms^w_;2Vhwl5lY7%AT6%h zr*|FS@H6<1tY~`GBfxUP+Yr6vx&GgW3}4l&d^C zSB`t1%jX*z$>oyIcg^d0PyS!;CIag|Z0)Eq-r?23T!`qHoLLl)6t^1luG>|tx{^|5 zD42zb&4Pu+T4a31)rt&XGYbzSKEV%&Ntjk$jVq^BC2!_0S^|DC(j0kWDI>CkGo6kDHHOld|%3oERY+YGVgAVDRAn znDx#?^T6*k3@FUD&E=?b;W2NHUIJ+*a!Ow@@L2aQwF~b9g%crpgQ1wAXys3oUaIA+ z5112ebd$Df`G!1nh7JRlm7c{=L-e$fY3n=k)d$O1r=G>|_{rPkM3`EZJKjX#W_ExNSm zAlE4DE*yy5$Q;D@W*nU-9c6$LW)Q_6F~^1n$r&RIWSdy{KJLu`#AvNZS+w4Pjg0G+cM zrIj^_9$Y{@StlrzE0tg*H1Nr4xk$um^+UoMu;hlm-HU5cQ+SzOqnm8IcyUpP_dLRc z^iFBBe6lzG6Rr_q5dwIml1=b`pG%VrmkMXR%x~xx_;=F>b^n_G9s%t0lK0^oT-kq9 zbA>+LUrmpO{JGVv1R0fwg&~mnuV_ND9>ox6d!p(xqhK)7F!CWMQCANhGAnk!)R|?& zS+YCZX(5pB`dO63-+d^?+)L!Qp8jWrLuV!VW}VJ^>pB$p`8W) zjIaV%dkrk|a;B0S93j1uA~l<)W6>f+&jINQekC;D$AHA8VdN&J8uJve;yM08FR|`3 z3^)}lX$SNVrbjaT#`xXAz&-KT$(0^p8vYIL$-fbCDDehJ@V9m#Ih1du^V86|+&O=n zua02L613`<%tz;obJYk%%wLD+Q^uoSd+E_7ZGGfPGzT=6SA|!RaEQdfJw3rz@1O<5 zH{2b&K8Ep3ug$zg^Lx~=b#!SEQFp*X$IV)M{P*zeh!e~ekBh|%AOT&#!HNSf|Cupg zjxA19E`nZ+#TLEBYdBxC#zK44p+fzT?!9W6$T%?Wz|6yPkMNM43S<^?Gc)I@Aan9W zylMEy2oNqa2+u!Td`%48_}lTcQQjL>Asw*{+|gs$2+X5e2O`u#PE zAg?0C8^O zb<6wU`}jKu#wG)bY@~Z9Nr_KOG#|#hyo5bcsig**+91%uSme2;6OxEFvXGyl6z7;v zlv7}n`ML6l9&odBqRnZ;n}q<&f@Z}C8<2cR%XI)V9`(|K|3W79B49I>!MIjoo%7Fl zzQ-51lHrBaJb%N>3-z;MkfbZE*t`}pI_aQ9PL=RlE@e(T@A3ZZZHQUUTn|i)uq^h^ znvF^TiN~p@p!?VyG~9k~$ndME#H$ka@Lw`!&M>-nrn&`-@8! z4%e+*sIqz~{4)$^p9J6H;A%P7o^Po<$cf+wwO=PzT`=vS#+(?5nR#cPnVXSk9%Q|L z^giF~yVD<;H^yIWH7oklzUj7v2))v(7G#2-Z+|6=#xgT-?m%kx^W(1x3!jHCQ1h3I z6VHjQ`Mh%l;^%iuh2*-5yZeXi3=xSTfL4jsInBcy3$aL$Q@ZXR*#>8Er3w2vRJ`v! zOe&ed|2>0;b3Va&*&@V8=y$+x&o+f}07b5r-Q=~ndp?VSY`29N?K$qVp=Efy8cKPE zM|-)8#&6u}<11BiN}X(wLnRv)x{S@qh>7kwFzyvuia@b=<^qI!N4IXgqH2}>tDfY& zHClLY7VyRje6991xY{fDO`%S;j2C}SZ}V1Z{_UD+eUHpJAP7?qBB=4??YUJ4iz#5o z#DTyy^D^?w+;bi?fAet`x|%ZqiQ*xYt7^N$gv)QFCPV4D5Xfi^G{(*2KH`bt&ytVsN^*2e_}e}OxY$F2?l&VOn+(F$dh zx#q@5`FmD~gUILs6Q^L43WDB8WLNpn6;+Sim>BJGER7E-5B5F zkBIWat^I=S>+1^c@y3K3!mSk*tqPq-ub##eFLqoB8Hj)+0tX%^fsj&EAZJ2+7-=i8 zR^%~SdSXtF{Ith7_%=6gk#f>%U>8qd7BO+0@J^R_9UO!g1dYXQmi%r_m6vNphv(np4+>c0sXyhd8QlM=_jr}Y{OQ#5 z0QM8=mNM#W`@*aeBLF%cdd+3flheTwMQg^YSv-E*8?!;luO~G5)F(3eiTg-eGYXqj^|`dr<%G-bsSA6#(67OJuO4wwp8%?`+MPrPJTsS^haDv^Fxa?(qwZh^N2%B7J8|j#rPoUa zlJr$CTtD>OjRkUC*Q;#H2VeF;%fshpO5g~}k}DM9#a}F5d%4USI5sd*g{K@Wl;R*W z4x_iYFYo6n?jgcuu4vz1lv6D}!;G$gDK;+Ib)` z-nBsDb5&57XdvWy+1e-ZsQH>t30dR829*l17WirF<3pZw;S05z+{qQ!=ihCnC_hn8 zGP!-B10~^vvFgW-E5}X-gdOklU&EFRGhNluG(!pXk)pHB{g((b>2ZC4Dlls+3yFk( zu0L5qP3zx+?DQ%Y8Dg_M@?Ck2)9Pxpri$vzguK3uDVwVcl9lwn)p?$NZhjt`vPddPBq);XSe0+M9%u&o9sO2|zz*9b-+BiM$#NqReF3f@xH^GHGHwGy#&O-#xn8)x{ z{D-6FJ%dj?N`2=(iq#j!_pRvp&YTaay3Ke2uQ@k24=wStRzM2NzpOVJ4fD}(A(!!C zXNb7wG>;c>UwoGQGg4N+V9`s|YCdTcsOHOj|MN*Pd;KHbV<5t`$|(M49upTL;Q%`& zTd5c;3fc5#?`yjj8y25g&TGNB3Aj|YK7Waqv4mLRVfxNQk_Yt*-op@>tnJtNf;OlS zIImyRunMAf=6-rlnRx`EC~UXCB-zRF?c|wUkI#;7hvxH!h5XA-g0SYZkMy1$ zz>E9pI|x&6iH0y1XlNds0wb64cs&R4RsEdotM*Api#y9ojIX9<9J>;sOq@Id3^N}+ z3zqPO9O~ zWX*z*A1YTW=c;}G;ZNj6#~61{z{pl&eNH&B4bV}YsZ?n)4MKPZ5+g`<=xLwT?#>cY z+|kv7%o_Ha(8nlEcv#X~;^_ot<}hok^NAh^+ycodk!&WUsOUWf@19|THmpClRzvIg zM?FcR6rk+pM&X>e?MA}dL3~-5d^(<(Cn`6XM_{B*ME4YVnD}PIXrAOb+hTB8-42x4 z>3dVphTNF>klVpUm%XhAl9%5HvPaE)pM(w6e<_U}DZWw^&XvZg4dBW9%UmFjasFHz z9x_bXh|IOayk6iGS450QMKsr32-_+|bKLN>POeZIA43=IoyC$fVvI1100=y;rD)Y6 zb%)_#yQTm!LFW*s5SV1c^w1KedGIHFV}z5bc)g-~M@q&`=4D`=xynp)mb>L>#3c(K zwy)!KT8Kq{9-=oLpm6wW>2JHk;TSj`hAq*kLJRNjO-qZ zK`~?LS{OztScYTJ=zH5ham$!vkg(7T7N}!)<~e(&G+5Zl@e1F6c!qFgyQ2BkOmmVj zRs*HW#gg`D2oM6J3VouEST%E*_&r>pOVP5ZgK37VSxxsoZwQR&Wkt{lC^AZODhmz4 zt0~dEUH0}2$sy-MO|6fd*aW2cmjOHmr1w?FkEe^Dg8;=K`IEx`zr>Rom&lSnd)ivp zGx41`|AF?r4d(1Ia#XB`YXY%4SIY(E$YKn#;7jO;W^4{74pVJGQ6~;XgYHe|z z%RI>V?FDdko~TevJK(98TsY&iW`y~ba-9>iw>Sq@Ye(;?`dRk(wO zT~uA-4f(Q1 zJX7!aoUuZ5K;ba>BpJ7p#{A|ijiyUwPT!|48^e_t9S=P>9YSf|C{hjb@$rG1`A4<1 z4D)?)(la5Q3B<~ZPd0)Sn+0fl+`@^@y96sBv6rt@7k{iKWb6X)ic>x=^5b?=fFN%( z=`AYNvCC z3BJbP@T}&B!c!N2IaIQ;sbildN;xq3SwxI|Tj)J&)agmE9=XntV zd&0CO(s?5b4!pv@42c$8Nt~&_8V^B`5&q!N^E!cy{%ycq{@4ym;hpD6Z2%>Y*$47& zRk0vQ(6u@|-1!@VZs;^7>KNI8aT17uY--RaS!O(FZp$!^PsAD zx3nW`1&fGj2isj$W_MgQ9QYhTZjRJ(@|-Ir7-$asyM(I@m`2*qin&ub&aF0>r!uIme0mP)&beI8%=f2?>Rl zSy^|*KbTzK;0KT|)40woKhhG-0rPx8 zud0NLTl63356NQ>jU_P2^-rd^xkjr^XVHLq@Feq(U@1s^e+=Be=U z4c((Bphv)gee8VbJnDl#+D4&mzB6<9H55GL3}(U)m7W|o5$w=9JrpVZrQ(hz+k(b5 zgM&zgMKuQhshVFuE%uGJWZ2_4?rOv3ka%wrAA7+F4tL8!FX(rRMr!<~+bra!c1WwuACH zb?<;D zFjOL0PE0Q6G;O#q@JUy)Vbg)-0Mk$r(-_gD%lLUG&dJf9iQReNU>%$Y7a3$)MpXP3 zPoZn-10uK`&3YLXa9W4UXaW~{>g%78;B$!_&Z+qdGN*~{s*YIYW2Hg3wW+wd`_0^k zjmySIdkUc=r6K3REq=b#Y9ZegI>bs9XA`Lv$cHS z07p^{J{|9G32tj8wy?PQ1#**dS(;x$HcVFpL@`PA_xt|R@>*{+_-u|h8h$)Os2I=? z>LFi9BoDkIDtz_GdFVWb$Zu}fy++xu^~(;58NEqd+_Jf5o27~AIjQ`Wn^Z=QBDp}S zus*lXA;R8txZ;*W0+XDp;^Rk75g>XCw*A2sYV0S^N};`;t%nK4br?~s3b{sNFJ8&#aYPW;W#L)AD}f>jt36Ue0>vE^3Alka?#S<4%q(wv;AAm)QuI9$=#8DsYt9y?~=Su*jSEuA;#kzj&O z&+Lu9zp_15?W>#0qOy!DjsUMCa_7l!zD+ZrM7-eSHwxmZLJ=*Cr8*K(`Lc&3t+qnd zPIPQ(kxRyr9nLD-N&^iB#2YxZ59m&t8~DFOdpc>!65Y_u@a?Vhm@xkg-yP2dSnS{F z<(zk8(M!*!KE#*6VB}RUemT& zQ^wEpaQfDq2yB1eg`3BmUeh7 zrf*F!tga0FMR)92*ip7;Qj z-4Bgv=R}I?@>Xlhe6~E-ok-1)`-OQ2*YyxG7AAB>CabIwiAJRfM2RDD2~EA7lYyOtvKP|D`;>L!GDEG=}Ex#{;5V>}h#CbWCk z*r@hJ-{Mo#8w0j{oYQ#%+^ioIbD}khWcOg{>1g-(Lh0cdN}krksgM-IBpFEqC!0)Q z;fO)#uTPvs4GK|uorI_=Hocoa^SbsNl2`+A@?i6I1ev^YX2A*V`>X09 zo{4LOI|qgVa#AyqbiT$>=Iu#phP6CL^b)TOH$taSoJNS#o5sp^n4&#w6baofKsXXj zPV>8jPz*RP$$QOWzRaqbLC)()gCunT$_MS1@4TTUJw}DuOmu0Q*NRw;N*>m=tbJ2N5rpn|Ya-wCG?k$*tW7L_F_wG_0 zXOZO6R5NTi*znfeokv!N$Y{RnY<*3u((IXQijZ@a{bYTRN?8~utoqft%^VB;r}vf2 zr+W%J(7AEBX1|#SfeW}^HT<_wH`Z_}6E51b+k62=ZoL7?0FgNkDwa}LgNi3c0>Rwe z^m_h!mJ|FFzo$1T`Aw6QpQmQe>>V85egjA?fyd#`$$AQ_RKu4_r5l5UQRxw>ZW(TT zSb^)}i`n|jbHt(KgpFL(_mHYSgGA;o>3q-pyhduAMKNEVqmU?NkU6Mx$VZhzC+d!r zs4$c_P~Yx>6T`+URyuiO;c1%T-@=vDO|mVjiQi%-w^>mbfTQ%jp8(VcT=-=8ujFo^ zGZaeI11RG#BH=_WG^#{EbRBW$0GCa(fk5^it3oEoDYW5z^298z*Q5cf#CZ~03<4!K z35m7F;LiGDMyM~in`KkvgI>c+!u zCmBC^peQ-3iK+&|S7Kql;7~+<0GE8jVy;^lpfoPGoD5j_ToWB3uCFPE?Y4DJB-nk0 z-J%s|Oi%Ls;)o9ftbH`}tTjX{eJhk|b;z!YqVi3C`!e{j(OE>8CL9V1A_#Gw(tXwLg;ruu1aJe@%S)3 zKQFF=s495RPI2IFfV3G|;&jjO%RSy0W^tJxxP#L(60Z-(d_+PZj5AS|hj0W6d5AEOT9>*adAY;Y2>?i4>eCwe~50Q^1f zBSbp4UKBuB#Y~Lj$Z$x&-;1A+=$6Lml8xXjX7<7$;ZU9#u!L-d8TVeeUCU9uG<2h~ zRs8jeARhbYjP7z+=St)v(@+TwvwNY`&>I?~J3_ptGq8PfSnO)!uSfX^_|<+M!_UUmB0Kvxf`hKJpZXJse=pF z6t>nDa=?3Z*kl!UaWXMzl*)c66=%6+&@bo_o-g+bJ3(j8$__F}vKN5H)VOnvIEytw zy?IaEY?6%W4dBw@ptOgJGzJBa_F}>t7`d;Ntp1h$ZSgpzJ+#Um7l$5E3_c03ZW=Ck zWTF^h=!`&d1EZUYu&PzWZU@-XMk7DXu*%L{V({{E!^&HFiRY`oSl+J{#wm^!K&&Zr zKJ>ORIF0UmYg@`6R6(InTFH7|a+^nibt!^dQdJ!pj$pJT;pBQ^9Z`uU!HXhI6epc@ z=S7xMK`^8oT5->0xugjYxM}>-Vr!V}3E>Jtt=}O%JrVA%Gd|c=Vcr3p$O<%V;YF@Q zPqEa7Qa-KzNZi5>5H+S(Ls5-?HqYjVG34Wn`>;WTjV6pphDk$>NO0slyAp{MLPBy3 z=P*1eaR*pc=$_FJ|QTE-l16B@2Z)$EpbEM)9(Ys0Cv z;{L*UfmYr@jXU@`IV?_kE}au(ewF8E?iStq06^!egDaOqygquAF`yEzDl8j%zv!~m&-uwn(yM3Pgc_84ffzmW#YMTFc+IbrWx>CwIJ(W}Qib!v{;VKw;7 zJJ{$WolNzJJ8%)t!pkkt3Fmqh!XDB(`J(71%lyO|B`&#v&S;|fak#xDo@?L?QUf#RqDqEFvn4#+H+(I#YNR*X)TCJVEd{9au%aHI#>{|0DC5{0jZnNFRs04A zIgW;p4*+8Ek&_SUgcen^93j*=9+_^8x*@ahmg^+?*-MUT5LnzhF@Z1q#CLy4_X^55 z-JE2bP^bT@poWjdail(15q1(r$O*l2GX44&f5UpIu#w8uIz4fih4eV_1G#4}@Oi}( zaU{C9c1akfb96^CeokOg7j5KD;$ za?V=Q3WOM^$qYJy3uC>1Z(4sf=o(+99XG5$lZ8WuMbtLOW_gB)(CGB zOB|}3vD|cYGt8L$!8^b!HLi|hLI<_&)<4MLIYv>Me~Ih#WF9olf$MtcWocYDFe=;u0PwaprL@B_k;xF&o$6oDu9iu7d3G2FZ6%JJo-}gy-Jm zME1a+hx|vFc+imzZk?C$E1{U2>nz_@BmBNl0l_<{nM3Cj3NmsqasS934>E`DJ8q>k zw8;DD912m#ExMu&2O&4+m-2A}qR^?_KV@GE(lL*Cu8@HhukY=bE=p)YWn<)M@1xl( za>(HoNmmPNkr7B|`)~Uh`AYE?>s4OK0MOb0; zNKq{=v|{dF>yh=&2ovEZ&0V5Os*?wjtZv+WzI?{o>s(GX;#Q(Y9Ydotq|GUUjet;= zD;OyjPm&QD5qwYde(t#JovZHPTy|q%D=I7oRx_2)Xtc^0T#%r!ZP3TmpK&`TbA1f5 zzX3DNbuGsk^YeyfPxTPIkiwJQVw_in9bg`IpE#o$t2UU#9lVXb#K&u#qSO^KQFaiV z4|nug^Tj5AZH~7nbnB5p8zy^1wSf#GA~Q+u@S+rht&R@|8|o;fL!0j(KA;#5r!kB{ z_}b_oLLDy+5x5Fz4^IgvD<1DR6((`vbilkR&4cypb2*wXJ#idYfx;srvQWE+m=>;P zAYOX#L6^XXLE#`1mSx_c(EmG&^O}}aU2x>8&+T1v#pMc-402KPFzuiLLa9t6BIINd z)mq4;cE3);4&$D)NOi-hy1nQOSU750=cyuEb){HA9`aeY#iTaE5C_xJCq>IL{% z?h+;n*%P~6+^KhuGr~9+n|*N_(3jJ71a0PE*~#{CWZR!u+%WOV<|ka>WH`PbDIo?s zk$v>Z{!&FDQs5&bMoBe98X&o>w#_V$p3(?U4};Svj3z|qN*OW~En<WfL!!;2r5G&Fv85T6I_i#=TchLP zuen<-2N};9Mc>3MPS&V{Jz~iYweOs!&9xzUu0$^obV@Ftn%6sPdpu6QnY*NFTY5@2 zod|T~YpPoq-wpj#_H1C;J6t_{je!f=nVyn-EU*4gW8kufBR z__eE6rTkXYft;;Pc2^9Ynr#AoyI>TAo|}fRh4z&fdJdh2ZU=M_LPq|2)jgLfXcRxG zG^{#WLG_=PD>u(>8o9KAm>eP|E^=?oPafs;bEPcK0ioj>I4a?zdgM?~%EO2oMn2pcF#FA3vycByzmexB(14_lL+g9qUB^TE?%f`RCje61fV!CUrCfv$U-Fp&B7WJ~w z_+0zD+S$-}*pL7D=C>l~8LstamYbCMWOgRt{xLB)+x}z4c=``1kB%>FOZNnsoaP%1Tx8uR7akr!lON%Dv;_-<4wawcaJ z@^E~m-RbEW*v%zCPcHj1d6{zp$AK1`TRNPF)2R{b{qgfA-hU4YhYn0fp*Q;-=H6qy;`JoklSJo3;nG0L=6d{Gup2AMXXHrFG4shgsFpW4b^*@%@F|iDeeE3>(ED%X z$#dD_Ecm3~pYrn{^1{I*%;(4xHWd6hRsJ`dQNg_Mik2G?qD}1c<+nn}6DQgQu zK6->LUsH;)1}zUg@62-|<87#aV8gS7!!lK}orGdpju_`i!Iyj#$+fN}^DrV1t7`@QQGG{@55i~# z2yi{@)s!$MU!sq>C!sA3J+h`brXSjP{M-BsDY7`Y>Z@X`-07`(tv2J|)vp@|^q3wn z&k%IScu<@6B!ThNnCUC|L$TJY%!Kl}|HCZ}M40DOnhyd5PKgMK&*UgOry7C5$q6BSqPn19|DjY3Lv(-q9B2+zYosBlgwcOnfFg8ZqQbPa99S6iIKmA9p!~1uuo{CdM zf_0V%2E-Qi*nvu`@RiT^;jZzV%JL3W&*oL9^oQ5T`_n=&K4$y`X=n8lTG4Is0!+d! z(q!@XaBd<_tl?&SkMh}&@qwTq8R>}84 z_89pDOx4@uN6zg;5IyI9TF&KxnN;ZuFV=jbPP^RyAL@(eqi{AE|Ps2=Ede=1UYjdKbR*54F{SZ4VY_$Y+SR) zOmA?Rx=I?7CoL8uI&1wvdI4{+b!culR+%yBUM%uoUP1KY z+c_OX9Eb>E^YF`Hvj0t! z3lBE3Is^9i#_+m0`1}7m4ePo(-iFM(^RN$Ta@j#rA~{5NTKsBoOO*}pnP}4&KgRh8 z{GzrM9N)kS5f_}gltRvKD!N1fhpm1K^0PyW6^dX^EOFCUXk?)0Y_6soq-yAhHA>^? zh49FCLseb`CK89qpHF1lUxcDXp!+-UUn`JhMbMiu0k2oMscTq-E}u`7BAZD(EcCmATs5vJmTxzKYP zh|B3SoeR<5>su85lDGqohvZ#)%se9Kmhrp1gb=x7=vZm~Rj-Rt*@NFMs^*KpM}QZ6 zpS`+Wn?FfEuFIz-UsdC(BeOQ5_{b0UH4VZG?g-xJi7$XUumT-xLEt|myR^bw;X#Cn zr~?^m>ylIcm*P;Jm3X$nX%=LFM4y7_*UN@{W1XgQ7}(qsNn6 z77OW^Cvcr6Am;7`-n(%xZ(uGT49<@WUCFbVxeLuoX<;U1-)2a--m%CmGr#ubaKBMv z#Q`&}`1|$U-oV${u}{Yr7@~mqx9Pj@RtC%e)+1|IR_=C{(Si9SLRLa=wg4YD&J1Qg zCUKLOz=+CS*Mvrx7afWb3`H%$cgNzQa|k)1@_%*!z6pjmshm=eV^|(FYOLt0dybSa z!&iFn8bbwei>Us1agH2L+kgd8Af;b$IFV%-m@tspT?la_LBwbA=&30uvV;vmG#_#S zQetArK@^q@0xvTha&Cm`n8i)zzhym&#OqYDKZ^Ni^6FtzA{u6W#wI7u zEyI`N`&u_b$b`dPD*`vvm1|1LdQb38`?c0RQ;aKtrkN2}7pQq+rA^DhN;j~~nTiKJ zzrDUkKXf8`(l8)vjoc&0Q= zZ;b`5X*vvE;0(kL5kete9&}o#mGo1{uz^B{$tCP4vDE|7Th=x0_mL&jv;kB zk6y^nz-yOl*ECFCcJ&CF0R24#gQWfD92gmxcV_Ir=Ru(z-`*pwRR4lQXbt z<@B6;pM-uNAEt>xg>E~%)&K2*eEWaTfxonW{)GAvJ2kSAUQ%H8n8jO%7nuox1vekw z7uGxLM3R^hmEXT#7R-hPS67kQ0KaX^h>#wbRb(i>TB^9K%*O!BNjXEn!65kg9Fte9 zkC3rS#uhf}0}9EAnVXqe4v(k#IP)ZF{2Eq$LQ8 z1Ph)Kg&u{J_Wmvi-^A4Am(?)KXAZFbOi|{a_aOotnw(*+P zfv>oFx!HQWbsP{^*4TI)3|v>)I;hC_ziS;$u%Xn33$*1Dcu1J>p$Xu*<59MUv-ht- zNFu!cZ{%hvan+GoCae}flq|C^P0TFlHvmsYHk1OKqXQvF$P4P+~>=}lBI&fmwJ|F;LRR6IV1mJA`Bfqf)l2sz;tjAGo6WQlg-%<npn(SU0bgAyZrp+W&GskYq83RcGi(i z<^N^8_(DNI)X3&^WT1lTxkiJu2a8A5Tn;H0^2u{Yd7`!BYp)FKamM;(jhqQ;WYa5Z zDb$`SFE%n<&@h?WqY;RFEca&?dqI&b@0LGov01#M+;2LBn*`ribEK@^E9>+QfP);9}eqie2^`s zz(3(_B64;_io8CS`gQzue;t3IC;+BGtk0+&D653KMU$IZOHJp`H^j3JCA*Jpy1l9!pYZ!nE)PoejlWw#YzSU2`Pd`bu9NZtGii93Y_aX=*%o zP`ESGJ6iY-&zQcNZQ+xWHG~~~?oO70fHg1vzUP+g(m^fI<#70J`ip7s&(i~ZWJc!bCpEqs|Plv<++W;!SatNc|;Wl&23JkteZsW>H zM;`rp6Sv4CLv!7co*bl?7g=TUeu&h5ojPom?zXffRRm3HL48iE^D*)%KC$P_sU1A= z`s4Z&c>_NkRqO2unvOf9Sb#2eX@|q zVcC-fbY6eElx4Ni1H#Y|@GKG%mlScoCx16-DOs_l4Ovh-w`z3--cN=y4$2cVmba0W zfXgQ&<)OUMagw4XqXQ8eBHd(F*mYJ-H02ygtcpx;%*yLWnlaJVS ztmu*~F2Hu0Y>zWuDsv4qZYhX=gqOn-J#ZaN^OEH5lZY3$D&Js6_+v(t=O5-pP$atq zJWgsNFzYc-Y#;P99>N)6;nMRU1H*~%2|z&7NH8B5@7hY$FE8sJN#|p=vAHYHyua(t zbiW?>eRIA=DFjNi9J5krRZuFzL!x?>?MMA()S>kUMhR>Q~~% zX+q$3<#wPRPQOtPPl71|1g>NPc$_jXJ@O}2gFvSd$oqrQkD#1PDz|EJ)*;b%D&3;h zXQyng2lX!24{DpEukg0-kL+Eu*UXRLF$JRY>l}JrbY4Dh`ujVu z{22Mk^qHPhtS>;Vd(A!v5AmE!&y8sPoLr>EbV6q}Ju-&dhmFiu6IW?$kz!qTy_1D4 z-6J=_O!-wP9fUDL_f`Bi|CLSko+h%o ziGiniKR`UtlZa_)DX`o5@SL1(=$a{q%eoK?g}?H~Cqh^_d8bih_8Z8cHT;F&LoNpj z*sVQ<&xr5gpp_*~%pLnYhL(<*m*`lbxFT~hpDW=AiC9R8IywB%EiFB%!TeifIRr{V9=Rg(EnK?v1^}K9xrpbDo`;;D(681j!OnVsRL0^!J%2j+oxTJiMn=94hOZGL`C_ke{@kR* zcfBV?0>#l(MPL+KJL&=t|3LqS%d9Z*U=qXnQo%iwMwXIXUHP6jqA$oPZ8a3ZKt-EZ ztvMQ)?L|tED^GfQzS{61=fxB;0+;23ekQ(|6SJCz+tM%s2AH#X5aP+$-P)M@c7&WT z)>H%!L3t!Up;_VNI`5sHCc=a)G-Ejqcp1RgII*gQ+5TsG(R!l@ZuhQ;SO?|mNbc6- zYZRD&f+dQV>w$zWajITw)P4ALOngY>h??t1&g}55dh^LX{=OcBkQjCh!@mtGDxiUG zVG_ucXGa8)$jr-eHyg*|h~}15W4BK$uv?-@_A4|nj$LPZ9;U}H%-kvmqt`}PR;ob` z4*Cd6_r~xf8xLkolXQK!@(VwGe9TRgEy)upuTq$id`=SfjsheHwsdcFZr#myM~x=7 zuyTl3<2}|dB*oWjf|H=l#IK$%aK`r~3|Ws2^7AnA%ezw$o6WZFFDd6W?Uu_iMg zfz&LE0+Uv3pZ5l?uDn-X4x=-QkQxUcokl{KZjxj;#(=TaQKDkK=yh^%(~S*s=)C2w zYQ6hD&U-b5+L2^YglaL^i0#x1G~UDIZj>dAa`b(VF}bPx5klf&*%o9YXJCs za>kfZo=`Hy$-#%Z#@>(#UJeg!P8f{Ma;O^&&;-h%g9U0K1|%Yqo_jV9T46;W^1n67 zwtzJ2JYpGRfswD^D^C$iY}69~H{Tvm?a{Qxz z7-9FzLkgw-^Oe$~+d(i#jV;cL3DW0-4o%jT28@{#HM`r_8+;H_MlM3DlbvV{3ntR4mYlbIE=(5@c;5x`}2Qb;*c z?y)I%yLWz0AA}qx&v`4^!{>e6yvxta@ie&^K}O=E%)?WXE29guj_xb7*Mq|4<~4Jk z2{3Vc7N3Aqi~#rqG#C)SSfxk_CMS%xQ_`T!i?;6kI(nDE(*DW zm`{qPuNcu#nK6`-C>(^vYp$?~rf%eWS4hNEzHVRN*eo|X%LJ&18t&qBNf!>)6f=f_nb z)?xHG<7AFF;x#VSi3lxUmFi2W&7t_O#@;i$`!qlA%?j`J+3I`R1qX}OeIS^(G!kzf zwr_jUjh5{d<^C(mqn0n9)Gj022}KbeTFB@StXGYZ%fU#4u-H{(>hM^UmC3Qc&=7XO z#Kg$AI5cZ@s{8yHdDzX9g(TB?lgnA{gY%7B1&t|OU4i@;M+l}pFNe?~4Ih8@(& zA@WNF=9xJs{*xhGurVLZI^59b;T8~GMlHj8 z(S`Uj7LBpW0tOQY=He#uu~7ULG|i07NRFc(IkFnC*w6#R4yxg)*-KAC+yN6I4NtoR z8jc>4!GO#JS{N0qKjwTVq0mTJ{Q_AkgMYORt`tO;Fd7Of9^onxm_Js}e{e}Lxgyf^ z4kBfV`gC5nK}>skoMsvihjYuQVD-6G%Q?_7yZn{O z{+zbKXS!t=H*^^>9HNUM*FRobh`ahs_{^wFso_?&f_qM$jz1I>ZZd;Cdo46)_7yHw zSsMvn@|;rf!M4HC!io*x^7sGe5PZ?(`Ieo+7w};`zHKn4${TJXw?8uDiI3fkuvRx@ zkC+9qzF`EYa_fNr#K2XGm&XCE1}>QfauQ@{(5_KF5ZGFz7!9w9|Eb?R?B#9U;=d@m#sQLiH<{Y zYsL<}I9s?rGOF7UB^%U)=5knsLpc z2RO-byL|T?d-nKnp-bmagvWJ_F{5Z4IkcH)1s02iwYpclK*V@zhd1MG=ciWv`P25n zg}#8$|6M{i@?AtoY6?RAO#{&1NNNGLE#VwdxiIV^R%EAfu_wdAe2-g|TDm3`#e3QZ zZ$p4|5hC+aDlkDEoHcTjsUU96J>N1mm7An58Y8wP0}KsJoq#=h*P=O$=|Br1pvK0B zKq#tFg4hVDm^7bPtFw&2lt>Wbo^eccjkTAsV9&Neqw`e)?wtU<%3ojYDHRe;H6Y@u zfIB?hyOXFer*HMS9M6Xq1RWDST?L3IyCPv$4~@ll(P!Y5-Nywp$;w7IX`h!7%iKFY z&%fw@G(X{b^87FJ5^K^_`(Pkt7u)!WH#zr=2R1R+9cf}d?3~2l;BjS0Q?rhQc}4@mGiCw z`%gmrh!I^U-cf)SEE7d3yp$dg_Z+d;Jjh_pDY>c9a|r-$d>Q`OMz}?&Tx{h$e#XE{ zxb{}L>tXhhIZ%4~X+39-d;@iUdVA{msKmOTzi!A5TI*ramjDTIALJO~oDTtSntGsd zo?JcWC!e{4`h@5x{hZK!aQ$RXgKtv{jebxVabq_(9Rt+j-TN8Kyf=jg0y$^f5Bu4( z8!An--un@J?VDs=Z0d6;X&)Rd6iZKH#rUROQ_G&ef1h;o)iM?W+`)34n0e!qF!D>F zGXPgK0O|VhO?ntR&!xuSu8l?(AgwH6#O5H}b|iQLlY@$ctiW2&c(`SGAZ1iYcu3g9 z>uXNuG;hKKOO@y(z!--SLj*(x=hLillGRmn^6SIwv&SFt;>JUvDrDU@f*D753;6)E z>Tt0t`v)P5rB;}YDfXZYprD{XYj21Z3!Gq{1myWPmk5{V#K|6T5#S+eCENvuj(WWL z7x-i7+2hB8-BABtRsXY_kW>D?z2&%1>Gn0F{TC2cdkT z0pns&@k3K}HsXftgU>y4jzE+cdN&~UV#SYig{K#4r2FN<%8i*PxP$RE*WsEY>tp9r z9azp-qa&2N*6%)_UKfQoLmt9uu1;8rOq&0|_c{3w`MX~+BGYhXLM+>9_T{`YQ#2N? zsss5JzLk@d18?egN}D<%SuTybKVD6)Qu+$_+|&y~0|T_SEH^<*QEp`TIby6G+*TV@ zQeJbg;Je?cTxyg`w+TChw<>?aV%%!H(qd{4gwtrB<9Bmd{At#GPyrB`hUFmdH}62* z0rI+_z-qtD^Am>y8<8I$1T-+oWz2~IH;@`hgy4fsR|#qn*rgm5SQtuHID)(IVYG1A6U z{Ifi4<{_|5ytI!W&maFfM5#|`6R^l^S8%jk$W4abh`g_>{T%5WS*ct71*A0|Gk`5u zdhD9>b!Ef?gV8s@J#paY5GR6fvn;Yq*9kpJ9)eUUpjsJHN6~ZD$keC(p)qk!$PEl$ zJMb{MMcc_}dQK_P187hcM@TFEESE2Pyis&FW{_2g&IK|X2688hpIOJySA%j;K@#S! zd1pk%_Q1)TjTqpp0f~i<+jfIdD_!m`oUulwa|s0*Ic4sjqiD>1Ggol-?Zq>FJoCGcv%6#DlKAakxGeLeAfR~BR}ZsMLug!KG1<@uv~+B|iV&GX@N z&we9Y*&g`)tQ91cyY<3Bj>^szFVWPlRGxcolKZZW7kJP^qCugTr2%I*C+^DlRcGp~ zX^^W&oE@Ka@iX6}6gnMxI-sq6;)$zdNY41eZdX$lbnmht0IE)2S(*we>K6&P}* z;olkPclMlz$0jrB&B;M}Wg9@;bWc}WIu@oG>v$MA52k^m-9!$nu#(Tibw_AY^h%*c zn+c!aNx)E|=pY~*Afb8Ib!?;}`_D*?v1Z;=oaW4WT1J0bv{8cd<42mMZw-_c8u|_# zOg#R_EQ*8Gc&2>}8)V2idVy90JW3Tb{|1jFiPtAnbY7~c%f;fha#v1w&5%F;(I?!P zUQ=EA=~(LGpJ8!AT?GCYeesoAA<6SUP*ds57%Z*o%*4covmxQ~V-2~*Vndt(tZI#| z;khSg$YPdX2Y#V`u~a?3OayYOfe3-mG(qN!M$e^xy+tc@a%>OQdNDyN??^?9q8C>K z=vV~?!8hi`2*;e_%o!U48EF$71K4sRSB>-ufYdSIVicUOa=vsXQIRxsv<@0fLKapG zMwC+5LvW-Jm%lr<{WY7JW1z$Ct$2f)IJ&xtJO$&C3-yR5bNn=3GcSWjq2}<|UeC$> z2;4FciyP51bGkev{gt}SB#YuV@13a+6A`>w&)o*7+ zkLVLqBkO4F_)s?0#Nf1YNzSrESu$1$0_a|x`CR%`=(4r)9L<*XXmJA$#%4%2Vv?7) zomvL-=Of1nV!+59={^O!f;)If0j*C=e!*T9I2T z@ZcKZzxK^X5XbGN(JdY45)6bLF!2P+$!!flj=A2}#3Mwxd|TJ94obF~(eB{3HVJUi z;GuGbyNP@HDDHvHL*7M)|I%$Lp{F(KQZj|$XcX?B`b{^64r>{_@0+i!HLVOr)YQLs zz~QW(2;D(qVS6I+xtg4l+(U$BM$z1SKTZTf%r(bx-vY7AsOrrRfZsfk4RFm4Pi`bz`-RBhO0T6(QWl92W_L>dl zZSwg-?}*kjBWFO;m!z1*zl?f#p=!ODW@^BA8je*nSrM~gbl4nglrN6{QM8ExmRh10 zyV7}}u{2IecKnjww}#V8OPsmvu#s?l*~n?T0w2;33q{p68eiqpzs#vB%Jt^}QJ&ig{{Sscasx_F;JdL1%;JcK8~WiVl5nV< z(E#N7Z@$kQZfRzY?ZH3*QG#`W?eu`QHxJ2b*G_;sQ54RPl>lQCW5kaOk|D%Lp6AYm zHdG6wj~E5<%nmAt4kzvY=DKbokwbNUZebJ@(OKOXR8b$$%@4#L*rTOW1&{Eg(HN4j?B>NYit`$IYOAn9an&0Bfzg}K=dWKTMBilZ;*^2q+o`OF+^=LKjxa4TYZ)VgnQjz+lJ z>wm*@e+@IU+LJfX9i!7>x#D{FV#ZruN~2^SS4AUet}287u!CWZhB00&g}?QF1s2j; zuGC@HHY%nc3-^&#p*J-_tpz}`n1scJOioF;0AE0$zg6Hd^mCB${4`q59fKnyL?9p5 z`-3lXx0L6;Xi|AdM;stjMaFnNBk!P|bh9&JkSTm7kGCAM@?SJSmX}x{u}H4mCWtVW z#wN<#HN)!;VlL~hte;8Z7dW+%$j5ZVpk?%maj}cb_kNUy`J+8SHMR#v@iOU%XN%8A z12Atp{(tu$pH7x#AJbIv?_puu7J0rsSCL{oA^!@8J0-ZXE!auYDb!WO7a}Wop+q3V ze(-p+iaEUKIm~=(o01#Ka*}aG`PU6DmPG&4jgj*fBm{UwJo2;4MtiBGw8W)4V5dO? zu$BOeYgT>0b#&zUNA5d}l4&1XD9942BgZ@u@qu_wXvb5rnpIOVi;sCb6%`IQ<}-4s@#hHG zoU-qao^Qhq6GI>c!5}fp33LiG3$)%X2^~k1b3C^ZnAt+lPll+Gu&f*;bSXzB9-Vit z_e@C4Q}9Lh#oWsFWAKB_Gg_uAGC842q2M-bjw`~-H@~o@HFP>Tj((i3oY z@Z>n&QR7#;aSK0KoR(8f^VBGMxTYKVrVB}kn{Wy56ZtNbKM~PA=`Ovv?o~T?pE_;2P&P7Q76g|;+I9Q;u z0+1_QoToy(-{B~j{dq(Q@dj`Q5%c`VA&19qt=JeY6yPo$iIs$?OXm87Jn$&F`#feL zu&hr{%k*X;^m&btO^-|SV%wt2))m9}#>(^jGrp30jiPDCxQ4yZv!rI6_1Pkd%dKnF za1IGw)b9+&QeA9@4$!KH?dk_nzU@$P%$nlIE zB%5~PmC+deAmHQ4`Ox^+9pnM!HEH7{0QqqRvL2zlOgK@IR=)VmA)vw)r$U)NV&Ens zH-Xxmv)}1GK#ZJ~%P$=dd0j8zVGQ@u9TxnI z0IUrz>vch6%GAy0H+Tr~mY!3N&(8-tSHE7UKJ?oPO{bdXzdOROCTucAVrxiQcdM7YRu-c|(sR8us}Ol&h=?lRm-jiS@}wjT&fbGSwV_vZWMH?)8GVSf4?#s<*mAOYL9v>m*VfPu z5J!}y=d9QIgChY2V#&F8vN=AFyE=l?=h~Hsbu>n2ZlbB`)PQ+u_qE0AMxT4wF3dxA z;BLq79yA^WFPP(93$NFnhkw%VfreaaludI493oWy8NXMa4O`xQU;*NP-Jfbe@(gWZ z9u`ZbI{1e;Lg6mP{qX^6bd$}iW~NExo6Y)-k?^wr&3fNDpe|mUJN1yXQq+NfU!9Zd z}NW%_}kmFhsjthvNxdvon- zLj(p12diIAC>gn&WUM&(k5LzMlK}BI96x6b{5pREX#5LZCe~W^!>~#5A@@=pM2wsI zd0IJGovWJHX**YGv3j+CCNK#u=21p^P+7S7 zy721D#zl9weOa{8#b6IQn{_}-Hj`7x>0jl=JX2x3PHbFHyJ03WFueOF)5>&G8DxTh zpzTJ~B5B?k3~;!#jHggv{_O={==Fe67z>C){le+=8_SL+!s{9pn{#J3#OvJ|H%n}( z=0s~$nXu_ti<9Lo>i}`?OY&fiv-UTZ7itXi5S%b#3;kc`=~ceC*|r>b-`#eLknedC zadU1Pwevi8P-T2HB;;bNI<9;};(XEY`5I;C`HNmA_vXcvv@zzD{zFvjp~K;W;brs6 zb)>j4cLW|;DL74GYsSS6h1h!q5aXDD9ez|!ol<8aRcdmJ)AfBylGg<-)6^?k83Sf@ zCQ;Br)8I!?0^U8O$XRm6XSfu@&ne)8-%{sE z|6cU)>p8?f5txxtTdC*a;HU%RgToC7qI1mQ))MiN(ayp`iy-APAgM6S+?3d;&faF| z6ty$o>s(%t(RLtr9R9+g^U(1idDcAGHRclcqzBMERSqNKGH2oBDmfp7It4bJ&(B}s zLd@Crsh&jZlLh`~;@5Lp<1F3N$OoBAYl$Mmf0LHR_RgY;Epr@W#~z540b<>Qym#D_ znM2HuK)mT7Za(V{wby5sU+9j}ZWK2)hPm4Vj) z2^%eM#XRv7;NT)v_%dwnt7b-xm)~3E(&f(p^Kx`rxNDj>i7T~Y#1lWCA7`z+G#@|s z8K4$~xMO_I40N$*o~01;@p()J=tj)CGRFbVh|5CmJ^akmqHxu!PZXOg4?0E5==nWxL3x8y|J2^X3kfB+zu<%?*t7HrCaula^V7UFj`>j~7} z-A#_Rde@bI@xa~|<3C;Z^;dUWJ7vu2k^>h<*K$3TT1KudyP%DVhB=&lka=B1Y*fx_ z1G*@GCQJ-;hP+aOYn;R{1$?eT=VfnwiE%9SVLkuw@7p@v=wNWXJg6X&nKITTS93%* ze9r-W@R#q&&F(lkV0WQ~UU|+Y7e0O^kb{x`KqTN1yEwB20!XAFx$9gZo0GcHKoQQL zna9x%vkkR5FDW+HBK3ruGh*$m@-T4M%-4Xco*X31jWl~JUX!mp*UWq~kIeahr}vzX z%L4}l2UN9?*)g-qSF|8C^PkG&hAoYZ^b@NyX0B&gytrB=t@ zVM6XoDtU1JWSi-qR1fI{26PknpX@d)$C&I_yd-FnoH{A^11^Jp$RH)iG#3SfU}{h+}ALY;&KH zR7Vi+8f1pD@e@le?`ZxXL_Q7xIM=8D0IH0*Zk)K&k&&N0uTAbt>(8w3_h}s?8JAMa zb9)yi^~xGyxA}4n_u3{Unhn@FZsrT~8y1fZVdMREyVRQ(`W`)G@w$clacvKCn^0wg z{il6~{m)U-FKcKZU|!R0eHY`R*qvg zAY2Zud!Z7>XhJF29td7YLI|QP=U#dp;sPwWC8tvRv&F>Wf)3@t$KOXLq(b`z_p2?~ zae6!4NICJCp&-GR+Hoq)9Si7?&GGR%kcQ~vg3LQ`@^&ghc*+@e5J`vT<61Z}gS0>~ z@$tLW0U~H+^LH~?EIW4b0KO;8x#lhB#anF$ee|e>V}`K#pP5^4e~nS~=$KmWIskrV z%5ke<2Q*$B5ZL)tU=2X#nO`-)lQgJ*|BXW}ot66WvxVXJfAe`7s{uPyyiAHdunB`|Pj-%h@$UA;c= zNTL}fA_Mnb7CYkHM0i*Y7r%Jc+1XZqacQy3giRNC0VheqzKtQ!Y-m4TCj)J%$n{3& zgAT`Y#lW9_0WD^VOq6~$jNG4`5qTaPP|8Q-&(|x(MR2)sc=*6_b75hjwwX!?J#xUy z!Pqhp{D=I&QRk#f&mZVndF7FpYxti_`RhU-UVWLxYih=IIiqHHLnpBsJkAsNhzM^> z4CV7?cE0C*7w-MYckMCJmE;L56d^8GLRB7od>r`!G%|UOG)%>xdG?weKLx@**d+C$ zu_BH&7vTCKj#o~Hp`l`AM62^a*^ryIlAoJ{n{~|ilrJ!Jqu4@8Bh;Cd!Z#?@Y!jDO zXt~5Q*MR8o3SJ+-IzwqVP@hjBaLWx%eBR}HNU$mj=dbL6$bcne(b1WaNyYw4QW7eX zzo53ccUpf~Y9Hi=^_umHrGfyD@2a(X_N6I5H z2PEoHV$`2~F>IK|a+C?bnh}&xa|DXqg1&=@&-KbHQhM)i@IC-;szFh(N>+rJ<2bjYXz)QsRNy@Pi0}NFegDz)ITkqR4z4fH29St zpqXEWJu%?Tl~pPAD?(w>3_r@jLQ)_NMyt-6j})$nufpyQa5!9`_F43J+`b5m`ar!Bi$vt&G`}FAfL>B|F{Qeck{*lQ1gsEV&9AuUjQy+L-bG z==+|$O^qS=w0}T{AuH9h4neC#j(0F5(FrIZNmy=ZLmVzTzi1x%8T-fQot~~Ywi7b| z*VXCS=EnyivIDaIY8`1|uy~n$vHi5t3Wk}P;~^}nJ?M)yfw^V+dPg;OS$X&Ik~h|n zgcorpp6~k-7&(@F#H)}=YwYZ?#z$sQzS=^_zCYjoM4vBtJ!625m#`DKfkSe%;ShH4 zLGBTD4g+|Ad-fcG&F<-3Cw|M4JBEV*3~YGaMS9j@grcv2RTr+w1(}iqh1?BU-NWD} z%gY&XE+t;-ZXI@bnadqRj@C~#-xjlbk5P%^SLF|>1jWRIoDl~F9}uX1Gfr8`=Jd>P zr*~v}u=#%(Dm3saf|=L00)dp6Vg@lfumaky{N#kuLU9YA!v` z-Pbfg3J)LkX0DdNc@UUKiV{5iu@aIRo^$`4-nL)yNm3>1(s1j!$X*YwFD(}XCzF=# zi44Yvki;3tsm7epv>)s|p2mx*eoQ_k@VNOhLSe7vp!c`^(l`~khAW^~s=CI7T=&1Q z&xoI)%+&m`--1NM0lOHxM zSN1+${fI@2qerwff!KKhf_%u0NHq$;7>XXwHWwjGS`}9Oe=dw>5P_g(KexFg4kT`Vqmy{Cjqrzg@;&YN z;Oz-8jXKPeiiYpxu>&}4E*i_jW8@t2k;wQY>OP*AR(wJnOdOQ5YeZg$Oz6IjBS88a0qS1f!<;M`c)6gtZ26%eMii)oW9dzqXD)>Jtn^z zj=-Q=Aq;*h56_TCHRvPH$BNW4>8c9K!8<`AFI;q=H`Q_C9AOgP3>l0X%DdJ{*UU1Js z3IiEm@?77|C(CF?jsdZO;L62>Y%{;?UMXMe+xEYiHQ%NtEM^^#!QP=-U|=e|jWE|z zHz1Cg2XE9CVd29+64{u@n7WP+N0eFQNMuN8R<5W=e(19`t6z3Ee-g@EzpN4jH(=~f z{^K`bq!3NBHN9WTxdB@cE;%@+#qkIB^#^qBIwAQ-`d6n(^<*a50uN%IC|LZuXN=(X z-i_yfnU^RtP9-1mjG!Vb7?UB;(lZLKb^PQmojd;=DE5z~%gE4kAA$I%Qe%40q3wyTkkM2`|_ zJ-p}5GY7h@!R=tuK38V~tv=_Up|av^q(YNWPM!caEob_CNL;CzC=oy=1sWD44KIg@ zlhF+%P6h;qSn1?`nWX-g0w5&Y=u0Mn2q}ZJ+Yf-v^d761%1SJd8^0qf*uE}<8_WT() z$@q2lIQCq=PaXdJo1p?6Nr@*12aRBmIXy1rNA64q2TKIA+YL?uguzeudHrDFQr(pk z4o+LB?a$@r;-wf&lP|fb57j!c!)-%>P3K19BG5C7y~mNr!rb_|`TV@~$VvtVjYZFS z>+BPq*Wihj!oPil%1zFjG1dL4<3-HL^WO_2v!-+|94unYERQvR+UYfS`~6*)H$qWX z`7-SV*HzX=GE2HLUNc*K|7%)q6XuIAD!kfAo3Y;DP2^La>OWpB#5Y)}!L~af;4=cGddxyC3eMtMWI`47A%^VcERD~324ujR?S1yHs z!?c5^&={T%NP(}X;UM@?3QWHm5o-_zB1ygH!}5WV(|r{aIg0!YGa%Im{J8X1hgfE= z?G6UMlSkof`e)*$vV)0I_F)L7P+|CZHe9P|3N8lTMZSLywbaN;XC1VBomiGzu zZ>y3Wp#@ePd@j8Qp!3{RNU|P0f5ofvCEH*z$nYZXVgXVP)CJ@an)g7=0H9X2Rt8Q! zsd)|#>~0%`OUUON+&2^QWHKXTO@v|g6Z5<#@;dXB(YgHKc1jN$IT;4){p4R>jx=u* ze#D9!h}TyGI8iVmjr{anGypxH-xKmWfrRnlsiJXyoR-7xZFEnY%WywrIe^fXu>orO4sEEp+~r#g8=;Ec7zwwnH774HJM7 zLuS6`Adf$8q_`O^xOob&xJlCQi3>r8+J}AH*+bVPTUuW6fp1aA%iVVbF%6-P8xcL* z#5Y-3*Lnz$C}bEx90902L{|hXIP?vN#|V#J)+&OCZl{9x_6g#nOo)cgzlAtCl#txh zMu&r$1Q}i2L7PWi%Tj%eyvzYJG+L?#^#}5UfJC8fkEi2dnnwgcG(Xwv=O8I(Kqf6> zd2v#Yr%-`OkdNfdUV5GMKi`1K9j4pwFH_J!W1eFH|4mo{!D<^8uCQ73Zgn zc@1^R&wQDu)QcYze)Su8q+$8W=}%GJNz4j7O9osUui!TF^tfr7H9}SOw^7ACSI{~j zDWS4exMuVSB4TpZb?XLJR1t83xyu-Qfn}3;{|I&^fAhpZMREDWU_xiFS(tYqa}sRS z6yO(odT~v@#CVCRu#8V4e>cSdr)tg5_}^Pqu&;Sn#ezBqu+>)%?K=kdTb$j0le+MY zu6}rb@pTdToC~E*Z>YHW#ks`9zvllh0Q>{w&I(bS;`P2^z9F-F_DoO~8k*(5kUhY5 zK<1~x6#1(W4dxIZ=26_pt8^QYo8Uha?iUPPo4+F;KabRcsB>`J!fGJJS`zX+$IkYz zef{w-vd60_eZnd2sW*PJogZ(BYVZ|#8R767c7Rtn5%@~aoraCAGlMyTPYAV7m?1y- z@>4#dkV2;6UFzRWXiQoQiXq4tZzA9084O#VGYnLbHHw*gd?V6N%NLyuI!+`%X$>;+ zz?}s>mpL~xf8+fCf#>qo`^Tr z)w?_1hxtvzM(d!Bz&v_<*XwHDm;=cOSWAiPQpNTm-voPkUf4B7-qz%Qyy2PFUL(A5 zHWTQ6Zr$pz;_fAeJm=T^Z2T#Y^OaMHFO)9>hfoOc>*k+EHCpvpu~us?e`F=M7TF&3 zvSBTc8*(MeiIMYmUg&x7HJ^}RbEinBg8+AbZTB<>hyQnc8;yUN09WQl44zM6fKT%H zPITUC!}rP&-WC*pL0@X#UqYe4U+hlWo1dm&U&6+Fz1EWA;Kj}wn}x+;AWTj&UzgM7 zN9Ja&-;l{sXlG7SmUtjivZ6&{fY;vLz3RR-C(8|jwt)tybU(Yu_yV0b8V3z;gLdLD zszgV8mK+pnR6)_CaW_(x;DxOk{&5HV{#{Z)l?pe7sM>wr2sD;RfUha%Tp9|%=`Hdz zdbxTq#m536cYfpb%d25g_xrXe<>M@;yn}{Rkkjy7LIA;CX1RtAZU>%Q-IQ;jRH zxqY5%Bf;9it}54*l6zZb-E**UK;RX3Z@;|>L82STG_C2u=dW5WIzBG#a^@XeH)p(U zVP%aQF3Tff!FBNqz8(xYuW~EdT?D9=YV7=i!b* z#M^?N?W_G}yj&jc+T-D{z+c|TedB9Zl57l_q5Vb^c43x0{~E8YDKxl^*r%UlbeE;& z=C)7e`Jd&*0_Yp`Gs}>pC_H#FSeyfodb%FG2vvz^T15i`uScWtAk@9c96u3iG!*~s zzoIK{77i1JxB!O4ITT*sStG!C=nZb>x`UREfftFB*^j|<_7VAUxW>Fo;lkoiykQM2Y&~0ZPjiF_fw!? z-Bpb#Bw69gcU9@Gt}`$*k?;CNPR8Fyv{u;q?A~s>gI~|<0)Eyzg0=djz)pdJ4!s28 z_}5%{DpO&U&Jvab9P*ja>m^p#M@+7n?SxGT3LB#%5`IdnxvjvN1tTn1uCcj(!Qvw2 zikC|n0U9`Xd7MJw!aq6160dO%hZi1WVlbszxmdZutKQ7$RHJOBO2cz@P8Q{ zNgV|1?Wr=;QXu&t3oxP7=+R=R_~>bOsjFNgcg$zTEd@vh9+?;k{>$ggNfb5m3wErT zt6JarG7h7#;V-NRiEG6DMix3r9~GAzyW>i4Tu0c?N#*qX1=PV`u&6Ny<8?Crv>q26 zd>Ik2(aCzL0nu^Lf!TFuz^K;V)E!|Ep(QJf5p;qDiM?E^WifL=;OD{%I}jV`XXZPa z1!hi}L-3p%mrtIP!*5vG@3DMCYk}>HkUs;*kDf>D&j*0CH>mlNs;h8XijE-oC zO%=KB8F9wOBssD4pfbZkw=)Ei^*7M)SGeV^;x~ovSp0eKK}xZVLWqwjgJ)L+%#e{j z{F2W((jsUj7&r1h?B>m7g&?c&E&5D$4I*r1IPYb=)F=<(Lwqr~A|I|97QVn^IQ}`l z?O7Dxq%h)_LgJESJd1`AmI5qE3h!YMYX2e{LWlq51XYgxobuUuo_MgofA} ztHGz^r}5Dj4qRVGr9tj@t10>s5ZQ$jO4@-N{1}4nHAaIcg$iM!&WJKkeaI_tq4q+N z=fk5zLUah^Wi_Q$&hR**VCr55l)nQ?kEC|+L7?2jD0vo2_WBvQ>f|`V6wbMU+l_`> z`2Bvqk&l^Ed;MIcnr7JqL0*%sj|Et|!CqJBC7v ze`$7afNL%e_fNKO^I<`Ut$a{1@EvSEzU~bV?z@pOE<$%q1r?@OJ4Y0q=c;K&?~{NhSyVQ@nhwOi&8boAE4J8sctyLzWyXGEiT1KBSY(Hajl+0a6SC#R7^o*SP zzwe&rN5@NvKJ_qhD*4R3?dH`3iQBASj#ICLI?2qusJhy7!Q#f2Eqfb)3j z23+_3L5AN1Ij*i!d*J&(KnuFRTia^OA1Igi4Q4+;m(ee-$QVpPvR*lU10BY9?~ zNNZIcZYD7TpkT*Q%? zyyy5ibC~&2jmYOC=Zc)mGxN?o9rwx(q(RqDt@6Cgp12#ayh@h)B84E&1Z4d7$N%lWeE{i@`8ivD8Lc0LUqf{@j(@|wH@t%X~%dnA#@^bOKCoj3g*<;P{ zObSQ71X-#hAT}0B>!0)A`;R{@YaTY>eH4;B6h^g{VoxMAw6zth;^TzA0~xnwz9t_M zXFPg7ZX#2S=DHlZLdpRS!i!7A@*>DZEOuK%#>?|?kr?2wLD_fcQUNo&9t88yHdnAw z5P0;3f%7YI@Gx*Ad(sopnJ^PF3eLG^S{`enPW1pIA}0g?04{Sjb&@!{P^$}9t2Z47 zqaWj+;36eNPcd?x+;Y*-d64U*RmK*E$h{Pp>^-d9K!M`HJ(HLlS)XIkqxI8q**a3u z!l<(-?03WESDHZbvc~B?=ufU(C&j7)6WGpZ+w2APtPTOnPo)NMWG4Wd?4d= zR*I-a&14oc3;B>3mUQlp$Jh8BT;t1q9*$l8 z*?r_dXOcih&g@3CayBSIQIh?^kZZQjQXChqtxZl+PdtVYDJ20@VO%{}#Op*t!djyA4nDT$k90L+>770sj)VXoL;@fS} z*zfXtbshL>KQ8^x)Ctt?4)Ayhj)fNIn++N7pYiXwmhFQI14eJBU}ewP`>Fyh4?4;+ zaqu12vNE6CJscoqG#e^!M=)@d-l$DJBY^E)!R2!6RcU_khjHdgW)d()uc^ZWBM#TB zPiolOs%62N>Jlx@phIETvhaVlU(2EQ#>v-U<1Z{91aMlixPQ;L*IQ94^Y! z6tdio>j|agMq%dDo1SOlOdd%m!kHVnu?0UB=w~FV2bG^snmRpFgDh~?0fEDhncwU| zdcw=DFX*0ZU0CG%OykI`Ou=3Oo73qKJ;fpN#F~fi^Ih`y<$|6&rWXp7%Xx8C#@xQ| zO%8$Pd@Y48Uj!r2=EcHDLDSuSx5xOnw(0XRkOt?r{BBsii0fRF8(K|8FBd~UnpcmZ z+kGC)HMLW7KOi+0S1t&3qf4Er2Lw5PFJ@A?l(;rYPRm1{s2fD`B7(w*z-`9`R^d}9 zg!vs5kS2}|+3zT>TbOwD=`#05b8X$Yyk>VcfU^9Y!kB*nSY}1c^_FYWO}lS2V&8pH zcw06q2LGc_=2e!8)Im&)4TiV_jPq$S%K+>xCu1&#HJ=|x;f{z)yo-ZK$9L%&1nL>1 z!Z%^@i2395!}7v}YQ!Z^7jS11#>j&^b>Gl|vAPOw-0ISoWnC3r{mRvX-gB)kJ~lg9BosK^Jh1x?Z4WJ7IsONb zM(UymPMO)w%TBE1yhKHd8=3z^l2A+a!wL7AGo3ynF@qdGDg|nuc9LQ#Zx0G>CiDVf z(NZPO9Xjve?41{$R?~QKpzJuZ>wUN9ANijhW0D!g(<#LHA_%hDk{H#Z#^3N%ohUuu zrx0Hu2N8SwIP2pRM1kHJ)2~)pnH>U`t5Xx{$%gYF0H2eUp)dmQpSR5voCM^DGlEk) zLm$l%n79R)mkrva>u)rPOXXrA!HPqA> z-}jrJf0TuU@0GiCx|w0*&UGjXcrBo%>d@M{Exol}Y%=5UV{Tmk z_Iwv46cy|yzlFNC!~cX~eWtj2FxgwmhX@lKp{ozIju_-oyJ^KtU|Tv@-Y`+MufD{sQE z`8nT+mvpDdfA^54#7Sp-&0F^MA0+`?WD4%ehd<~$sCN6I7<Wl=-aBN@rvUr zA_cD*T(0HDX2JH>5bsGyYu7DfX;=&%+n!>HTduGLB()TUHasdD@t&;@iWZw$ zL=~={lSZP!V4QM#A3tKYCQwAqdNFdbvl{4mVy_%5f265A=Qa&+)0~QvjdAmi>)lhK zBHBjn*P|MFFgWz@UKF@QUJk>W06V*x+ulLxxq!`oaLu{_)dCB== zaw!)U-8vmhxk-^R@AA@W{B5tg{xX^G|Kkh4Z`P7;x9F8go{lK?I;UA;6>VC)_&`WJ zym2JipGelc+2`5JiI**rTGPKwF~&C!AE5I$KKAk$wgHT9u=}uvf(UCtj&;z=EqyA^YufQi(_$ln+!MnWmok( z(D+7znz>Ltm^}=xnVW-yiO(5ymoLs;voB*_>$(2Ka=~75IX+Lcoo$bnT7CVxL=<(2 zkL4aq0loUnSOc#ZA8}voDC%`LWnZo-r$^m1KfN?_q<{%T4+Ld*G3u#_?S_Fwd}@d- zBIvm&JRw3x5OivpuLSO7;0|ZWd>Fgu(}yT$^kwYZ5>5#fZI?ZFQ$4!CJ924jQe+1- z(DHoHZWo-%MA5UKg2m7IaZOU{2iu2Ceq2?q0iH@x2s3-NK%9zIWUlk$`Nw;$+>EBE zLs7^}ML1U-i=9PCu|9r)>9cOGXL5Q9@FE_r4uBGMrC3daBKwg$Fvf>*K3219Lu#V{#B9@98R&y=Mr*ni;b?u0-Q!hY;f`Y z2Pr>+vQ)l_(q0cT>gDtKYs|NQMptfV8x{>#qLssU2*~SPwmoUWuRVmmN0-;d$GeIs#z2taCltGUyO4F>N60U)r}OrQ z2_=t1UAa7t15HLBVFy`u)N_g7#%hGrY{tCqhsI?#oz6dz2T0j7QAu%mn zu?Vt=9gKd4nH?#HIpbdf;V|=r?zAnrcWd5(%=?teQ>TdHjhKt?JM;T|r{v5dENrqr zzYufYHU|>_!&ncUU*_TDK>cz}Z^V?@eDP9>V>UihQZnA&BV%hwI5@~2Gd+$B{{pu! z6!VTdlFh$v+6fQMp5kDNXC5{tN$h~a!XmWgMFNzNF3=y9f@aEUo^-@V0TZisaZ zd8jg$zmQ^@(;i^2wu@kkrUzkUDYcg=z5VqWYUl>Y1S%u0h0o{53EztMLz{gSAS`YJ z2_-Z_+&bJUMO8&`-TG184;u5X;1}j%+XN>2EaBdRF>icy$$gJLul69tSIF-OifA+YUb3T)0ak2JG0qwHiy+HIHKAFZ>&PQgYl{i1%Mc#LpRs7-xwyFp zI2gu)^NW^-QO-A%*ko^dZ{pB=UdaQ%1%sSHN6G4&Ekv|jFUu2Vid64rEa*Xkz@|3*;_I!0u0bKPJ@Jb1}VAU2B?`&j0 zT#$R2antv@yGLO*PsPzFGrV8vb1n^S*qm@boKQkh&%^)6Oft3SFspZIqwMGbC?y^=y`9rObSA?d+l?W{l}Nx#Xn#7XSV5YCMG{KSTo7qaaV+yxh}X-U}McY z$SQr2hcFDY-+#k-?F4{d9q+(zZ@r3(#IA$Q&A--v;@tR}yW%Ee{_XA(IJdR(J}!YJ z8^^a>8QES+aqYS^LE!UPh`Z($jJWu-W(+mQR~m`;@({4=smNl01U3c2msy7k^%T)Q zRPa%nEO7oELP(=}fR^R+^gFO;1%(N5NHp--`5@z_8Gc&d5FevHS@}Hg0E?i2%BC`G zuMym`E=?TxBF94E9qvt)@6tIKPXy!{`j0ELgE~2dU`Bt3-&+%doHcm`c$s+(eomkD z9Rwx@j+rPdo9}v_xhykPis!64F1yxcN2rS`VOK|SL<1V9@>&763mZ4pY>$)>a(t&dUMZZ%bxdN@gD{fFaF6# zhBP+8;BQ47Qw{`1^ihYF69(hrjc5YG1J?;BC@ieBW){FTKF)> zdloje?2z1r)Atm5GC%+ZLp!K#%F>cUU6jM@|93YhY$Sn$YmMBuw=R+GrKPyZtg= zSFrJ=zEFAyO>Q{+Tahfy^X-2!*vOH{x0*;sdA?R&G`<%sitsGNiCnmdCOX{hJ|6ly z(Yia8mMeRf%B%uT4xGJV=Gs-_7B7gWi%L^kGLVC$vg+jO)a2y^#7iD3N>&bmxQZWP z5G6j0;ZdJ$lsIPz7!D+M4&QQadUVGHDo40?7VkP zA!Vsoj$NJ_VHj~s``;L5_uRn*Ov9n>z&^CIaKeL|ugj0li|*rd7(C?NUhIN-rY1_$ ze-y|7(2BxSyAYJj!@^a@D4gT|dfza_xF&K2xgo0h{!*@flw>kn|Mc2us+(u!iCu43h#DP|e&Zh^Gb$?O1mZc? zCk_Mq$Vv1}A;C(|1mPQt;pIqF5_1(v*`*@sn{$^J*GlOXs|tN{!zD$YtbMLmT|$uM z6*75kfZrSHeAZ}~+9|!ikE{gJOy$egxDi+cUi^N5FZI?US8C17n5FYFfVc8v_&idU)QK$J+0UO8I@|i(8ap|~5 z4rXqFhkhe5$k@{w%TLd7-e$0|qV_BLRD>n88bWkxHx{2rJ56D^1h` z1QOZug1T%;&w8iFT?{n}K~wxcK4%7N7HI((XS*J4)@R<9yWIf;o5UYJA!&g z2aldNod|PB0FS+Ls2*FAbQ0@XCGz~;Z?FWfcO6t?2mhZ}9OTI|#+bO&pCIFJYM8<7 z1Tj;ur4ybI;gnoKY(QU~+0Q?~A1Aq?y5r`c&!LIuI6E(WDq?Xpdj!tad@iHOC-9_ z3q?bKhebRjdSc6uoaMe;_2D{i%1?_gqe9m~VC;zJpfncjvYUy=;KlW|?|0OQTDY8C zaNniE0hDfbrnvFtQ&jUMuNQL8CpVUK4)%KQA3CBw@b7r?muJ5^_s}C_-@H$8rm_A@ zLz(HnaixH%T2$z|ha=+?&?9-UPdxi0XT{`jBkkyr3C7AgZ<`6<`bvwu=J6{;go#nr zz4DHTP|v4rX6EDcn)q{%KnSiKeHJZ)=Z%H5>8zw8B{6xSKIC7_7r6N?+TgO7%KraQb;f?Jdc#8pS z3$ELdCYT(4$2tZx<<5o=^DO}3wG6z=h>q@B)pwAba+|cmYXdZRVqVy;Hx4G40c;&^ zq>?-2my2l9$>VP;X!|2tv3miJr6W8tGBcmDfb`G?II>Be2fN};BrAfLG1h!>2~9#d z>)R6|&LU#D&+NML-U{*hpub zPy&lv`c-jO?!PC&1(AMdhly!U!yA#D`x_ETT|klFKOK3utVZ0M)8;&qUjE_^O;qVQ z$+Xw5DR5q{_I28}R0Zx9!r>t^=jfi-tu^$+R*|FX>eDx+i7RuZy_&VJHHo2;MB6L`qEsQ_;O&6 z^AizA{?*Bx_ed^?2CSc96v9Zev}n!zmn?p0Agl<1Jr0~nl`=B+s-qjGCQfJE!6L+t zGN1D1;yQTUbXL(zqf0U`2zf)qT-GrRpA7kTa(d(pQx~UZ)@WYvmIp=P+6AW`ay7p# z_XPNlq2oBOT0YoY#NK7%J~?|1e)$o-YvvSo;J%d-n-^MsaN(=oZu!CPrZ!H4jojDm z@Y$6jxpx?10s6W-kHyOj0wiSg=x&Z)%}m-C9cOCjjfW`r*GF12|eC&2t;n#cw3Mf%pEWXQ~-$dOE7PQ)B<1 zuFXo?1XNu9YTu&fo<-rE{GnewKycPV=#Eo|P0gMT`uq~Fm)*vg#~2dVY%^$d9D~iy znljRI-Qtw*ug@L9U4Pb)spZr3=iZbJMBc~sNP8RjYkt%acFcb@WY4B!^LLLnb$%K; zc2I;yF1yqG^N)P~aIHVp@D_aDPyXXv zoEmOJ;0Ax<*Z_L#OV2fq`C)(d?Qgq#8Q`tyKJPu>`-k((92$diQ}{B=2D?~tXDs8G z*Zk*?e(9_4ULJUBy!sWdc;##72K2!n{6`tXEnaSRzhHxvt9If)>;5mkv;4Y~2VeV! zulU`6x%u-6-tIL1`ujf<|KHxeT=6#Y9RDMWgdBU-5Eke4)00?u{>{*6RTTATqUg|= zAcKJn0HdpJIezbXv^Il9=iAMD@l9I@A|NZAbK%@$4IxrGh3caT==D|$fE+6X&@KAq zHV+>Aq~4Hc*OFwI1<$yAy@-$ym`fuIB3CI;ooWRVEF~=R{40K)_&XqQP)5VQby0KPX{?RSXcX0;)-rK$m#2OC{!#Y(_hH#t>%I3(ww^}@xiG;+u>#c^DJZR{aGnhciL(^& zuxxFbuuHs3(8T(`eDJ>)PBW8kX>jC-*Il+`qhb%f&mj z$PbDCE3`s1v{fLmKy(`7v_Ee9@lWeP(}e6&iTTxa^Lusm=jF`o6g)B+V&=HxXS|Bq zkUg)_Voipq z^h5wNo-;bmqyKZJ`@4W`vrr5yJ%?k|a>6!2I#QSIbglG=rc5M}3rIVSRfk3=JV^o2 zcH`k}_|*5x^K*vY`jut+$cQQyD3)^3eeHP-z5D*F_sje|vtgR<`H~nAH)d#9XHT|u zL~L}W#_#Clk^ix@46prkfYQu~m9<;Fz$O{Apr4Xi%#G)5%y`!8<&y6qC-3KJ^)&Y% z2Xb}WV_6hk-*Iu*{$rFBUDxFXfA)Lbo$ql4o&Wpk@MYKdB)OClo(&jwks+zB;{4ZQ zA}r%c{&&~^%m4TO_j~mB75{70|NruYi-M>ra1fkG0{|p21LXix0e}F2@cogUZCJ={|ygQh)xrl{_c^ zDk}$nt9!=F@SDgDz;DiN#((e5{O$Fh|K50+dItFY?dN{{U6~!R=lD*%_#XHj_9(gs zU$cMve){=5z#S@sNC5nr{bVmvKk%&hmj9$Tpr3@}{T==tdjbAY{Z{`af7|u=eeuci z>;8FsS==+8O!}XuhVpmp{{FsvvHR_SoFf_Qfhnuq0p?kWi~I%N1@qp z%W7Gb4MVfxme#N;AB1MXEvjW!+zU;ITUN=cycL)YHZPY}`Y1FRZdfh;_Y=fPi(t&B z6bzX(kCoT&9jN^-b2^L;*I8sYS}Hq{OkoCW>yI zgU#{@#E=gkJKeXf&ikhSWiPYZ4N<2ct4)f&=TA4RkUWz&Jw=)AeO$rZX7q-=tSG@r zj)9G_6qf%t0WCdQ*n>6<=8*I`z12bbcPNG| z{;zK?BX+h^9rF!G;!X7Vf~s`NmHjug95wUs97e4?5=0+Z1Hig~=t4krf$Qg6{g)2c zCa0|X5AfYgDL!sLWSBkmd2_f=)O9?rlxzcx>_K+BQYoOFk6R^HTBYeA9z@I2 z)rFnjM|OMWn}v0sc(zkt>Q9c zS_Ol)drd)E?{c+ApZ7B*}Ov5$Rl}xG87MD0|iM1YIOIz^KV}g41|EG1i4KV3X>55uuj5!MbA?G2n|05 zyZD5$H^CwmWLJ2P;kV(PiR34+_-DdVe(Ad_ZD+g-j)>zXuDYyxmTH4DxNV!Cmb>PK zjj=PC8%2B+cHg;t%|*)#=Vc6}xFV7+vcZ_~^Ro(!K!Vz4g`v>VqhMGT+`GIyOcLcX zrVn(B<+1rulnB?BViz>tTqC6dUDNEdH5XyI-1YOlES(GDTR|YRM*dQ~4{_-E>TTf@hTDOPx_vB5<*4`4E$7hUU!Y2; zjftNa=a?`T39fjCi+~Da85naPb0qf09rM}}msao*fP0V8o`{Prb;1n~k>ZDMs{G}& zGAHRv8F-0uY`DcV(RPfzA&KQuV1})xJ)R>NNcoCorH{{7&pe!t+M!?L+R5*fFV=ID zBVjy|@nPe~4h4ERfX27WkRc`BDp_vwt}0os!uWO2ryBC6CT85Pl6UemVA+m zVY0abM(*aY^Cbc)Etih)6xPu#vnMydOnJw$AO8rYaGmq6Q6_PT+=|PRxY`MHa;IYH zW4IQwF&AWaStY@8>|PYD)k6d=+il~up~?uZ2|=N|)3)8eBv&L$gmPJAkzasD5tJ4) zWn?*#S2e_(4xoHdnIA5`3R#APcT^RWFNQ-AL*y#2U>8nI-A$;x=_qk{FE1M2BJUEVJc!c1?$Mer#lYHT4Vf0X~Nh+71J4< z<#?88sx}35Me(nw<(Fm@d6rdOS4unuY zmpK^%zyxFGQ2rmB92&9?d42ptf71X<=l*d&v!R{|#IM$g`*!(qgO3wrN1!b;&`*Wn zL@>B9g3djOS`56~+TA1H5i`_f1rJ4@&9k%q)9l5L@>?+qd+m0qK`=+?~(ip+B6ht8;u3Io)WMagp!^_1F9v{&{Ku?P+P$&miXYx#@3ypWV8E zeDqUeA}d49P|5Jvvw)xK(x=|)8i+h8eI^wUB96K#TjUy*d2PVj06MqVqj(t3yRN9{ zY4VuCkAb2kS&n3RYfG+DyciMpH4-f^xM9s+7-O#1cnhw9ZFNXQnr*y|EPtZevyLG% zPOQveBjbvtxkTu?zdbJiDByF$qTB)}ec1VY$#*Y_Lw%n`L2N2DVu$auG!zO_6`1gR{$`fShSo7|K84n}3>WpEr>p$E~3p^u!9 z-{QL7_fuy+kVaaL|LyQSNzjBYJ{p_bKD4;8{oPB+mUYru6UiU$9gkYGbn+}!UzN9& zGkdWo7NV_Rs1qNZ7+4|e_ayT{Oc+Xof%de)>Ui8@CGcyvO7lz z2?+6588Ygd31)(c;`BB@h)>#1mbNA_$XH3pc|L4g^D`M(y<%gD-Nxf$YMRl{mjYbfKkc$vRv(2hb3uRyQOi?3h7_1}{s8WmQkWO8mg=nUDTuLOR-gAo^a8UtQ z8THAr3_78DcoN(Rmc;S;o(kIYSS$(xJ4BuMiE@T_ay@iFUzPKi>YMP_yr&aCw6t5$ z=FIHy*~_}9-}6%MDLYw`Vb*9D{r(3(otaOdTr6y0q%|@ zVQn)Wywa=TQKu1}NNSdmL)X^ug^&_?9^_VYayLsmArqb9^1Z{S)=j9G#1kZ!^o5+7 z`)*njBysFVwWT_#moA?>EcW_p7&FodC^Wnmi;kIqAaFz=J>0x*%@;2s_1Ge(#jg@N zfH(F^j3hl}IOtG+0!+G~LS42AJiL?KG#i zDHeSetinSSLMAqDIC*BC>hI!^V5$VP zdW7;vW%!(>lP*QM`Rvlf&cAY24b?bBLsc~@q6$Qcf-*mRdp|8igK;I!h#S4 zX~b@)UfQZ-=5>8Sj%4#oAgebuAqn==VkC>bdCX4Habkbu8uK&=gYfjnnMmvxpD9VJ z*+OKbewtU`ns?lr(_U=431MsZZMojOQ=H23Ly$I+Kp+oLZ{*Kpt8NGQ4u^x*#f3jZ zBo0#E{PA-9s-vz;nV{Z4Pgb``Cu`KkC0`cS&w8RH`5;VAXUhq6Syt~|ql!sG zMLVq#xDV|h(asq}^IH0wB(lebURyZjxg~RzdhALfWfu_%1Z;4=Gtymna-M4Sz2_8P z=1VIpuX-$eQYV)*8Jg_A_K#KBKr*lJtS0b?Ph!{lG=1k2`DF;`_hgtTclN1z5S?D& z$jPHL+t^=&eu(|+0-wNS$Ts4=IXul(f{L0T(a?Q$YLzz)lm=_LseKc&K0$WQ(3`-6 zUHhh4;H0TtfIi$GkG%ztrW1QnBxl6(k7f|kKbHp&c3q5J1!3R<;Pk|iiR{9Uo(2TI z3yvOtU1k!?HrYl-KUr1R=E`f8`K_Bqpo_UTW^?Y=#*RzNT420NN^p_Z&leWe$`Om{ zr#3?|13@iWRT*=%g*4{wwS{L$y%$soR-VWy4?SK zDXf>$+0CKuPL*cOv3OE5#nt3qmeoEv`+OD^bgCfd?5Tk6zqP#VMzg={Jr(JCS4de4 z*?p($baPdKvW}SCKZ&woc9VPb(xphOpcqOL1!9)NNw2T_K{_Low)Ug*3ERwB$byw_ zVg;nZg^Euy)zHqkC;wDWBtX`3U|~lwC$w+D3V>4F_aADw%uN(+dRjjfZns?O#k>aVUg~{c}GDy zX_SALRpgpByBRBMH6WJ&Li__wwE*}f^YT*!BBPNG{L3=zuD2|X)9D*IE9Dap-3vXG z>WF)7z}n6(%~beFn>DJp71?|hc#QUKsy3!*j8R;qe4KoUkt-y_)O}!c&mW0tkZA{) zI8DNfmCxnzClM0{g0h4B&lp{M)>?#Ia?DgSllLXx|AZX<60YZrynUC@&zK}o-gTwS zk+Uz1QsF@yOZ~IJwM7C!F=rcP);aYq&xxG#dN-UCEpJtJmn4WbrN}A&X~(1=F|bTODlq zK_)8G#ryT$@_+@GSoE5Y%e9Frhq}@7(o`v1(k3G^J3bk(&Yz^1UE2}=e;Qgm#{FoG z!ScETC_03qu4w{kw$`?$OLUUL@>n41{AySbFHE~~IFvFlWk<}^E`L~~bC%8P1t#k= zoU*9K-CGx zMlJQ_OKC8Uy$-qHzxQwN`wtV}6?kR>-L%aT96Z$HW{#~yY?{(DO+ zTr0;_W)_HWSpqLtj*LKdLWnkcdk}O%t*4zwLU!SpDnFBR#>%PcHu%<=b%p={sJNV# zmOTcEFKc=iGQc&Rdd?W#~4l15{6SZf!@% zOQ*23h%b*+`2)#W(%zxf>vS%gVick&*;i%7q6V(acHqZYWmAL`vA~Y?h>O*NVWdL@ z<1c>emSdBmh7YlIa)H&w)6H}wvqW52Mj(F6yVszGcLgGVCHL4)&Q#06jj>VqRl~L0 z5l}D-U%xvx*2?cpQs8-9{ob#E$F|KmMSHw+CPsg+ruX#n1j3#%nu&?&pdHiKc|kf? zKs!k`uRHnCj0l4e(kL2FpuDdv`MP?evfQ6~(rm&*-P>!Ds6=1x_LZuw=lnez;5%H|7<7&0Ajc5#gpXJ zG7Cp(U4Pb`BKA{SiQhb1Jzk`;>Oy`by@ED(x1`+BIQMy&BTwycFw$t}h`anAkAaCM zFgL;@2O^hYPXVjxLk)Yq{DP?~R%=@OCAsrv%wfB}*a9e|PFIBn2j93@Qs0}(zpZ#9 zlCbcb-c0g?NxH~9CM409{ZMJ{-jn|1y!U_E()ma=FO^LfjL)B{Z_2-8ay77xI6)n0 zZd9~4i`IK^nwfXFILxBkEVmjX5JpD!t%8j~Y!&AB)=(LKK>bdgxo}-EeIw7;2$h1$gUBffVlfVtoQ zNy8ubBGL5YZHI0{j8GZlwyQkrrBd0B^fwz)S0Ph?-`Z-(Zfxgsb87mt=SdBkCfhS{ z+}(Hhw^r1D(gp82@~ne^4ck%85+6)>LPti*B=(E!gqV3@;{}rYsk$V)EIg89Nfs#YL-oYbN>KF zcf1QaH~*EuVAv_LO|I7RV4Q|W@T~)EmUd;!mc_pl3M6XL^yv1>?dtKULu9e>j3(>@rX5RUt2CbFH=Flu(4ClX(2% zibsIm8E1fgzlrLeF&%aHZ!gzblG2=0vfYfiegPQDyR3UUxlcbCj`E*(7v+mV-E#27 z)Njb|kt5_CKkDw7*P1^8sOaG3OM}Cu&c>LbMQ?-3`oR-nRJ$#dVqlWJ! z+oBXyvW8cK7ZD-d>4KIJ7~oH8_u`uP6L16#fLQFL-pD$#kVw_%qDkp->qc#l6g|1k zq=VRNwNG8v>bnc&M(!E5+9%)sA&R~jS>K>ABV=>^w;k`7q=Cnby8EgXXr|T2XN3N1 z?fYrLTZ-|sRp$dx*i*Z`vgR_v9o+!Eh}vfOtp@q)qB@#Ni5}9cSgps z4;#G$U+_rwiX7vtB#_sk=eOTpnd_$3ob>FO=bgykF28;%Sf+W+3`JY>4pP`vs{K`qU)%?h&FYd`S@3^(2%2oKvezr^gj7hcIuT7VEuaDm ze@K{gvXv^x$!q&upc!cA{VB3z{M#pqpI-y~)#S`+Nj<*7_B7&y@o967P9UMgD4#Wc!|OXr}*1w=tOdtDmyU)(Or zGuwO+Dq$PfYxjNQTVE@82hUABXY%BJ(uJ(Dm^i}j!grB2aiYp<3oiMd=w1~W37=6& zkQtbd{US*SsjE|q;TS_ef~JS5Vd7}x>Q|+2==s+f85*x3t?JvWWf|FiN*r7>h z>O6{^1b26~@C3JdtY6tMkA#UYR0o6t=#@(eGo(`gG04Uc3XQcnW5{J z^)Z7J&LhshP1qs@kZuP)pEq!v=VOa!VZy$!qRbG|wdlc(m{ADo%P360LzP3gcT9RK zWw(iMX6WR@oI)}`;)s7(dN6h&^_mT3oS55YjSvFJu3v!8&UV1LJLz@7H~GiM33KE& z=H8a|L$E~ZiUcIHBk@IXGH=NzZ_N;}_^04+=xHZpPA8eo(W06`?Nhz?onyvRvsFdiGP!3W5S1Q5Un)053~?Ucb3_?1lBQh$>rfg zAozW|d;ot;H$tpAt&!Q>{jM{}ptjAxba831CsF#j642fb^hll(+~)ou+YIRGz(wfx zQSD_+c4-yGsfkfnerKb8sKi)%A1tUYl9^1P+hSTIeC6|rBKmUdrjgX+#rW-IaP=BT zy7h7018?;~)>fLXu&6Rj25dvorWgEx?qX;m_lxW+4h6@Z)ST(DlYgC!&4}dj7@u}m zq0addQ2a1SRCKUZVQD5w4dU^BoRlNL>Uc3&vA@gecV35Xh6@clrG zRdRrgG73gwCAddpU6e6F?V45&R)hc}a-JyXa+EsHK7BBTFAl&?RS$R)^dz~tT+x-k zH#-&pFw091?S*amH|a7U1|m1Bg7|m5L&T!rT?MXx(eweOS-ejw_e!AQW>u&KHC9Ce z1t;>O15NM&=rdxf2Q9F?ksOO!G}L?qsHA|u*F@0(W0;Gh$5y`7KYw)C=O%`J39CR~ zWO+7}i0S_oCL6m;2qg2aR&+p8Hlr9#q&VFF%d^)9!yA6;IVI6>91qc<2(YI*K(Uhw z_zU8%qv(7=FXQbL`1+8N1?Y30Vm2X#nGpfZ41kiT<+@KR{+6456|uoZ3RBNSZi8O+QuuCdyQ7kLb5C|Lh0`^dDTy$BW=@NnP;Z& zz(`=}FgGll446~>DNK*WDLBnsl|XBSx3T>od7XE!+Gaxe+Ep+fPLeaPUxI;|76 z4Q1WR$QPH%yXDgZJ!ogHmCE(14KPf7eJ^Yl?C|Nm@Mw&5p)l-(}Q&55` zvtbUi8Qav|&9YOcu8QaI6u%XL+<&uHdf%@%{+c zdyzFXo@8mSf!^m(?j8rfNemY=`SQHd{$nf#HX~ zt_DM4rnn)~o+}wOnjZtixm^_r6tM(m3ZbPXR znUH*yF+7)zMv!dxdUi=GJh~-1;MUdaE9I313%82yX;sC-du8OWy7X-rdIfKv$-!LN zAaj@}i_#St`K%0!nBjZe{3#hm5KHWZtC_Ecjj`ODAAm}a?!kRnSXuCjyl4}hDEJ%s z=5xaw_JhsmZZ%xY<#@oT(j#wLG*@3~aJ85HCn*Y0d$7?Du<+z@$tjJzD^#2n(V-!B zy;g5;TDJ((Vx^y-dWPTO>-vaX$dR#6yZEobsR~LrKBVyt6gln0mSKn(mN{@`lV4qM z0@$VyyhK?%(P8{)zrb`$)SIyza)QtRci^cr-*o%S*;QMdI_1j;$KUPGFEBMW=7>Z2 za)*gBfHb-<{esn@?gvCNB_tOT7=uocMmde)g};}He!NcsBt`TRj`3yIb;yX<4eYH! z;zBtMuGi})AxC`HmE?+nFzzGZU!fk1d-`CgeJ<)Bhaty2F?vjWrUC^40Xp@kb>U$> z;1hgnHS+OAhcWqBsDW}zeC369?O-Quw!|B#%Ia?kOA5ePY9ICo2I3QTq>WH(I!`ZzH1xb2mXwf z`4YaLG#_fM6S=4t8`lG5FC6r|r|YkQRq+gso15_8Z56(<&qIewSA_M@3n4LJBo|SI zH+vUWo$G>z<>%V{Q}^bK8#R!3Siqk2=;z4h+$4Z;(<<3lIaT+a>iUN zxgZE^wFp@&PF^&YvYE*UC(rFe1IZblh)to&2XdN&T&3^p^R=OnrmP-BSIW68 z+rh*&B^tKwxB+aYK33rFM#u1-;Pw7ISDmWH8rBKyi9@5<4z%oj8QDmaBa4Yj3C0|) z^;YKah*a3~d-$gYsS1Ew`?IU=Y-75CL*1Y2`7~xtgQIi06x=NmLg|eb;U~oRem15L zTK34GBF3s-M|_S=KlZJtozFHpk_`ZjWRn9yu?bX5H`nyB?w2YwTvRF33^;oDrr zk+L=ZkAiVEF8NH=27TRw^=3zEo<^#1AdMuqGX_xBsax5X4daOzVum-l+v+=D5IWxz z@>taztrwa!11WO^Gb-|z(hDS70s4i8g^$ijX;5d6iXEB;k3##b;{l8w&H%@qhOMY; zwjkI7eVN_(_?dNDLqf=TvLf*lR!1XpDRUNj6TZAWtZ3mT%EMC#E@Vvs?6ui*Pw#nv z!vj@WRUE|AD(!h1)0fLE6}by!+#&gb-Gp-MQ!JdB0ZfJwN=gmlOS52AG5{ce#0Q!3 zJUT$-bPq}r^95mm{az+GV2FU(i+whr@nR$Jg!|H43Fy&6_1H|;#7HLAvK9BI&_Q^I z+Pv9qyjpubp2ylaFOrn=$7W1UB;HctNrwgkP|7JTcZ@)hPZS~mU*^cgW7)zpQ>S9tM01fNnbMK?mKtiT`ADX3N0HD*M0pHy*% z&=Qyzx#x@2t&U$1uBlR+g<0{=Zu-=iASm7-_M%@0I*fN!Cuk-UU{^%0ghEpEYOM2W zxsiXzfxhI%a;f!2OXTqM8gpIhE*JQZaJTE-0>t|pG`KnY>ulk@E-(iML7f!=$R{ON z3=i@r!xg6+Fg?}r7MM)K6JL9HR(9C5#Ym-2eG=JoVZ_a8UA5gV4_BC>Fp6oP77mmY_d_-Sm^%_p2U*hYNs5 zW+^S09|H6+n>lCPu9q~B)QcuZj#b(uQwtX)$Me`GuF3|uygud_sjlL>Fh zZtwZHj;2~l^x=Aq_$zW2`*%>T@Bxy{_66gUpO%E)rDyLJ0=2jkesymg2g2dT%q7Tmi{gf)2DvwenbHg7Nbb8HskMwvvjW7BlKR z5HYvXld6Qs2Z6i=WXrkLx~o5;d*ONFqk07Fvx=UvkWo1Z$fJLty94@h@L2l~5da`V zWo75)!;iC;fBi`QvV|#yISjQWlI`W4k}M&hr!{qb>#T1hUP=^Z&s_H5az-aXyS=np z68&z8lGcw*?#oLbD0~dt`K}As%okk2hz%L&Hg(=%4d*$2cda_?%?OU-@cF%p%0{S< zFf%C;ruOr4RT+>wV_jzTdB-QPKY=7{87R1&H}Sp`i7fELcdN9z{9mI7n=n(I zScE?XZtbW&Y(ILt=Sa>V`khYlWLk`<^xotQz^>JaezK__Nft^Z%fj%2FaE$j82Y!- zj)!154mbYcxoew?ntqn;+1Jt)gQBIyqv%lMi{?C+*^c7Q*HpZM% zRaGM@;Xlb9<-6E%!5w$;23!t|tPpcFjun<+)6k+@y*l%#8)Js{YLR2}8}N9N@uAPR z>8<0EdX=agS3O$(cWt^A@QpzjIGs$fpGoDhV71z>d1)*&sh`K$a)R%B{b-NcUvVO3oWo!)5gPs%#c;Q!%OH`r{ zMMbk!Mc0}y-bqgZS+NT&4QNS&?v^GzZgpZFVGco~@36+XZl0n}y0=5L_FvoR@MS~h zy;-_#%YN1%%5g^q&x0~QdRYav5y!(sEZr!RiQXrnT1BPU1z((-w9Rcf=~76l)uJ*7 zZku#^Xtjxhw~t#^mE*EYvnV7lWy!(L;ZUyQuOW+#gWL^)fQXrNd1JY|H@WT!u8dcQ z!pGDZq)9Hxl8#yt__;s9%+IJvzXe8%hJVmPVOxp%8vu`Uk8bJ_x$UhWaz0r>MF0>x z!bq=GNsNmrx+taU;z`lzDAc_FBCq81+mHG+Cbkj*|3GXiyyZ4LzPg5vnOlTwe&X55 zGSk+P@ytYJ*PwS+XXQgC*5b8?DpswwZjM$y&~cQ!NC>1FoT*>aM0bWZC)6yAkh9sO zzSu{{yc8vkq+wgUTE}Wo^FMnAZ=Bq6G%M-gK@t+~m=-R5#*ISC5mk?kAq%{R!tIN3 zAD-D@^UA}lQ|<%#+~J@ZD;U`oI9YVmCiC^T4F;>2#;ggv*8#xnN?og>S0x+FOVp}H zc5UMVxv`)@7JFMeS9VWG7fNxN_AT)?eRGy#8ofEIcyOHh)TzWF(R!jR*%E-Xb>kTU z;u#iLTgNvt0q+RUOo^9J`!z*0@psbt)ad(274=d~H1LuxizVp6w9D|XqC>T3Qjeea z|I8jg!isy;JsNdp+P9s$wBZJN@B%8PS?ST!3C`OVx?SykASW2tMDUE+PHk-x8DY!% zoo&!IAH%bdAd`t>`(HSKI#UJS-BPHnIk+`eoO4963t@ZHK$f-5Ye_VKVsQUit+u@J z)Jv2PI#Z5q+=yt+;}6|V-)thQ104H+m)9EZ8WvL&iEr@pG{_P(`jx3orCkbifYYvx z;L98S$_W%{XU->7MhSTv?3zfdrW8S2Z6aL^SRE<7wKlIrhuYkCQP5EkzRC%yxPL;J z)QH~JF;yeQ?L^r3kuT#&oFWC;RMwaL!1g>_N#~xI_Dh6O=MEN@oo|uCEWc`~#%qDZ z2GK9%ylcSYQY}A(1cqC+HwBLQz8OIdkA&|N-RZh@tUFiX@bY6)Q^6T6l zr17sAeAj$f0R9+IJ)ozQxHFL`=n9L~_@-0B11_)ey1KPfs@4sbE%mj4kG>!yjuYTRjJ{#xKg1>JSf4oagXzaX`<@2?m zfIowbaJ&3X*SBOX5|~NcsdvJ281_SrH0N00o14VbBc{01RhFE2Y&wPyd5o0wo=?a# zWoeVZG=;Gm8hf$@SRU^V7@=r#bw6J}J6~U>JAw8Mn5rqzXT<{TlZ1%3x_1a&G`xN2 z(XG+=7aIm&0CFV5)Ht;-^$kPV!ayK1y80Q|WH-0pJhLKkl_UJgw)T*`A03ev#wCKV z{!1;YgOK%0WrwRjB|XdKV`)j{u7uwm0U9zdE9lFCacE2f=n}HpuDw@x%z8C{ZljRHOqiD4)V$g2j8SB+6mdaGaCxxA3MAxgt?~!f0Ur zW}A)jE;h?r_xsegZ{;9k?ZCNvB8?hJZTEfVw%`Gi{8${cgIs|N7lF%8b?q}U5Q_y9 zR=;`GLK3u4V^g)`BFXfHj3pIiI#bK2Xjb?@Dot^#DnkAk5#B8OkKU{7Y^#vfaV+Y; zT6HU<-k1M>Rr~rOge@^R=aq>wPAFvweI$yZ?#;_ow3FSr7QFL|nkO~%VZ!wrA1P)|hhCZ>%c&@;#0-C2^E2F1H|O8yJJ7KhnXK(nXjo8(dwBg#)%-RKRFjqJq*VQ1uQ4Zx=2ozcexmKAFtJ)=UZ#{RV? z+eMZsb4uvAHl=paKP-01Yro@zkNeep?tJ%YLz&o9De_+-;9wTa4j=ao40aFbh`AeD zIgvu>B3mpE^`znw9Q6sb%-rudPya}xfJ6wn%ciDrf8_jvOdVx4O#z)R%M?GXZtrt_7Bmn!$W@g?4YMd zbxndtQ{ws9`e9OB zj(cNTbVsBToy|=63jtrCk9*YW+jJ+Dl|>17oe73vv8cg}stphoQ3OWm)uCyMk*)&x z*lp~8v9|7j_1KeKT2#l5Qn zF;c?cu*araiX4)nSl?X0r`uiK0Gz9dD9A?^+(*w1$;^VfUtt^pV2JhRf15s?7t5~tm)%xDoY zMu&p2F1=_qYV;@kWBCxlZ!3nYb1|`nQB8O>Nf^6POYDJtOaNuro#KE)<{wO}uD}gx z@&jibTez>g%8QZbwlTQF39BxnB}c`<6^Vqo#J!3m0qd7BU6{FMDonyAiV{QR=vJW(S^W+!Oca;fqqNf2eeL3dLW;-<=$Or<0DnguyDwN-~U}CU| zy@@j0`PFTytHTfDsZ4p+4Wvms26ADBG%JDVsf;He?T@uK^MeruhstcxZbs@vw%2@i z3e2P2lk_XswQcK>PxcjQJj8dWP|J?L?TumTa0qVFzH}_j`z3+Fl`)OBozW6f+)Zau zHA9%9DY&V2XNQ>Zdl&1IrQTu0J!_eqTUJrxnWeo!E)DI&-5Ia;yQ28+_P(yahPrznF#!A2C}$a6KfJ6qo#>d{;wO^z>-|l4H6e5JIVL!;^qUU* z;{(@v~%DVh5-0ir%xrA?0 z`^CFu!(!{C!Ae}iD>eTxKPnXYj~~D+MJhQPT)S3!(uAe}9S+~lnB$l5Xi#MCcO54y z8!PXVC69jX5tCN0W?c$u%`RN|E}wsGGsi3|33e~#5wYuzhun41AXc?cCs?Pa{pJLP zt_}~98AxA4{e!=G;LJ#}=*`^n4AAAIg6aKEq{E|Wg|hGWM8~*h2AvE^|7!5A4bw3v zqQFtbZFAus61#xOP{zA-EYB9XWp~Dfy{NR*dygjyZkJ5L45jVBCP^4W!xaK89 zTcL>M#C&I^fetIJ)P)+MI_<1@3qR@K9tj0yx8?wuT*(3O`O;Qmq+`B)bd zhQ`p|>WxHaY~dj%m$hcYCRrCNpkBEFEIgGdZdP`KOx3#r%B+66+!W1g0i}TeoG>OP z5&>!EUuu-)hBtf)R=<%$LB7Bt8;`06{GLCXUDk0>(0%JMbgOvyO{Z~;aQ`%bOalT~k?yv&`;0oO9rHQ^LDCLfxC!;Y<-AA9vTYNb@MsKQCTLe~s@eShOzdX-iijIAy&#eU2-t z$I$Y6v!rlFM(y)^!lNqcs=Jv@`eMKbvPYSuDDL)f0r;phVr8s(xsfck*(}mT{sk9q%9ST?=lS|Cf2o)O>)C;DeN$6z_9w* zyHQN>u=(4Xh|cgRq8UQtT@dglb&B}BjXEpv(M$a0vfFPYAzHddNxd;fT3{G;O$_$Y zVQ3j9yx^--*&E#3%b;U6CWQ^{X9TdDg~U?=2iZtKx;hK>Ydk`B*5N8s@_Q#=$DbQd z-rWQVebX3Q=id!>(Gi}oYQQ^5+G${5Y0P|@Kiu|ZHfWlDEzJxD)`#xTfepbo!h?{TPxmp4F2`^!b}uSj@h|-i&5WSY#eBhi;9UA(R<(tPtQOIF`e$!>$xMIg_>*%h|i4EoW6zK|MLq%2o=_VLYu4*Ep0o>(z{*iXI>S0L^mR$ z$wFhCT~f_OrJ5MZtX&;ftmc6LT#PZ6pgki#e_Z~jmL1Jg1$LJ`xIxRm@>YIxKJUI6 zOhn53o1y7D;D`<$=Lr0QupR;{JO7l8}8ET$a7QnF*6(j^WSR9MdDT&Q3#bqs9j_5-_=x1L+{O zth*(~nYUpr@dzREzKlBZsWHzp1D(QjDk(L8oZKmar87qlQ)JhxN%E{hR5Gr+t9Snc zpdE|?o#*YXvi}9TLiyGl6!Lt7++44BT!mh zui_T*U{GNQ45QkvijMoEws;8KhxehrWs#M%&&35mAkb+G5U0AuGJqTQ)e$9B5lv{M zx$kqR;%Sv$PP)kk)Cs#7?0x>(_DbzTx|Tu{2?uMP^IqGou^(iVf0?L1ES5*^+;r1W z^37_MA8d3xv$256LFde#>DlYD+?%|-LELIP69{je!XgMf7-eOxL~Fx zX^x0^=^uw~Y(9y!5=5xe3-?xoKgfdB6ZUnNsgS^;>?@=P+jA2YCg+;hW?6J|-nXeH z!--mdoljOLKOrqRtj{T@aX$de#K379S3?S^Y=c00Z#B^d48B}-7aZ4=ycvK<^K9vR z5+#3i7b|0T%?d=MH~4Z-n=KNy(nNM*7 zRlW!`v!FSFJT|Of;Vy<9Nq|W*4Aw4(&*A$q0Uh|FY~@Wq{&f>`nj3E@#h;QD$`#?_ zBAl+~3!I|VnO@@815JI+bpHx^}nctlwE;cVS{ zf-r;7e=&)gI!w5p2f#v>97k;I?22Fsm(=uJKsRP}&QYBvY`56~4Tt7U^)~n)0XYoD z^Km1M98wR$w9eTxE$>J@lT2iVufQe@SKfrEGZ8Jyvf1PPrmjKvt*A6`$q|Z*g$r8G zvzBd;-!+HEGfUBNBdY~^&5uG^-c1*_txHa@DrynRIyvk+#7-(s_cT+Y=*JQJNo~g9 zOkLXkIG2C|ksDZb~aTi*dfhtJpNd$yP zepvkqy|zWP-Viv2I16Zv4~JMS%a1DTWM7v>Ev76qfK(4^!E?X3>-(7791o&S_q-U z@{bP?P>D5LAOA?+pUz_Xo27l*-Ggf0e2NA=MfF^hd{xqy)Uic2DqG%vg(B9*g>SD^ zfX&j0FpqY(B#u-GfaP#JWnQn@OOg)(z)Mygw-2O4%+?3_S+v?=Jtq`>AkCZqZG!$A ztlYfLg8i&BQsSkJq8Rjp(PA<}fZYz|V}#B7=Ri6i*;3dh-Qyq=Zse*Nh(56h7&v!L zrWxGFIHMj)uZ6GgHuSF`ourSvmm4C{xP(>Jl#IU;vHf{hEGvht;znCJ9Khm|3F~_8fQ2ej}AT5 zg@AX^No#;35u1nZamZbGW!M07!J+-<2*A{YI9*a!b9&7>K%VNdlDTWFV3-eM@Vpt% zqWfL+tkp#4KnZ2XFu`&m9T8-cjPllg`?Uiis`xK&wh-RIp6WR9R^|)6qAlPEE<1&L zf;29KLYz8{!fEJmuJ`!h zHxWBz=PXr&sn!7W?z`k#mw~fm>y>)c2bWbF`KeOg!VY@2tblRb#UN_D5dH83ecIHP zTH4OTg93Wkiu(^VM5~>f__3?joGtay6KBl-BAA0ji*nX5P3!iOerl;|j-#V&YH-vK z6u&Y?+zF3oZ9u^cRBXC<6m^sP;rn4kLc*Ce1*P7I{bd!Rk z&S1V`RB=?Jnln>tB8x%b24PeD$XOdGHv_-R7#t8CL>i~3?e754GZ!c82;M_3(4Msc zd2n*0(-)a0q3;+Z7Pul(fhM1CxmF6dk?;FX@;;JCJ93klFtQ6G1LLfDR%efPA&0pj zur!xcTCgY=&D&!;Fd2G=$PBxTTFIQB}ChIc}ft_l-wv#Y-ZZ~RRdFt-2Vq}QQKA#GX8r(@v6)8HqGm? z?L@joXp?+vt&mthTF0y&fx;L0Uazt}9l>#Iv#bH8u+z(>AeW+uT$WAsxqZDY8_~aI zT}aAynYJiG&zI2m8gJ~;Mh;;Kdsl&0s1Ctv?iwWnDHn2Cpw+Msamc6NLB?R9V(yUB zspmo?Sgx*=V~guHOfby}km{H{LZcvrNDS+;J%Bm?IaqD)anTODP^~(v@zwx-a-*V} z?2LCXJFpp8Fr`d0cb^{cBO7H0@kfrhY*NENioHb=ZExsZV35L6y)Xbb23JL1Ub~EQ zCtjZD2H-n+RfQYCHZw=0qo0kxD{%898`Pn7l8N^%__++s+n-j3+fpxgYLTg2ao^@JR`c#p8a?{{}%Hj7l|Ig85S*^rXMrpAvt8jbA9kK zPVuM23zk75c(%ZR0SW=CFLWWipQ_0S;F!I^T@L@dfv>gsG+Lj}drdsx4`a>%=`mpm zWWYZ)t^3y5v*x2w>&AFsn89t2F>hM#GLtD8?KjT|=047GXhFLSU^f@?DyNF_+_Y;K zxE0P*bM&mAe3CvcFNwQ#X1b4+sepB)}W|azFqS`N+%8)5Z6J z-I42nM**#<_is{;t_K(g43m;{d?c(|&6yDhI)hD*rq{nnr@Agx4HBI z?wPuS01gv}mSHyVYXH@D<|eKdy2EG&njsgWSa)*0bF4ZHhR6r=-Z(k(Xxa;DN0cgi zQQ*xKCQ>_(u0Y8qsC4xYOjz1!^BADn#0_X6XUaUD|NBTno`~bfPyhe`0hhz@^rF0K zSdy!5H9VviRBzdRoS+WcM^NSvbG=FvshT#Lf=5++_Pskaj@(>r?H<4(CJR^6@a4MN zVd}hH<^Klf*|b)C%iq&tO>78z!32;U8j{dbb!U6qD)!Eesn;;*WV2ZgE>4Kq zz~Ihx-wrf-eeFqD zrP7vIHJUk|owPPzGqM`+px+Pg_WZhogIK$T|H~?}?Yi!2bzgE+DvG%(6-8W?3Zhg1 z00fMsAiN!e)UFtnxwfQOX3ym!Gen|&LSXB#a$^IpFv9VOsH1} zhcGbl*4}mH)L0&>4;GZAxVuV^NOKIINW7)RdTi0;mU@5@GaurSmirU4&+ z7C#F1L*I~zRm+p>iX*R8pJLzOfES#e|Dvz}je=bX^J897^JsMX`F2S;3o20xpZQRZ zws2f|gkYQR{iwf+bOcxc000000000000000000000000000000000000000000000 N0000000000004{pTsQy# literal 17464 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 D$I$vI diff --git a/resources/placeholder.png b/resources/placeholder.png deleted file mode 100644 index 428d5c088756d7d27049a25fab3f43f38109f102..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 300162 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 z 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 $ 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 IbxsLQ02MJ)DF6Tf From 2b84c574ba56882aaeea3b6bca69b7d94c04a7a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Deluan=20Quint=C3=A3o?= Date: Sun, 30 Mar 2025 17:06:58 -0400 Subject: [PATCH 51/51] fix: restore old date display/sort behaviour (#3862) * fix(server): bring back legacy date mappings Signed-off-by: Deluan * reuse the mapDates logic in the legacyReleaseDate function Signed-off-by: Deluan * fix mappings Signed-off-by: Deluan * show original and release dates in album grid Signed-off-by: Deluan * fix tests based on new year mapping Signed-off-by: Deluan * fix(subsonic): prefer returning original_year over (recording) year when sorting albums Signed-off-by: Deluan * fix case when we don't have originalYear Signed-off-by: Deluan * show all dates in album's info, and remove the recording date from the album page Signed-off-by: Deluan * better? Signed-off-by: Deluan * add snapshot tests for Album Details Signed-off-by: Deluan * fix(subsonic): sort order for getAlbumList?type=byYear Signed-off-by: Deluan --------- Signed-off-by: Deluan --- model/metadata/legacy_ids.go | 16 +- model/metadata/legacy_ids_test.go | 30 ++ model/metadata/map_mediafile.go | 24 +- model/metadata/map_mediafile_test.go | 28 +- model/metadata/metadata_test.go | 5 +- persistence/album_repository.go | 7 +- resources/i18n/pt.json | 1 + resources/mappings.yaml | 4 +- server/subsonic/filter/filters.go | 9 +- server/subsonic/helpers.go | 4 +- ui/src/album/AlbumDatesField.jsx | 19 + ui/src/album/AlbumDetails.jsx | 95 ++-- ui/src/album/AlbumDetails.test.jsx | 327 ++++++++++++++ ui/src/album/AlbumGridView.jsx | 19 +- ui/src/album/AlbumInfo.jsx | 15 + .../__snapshots__/AlbumDetails.test.jsx.snap | 425 ++++++++++++++++++ ui/src/artist/ArtistShow.jsx | 4 +- ui/src/common/RangeDoubleField.jsx | 50 --- ui/src/common/index.js | 1 - ui/src/i18n/en.json | 1 + 20 files changed, 929 insertions(+), 155 deletions(-) create mode 100644 model/metadata/legacy_ids_test.go create mode 100644 ui/src/album/AlbumDatesField.jsx create mode 100644 ui/src/album/AlbumDetails.test.jsx create mode 100644 ui/src/album/__snapshots__/AlbumDetails.test.jsx.snap delete mode 100644 ui/src/common/RangeDoubleField.jsx diff --git a/model/metadata/legacy_ids.go b/model/metadata/legacy_ids.go index 91ae44b89..25025ea19 100644 --- a/model/metadata/legacy_ids.go +++ b/model/metadata/legacy_ids.go @@ -51,20 +51,6 @@ func legacyMapAlbumName(md Metadata) string { // Keep the TaggedLikePicard logic for backwards compatibility func legacyReleaseDate(md Metadata) string { - // Start with defaults - date := md.Date(model.TagRecordingDate) - year := date.Year() - originalDate := md.Date(model.TagOriginalDate) - originalYear := originalDate.Year() - releaseDate := md.Date(model.TagReleaseDate) - releaseYear := releaseDate.Year() - - // MusicBrainz Picard writes the Release Date of an album to the Date tag, and leaves the Release Date tag empty - taggedLikePicard := (originalYear != 0) && - (releaseYear == 0) && - (year >= originalYear) - if taggedLikePicard { - return string(date) - } + _, _, releaseDate := md.mapDates() return string(releaseDate) } diff --git a/model/metadata/legacy_ids_test.go b/model/metadata/legacy_ids_test.go new file mode 100644 index 000000000..b6d096763 --- /dev/null +++ b/model/metadata/legacy_ids_test.go @@ -0,0 +1,30 @@ +package metadata + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +var _ = Describe("legacyReleaseDate", func() { + + DescribeTable("legacyReleaseDate", + func(recordingDate, originalDate, releaseDate, expected string) { + md := New("", Info{ + Tags: map[string][]string{ + "DATE": {recordingDate}, + "ORIGINALDATE": {originalDate}, + "RELEASEDATE": {releaseDate}, + }, + }) + + result := legacyReleaseDate(md) + Expect(result).To(Equal(expected)) + }, + Entry("regular mapping", "2020-05-15", "2019-02-10", "2021-01-01", "2021-01-01"), + Entry("legacy mapping", "2020-05-15", "2019-02-10", "", "2020-05-15"), + Entry("legacy mapping, originalYear < year", "2018-05-15", "2019-02-10", "2021-01-01", "2021-01-01"), + Entry("legacy mapping, originalYear empty", "2020-05-15", "", "2021-01-01", "2021-01-01"), + Entry("legacy mapping, releaseYear", "2020-05-15", "2019-02-10", "2021-01-01", "2021-01-01"), + Entry("legacy mapping, same dates", "2020-05-15", "2020-05-15", "", "2020-05-15"), + ) +}) diff --git a/model/metadata/map_mediafile.go b/model/metadata/map_mediafile.go index 47d2578ec..9a96ae922 100644 --- a/model/metadata/map_mediafile.go +++ b/model/metadata/map_mediafile.go @@ -1,6 +1,7 @@ package metadata import ( + "cmp" "encoding/json" "maps" "math" @@ -39,11 +40,9 @@ func (md Metadata) ToMediaFile(libID int, folderID string) model.MediaFile { mf.ExplicitStatus = md.mapExplicitStatusTag() // Dates - origDate := md.Date(model.TagOriginalDate) + date, origDate, relDate := md.mapDates() mf.OriginalYear, mf.OriginalDate = origDate.Year(), string(origDate) - relDate := md.Date(model.TagReleaseDate) mf.ReleaseYear, mf.ReleaseDate = relDate.Year(), string(relDate) - date := md.Date(model.TagRecordingDate) mf.Year, mf.Date = date.Year(), string(date) // MBIDs @@ -164,3 +163,22 @@ func (md Metadata) mapExplicitStatusTag() string { return "" } } + +func (md Metadata) mapDates() (date Date, originalDate Date, releaseDate Date) { + // Start with defaults + date = md.Date(model.TagRecordingDate) + originalDate = md.Date(model.TagOriginalDate) + releaseDate = md.Date(model.TagReleaseDate) + + // For some historic reason, taggers have been writing the Release Date of an album to the Date tag, + // and leave the Release Date tag empty. + legacyMappings := (originalDate != "") && + (releaseDate == "") && + (date >= originalDate) + if legacyMappings { + return originalDate, originalDate, date + } + // when there's no Date, first fall back to Original Date, then to Release Date. + date = cmp.Or(date, originalDate, releaseDate) + return date, originalDate, releaseDate +} diff --git a/model/metadata/map_mediafile_test.go b/model/metadata/map_mediafile_test.go index 7e11b1541..ddda39bc2 100644 --- a/model/metadata/map_mediafile_test.go +++ b/model/metadata/map_mediafile_test.go @@ -35,7 +35,7 @@ var _ = Describe("ToMediaFile", func() { } Describe("Dates", func() { - It("should parse the dates like Picard", func() { + It("should parse properly tagged dates ", func() { mf = toMediaFile(model.RawTags{ "ORIGINALDATE": {"1978-09-10"}, "DATE": {"1977-03-04"}, @@ -49,6 +49,32 @@ var _ = Describe("ToMediaFile", func() { Expect(mf.ReleaseYear).To(Equal(2002)) Expect(mf.ReleaseDate).To(Equal("2002-01-02")) }) + + It("should parse dates with only year", func() { + mf = toMediaFile(model.RawTags{ + "ORIGINALYEAR": {"1978"}, + "DATE": {"1977"}, + "RELEASEDATE": {"2002"}, + }) + + Expect(mf.Year).To(Equal(1977)) + Expect(mf.Date).To(Equal("1977")) + Expect(mf.OriginalYear).To(Equal(1978)) + Expect(mf.OriginalDate).To(Equal("1978")) + Expect(mf.ReleaseYear).To(Equal(2002)) + Expect(mf.ReleaseDate).To(Equal("2002")) + }) + + It("should parse dates tagged the legacy way (no release date)", func() { + mf = toMediaFile(model.RawTags{ + "DATE": {"2014"}, + "ORIGINALDATE": {"1966"}, + }) + + Expect(mf.Year).To(Equal(1966)) + Expect(mf.OriginalYear).To(Equal(1966)) + Expect(mf.ReleaseYear).To(Equal(2014)) + }) }) Describe("Lyrics", func() { diff --git a/model/metadata/metadata_test.go b/model/metadata/metadata_test.go index 5d9c4a3ed..d7473afa7 100644 --- a/model/metadata/metadata_test.go +++ b/model/metadata/metadata_test.go @@ -90,13 +90,14 @@ var _ = Describe("Metadata", func() { md = metadata.New(filePath, props) Expect(md.All()).To(SatisfyAll( - HaveLen(5), Not(HaveKey(unknownTag)), HaveKeyWithValue(model.TagTrackArtist, []string{"Artist Name", "Second Artist"}), HaveKeyWithValue(model.TagAlbum, []string{"Album Name"}), - HaveKeyWithValue(model.TagRecordingDate, []string{"2022-10-02", "2022"}), + HaveKeyWithValue(model.TagRecordingDate, []string{"2022-10-02"}), + HaveKeyWithValue(model.TagReleaseDate, []string{"2022"}), HaveKeyWithValue(model.TagGenre, []string{"Pop", "Rock"}), HaveKeyWithValue(model.TagTrackNumber, []string{"1/10"}), + HaveLen(6), )) }) diff --git a/persistence/album_repository.go b/persistence/album_repository.go index 0f2a46dec..be2af3ee3 100644 --- a/persistence/album_repository.go +++ b/persistence/album_repository.go @@ -97,9 +97,10 @@ func NewAlbumRepository(ctx context.Context, db dbx.Builder) model.AlbumReposito r.tableName = "album" r.registerModel(&model.Album{}, albumFilters()) r.setSortMappings(map[string]string{ - "name": "order_album_name, order_album_artist_name", - "artist": "compilation, order_album_artist_name, order_album_name", - "album_artist": "compilation, order_album_artist_name, order_album_name", + "name": "order_album_name, order_album_artist_name", + "artist": "compilation, order_album_artist_name, order_album_name", + "album_artist": "compilation, order_album_artist_name, order_album_name", + // TODO Rename this to just year (or date) "max_year": "coalesce(nullif(original_date,''), cast(max_year as text)), release_date, name", "random": "random", "recently_added": recentlyAddedSort(), diff --git a/resources/i18n/pt.json b/resources/i18n/pt.json index d856391ff..59e7a775d 100644 --- a/resources/i18n/pt.json +++ b/resources/i18n/pt.json @@ -57,6 +57,7 @@ "genre": "Gênero", "compilation": "Coletânea", "year": "Ano", + "date": "Data de Lançamento", "updatedAt": "Últ. Atualização", "comment": "Comentário", "rating": "Classificação", diff --git a/resources/mappings.yaml b/resources/mappings.yaml index f4de96a74..66056fd57 100644 --- a/resources/mappings.yaml +++ b/resources/mappings.yaml @@ -118,10 +118,10 @@ main: aliases: [ tdor, originaldate, ----:com.apple.itunes:originaldate, wm/originalreleasetime, tory, originalyear, ----:com.apple.itunes:originalyear, wm/originalreleaseyear ] type: date recordingdate: - aliases: [ tdrc, date, icrd, ©day, wm/year, year ] + aliases: [ tdrc, date, recordingdate, icrd, record date ] type: date releasedate: - aliases: [ tdrl, releasedate ] + aliases: [ tdrl, releasedate, ©day, wm/year, year ] type: date catalognumber: aliases: [ txxx:catalognumber, catalognumber, ----:com.apple.itunes:catalognumber, wm/catalogno ] diff --git a/server/subsonic/filter/filters.go b/server/subsonic/filter/filters.go index 1b5416695..f8b42d312 100644 --- a/server/subsonic/filter/filters.go +++ b/server/subsonic/filter/filters.go @@ -62,13 +62,14 @@ func AlbumsByArtistID(artistId string) Options { } func AlbumsByYear(fromYear, toYear int) Options { - sortOption := "max_year, name" + orderOption := "" if fromYear > toYear { fromYear, toYear = toYear, fromYear - sortOption = "max_year desc, name" + orderOption = "desc" } return addDefaultFilters(Options{ - Sort: sortOption, + Sort: "max_year", + Order: orderOption, Filters: Or{ And{ GtOrEq{"min_year": fromYear}, @@ -118,7 +119,7 @@ func SongWithLyrics(artist, title string) Options { func ByGenre(genre string) Options { return addDefaultFilters(Options{ - Sort: "name asc", + Sort: "name", Filters: filterByGenre(genre), }) } diff --git a/server/subsonic/helpers.go b/server/subsonic/helpers.go index 56b65f894..4faec158f 100644 --- a/server/subsonic/helpers.go +++ b/server/subsonic/helpers.go @@ -296,7 +296,7 @@ func childFromAlbum(ctx context.Context, al model.Album) responses.Child { child.Name = al.Name child.Album = al.Name child.Artist = al.AlbumArtist - child.Year = int32(al.MaxYear) + child.Year = int32(cmp.Or(al.MaxOriginalYear, al.MaxYear)) child.Genre = al.Genre child.CoverArt = al.CoverArtID().String() child.Created = &al.CreatedAt @@ -380,7 +380,7 @@ func buildAlbumID3(ctx context.Context, album model.Album) responses.AlbumID3 { dir.SongCount = int32(album.SongCount) dir.Duration = int32(album.Duration) dir.PlayCount = album.PlayCount - dir.Year = int32(album.MaxYear) + dir.Year = int32(cmp.Or(album.MaxOriginalYear, album.MaxYear)) dir.Genre = album.Genre if !album.CreatedAt.IsZero() { dir.Created = &album.CreatedAt diff --git a/ui/src/album/AlbumDatesField.jsx b/ui/src/album/AlbumDatesField.jsx new file mode 100644 index 000000000..e4cdeedce --- /dev/null +++ b/ui/src/album/AlbumDatesField.jsx @@ -0,0 +1,19 @@ +import { useRecordContext } from 'react-admin' +import { formatRange } from '../common/index.js' + +const originalYearSymbol = '♫' +const releaseYearSymbol = '○' + +export const AlbumDatesField = ({ className, ...rest }) => { + const record = useRecordContext(rest) + const releaseDate = record.releaseDate + const releaseYear = releaseDate?.toString().substring(0, 4) + const yearRange = + formatRange(record, 'originalYear') || record['maxYear']?.toString() + let label = yearRange + + if (releaseYear !== undefined && yearRange !== releaseYear) { + label = `${originalYearSymbol} ${yearRange} · ${releaseYearSymbol} ${releaseYear}` + } + return {label} +} diff --git a/ui/src/album/AlbumDetails.jsx b/ui/src/album/AlbumDetails.jsx index 690ae6604..f796f3b9d 100644 --- a/ui/src/album/AlbumDetails.jsx +++ b/ui/src/album/AlbumDetails.jsx @@ -1,4 +1,4 @@ -import { useState, useEffect, useCallback } from 'react' +import { useCallback, useEffect, useState } from 'react' import { Card, CardContent, @@ -10,25 +10,25 @@ import { withWidth, } from '@material-ui/core' import { - useRecordContext, - useTranslate, ArrayField, - SingleFieldList, ChipField, Link, + SingleFieldList, + useRecordContext, + useTranslate, } from 'react-admin' import Lightbox from 'react-image-lightbox' import 'react-image-lightbox/style.css' import subsonic from '../subsonic' import { ArtistLinkField, + CollapsibleComment, DurationField, formatRange, - SizeField, LoveButton, RatingField, + SizeField, useAlbumsPerPage, - CollapsibleComment, } from '../common' import config from '../config' import { formatFullDate, intersperse } from '../utils' @@ -140,69 +140,55 @@ const GenreList = () => { ) } -const Details = (props) => { +export const Details = (props) => { const isXsmall = useMediaQuery((theme) => theme.breakpoints.down('xs')) const translate = useTranslate() const record = useRecordContext(props) + + // Create an array of detail elements let details = [] const addDetail = (obj) => { const id = details.length details.push({obj}) } - const originalYearRange = formatRange(record, 'originalYear') - const originalDate = record.originalDate - ? formatFullDate(record.originalDate) - : originalYearRange + // Calculate date related fields const yearRange = formatRange(record, 'year') const date = record.date ? formatFullDate(record.date) : yearRange - const releaseDate = record.releaseDate - ? formatFullDate(record.releaseDate) - : date - const showReleaseDate = date !== releaseDate && releaseDate.length > 3 - const showOriginalDate = - date !== originalDate && - originalDate !== releaseDate && - originalDate.length > 3 + const originalDate = record.originalDate + ? formatFullDate(record.originalDate) + : formatRange(record, 'originalYear') + const releaseDate = record?.releaseDate && formatFullDate(record.releaseDate) - showOriginalDate && - !isXsmall && + const dateToUse = originalDate || date + const isOriginalDate = originalDate && dateToUse !== date + const showDate = dateToUse && dateToUse !== releaseDate + + // Get label for the main date display + const getDateLabel = () => { + if (isXsmall) return '♫' + if (isOriginalDate) return translate('resources.album.fields.originalDate') + return null + } + + // Get label for release date display + const getReleaseDateLabel = () => { + if (!isXsmall) return translate('resources.album.fields.releaseDate') + if (showDate) return '○' + return null + } + + // Display dates with appropriate labels + if (showDate) { + addDetail(<>{[getDateLabel(), dateToUse].filter(Boolean).join(' ')}) + } + + if (releaseDate) { addDetail( - <> - {[translate('resources.album.fields.originalDate'), originalDate].join( - ' ', - )} - , + <>{[getReleaseDateLabel(), releaseDate].filter(Boolean).join(' ')}, ) - - yearRange && addDetail(<>{['♫', !isXsmall ? date : yearRange].join(' ')}) - - showReleaseDate && - addDetail( - <> - {(!isXsmall - ? [translate('resources.album.fields.releaseDate'), releaseDate] - : ['○', record.releaseDate.substring(0, 4)] - ).join(' ')} - , - ) - - const showReleases = record.releases > 1 - showReleases && - addDetail( - <> - {!isXsmall - ? [ - record.releases, - translate('resources.album.fields.releases', { - smart_count: record.releases, - }), - ].join(' ') - : ['(', record.releases, ')))'].join(' ')} - , - ) - + } addDetail( <> {record.songCount + @@ -215,6 +201,7 @@ const Details = (props) => { !isXsmall && addDetail() !isXsmall && addDetail() + // Return the details rendered with separators return <>{intersperse(details, ' · ')} } diff --git a/ui/src/album/AlbumDetails.test.jsx b/ui/src/album/AlbumDetails.test.jsx new file mode 100644 index 000000000..e03022677 --- /dev/null +++ b/ui/src/album/AlbumDetails.test.jsx @@ -0,0 +1,327 @@ +// ui/src/album/__tests__/AlbumDetails.test.jsx +import { describe, test, expect, beforeEach, afterEach } from 'vitest' +import { render } from '@testing-library/react' +import { RecordContextProvider } from 'react-admin' +import { useMediaQuery } from '@material-ui/core' +import { Details } from './AlbumDetails' + +// Mock useMediaQuery +vi.mock('@material-ui/core', async () => { + const actual = await import('@material-ui/core') + return { + ...actual, + useMediaQuery: vi.fn(), + } +}) + +describe('Details component', () => { + describe('Desktop view', () => { + beforeEach(() => { + // Set desktop view (isXsmall = false) + vi.mocked(useMediaQuery).mockReturnValue(false) + }) + + test('renders correctly with just year range', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + year: 2020, + } + + const { container } = render( + +

+ , + ) + + expect(container).toMatchSnapshot() + }) + + test('renders correctly with date', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + date: '2020-05-01', + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + + test('renders correctly with originalDate', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + originalDate: '2018-03-15', + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + + test('renders correctly with date and originalDate', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + date: '2020-05-01', + originalDate: '2018-03-15', + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + + test('renders correctly with releaseDate', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + releaseDate: '2020-06-15', + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + + test('renders correctly with all date fields', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + date: '2020-05-01', + originalDate: '2018-03-15', + releaseDate: '2020-06-15', + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + }) + + describe('Mobile view', () => { + beforeEach(() => { + // Set mobile view (isXsmall = true) + vi.mocked(useMediaQuery).mockReturnValue(true) + }) + + afterEach(() => { + vi.clearAllMocks() + }) + + test('renders correctly with just year range', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + year: 2020, + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + + test('renders correctly with date', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + date: '2020-05-01', + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + + test('renders correctly with originalDate', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + originalDate: '2018-03-15', + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + + test('renders correctly with date and originalDate', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + date: '2020-05-01', + originalDate: '2018-03-15', + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + + test('renders correctly with releaseDate', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + releaseDate: '2020-06-15', + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + + test('renders correctly with all date fields', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + date: '2020-05-01', + originalDate: '2018-03-15', + releaseDate: '2020-06-15', + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + + test('renders correctly with no date fields', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + + test('renders correctly with year range (start and end years)', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + year: 2018, + yearEnd: 2020, + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + + test('renders correctly with originalYear range', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + originalYear: 2015, + originalYearEnd: 2016, + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + }) +}) diff --git a/ui/src/album/AlbumGridView.jsx b/ui/src/album/AlbumGridView.jsx index efbfe6173..475519fca 100644 --- a/ui/src/album/AlbumGridView.jsx +++ b/ui/src/album/AlbumGridView.jsx @@ -13,14 +13,10 @@ import { linkToRecord, useListContext, Loading } from 'react-admin' import { withContentRect } from 'react-measure' import { useDrag } from 'react-dnd' import subsonic from '../subsonic' -import { - AlbumContextMenu, - PlayButton, - ArtistLinkField, - RangeDoubleField, -} from '../common' +import { AlbumContextMenu, PlayButton, ArtistLinkField } from '../common' import { DraggableTypes } from '../consts' import clsx from 'clsx' +import { AlbumDatesField } from './AlbumDatesField.jsx' const useStyles = makeStyles( (theme) => ({ @@ -187,16 +183,7 @@ const AlbumGridTile = ({ showArtist, record, basePath, ...props }) => { {showArtist ? ( ) : ( - + )} ) diff --git a/ui/src/album/AlbumInfo.jsx b/ui/src/album/AlbumInfo.jsx index d6d123895..453dbb167 100644 --- a/ui/src/album/AlbumInfo.jsx +++ b/ui/src/album/AlbumInfo.jsx @@ -20,6 +20,7 @@ import { ArtistLinkField, MultiLineTextField, ParticipantsInfo, + RangeField, } from '../common' const useStyles = makeStyles({ @@ -47,6 +48,20 @@ const AlbumInfo = (props) => { ), + date: + record?.maxYear && record.maxYear === record.minYear ? ( + + ) : ( + + ), + originalDate: + record?.maxOriginalYear && + record.maxOriginalYear === record.minOriginalYear ? ( + + ) : ( + + ), + releaseDate: , recordLabel: ( Desktop view > renders correctly with all date fields 1`] = ` +
+ + resources.album.fields.originalDate Mar 15, 2018 + + · + + resources.album.fields.releaseDate Jun 15, 2020 + + · + + 12 resources.song.name + + · + + + 01:00:00 + + + · + + + 100 KB + + +
+`; + +exports[`Details component > Desktop view > renders correctly with date 1`] = ` +
+ + May 1, 2020 + + · + + 12 resources.song.name + + · + + + 01:00:00 + + + · + + + 100 KB + + +
+`; + +exports[`Details component > Desktop view > renders correctly with date and originalDate 1`] = ` +
+ + resources.album.fields.originalDate Mar 15, 2018 + + · + + 12 resources.song.name + + · + + + 01:00:00 + + + · + + + 100 KB + + +
+`; + +exports[`Details component > Desktop view > renders correctly with just year range 1`] = ` +
+ + 12 resources.song.name + + · + + + 01:00:00 + + + · + + + 100 KB + + +
+`; + +exports[`Details component > Desktop view > renders correctly with originalDate 1`] = ` +
+ + resources.album.fields.originalDate Mar 15, 2018 + + · + + 12 resources.song.name + + · + + + 01:00:00 + + + · + + + 100 KB + + +
+`; + +exports[`Details component > Desktop view > renders correctly with releaseDate 1`] = ` +
+ + resources.album.fields.releaseDate Jun 15, 2020 + + · + + 12 resources.song.name + + · + + + 01:00:00 + + + · + + + 100 KB + + +
+`; + +exports[`Details component > Mobile view > renders correctly with all date fields 1`] = ` +
+ + ♫ Mar 15, 2018 + + · + + ○ Jun 15, 2020 + + · + + 12 resources.song.name + +
+`; + +exports[`Details component > Mobile view > renders correctly with date 1`] = ` +
+ + ♫ May 1, 2020 + + · + + 12 resources.song.name + +
+`; + +exports[`Details component > Mobile view > renders correctly with date and originalDate 1`] = ` +
+ + ♫ Mar 15, 2018 + + · + + 12 resources.song.name + +
+`; + +exports[`Details component > Mobile view > renders correctly with just year range 1`] = ` +
+ + 12 resources.song.name + +
+`; + +exports[`Details component > Mobile view > renders correctly with no date fields 1`] = ` +
+ + 12 resources.song.name + +
+`; + +exports[`Details component > Mobile view > renders correctly with originalDate 1`] = ` +
+ + ♫ Mar 15, 2018 + + · + + 12 resources.song.name + +
+`; + +exports[`Details component > Mobile view > renders correctly with originalYear range 1`] = ` +
+ + 12 resources.song.name + +
+`; + +exports[`Details component > Mobile view > renders correctly with releaseDate 1`] = ` +
+ + Jun 15, 2020 + + · + + 12 resources.song.name + +
+`; + +exports[`Details component > Mobile view > renders correctly with year range (start and end years) 1`] = ` +
+ + 12 resources.song.name + +
+`; + +exports[`Details component > renders correctly in mobile view 1`] = ` +
+ + ♫ Mar 15, 2018 + + · + + ○ Jun 15, 2020 + + · + + 12 resources.song.name + +
+`; + +exports[`Details component > renders correctly with all date fields 1`] = ` +
+ + resources.album.fields.originalDate Mar 15, 2018 + + · + + resources.album.fields.releaseDate Jun 15, 2020 + + · + + 12 resources.song.name + + · + + + 01:00:00 + + + · + + + 100 KB + + +
+`; + +exports[`Details component > renders correctly with date 1`] = ` +
+ + May 1, 2020 + + · + + 12 resources.song.name + + · + + + 01:00:00 + + + · + + + 100 KB + + +
+`; + +exports[`Details component > renders correctly with date and originalDate 1`] = ` +
+ + resources.album.fields.originalDate Mar 15, 2018 + + · + + 12 resources.song.name + + · + + + 01:00:00 + + + · + + + 100 KB + + +
+`; + +exports[`Details component > renders correctly with just year range 1`] = ` +
+ + 12 resources.song.name + + · + + + 01:00:00 + + + · + + + 100 KB + + +
+`; + +exports[`Details component > renders correctly with originalDate 1`] = ` +
+ + resources.album.fields.originalDate Mar 15, 2018 + + · + + 12 resources.song.name + + · + + + 01:00:00 + + + · + + + 100 KB + + +
+`; + +exports[`Details component > renders correctly with releaseDate 1`] = ` +
+ + resources.album.fields.releaseDate Jun 15, 2020 + + · + + 12 resources.song.name + + · + + + 01:00:00 + + + · + + + 100 KB + + +
+`; diff --git a/ui/src/artist/ArtistShow.jsx b/ui/src/artist/ArtistShow.jsx index 2f3ff4299..b20fffeef 100644 --- a/ui/src/artist/ArtistShow.jsx +++ b/ui/src/artist/ArtistShow.jsx @@ -50,7 +50,7 @@ const ArtistDetails = (props) => { ) } -const AlbumShowLayout = (props) => { +const ArtistShowLayout = (props) => { const showContext = useShowContext(props) const record = useRecordContext() const { width } = props @@ -98,7 +98,7 @@ const ArtistShow = withWidth()((props) => { const controllerProps = useShowController(props) return ( - + ) }) diff --git a/ui/src/common/RangeDoubleField.jsx b/ui/src/common/RangeDoubleField.jsx deleted file mode 100644 index d388abeb7..000000000 --- a/ui/src/common/RangeDoubleField.jsx +++ /dev/null @@ -1,50 +0,0 @@ -import React from 'react' -import PropTypes from 'prop-types' -import { useRecordContext } from 'react-admin' -import { formatRange } from '../common' - -export const RangeDoubleField = ({ - className, - source, - symbol1, - symbol2, - separator, - ...rest -}) => { - const record = useRecordContext(rest) - const yearRange = formatRange(record, source).toString() - const releases = [record.releases] - const releaseDate = [record.releaseDate] - const releaseYear = releaseDate.toString().substring(0, 4) - let subtitle = yearRange - - if (releases > 1) { - subtitle = [ - [yearRange && symbol1, yearRange].join(' '), - ['(', releases, ')))'].join(' '), - ].join(separator) - } - - if ( - yearRange !== releaseYear && - yearRange.length > 0 && - releaseYear.length > 0 - ) { - subtitle = [ - [yearRange && symbol1, yearRange].join(' '), - [symbol2, releaseYear].join(' '), - ].join(separator) - } - - return {subtitle} -} - -RangeDoubleField.propTypes = { - label: PropTypes.string, - record: PropTypes.object, - source: PropTypes.string.isRequired, -} - -RangeDoubleField.defaultProps = { - addLabel: true, -} diff --git a/ui/src/common/index.js b/ui/src/common/index.js index 91d153e29..1a43047c1 100644 --- a/ui/src/common/index.js +++ b/ui/src/common/index.js @@ -13,7 +13,6 @@ export * from './Pagination' export * from './PlayButton' export * from './QuickFilter' export * from './RangeField' -export * from './RangeDoubleField' export * from './ShuffleAllButton' export * from './SimpleList' export * from './SizeField' diff --git a/ui/src/i18n/en.json b/ui/src/i18n/en.json index 678e42cd4..4183d0ccd 100644 --- a/ui/src/i18n/en.json +++ b/ui/src/i18n/en.json @@ -58,6 +58,7 @@ "genre": "Genre", "compilation": "Compilation", "year": "Year", + "date": "Recording Date", "originalDate": "Original", "releaseDate": "Released", "releases": "Release |||| Releases",