Support original-language movie requests and fix repair dialog layout
This commit is contained in:
@@ -55,7 +55,7 @@ export default function DuplicateAccountRepair({ row, onClose, onSaved }: { row:
|
||||
{preview.accounts.map((account) => <option key={account.id} value={account.id}>{account.username} — Magent {account.id}{account.id === preview.recommended_id ? ' (recommended)' : ''}</option>)}
|
||||
</select></label>
|
||||
<p>The recommended row already owns the Jellyfin link, or is the oldest row when neither owns it.</p>
|
||||
<div className="identity-mapping">{preview.accounts.map((account) => <div key={account.id}><strong>Magent {account.id}{account.id === preview.keep_id ? ' · Keep' : ' · Consolidate'}</strong><p>{account.username}</p><p>{account.email || 'No email'} · Profile {account.profile_id ?? 'None'}</p><p>Last login: {account.last_login_at ? new Date(account.last_login_at).toLocaleString() : 'Never'}</p></div>)}</div>
|
||||
<div className="identity-mapping identity-duplicate-accounts">{preview.accounts.map((account) => <div key={account.id}><strong>Magent {account.id}{account.id === preview.keep_id ? ' · Keep' : ' · Consolidate'}</strong><p>{account.username}</p><p>{account.email || 'No email'} · Profile {account.profile_id ?? 'None'}</p><p>Last login: {account.last_login_at ? new Date(account.last_login_at).toLocaleString() : 'Never'}</p></div>)}</div>
|
||||
<h3>Resulting account</h3>
|
||||
<p><strong>{preview.proposed.username}</strong> · Magent {preview.keep_id} · Seerr {preview.proposed.seerr_user_id ?? 'Not verified'}</p>
|
||||
<p>Jellyfin / Jellystat: <code>{preview.proposed.jellyfin_user_id ?? 'Not verified'}</code></p>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.identity-review { display: grid; gap: 20px; min-width: 0; }
|
||||
.identity-resolution-entry { display: grid; justify-items: start; gap: 12px; margin-top: 16px; }
|
||||
.identity-resolve-dialog { width: min(900px, calc(100vw - 32px)); max-height: calc(100dvh - 40px); padding: 0; color: var(--ops-text); background: var(--ops-panel, #1b1b1d); border: 1px solid var(--ops-line); border-radius: 16px; }
|
||||
.identity-resolve-dialog { position: fixed; inset: 0; margin: auto; overflow: auto; overscroll-behavior: contain; width: min(900px, calc(100vw - 32px)); max-height: calc(100dvh - 40px); padding: 0; color: var(--ops-text); background: var(--ops-panel, #1b1b1d); border: 1px solid var(--ops-line); border-radius: 16px; }
|
||||
.identity-resolve-dialog::backdrop { background: #000b; backdrop-filter: blur(4px); }
|
||||
.identity-resolve-content { display: grid; gap: 20px; padding: 24px; min-width: 0; }
|
||||
.identity-resolve-content > header { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
|
||||
@@ -76,3 +76,5 @@
|
||||
|
||||
.identity-import-option > span { display: flex; align-items: flex-start; gap: 10px; line-height: 1.6; }
|
||||
.identity-import-option input[type=checkbox] { flex: 0 0 20px; margin: 3px 0 0; }
|
||||
|
||||
.identity-duplicate-accounts { grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr)); }
|
||||
|
||||
@@ -7597,3 +7597,9 @@ textarea {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
.request-language-notice { display: grid; gap: 12px; padding: 20px; border: 1px solid #a88445; border-radius: 12px; background: #a8844512; }
|
||||
.request-language-notice h3, .request-language-notice p { margin: 0; }
|
||||
.request-language-notice p, .request-language-notice small { line-height: 1.6; }
|
||||
.request-language-notice label { display: flex; align-items: flex-start; gap: 10px; }
|
||||
.request-language-notice input[type=checkbox] { flex: 0 0 20px; width: 20px; height: 20px; margin-top: 2px; }
|
||||
|
||||
@@ -28,6 +28,7 @@ type RequestOptions = {
|
||||
episodeCount: number
|
||||
airDate?: string | null
|
||||
}>
|
||||
originalLanguage?: { code: string } | null
|
||||
existingRequestId?: number | null
|
||||
}
|
||||
destination: {
|
||||
@@ -115,6 +116,7 @@ export default function NewRequestClient() {
|
||||
const [options, setOptions] = useState<RequestOptions | null>(null)
|
||||
const [loadingOptions, setLoadingOptions] = useState(false)
|
||||
const [selectedSeasons, setSelectedSeasons] = useState<number[]>([])
|
||||
const [acceptOriginalLanguage, setAcceptOriginalLanguage] = useState(false)
|
||||
const [submitting, setSubmitting] = useState(false)
|
||||
const [operation, setOperation] = useState<OperationProgress | null>(null)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
@@ -132,6 +134,7 @@ export default function NewRequestClient() {
|
||||
const changeTitle = () => {
|
||||
setSelected(null)
|
||||
setOptions(null)
|
||||
setAcceptOriginalLanguage(false)
|
||||
setSelectedSeasons([])
|
||||
setOperation(null)
|
||||
setError(null)
|
||||
@@ -146,6 +149,7 @@ export default function NewRequestClient() {
|
||||
setSearchAttempted(false)
|
||||
setSelected(null)
|
||||
setOptions(null)
|
||||
setAcceptOriginalLanguage(false)
|
||||
setSelectedSeasons([])
|
||||
setOperation(null)
|
||||
setError(null)
|
||||
@@ -165,6 +169,7 @@ export default function NewRequestClient() {
|
||||
setSearchAttempted(true)
|
||||
setSelected(null)
|
||||
setOptions(null)
|
||||
setAcceptOriginalLanguage(false)
|
||||
setOperation(null)
|
||||
setError(null)
|
||||
setSuccess(null)
|
||||
@@ -207,6 +212,7 @@ export default function NewRequestClient() {
|
||||
const selectResult = async (item: DiscoveryResult) => {
|
||||
setSelected(item)
|
||||
setOptions(null)
|
||||
setAcceptOriginalLanguage(false)
|
||||
setSelectedSeasons([])
|
||||
setOperation(null)
|
||||
setError(null)
|
||||
@@ -285,6 +291,7 @@ export default function NewRequestClient() {
|
||||
body: JSON.stringify({
|
||||
mediaType: selected.type,
|
||||
tmdbId: selected.tmdbId,
|
||||
acceptOriginalLanguage,
|
||||
seasons: selected.type === 'tv' ? selectedSeasons : undefined,
|
||||
}),
|
||||
})
|
||||
@@ -489,6 +496,12 @@ export default function NewRequestClient() {
|
||||
</fieldset>
|
||||
)}
|
||||
|
||||
{options.media.originalLanguage && <div className="request-language-notice">
|
||||
<h3>Check the audio language</h3>
|
||||
<p>This title’s original language is <strong>{new Intl.DisplayNames(['en'], { type: 'language' }).of(options.media.originalLanguage.code) || options.media.originalLanguage.code}</strong>. An English audio track may not be available. Title metadata does not confirm the audio or subtitles in a download.</p>
|
||||
<label><input type="checkbox" checked={acceptOriginalLanguage} onChange={(event) => setAcceptOriginalLanguage(event.target.checked)} disabled={submitting} /><span>I’m happy to watch in the original language.</span></label>
|
||||
<small>{acceptOriginalLanguage ? (selected.type === 'movie' ? 'Search for original-language audio using the same quality requirements.' : 'Continue with your selected seasons and the configured TV quality requirements.') : 'Leave this unchecked to keep the standard request settings. An English-only profile may leave this title waiting for a suitable release.'}</small>
|
||||
</div>}
|
||||
<div className="request-submit-bar">
|
||||
<div><span>Delivery route</span><strong>Seerr → {options.destination.collector} → Grizzlyflix</strong><small>Your request uses the default quality set by your administrator.</small></div>
|
||||
<button type="button" onClick={() => void submitRequest()} disabled={submitting || (selected.type === 'tv' && selectedSeasons.length === 0)}>
|
||||
|
||||
Reference in New Issue
Block a user