Merge branch 'master' into dlna-spike

This commit is contained in:
Rob Emery 2025-03-12 20:15:58 +00:00
commit 6dcabcc35d
14 changed files with 73 additions and 61 deletions

View File

@ -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 {

View File

@ -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"
}
}
}
}

View File

@ -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) => {

View File

@ -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))

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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)),
})
}
}

View File

@ -10,6 +10,7 @@ export const ShuffleAllButton = ({ filters }) => {
const dataProvider = useDataProvider()
const dispatch = useDispatch()
const notify = useNotify()
filters = { ...filters, missing: false }
const handleOnClick = () => {
dataProvider

View File

@ -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>

View File

@ -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>

View File

@ -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}>

View File

@ -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 }) => {

View File

@ -16,7 +16,6 @@ export default defineConfig({
filename: 'sw.js',
devOptions: {
enabled: true,
type: 'module',
},
}),
],