Finalize dev-1.3 upgrades and Seerr updates

This commit is contained in:
2026-02-28 21:41:16 +13:00
parent 05a3d1e3b0
commit c205df4367
27 changed files with 1201 additions and 214 deletions

View File

@@ -22,7 +22,8 @@ const SECTION_LABELS: Record<string, string> = {
magent: 'Magent',
general: 'General',
notifications: 'Notifications',
jellyseerr: 'Jellyseerr',
seerr: 'Seerr',
jellyseerr: 'Seerr',
jellyfin: 'Jellyfin',
artwork: 'Artwork cache',
cache: 'Cache Control',
@@ -89,7 +90,8 @@ const SECTION_DESCRIPTIONS: Record<string, string> = {
'Application runtime, binding, reverse proxy, and manual SSL settings for the Magent UI/API.',
notifications:
'Notification providers and delivery channel settings used by Magent messaging features.',
jellyseerr: 'Connect the request system where users submit content.',
seerr: 'Connect Seerr where users submit content requests.',
jellyseerr: 'Connect Seerr where users submit content requests.',
jellyfin: 'Control Jellyfin login and availability checks.',
artwork: 'Cache posters/backdrops and review artwork coverage.',
cache: 'Manage saved requests cache and refresh behavior.',
@@ -106,6 +108,7 @@ const SETTINGS_SECTION_MAP: Record<string, string | null> = {
magent: 'magent',
general: 'magent',
notifications: 'magent',
seerr: 'jellyseerr',
jellyseerr: 'jellyseerr',
jellyfin: 'jellyfin',
artwork: null,
@@ -234,6 +237,8 @@ const MAGENT_GROUPS_BY_SECTION: Record<string, Set<string>> = {
}
const SETTING_LABEL_OVERRIDES: Record<string, string> = {
jellyseerr_base_url: 'Seerr base URL',
jellyseerr_api_key: 'Seerr API key',
magent_application_url: 'Application URL',
magent_application_port: 'Application port',
magent_api_url: 'API URL',
@@ -278,6 +283,7 @@ const labelFromKey = (key: string) =>
SETTING_LABEL_OVERRIDES[key] ??
key
.replaceAll('_', ' ')
.replace('jellyseerr', 'Seerr')
.replace('base url', 'URL')
.replace('api key', 'API key')
.replace('quality profile id', 'Quality profile ID')
@@ -289,7 +295,7 @@ const labelFromKey = (key: string) =>
.replace('requests full sync time', 'Daily full refresh time (24h)')
.replace('requests cleanup time', 'Daily history cleanup time (24h)')
.replace('requests cleanup days', 'History retention window (days)')
.replace('requests data source', 'Request source (cache vs Jellyseerr)')
.replace('requests data source', 'Request source (cache vs Seerr)')
.replace('jellyfin public url', 'Jellyfin public URL')
.replace('jellyfin sync to arr', 'Sync Jellyfin to Sonarr/Radarr')
.replace('artwork cache mode', 'Artwork cache mode')
@@ -352,6 +358,21 @@ export default function SettingsPage({ section }: SettingsPageProps) {
const [liveStreamConnected, setLiveStreamConnected] = useState(false)
const requestsSyncRef = useRef<any | null>(null)
const artworkPrefetchRef = useRef<any | null>(null)
const computeProgressPercent = (
completedValue: unknown,
totalValue: unknown,
statusValue: unknown
): number => {
if (String(statusValue).toLowerCase() === 'completed') {
return 100
}
const completed = Number(completedValue)
const total = Number(totalValue)
if (!Number.isFinite(completed) || !Number.isFinite(total) || total <= 0 || completed <= 0) {
return 0
}
return Math.max(0, Math.min(100, Math.round((completed / total) * 100)))
}
const loadSettings = useCallback(async () => {
const baseUrl = getApiBase()
@@ -642,7 +663,7 @@ export default function SettingsPage({ section }: SettingsPageProps) {
magent_notify_webhook_url:
'Generic webhook endpoint for custom integrations or automation flows.',
jellyseerr_base_url:
'Base URL for your Jellyseerr server (FQDN or IP). Scheme is optional.',
'Base URL for your Seerr server (FQDN or IP). Scheme is optional.',
jellyseerr_api_key: 'API key used to read requests and status.',
jellyfin_base_url:
'Jellyfin server URL for logins and lookups (FQDN or IP). Scheme is optional.',
@@ -677,7 +698,7 @@ export default function SettingsPage({ section }: SettingsPageProps) {
requests_cleanup_time: 'Daily time to trim old request history.',
requests_cleanup_days: 'History older than this is removed during cleanup.',
requests_data_source:
'Pick where Magent should read requests from. Cache-only avoids Jellyseerr lookups on reads.',
'Pick where Magent should read requests from. Cache-only avoids Seerr lookups on reads.',
log_level: 'How much detail is written to the activity log.',
log_file: 'Where the activity log is stored.',
site_build_number: 'Build number shown in the account menu (auto-set from releases).',
@@ -805,6 +826,13 @@ export default function SettingsPage({ section }: SettingsPageProps) {
const syncRequests = async () => {
setRequestsSyncStatus(null)
setRequestsSync({
status: 'running',
stored: 0,
total: 0,
skip: 0,
message: 'Starting sync',
})
try {
const baseUrl = getApiBase()
const response = await authFetch(`${baseUrl}/admin/requests/sync`, {
@@ -829,6 +857,13 @@ export default function SettingsPage({ section }: SettingsPageProps) {
const syncRequestsDelta = async () => {
setRequestsSyncStatus(null)
setRequestsSync({
status: 'running',
stored: 0,
total: 0,
skip: 0,
message: 'Starting delta sync',
})
try {
const baseUrl = getApiBase()
const response = await authFetch(`${baseUrl}/admin/requests/sync/delta`, {
@@ -853,6 +888,12 @@ export default function SettingsPage({ section }: SettingsPageProps) {
const prefetchArtwork = async () => {
setArtworkPrefetchStatus(null)
setArtworkPrefetch({
status: 'running',
processed: 0,
total: 0,
message: 'Starting artwork caching',
})
try {
const baseUrl = getApiBase()
const response = await authFetch(`${baseUrl}/admin/requests/artwork/prefetch`, {
@@ -877,6 +918,12 @@ export default function SettingsPage({ section }: SettingsPageProps) {
const prefetchArtworkMissing = async () => {
setArtworkPrefetchStatus(null)
setArtworkPrefetch({
status: 'running',
processed: 0,
total: 0,
message: 'Starting missing artwork caching',
})
try {
const baseUrl = getApiBase()
const response = await authFetch(
@@ -1202,7 +1249,7 @@ export default function SettingsPage({ section }: SettingsPageProps) {
setMaintenanceBusy(true)
if (typeof window !== 'undefined') {
const ok = window.confirm(
'This will perform a nuclear reset: clear cached requests/history, wipe non-admin users, invites, and profiles, then re-sync users and requests from Jellyseerr. Continue?'
'This will perform a nuclear reset: clear cached requests/history, wipe non-admin users, invites, and profiles, then re-sync users and requests from Seerr. Continue?'
)
if (!ok) {
setMaintenanceBusy(false)
@@ -1264,7 +1311,7 @@ export default function SettingsPage({ section }: SettingsPageProps) {
const cacheSourceLabel =
formValues.requests_data_source === 'always_js'
? 'Jellyseerr direct'
? 'Seerr direct'
: formValues.requests_data_source === 'prefer_cache'
? 'Saved requests only'
: 'Saved requests only'
@@ -1485,22 +1532,16 @@ export default function SettingsPage({ section }: SettingsPageProps) {
</span>
</div>
<div
className={`progress ${artworkPrefetch.total ? '' : 'progress-indeterminate'} ${
artworkPrefetch.status === 'completed' ? 'progress-complete' : ''
}`}
className={`progress ${artworkPrefetch.status === 'completed' ? 'progress-complete' : ''}`}
>
<div
className="progress-fill"
style={{
width:
artworkPrefetch.status === 'completed'
? '100%'
: artworkPrefetch.total
? `${Math.min(
100,
Math.round((artworkPrefetch.processed / artworkPrefetch.total) * 100)
)}%`
: '30%',
width: `${computeProgressPercent(
artworkPrefetch.processed,
artworkPrefetch.total,
artworkPrefetch.status
)}%`,
}}
/>
</div>
@@ -1517,22 +1558,16 @@ export default function SettingsPage({ section }: SettingsPageProps) {
</span>
</div>
<div
className={`progress ${requestsSync.total ? '' : 'progress-indeterminate'} ${
requestsSync.status === 'completed' ? 'progress-complete' : ''
}`}
className={`progress ${requestsSync.status === 'completed' ? 'progress-complete' : ''}`}
>
<div
className="progress-fill"
style={{
width:
requestsSync.status === 'completed'
? '100%'
: requestsSync.total
? `${Math.min(
100,
Math.round((requestsSync.stored / requestsSync.total) * 100)
)}%`
: '30%',
width: `${computeProgressPercent(
requestsSync.stored,
requestsSync.total,
requestsSync.status
)}%`,
}}
/>
</div>
@@ -1860,7 +1895,7 @@ export default function SettingsPage({ section }: SettingsPageProps) {
}))
}
>
<option value="always_js">Always use Jellyseerr (slower)</option>
<option value="always_js">Always use Seerr (slower)</option>
<option value="prefer_cache">
Use saved requests only (fastest)
</option>
@@ -2005,7 +2040,7 @@ export default function SettingsPage({ section }: SettingsPageProps) {
<h2>Maintenance</h2>
</div>
<div className="status-banner">
Emergency tools. Use with care: flush + resync now performs a nuclear wipe of non-admin users, invite links, profiles, cached requests, and history before re-syncing Jellyseerr users/requests.
Emergency tools. Use with care: flush + resync now performs a nuclear wipe of non-admin users, invite links, profiles, cached requests, and history before re-syncing Seerr users/requests.
</div>
{maintenanceStatus && <div className="status-banner">{maintenanceStatus}</div>}
<div className="maintenance-grid">