Add config option to enable/disable Transcoding configuration

This commit is contained in:
Deluan 2020-04-27 21:23:15 -04:00 committed by Deluan Quintão
parent eb7d2dcaa1
commit c816ca4525
12 changed files with 134 additions and 49 deletions

View File

@ -27,9 +27,10 @@ type nd struct {
IgnoredArticles string `default:"The El La Los Las Le Les Os As O A"` IgnoredArticles string `default:"The El La Los Las Le Les Os As O A"`
IndexGroups string `default:"A B C D E F G H I J K L M N O P Q R S T U V W X-Z(XYZ) [Unknown]([)"` IndexGroups string `default:"A B C D E F G H I J K L M N O P Q R S T U V W X-Z(XYZ) [Unknown]([)"`
TranscodingCacheSize string `default:"100MB"` // in MB EnableTranscodingConfig bool `default:"false"`
ImageCacheSize string `default:"100MB"` // in MB TranscodingCacheSize string `default:"100MB"` // in MB
ProbeCommand string `default:"ffmpeg %s -f ffmetadata"` ImageCacheSize string `default:"100MB"` // in MB
ProbeCommand string `default:"ffmpeg %s -f ffmetadata"`
// DevFlags. These are used to enable/disable debugging and incomplete features // DevFlags. These are used to enable/disable debugging and incomplete features
DevLogSourceLine bool `default:"false"` DevLogSourceLine bool `default:"false"`

View File

@ -7,6 +7,7 @@ import (
"strings" "strings"
"github.com/deluan/navidrome/assets" "github.com/deluan/navidrome/assets"
"github.com/deluan/navidrome/conf"
"github.com/deluan/navidrome/engine/auth" "github.com/deluan/navidrome/engine/auth"
"github.com/deluan/navidrome/model" "github.com/deluan/navidrome/model"
"github.com/deluan/rest" "github.com/deluan/rest"
@ -41,12 +42,12 @@ func (app *Router) routes(path string) http.Handler {
r.Use(mapAuthHeader()) r.Use(mapAuthHeader())
r.Use(jwtauth.Verifier(auth.TokenAuth)) r.Use(jwtauth.Verifier(auth.TokenAuth))
r.Use(authenticator(app.ds)) r.Use(authenticator(app.ds))
app.R(r, "/user", model.User{}) app.R(r, "/user", model.User{}, true)
app.R(r, "/song", model.MediaFile{}) app.R(r, "/song", model.MediaFile{}, true)
app.R(r, "/album", model.Album{}) app.R(r, "/album", model.Album{}, true)
app.R(r, "/artist", model.Artist{}) app.R(r, "/artist", model.Artist{}, true)
app.R(r, "/transcoding", model.Transcoding{}) app.R(r, "/player", model.Player{}, true)
app.R(r, "/player", model.Player{}) app.R(r, "/transcoding", model.Transcoding{}, conf.Server.EnableTranscodingConfig)
// Keepalive endpoint to be used to keep the session valid (ex: while playing songs) // Keepalive endpoint to be used to keep the session valid (ex: while playing songs)
r.Get("/keepalive/*", func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte(`{"response":"ok"}`)) }) r.Get("/keepalive/*", func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte(`{"response":"ok"}`)) })
@ -59,18 +60,22 @@ func (app *Router) routes(path string) http.Handler {
return r return r
} }
func (app *Router) R(r chi.Router, pathPrefix string, model interface{}) { func (app *Router) R(r chi.Router, pathPrefix string, model interface{}, persistable bool) {
constructor := func(ctx context.Context) rest.Repository { constructor := func(ctx context.Context) rest.Repository {
return app.ds.Resource(ctx, model) return app.ds.Resource(ctx, model)
} }
r.Route(pathPrefix, func(r chi.Router) { r.Route(pathPrefix, func(r chi.Router) {
r.Get("/", rest.GetAll(constructor)) r.Get("/", rest.GetAll(constructor))
r.Post("/", rest.Post(constructor)) if persistable {
r.Post("/", rest.Post(constructor))
}
r.Route("/{id:[0-9a-f\\-]+}", func(r chi.Router) { r.Route("/{id:[0-9a-f\\-]+}", func(r chi.Router) {
r.Use(UrlParams) r.Use(UrlParams)
r.Get("/", rest.Get(constructor)) r.Get("/", rest.Get(constructor))
r.Put("/", rest.Put(constructor)) if persistable {
r.Delete("/", rest.Delete(constructor)) r.Put("/", rest.Put(constructor))
r.Delete("/", rest.Delete(constructor))
}
}) })
}) })
} }

View File

@ -22,10 +22,11 @@ func ServeIndex(ds model.DataStore, fs http.FileSystem) http.HandlerFunc {
t := getIndexTemplate(r, fs) t := getIndexTemplate(r, fs)
appConfig := map[string]interface{}{ appConfig := map[string]interface{}{
"version": consts.Version(), "version": consts.Version(),
"firstTime": firstTime, "firstTime": firstTime,
"baseURL": strings.TrimSuffix(conf.Server.BaseURL, "/"), "baseURL": strings.TrimSuffix(conf.Server.BaseURL, "/"),
"loginBackgroundURL": conf.Server.UILoginBackgroundURL, "loginBackgroundURL": conf.Server.UILoginBackgroundURL,
"enableTranscodingConfig": conf.Server.EnableTranscodingConfig,
} }
j, _ := json.Marshal(appConfig) j, _ := json.Marshal(appConfig)

10
ui/src/common/DocLink.js Normal file
View File

@ -0,0 +1,10 @@
import React from 'react'
import { docsUrl } from '../utils/docsUrl'
const DocLink = ({ path, children }) => (
<a href={docsUrl(path)} target={'_blank'} rel="noopener noreferrer">
{children}
</a>
)
export default DocLink

View File

@ -7,6 +7,7 @@ import SimpleList from './SimpleList'
import RangeField, { formatRange } from './RangeField' import RangeField, { formatRange } from './RangeField'
import SongDetails from './SongDetails' import SongDetails from './SongDetails'
import SizeField from './SizeField' import SizeField from './SizeField'
import DocLink from './DocLink'
export { export {
Title, Title,
@ -18,5 +19,6 @@ export {
SimpleList, SimpleList,
RangeField, RangeField,
SongDetails, SongDetails,
DocLink,
formatRange, formatRange,
} }

View File

@ -1,8 +1,12 @@
// These defaults are only used in development mode. When bundled in the app,
// the __APP_CONFIG__ object is dynamically filled by the ServeIndex function,
// in the /server/app/serve_index.go
const defaultConfig = { const defaultConfig = {
version: 'dev', version: 'dev',
firstTime: false, firstTime: false,
baseURL: '', baseURL: '',
loginBackgroundURL: 'https://source.unsplash.com/random/1600x900?music', loginBackgroundURL: 'https://source.unsplash.com/random/1600x900?music',
enableTranscodingConfig: true,
} }
let config let config

View File

@ -14,6 +14,7 @@ import HelpOutlineIcon from '@material-ui/icons/HelpOutline'
import { changeTheme } from './actions' import { changeTheme } from './actions'
import themes from '../themes' import themes from '../themes'
import i18n from '../i18n' import i18n from '../i18n'
import { docsUrl } from '../utils/docsUrl'
const useStyles = makeStyles({ const useStyles = makeStyles({
root: { marginTop: '1em' }, root: { marginTop: '1em' },
@ -53,9 +54,7 @@ const SelectLanguage = (props) => {
choices={langChoices} choices={langChoices}
onChange={(event) => { onChange={(event) => {
if (event.target.value === helpKey) { if (event.target.value === helpKey) {
openInNewTab( openInNewTab(docsUrl('/docs/developers/translations/'))
'https://www.navidrome.org/docs/developers/translations/'
)
return return
} }
setLocale(event.target.value) setLocale(event.target.value)
@ -85,9 +84,7 @@ const SelectTheme = (props) => {
choices={themeChoices} choices={themeChoices}
onChange={(event) => { onChange={(event) => {
if (event.target.value === helpKey) { if (event.target.value === helpKey) {
openInNewTab( openInNewTab(docsUrl('/docs/developers/creating-themes/'))
'https://www.navidrome.org/docs/developers/creating-themes/'
)
return return
} }
dispatch(changeTheme(event.target.value)) dispatch(changeTheme(event.target.value))

View File

@ -7,6 +7,7 @@ import {
SimpleForm, SimpleForm,
useTranslate, useTranslate,
} from 'react-admin' } from 'react-admin'
import { Card, CardContent, Typography, Box } from '@material-ui/core'
import { Title } from '../common' import { Title } from '../common'
const TranscodingTitle = ({ record }) => { const TranscodingTitle = ({ record }) => {
@ -18,29 +19,48 @@ const TranscodingTitle = ({ record }) => {
} }
const TranscodingEdit = (props) => ( const TranscodingEdit = (props) => (
<Edit title={<TranscodingTitle />} {...props}> <>
<SimpleForm> <Card>
<TextInput source="name" validate={[required()]} /> <CardContent>
<TextInput source="targetFormat" validate={[required()]} /> <Typography>
<SelectInput <Box fontWeight="fontWeightBold" component={'span'}>
source="defaultBitRate" NOTE:
choices={[ </Box>{' '}
{ id: 32, name: '32' }, Navidrome is currently running with the{' '}
{ id: 48, name: '48' }, <Box fontFamily="Monospace" component={'span'}>
{ id: 64, name: '64' }, ND_ENABLETRANSCODINGCONFIG=true
{ id: 80, name: '80' }, </Box>
{ id: 96, name: '96' }, , making it possible to run system commands from the transcoding
{ id: 112, name: '112' }, settings using the web interface. We recommend to disable it for
{ id: 128, name: '128' }, security reasons and only enable it when configuring Transcoding
{ id: 160, name: '160' }, options.
{ id: 192, name: '192' }, </Typography>
{ id: 256, name: '256' }, </CardContent>
{ id: 320, name: '320' }, </Card>
]} <Edit title={<TranscodingTitle />} {...props}>
/> <SimpleForm>
<TextInput source="command" fullWidth validate={[required()]} /> <TextInput source="name" validate={[required()]} />
</SimpleForm> <TextInput source="targetFormat" validate={[required()]} />
</Edit> <SelectInput
source="defaultBitRate"
choices={[
{ id: 32, name: '32' },
{ id: 48, name: '48' },
{ id: 64, name: '64' },
{ id: 80, name: '80' },
{ id: 96, name: '96' },
{ id: 112, name: '112' },
{ id: 128, name: '128' },
{ id: 160, name: '160' },
{ id: 192, name: '192' },
{ id: 256, name: '256' },
{ id: 320, name: '320' },
]}
/>
<TextInput source="command" fullWidth validate={[required()]} />
</SimpleForm>
</Edit>
</>
) )
export default TranscodingEdit export default TranscodingEdit

View File

@ -2,6 +2,7 @@ import React from 'react'
import { Datagrid, List, TextField } from 'react-admin' import { Datagrid, List, TextField } from 'react-admin'
import { useMediaQuery } from '@material-ui/core' import { useMediaQuery } from '@material-ui/core'
import { SimpleList, Title } from '../common' import { SimpleList, Title } from '../common'
import config from '../config'
const TranscodingList = (props) => { const TranscodingList = (props) => {
const isXsmall = useMediaQuery((theme) => theme.breakpoints.down('xs')) const isXsmall = useMediaQuery((theme) => theme.breakpoints.down('xs'))
@ -23,7 +24,7 @@ const TranscodingList = (props) => {
tertiaryText={(r) => r.defaultBitRate} tertiaryText={(r) => r.defaultBitRate}
/> />
) : ( ) : (
<Datagrid rowClick="edit"> <Datagrid rowClick={config.enableTranscodingConfig ? 'edit' : 'show'}>
<TextField source="name" /> <TextField source="name" />
<TextField source="targetFormat" /> <TextField source="targetFormat" />
<TextField source="defaultBitRate" /> <TextField source="defaultBitRate" />

View File

@ -0,0 +1,40 @@
import React from 'react'
import { TextField, Show, SimpleShowLayout } from 'react-admin'
import { Card, CardContent, Typography, Box } from '@material-ui/core'
import { Title } from '../common'
const TranscodingTitle = ({ record }) => {
return <Title subTitle={`Transcoding ${record ? record.name : ''}`} />
}
const TranscodingShow = (props) => (
<>
<Card>
<CardContent>
<Typography>
<Box fontWeight="fontWeightBold" component={'span'}>
NOTE:
</Box>{' '}
Changing the transcoding configuration through the web interface is
disabled for security reasons. If you would like to change (edit or
add) transcoding options, restart the server with the{' '}
<Box fontFamily="Monospace" component={'span'}>
ND_ENABLETRANSCODINGCONFIG=true
</Box>{' '}
configuration option.
</Typography>
</CardContent>
</Card>
<Show title={<TranscodingTitle />} {...props}>
<SimpleShowLayout>
<TextField source="name" />
<TextField source="targetFormat" />
<TextField source="defaultBitRate" />
<TextField source="command" />
</SimpleShowLayout>
</Show>
</>
)
export default TranscodingShow

View File

@ -2,10 +2,13 @@ import TransformIcon from '@material-ui/icons/Transform'
import TranscodingList from './TranscodingList' import TranscodingList from './TranscodingList'
import TranscodingEdit from './TranscodingEdit' import TranscodingEdit from './TranscodingEdit'
import TranscodingCreate from './TranscodingCreate' import TranscodingCreate from './TranscodingCreate'
import TranscodingShow from './TranscodingShow'
import config from '../config'
export default { export default {
list: TranscodingList, list: TranscodingList,
edit: TranscodingEdit, edit: config.enableTranscodingConfig && TranscodingEdit,
create: TranscodingCreate, create: config.enableTranscodingConfig && TranscodingCreate,
show: !config.enableTranscodingConfig && TranscodingShow,
icon: TransformIcon, icon: TransformIcon,
} }

1
ui/src/utils/docsUrl.js Normal file
View File

@ -0,0 +1 @@
export const docsUrl = (path) => `https://www.navidrome.org${path}`