mirror of
https://github.com/navidrome/navidrome.git
synced 2025-05-12 16:16:37 +03:00
Merge branch 'master' into msi-insights-detection
This commit is contained in:
commit
d342a9a225
@ -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"]
|
||||
|
@ -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"
|
||||
)
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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]
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -201,7 +201,7 @@ func loadTagMappings() {
|
||||
aliases = oldValue.Aliases
|
||||
}
|
||||
split := cfg.Split
|
||||
if len(split) == 0 {
|
||||
if split == nil {
|
||||
split = oldValue.Split
|
||||
}
|
||||
c := TagConf{
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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{
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user