mirror of
https://github.com/navidrome/navidrome.git
synced 2026-11-09 03:38:48 +01:00
fix(transcoding): honor player forced format on the WebUI transcode flow (#5613)
* feat(stream): add ClientInfo.ForceFormat for browser-aware forced format Restricts the client to a forced transcoding format and suppresses direct play, but only when the client declares it supports that format. Part of #5583. * fix(transcoding): honor player forced format on getTranscodeDecision When the WebUI player has a forced transcoding format configured and the browser declares it can play that format, transcode to it (suppressing direct play). Fall back to normal negotiation with a warning when the format is unsupported. The MaxBitRate cap still applies on top. Fixes #5583. * test(e2e): cover player forced format on getTranscodeDecision Forced format honored when the client supports it, falls back to negotiation otherwise, and the MaxBitRate cap still applies on top. Part of #5583. * feat(ui): remove obsolete 'format ignored' helper text on player form The web player now honors the forced transcoding format, so the caveat added in #5611 no longer applies. Reverts the Transcoding field to a plain selector. Part of #5583.
This commit is contained in:
parent
c4c70519b5
commit
08a027dbcc
9 changed files with 234 additions and 86 deletions
|
|
@ -187,9 +187,6 @@
|
|||
"lastSeen": "Last Seen At",
|
||||
"reportRealPath": "Report Real Path",
|
||||
"scrobbleEnabled": "Send Scrobbles to external services"
|
||||
},
|
||||
"helperTexts": {
|
||||
"transcodingId": "The web player ignores the transcoding format and only enforces the Max. Bit Rate limit."
|
||||
}
|
||||
},
|
||||
"transcoding": {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import {
|
|||
SelectInput,
|
||||
ReferenceInput,
|
||||
useTranslate,
|
||||
useRecordContext,
|
||||
} from 'react-admin'
|
||||
import { Title } from '../common'
|
||||
import config from '../config'
|
||||
|
|
@ -20,35 +19,17 @@ const PlayerTitle = ({ record }) => {
|
|||
return <Title subTitle={`${resourceName} ${record ? record.name : ''}`} />
|
||||
}
|
||||
|
||||
export const TranscodingInput = (props) => {
|
||||
const translate = useTranslate()
|
||||
const record = useRecordContext(props)
|
||||
const isWebPlayer = record?.client === 'NavidromeUI'
|
||||
return (
|
||||
<ReferenceInput
|
||||
{...props}
|
||||
source="transcodingId"
|
||||
reference="transcoding"
|
||||
sort={{ field: 'name', order: 'ASC' }}
|
||||
>
|
||||
<SelectInput
|
||||
source="name"
|
||||
resettable
|
||||
helperText={
|
||||
isWebPlayer
|
||||
? translate('resources.player.helperTexts.transcodingId')
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</ReferenceInput>
|
||||
)
|
||||
}
|
||||
|
||||
const PlayerEdit = (props) => (
|
||||
<Edit title={<PlayerTitle />} {...props}>
|
||||
<SimpleForm variant={'outlined'}>
|
||||
<TextInput source="name" validate={[required()]} />
|
||||
<TranscodingInput />
|
||||
<ReferenceInput
|
||||
source="transcodingId"
|
||||
reference="transcoding"
|
||||
sort={{ field: 'name', order: 'ASC' }}
|
||||
>
|
||||
<SelectInput source="name" resettable />
|
||||
</ReferenceInput>
|
||||
<SelectInput source="maxBitRate" resettable choices={BITRATE_CHOICES} />
|
||||
<BooleanInput source="reportRealPath" fullWidth />
|
||||
{(config.lastFMEnabled || config.listenBrainzEnabled) && (
|
||||
|
|
|
|||
|
|
@ -1,54 +0,0 @@
|
|||
import * as React from 'react'
|
||||
import { render, screen, cleanup } from '@testing-library/react'
|
||||
import { describe, it, expect, afterEach, vi, beforeEach } from 'vitest'
|
||||
import { useRecordContext } from 'react-admin'
|
||||
import { TranscodingInput } from './PlayerEdit'
|
||||
|
||||
vi.mock('react-admin', async () => {
|
||||
const actual = await vi.importActual('react-admin')
|
||||
return {
|
||||
...actual,
|
||||
useRecordContext: vi.fn(),
|
||||
// Mock useTranslate to return the key verbatim so assertions don't depend
|
||||
// on ra-core's out-of-provider translation behavior.
|
||||
useTranslate: () => (key) => key,
|
||||
// Render the inputs as simple stand-ins so we can read their props.
|
||||
ReferenceInput: ({ children, variant }) => (
|
||||
<div data-testid="reference-input" data-variant={variant || ''}>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
SelectInput: ({ helperText }) => (
|
||||
<div data-testid="select-input" data-helpertext={helperText || ''} />
|
||||
),
|
||||
}
|
||||
})
|
||||
|
||||
describe('<TranscodingInput />', () => {
|
||||
beforeEach(() => {
|
||||
useRecordContext.mockReset()
|
||||
})
|
||||
afterEach(cleanup)
|
||||
|
||||
it('shows helper text for the NavidromeUI player', () => {
|
||||
useRecordContext.mockReturnValue({ client: 'NavidromeUI' })
|
||||
render(<TranscodingInput />)
|
||||
expect(screen.getByTestId('select-input').dataset.helpertext).toBe(
|
||||
'resources.player.helperTexts.transcodingId',
|
||||
)
|
||||
})
|
||||
|
||||
it('shows no helper text for other clients', () => {
|
||||
useRecordContext.mockReturnValue({ client: 'DSub' })
|
||||
render(<TranscodingInput />)
|
||||
expect(screen.getByTestId('select-input').dataset.helpertext).toBe('')
|
||||
})
|
||||
|
||||
it('forwards the form variant injected by SimpleForm to the input', () => {
|
||||
useRecordContext.mockReturnValue({ client: 'DSub' })
|
||||
render(<TranscodingInput variant="outlined" />)
|
||||
expect(screen.getByTestId('reference-input').dataset.variant).toBe(
|
||||
'outlined',
|
||||
)
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue