mirror of
https://github.com/navidrome/navidrome.git
synced 2025-05-11 23:56:37 +03:00
Merge branch 'master' into dlna-spike
This commit is contained in:
commit
6dcabcc35d
@ -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 {
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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) => {
|
||||
|
@ -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))
|
||||
|
@ -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)),
|
||||
})}
|
||||
:
|
||||
</TableCell>
|
||||
|
@ -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) => {
|
||||
<AutocompleteInput
|
||||
emptyText="-- None --"
|
||||
optionText={(record) =>
|
||||
record?.tagValue
|
||||
? inflection.humanize(record?.tagValue)
|
||||
: '-- None --'
|
||||
record?.tagValue ? humanize(record?.tagValue) : '-- None --'
|
||||
}
|
||||
/>
|
||||
</ReferenceInput>
|
||||
|
@ -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
|
||||
|
@ -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)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ export const ShuffleAllButton = ({ filters }) => {
|
||||
const dataProvider = useDataProvider()
|
||||
const dispatch = useDispatch()
|
||||
const notify = useNotify()
|
||||
filters = { ...filters, missing: false }
|
||||
|
||||
const handleOnClick = () => {
|
||||
dataProvider
|
||||
|
@ -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) => {
|
||||
<TableRow key={`${record.id}-${key}`}>
|
||||
<TableCell scope="row" className={classes.tableCell}>
|
||||
{translate(`resources.song.fields.${key}`, {
|
||||
_: inflection.humanize(inflection.underscore(key)),
|
||||
_: humanize(underscore(key)),
|
||||
})}
|
||||
:
|
||||
</TableCell>
|
||||
|
@ -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 }) => {
|
||||
<TableRow key={key}>
|
||||
<TableCell align="right" component="th" scope="row">
|
||||
{translate(`about.links.${key}`, {
|
||||
_: inflection.humanize(inflection.underscore(key)),
|
||||
_: humanize(underscore(key)),
|
||||
})}
|
||||
:
|
||||
</TableCell>
|
||||
|
@ -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 (
|
||||
<TableRow key={key}>
|
||||
|
@ -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 }) => {
|
||||
|
@ -16,7 +16,6 @@ export default defineConfig({
|
||||
filename: 'sw.js',
|
||||
devOptions: {
|
||||
enabled: true,
|
||||
type: 'module',
|
||||
},
|
||||
}),
|
||||
],
|
||||
|
Loading…
x
Reference in New Issue
Block a user