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,6 +27,7 @@ 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]([)"`
EnableTranscodingConfig bool `default:"false"`
TranscodingCacheSize string `default:"100MB"` // in MB TranscodingCacheSize string `default:"100MB"` // in MB
ImageCacheSize string `default:"100MB"` // in MB ImageCacheSize string `default:"100MB"` // in MB
ProbeCommand string `default:"ffmpeg %s -f ffmetadata"` ProbeCommand string `default:"ffmpeg %s -f ffmetadata"`

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))
if persistable {
r.Post("/", rest.Post(constructor)) 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))
if persistable {
r.Put("/", rest.Put(constructor)) r.Put("/", rest.Put(constructor))
r.Delete("/", rest.Delete(constructor)) r.Delete("/", rest.Delete(constructor))
}
}) })
}) })
} }

View File

@ -26,6 +26,7 @@ func ServeIndex(ds model.DataStore, fs http.FileSystem) http.HandlerFunc {
"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,6 +19,24 @@ const TranscodingTitle = ({ record }) => {
} }
const TranscodingEdit = (props) => ( const TranscodingEdit = (props) => (
<>
<Card>
<CardContent>
<Typography>
<Box fontWeight="fontWeightBold" component={'span'}>
NOTE:
</Box>{' '}
Navidrome is currently running with the{' '}
<Box fontFamily="Monospace" component={'span'}>
ND_ENABLETRANSCODINGCONFIG=true
</Box>
, making it possible to run system commands from the transcoding
settings using the web interface. We recommend to disable it for
security reasons and only enable it when configuring Transcoding
options.
</Typography>
</CardContent>
</Card>
<Edit title={<TranscodingTitle />} {...props}> <Edit title={<TranscodingTitle />} {...props}>
<SimpleForm> <SimpleForm>
<TextInput source="name" validate={[required()]} /> <TextInput source="name" validate={[required()]} />
@ -41,6 +60,7 @@ const TranscodingEdit = (props) => (
<TextInput source="command" fullWidth validate={[required()]} /> <TextInput source="command" fullWidth validate={[required()]} />
</SimpleForm> </SimpleForm>
</Edit> </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}`