qBitrr2 5.8.6__py3-none-any.whl → 5.8.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"ArrView.js","sources":["../../../webui/src/components/StableTable.tsx","../../../webui/src/utils/dataSync.ts","../../../webui/src/hooks/useDataSync.ts","../../../webui/src/pages/RadarrView.tsx","../../../webui/src/pages/SonarrView.tsx","../../../webui/src/pages/LidarrView.tsx","../../../webui/src/pages/ArrView.tsx"],"sourcesContent":["import { memo, useMemo } from \"react\";\nimport {\n useReactTable,\n getCoreRowModel,\n flexRender,\n type ColumnDef,\n type Table,\n} from \"@tanstack/react-table\";\n\ninterface StableTableProps<TData> {\n data: TData[];\n columns: ColumnDef<TData, any>[];\n getRowKey?: (row: TData) => string;\n}\n\nfunction StableTableInner<TData>({ data, columns, getRowKey }: StableTableProps<TData>) {\n const table = useReactTable({\n data,\n columns,\n getCoreRowModel: getCoreRowModel(),\n });\n\n return (\n <div className=\"table-wrapper\">\n <table className=\"responsive-table\">\n <thead>\n {table.getHeaderGroups().map((headerGroup) => (\n <tr key={headerGroup.id}>\n {headerGroup.headers.map((header) => (\n <th key={header.id}>\n {header.isPlaceholder\n ? null\n : flexRender(\n header.column.columnDef.header,\n header.getContext()\n )}\n </th>\n ))}\n </tr>\n ))}\n </thead>\n <tbody>\n {table.getRowModel().rows.map((row) => {\n const stableKey = getRowKey ? getRowKey(row.original) : row.id;\n return (\n <tr key={stableKey}>\n {row.getVisibleCells().map((cell) => (\n <td key={cell.id} data-label={String(cell.column.columnDef.header)}>\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </td>\n ))}\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n );\n}\n\nexport const StableTable = memo(StableTableInner, (prevProps, nextProps) => {\n // Only re-render if data reference changed\n return prevProps.data === nextProps.data && prevProps.columns === nextProps.columns;\n}) as typeof StableTableInner;\n","/**\n * Data synchronization utilities for efficient change detection and incremental updates\n */\n\n/**\n * Fast hash function using FNV-1a algorithm\n */\nfunction fnv1aHash(str: string): string {\n let hash = 2166136261;\n for (let i = 0; i < str.length; i++) {\n hash ^= str.charCodeAt(i);\n hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);\n }\n return (hash >>> 0).toString(36);\n}\n\n/**\n * Generic interface for items that can be hashed\n */\nexport interface Hashable {\n [key: string]: unknown;\n}\n\n/**\n * Result of change detection\n */\nexport interface ChangeDetectionResult<T> {\n added: T[];\n updated: T[];\n removed: string[];\n unchanged: number;\n hasChanges: boolean;\n}\n\n/**\n * Normalized data structure for efficient lookups\n */\nexport interface NormalizedData<T> {\n byId: Map<string, T>;\n byHash: Map<string, string>;\n allIds: string[];\n lastUpdate: number;\n}\n\n/**\n * Create hash from item based on specified fields\n */\nexport function createItemHash<T extends Hashable>(\n item: T,\n fields: (keyof T)[]\n): string {\n const values = fields.map(field => {\n const value = item[field];\n if (value === null || value === undefined) return '';\n if (typeof value === 'boolean') return value ? '1' : '0';\n if (typeof value === 'object') return JSON.stringify(value);\n return String(value);\n });\n return fnv1aHash(values.join('|'));\n}\n\n/**\n * Detect changes between existing and incoming data\n */\nexport function detectChanges<T extends Hashable>(\n existing: NormalizedData<T>,\n incoming: T[],\n getKey: (item: T) => string,\n hashFields: (keyof T)[]\n): ChangeDetectionResult<T> {\n const added: T[] = [];\n const updated: T[] = [];\n const removed: string[] = [];\n const seenIds = new Set<string>();\n\n // Check incoming items\n for (const item of incoming) {\n const id = getKey(item);\n const hash = createItemHash(item, hashFields);\n seenIds.add(id);\n\n const existingItem = existing.byId.get(id);\n const existingHash = existing.byHash.get(id);\n\n if (!existingItem) {\n // New item\n added.push(item);\n } else if (existingHash !== hash) {\n // Item exists but data changed\n updated.push(item);\n }\n }\n\n // Find removed items\n for (const id of existing.allIds) {\n if (!seenIds.has(id)) {\n removed.push(id);\n }\n }\n\n const unchanged = incoming.length - added.length - updated.length;\n const hasChanges = added.length > 0 || updated.length > 0 || removed.length > 0;\n\n return { added, updated, removed, unchanged, hasChanges };\n}\n\n/**\n * Merge changes into normalized data\n */\nexport function mergeChanges<T extends Hashable>(\n existing: NormalizedData<T>,\n changes: ChangeDetectionResult<T>,\n getKey: (item: T) => string,\n hashFields: (keyof T)[]\n): NormalizedData<T> {\n if (!changes.hasChanges) {\n return existing;\n }\n\n const newById = new Map(existing.byId);\n const newByHash = new Map(existing.byHash);\n const newIds = [...existing.allIds];\n\n // Add new items\n for (const item of changes.added) {\n const id = getKey(item);\n const hash = createItemHash(item, hashFields);\n newById.set(id, item);\n newByHash.set(id, hash);\n newIds.push(id);\n }\n\n // Update existing items\n for (const item of changes.updated) {\n const id = getKey(item);\n const hash = createItemHash(item, hashFields);\n newById.set(id, item);\n newByHash.set(id, hash);\n }\n\n // Remove deleted items\n for (const id of changes.removed) {\n newById.delete(id);\n newByHash.delete(id);\n const index = newIds.indexOf(id);\n if (index !== -1) {\n newIds.splice(index, 1);\n }\n }\n\n return {\n byId: newById,\n byHash: newByHash,\n allIds: newIds,\n lastUpdate: Date.now(),\n };\n}\n\n/**\n * Convert normalized data to array\n */\nexport function denormalize<T>(data: NormalizedData<T>): T[] {\n return data.allIds.map(id => data.byId.get(id)!).filter(Boolean);\n}\n\n/**\n * Create normalized data from array\n */\nexport function normalize<T extends Hashable>(\n items: T[],\n getKey: (item: T) => string,\n hashFields: (keyof T)[]\n): NormalizedData<T> {\n const byId = new Map<string, T>();\n const byHash = new Map<string, string>();\n const allIds: string[] = [];\n\n for (const item of items) {\n const id = getKey(item);\n const hash = createItemHash(item, hashFields);\n byId.set(id, item);\n byHash.set(id, hash);\n allIds.push(id);\n }\n\n return {\n byId,\n byHash,\n allIds,\n lastUpdate: Date.now(),\n };\n}\n\n/**\n * Create empty normalized data\n */\nexport function createEmptyNormalized<T>(): NormalizedData<T> {\n return {\n byId: new Map(),\n byHash: new Map(),\n allIds: [],\n lastUpdate: 0,\n };\n}\n\n/**\n * Check if two arrays have the same content (order-independent)\n * Uses fast hash comparison instead of deep equality\n */\nexport function arraysEqual<T extends Hashable>(\n a: T[],\n b: T[],\n getKey: (item: T) => string,\n hashFields: (keyof T)[]\n): boolean {\n if (a.length !== b.length) return false;\n\n const aHashes = new Map<string, string>();\n for (const item of a) {\n const id = getKey(item);\n const hash = createItemHash(item, hashFields);\n aHashes.set(id, hash);\n }\n\n for (const item of b) {\n const id = getKey(item);\n const hash = createItemHash(item, hashFields);\n if (aHashes.get(id) !== hash) return false;\n }\n\n return true;\n}\n","import { useCallback, useRef, useState } from \"react\";\nimport {\n type NormalizedData,\n type ChangeDetectionResult,\n type Hashable,\n createEmptyNormalized,\n detectChanges,\n mergeChanges,\n denormalize,\n} from \"../utils/dataSync\";\n\nexport interface DataSyncOptions<T extends Hashable> {\n getKey: (item: T) => string;\n hashFields: (keyof T)[];\n}\n\nexport interface DataSyncResult<T extends Hashable> {\n data: T[];\n hasChanges: boolean;\n changes: ChangeDetectionResult<T> | null;\n lastUpdate: number;\n}\n\n/**\n * Hook for managing incremental data synchronization\n * Automatically detects changes and prevents unnecessary re-renders\n */\nexport function useDataSync<T extends Hashable>(\n options: DataSyncOptions<T>\n): {\n syncData: (newData: T[]) => DataSyncResult<T>;\n getData: () => T[];\n reset: () => void;\n lastUpdate: number;\n} {\n const { getKey, hashFields } = options;\n\n const normalizedRef = useRef<NormalizedData<T>>(createEmptyNormalized<T>());\n const [lastUpdate, setLastUpdate] = useState(0);\n\n const syncData = useCallback(\n (newData: T[]): DataSyncResult<T> => {\n const changes = detectChanges(\n normalizedRef.current,\n newData,\n getKey,\n hashFields\n );\n\n if (!changes.hasChanges) {\n // No changes detected, return existing data\n return {\n data: denormalize(normalizedRef.current),\n hasChanges: false,\n changes: null,\n lastUpdate: normalizedRef.current.lastUpdate,\n };\n }\n\n // Merge changes into normalized data\n const merged = mergeChanges(\n normalizedRef.current,\n changes,\n getKey,\n hashFields\n );\n\n normalizedRef.current = merged;\n setLastUpdate(merged.lastUpdate);\n\n return {\n data: denormalize(merged),\n hasChanges: true,\n changes,\n lastUpdate: merged.lastUpdate,\n };\n },\n [getKey, hashFields]\n );\n\n const getData = useCallback((): T[] => {\n return denormalize(normalizedRef.current);\n }, []);\n\n const reset = useCallback(() => {\n normalizedRef.current = createEmptyNormalized<T>();\n setLastUpdate(0);\n }, []);\n\n return {\n syncData,\n getData,\n reset,\n lastUpdate,\n };\n}\n","import {\n memo,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ChangeEvent,\n type JSX,\n} from \"react\";\nimport {\n getArrList,\n getRadarrMovies,\n restartArr,\n} from \"../api/client\";\nimport { StableTable } from \"../components/StableTable\";\nimport {\n useReactTable,\n getCoreRowModel,\n getSortedRowModel,\n getPaginationRowModel,\n flexRender,\n type ColumnDef,\n} from \"@tanstack/react-table\";\nimport type {\n ArrInfo,\n RadarrMovie,\n RadarrMoviesResponse,\n} from \"../api/types\";\nimport { useToast } from \"../context/ToastContext\";\nimport { useSearch } from \"../context/SearchContext\";\nimport { useWebUI } from \"../context/WebUIContext\";\nimport { useInterval } from \"../hooks/useInterval\";\nimport { useDataSync } from \"../hooks/useDataSync\";\nimport { IconImage } from \"../components/IconImage\";\nimport RefreshIcon from \"../icons/refresh-arrow.svg\";\nimport RestartIcon from \"../icons/refresh-arrow.svg\";\n\ninterface RadarrAggRow extends RadarrMovie {\n __instance: string;\n [key: string]: unknown;\n}\n\ntype RadarrSortKey = \"title\" | \"year\" | \"monitored\" | \"hasFile\";\ntype RadarrAggSortKey = \"__instance\" | RadarrSortKey;\n\nconst RADARR_PAGE_SIZE = 50;\nconst RADARR_AGG_PAGE_SIZE = 50;\nconst RADARR_AGG_FETCH_SIZE = 500;\n\ninterface RadarrAggregateViewProps {\n loading: boolean;\n rows: RadarrAggRow[];\n total: number;\n page: number;\n totalPages: number;\n onPageChange: (page: number) => void;\n onRefresh: () => void;\n lastUpdated: string | null;\n sort: { key: RadarrAggSortKey; direction: \"asc\" | \"desc\" };\n onSort: (key: RadarrAggSortKey) => void;\n summary: { available: number; monitored: number; missing: number; total: number };\n instanceCount: number;\n isAggFiltered?: boolean;\n}\n\nconst RadarrAggregateView = memo(function RadarrAggregateView({\n loading,\n rows,\n total,\n page,\n totalPages,\n onPageChange,\n onRefresh,\n lastUpdated,\n sort,\n onSort,\n summary,\n instanceCount,\n isAggFiltered = false,\n}: RadarrAggregateViewProps): JSX.Element {\n const columns = useMemo<ColumnDef<RadarrAggRow>[]>(\n () => [\n ...(instanceCount > 1 ? [{\n accessorKey: \"__instance\",\n header: \"Instance\",\n size: 150,\n }] : []),\n {\n accessorKey: \"title\",\n header: \"Title\",\n cell: (info) => info.getValue(),\n },\n {\n accessorKey: \"year\",\n header: \"Year\",\n size: 80,\n },\n {\n accessorKey: \"monitored\",\n header: \"Monitored\",\n cell: (info) => {\n const monitored = info.getValue() as boolean;\n return (\n <span className={`track-status ${monitored ? 'available' : 'missing'}`}>\n {monitored ? '✓' : '✗'}\n </span>\n );\n },\n size: 100,\n },\n {\n accessorKey: \"hasFile\",\n header: \"Has File\",\n cell: (info) => {\n const hasFile = info.getValue() as boolean;\n return (\n <span className={`track-status ${hasFile ? 'available' : 'missing'}`}>\n {hasFile ? '✓' : '✗'}\n </span>\n );\n },\n size: 100,\n },\n {\n accessorKey: \"qualityProfileName\",\n header: \"Quality Profile\",\n cell: (info) => {\n const profileName = info.getValue() as string | null | undefined;\n return profileName || \"—\";\n },\n size: 150,\n },\n {\n accessorKey: \"reason\",\n header: \"Reason\",\n cell: (info) => {\n const reason = info.getValue() as string | null;\n if (!reason) return <span className=\"table-badge table-badge-reason\">Not being searched</span>;\n return <span className=\"table-badge table-badge-reason\">{reason}</span>;\n },\n size: 120,\n },\n ],\n [instanceCount]\n );\n\n return (\n <div className=\"stack animate-fade-in\">\n <div className=\"row\" style={{ justifyContent: \"space-between\" }}>\n <div className=\"hint\">\n Aggregated movies across all instances{\" \"}\n {lastUpdated ? `(updated ${lastUpdated})` : \"\"}\n <br />\n <strong>Available:</strong>{\" \"}\n {summary.available.toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Monitored:</strong>{\" \"}\n {summary.monitored.toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Missing:</strong>{\" \"}\n {summary.missing.toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Total:</strong>{\" \"}\n {summary.total.toLocaleString(undefined, { maximumFractionDigits: 0 })}\n {isAggFiltered && total < summary.total && (\n <>\n {\" \"}• <strong>Filtered:</strong>{\" \"}\n {total.toLocaleString(undefined, { maximumFractionDigits: 0 })} of{\" \"}\n {summary.total.toLocaleString(undefined, { maximumFractionDigits: 0 })}\n </>\n )}\n </div>\n <button className=\"btn ghost\" onClick={onRefresh} disabled={loading}>\n <IconImage src={RefreshIcon} />\n Refresh\n </button>\n </div>\n\n {loading ? (\n <div className=\"loading\">\n <span className=\"spinner\" /> Loading Radarr library…\n </div>\n ) : total ? (\n <StableTable\n data={rows}\n columns={columns}\n getRowKey={(movie) => `${movie.__instance}-${movie.title}-${movie.year}`}\n />\n ) : (\n <div className=\"hint\">No movies found.</div>\n )}\n\n {total > 0 && (\n <div className=\"pagination\">\n <div>\n Page {page + 1} of {totalPages} ({total.toLocaleString()} items · page size{\" \"}\n {RADARR_AGG_PAGE_SIZE})\n </div>\n <div className=\"inline\">\n <button\n className=\"btn\"\n onClick={() => onPageChange(Math.max(0, page - 1))}\n disabled={page === 0 || loading}\n >\n Prev\n </button>\n <button\n className=\"btn\"\n onClick={() => onPageChange(Math.min(totalPages - 1, page + 1))}\n disabled={page >= totalPages - 1 || loading}\n >\n Next\n </button>\n </div>\n </div>\n )}\n </div>\n );\n});\n\ninterface RadarrInstanceViewProps {\n loading: boolean;\n data: RadarrMoviesResponse | null;\n page: number;\n totalPages: number;\n pageSize: number;\n allMovies: RadarrMovie[];\n onlyMissing: boolean;\n reasonFilter: string;\n onPageChange: (page: number) => void;\n onRefresh: () => void;\n onRestart: () => void;\n lastUpdated: string | null;\n}\n\nconst RadarrInstanceView = memo(function RadarrInstanceView({\n loading,\n data,\n page,\n totalPages,\n pageSize,\n allMovies,\n onlyMissing,\n reasonFilter,\n onPageChange,\n onRefresh,\n onRestart,\n lastUpdated,\n}: RadarrInstanceViewProps): JSX.Element {\n const filteredMovies = useMemo(() => {\n let movies = allMovies;\n if (onlyMissing) {\n movies = movies.filter((m) => !m.hasFile);\n }\n return movies;\n }, [allMovies, onlyMissing]);\n\n const reasonFilteredMovies = useMemo(() => {\n if (reasonFilter === \"all\") return filteredMovies;\n if (reasonFilter === \"Not being searched\") {\n return filteredMovies.filter((m) => m.reason === \"Not being searched\" || !m.reason);\n }\n return filteredMovies.filter((m) => m.reason === reasonFilter);\n }, [filteredMovies, reasonFilter]);\n\n const totalMovies = useMemo(() => allMovies.length, [allMovies]);\n const isFiltered = reasonFilter !== \"all\" || onlyMissing;\n const filteredCount = reasonFilteredMovies.length;\n\n const columns = useMemo<ColumnDef<RadarrMovie>[]>(\n () => [\n {\n accessorKey: \"title\",\n header: \"Title\",\n cell: (info) => info.getValue(),\n },\n {\n accessorKey: \"year\",\n header: \"Year\",\n size: 80,\n },\n {\n accessorKey: \"monitored\",\n header: \"Monitored\",\n cell: (info) => {\n const monitored = info.getValue() as boolean;\n return (\n <span className={`track-status ${monitored ? 'available' : 'missing'}`}>\n {monitored ? '✓' : '✗'}\n </span>\n );\n },\n size: 100,\n },\n {\n accessorKey: \"hasFile\",\n header: \"Has File\",\n cell: (info) => {\n const hasFile = info.getValue() as boolean;\n return (\n <span className={`track-status ${hasFile ? 'available' : 'missing'}`}>\n {hasFile ? '✓' : '✗'}\n </span>\n );\n },\n size: 100,\n },\n {\n accessorKey: \"qualityProfileName\",\n header: \"Quality Profile\",\n cell: (info) => {\n const profileName = info.getValue() as string | null | undefined;\n return profileName || \"—\";\n },\n size: 150,\n },\n {\n accessorKey: \"reason\",\n header: \"Reason\",\n cell: (info) => {\n const reason = info.getValue() as string | null;\n if (!reason) return <span className=\"table-badge table-badge-reason\">Not being searched</span>;\n return <span className=\"table-badge table-badge-reason\">{reason}</span>;\n },\n size: 120,\n },\n ],\n []\n );\n\n const table = useReactTable({\n data: reasonFilteredMovies.slice(page * pageSize, page * pageSize + pageSize),\n columns,\n getCoreRowModel: getCoreRowModel(),\n getSortedRowModel: getSortedRowModel(),\n });\n\n return (\n <div className=\"stack animate-fade-in\">\n <div className=\"row\" style={{ justifyContent: \"space-between\" }}>\n <div className=\"hint\">\n {data?.counts ? (\n <>\n <strong>Available:</strong>{\" \"}\n {(data.counts.available ?? 0).toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Monitored:</strong>{\" \"}\n {(data.counts.monitored ?? 0).toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Missing:</strong>{\" \"}\n {((data.counts.monitored ?? 0) - (data.counts.available ?? 0)).toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Total:</strong>{\" \"}\n {totalMovies.toLocaleString(undefined, { maximumFractionDigits: 0 })}\n {isFiltered && filteredCount < totalMovies && (\n <>\n {\" \"}• <strong>Filtered:</strong>{\" \"}\n {filteredCount.toLocaleString(undefined, { maximumFractionDigits: 0 })} of{\" \"}\n {totalMovies.toLocaleString(undefined, { maximumFractionDigits: 0 })}\n </>\n )}\n </>\n ) : (\n \"Loading movie information...\"\n )}\n {lastUpdated ? ` (updated ${lastUpdated})` : \"\"}\n </div>\n <button className=\"btn ghost\" onClick={onRestart} disabled={loading}>\n <IconImage src={RestartIcon} />\n Restart\n </button>\n </div>\n\n {loading ? (\n <div className=\"loading\">\n <span className=\"spinner\" /> Loading…\n </div>\n ) : allMovies.length ? (\n <div className=\"table-wrapper\">\n <table className=\"responsive-table\">\n <thead>\n {table.getHeaderGroups().map((headerGroup) => (\n <tr key={headerGroup.id}>\n {headerGroup.headers.map((header) => (\n <th key={header.id}>\n {header.isPlaceholder\n ? null\n : flexRender(\n header.column.columnDef.header,\n header.getContext()\n )}\n </th>\n ))}\n </tr>\n ))}\n </thead>\n <tbody>\n {table.getRowModel().rows.map((row) => {\n const movie = row.original;\n const stableKey = `${movie.title}-${movie.year}`;\n return (\n <tr key={stableKey}>\n {row.getVisibleCells().map((cell) => (\n <td key={cell.id} data-label={String(cell.column.columnDef.header)}>\n {flexRender(\n cell.column.columnDef.cell,\n cell.getContext()\n )}\n </td>\n ))}\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n ) : (\n <div className=\"hint\">No movies found.</div>\n )}\n\n {reasonFilteredMovies.length > pageSize && (\n <div className=\"pagination\">\n <div>\n Page {page + 1} of {totalPages} ({reasonFilteredMovies.length.toLocaleString()} items · page size{\" \"}\n {pageSize})\n </div>\n <div className=\"inline\">\n <button\n className=\"btn\"\n onClick={() => onPageChange(Math.max(0, page - 1))}\n disabled={page === 0 || loading}\n >\n Prev\n </button>\n <button\n className=\"btn\"\n onClick={() => onPageChange(Math.min(totalPages - 1, page + 1))}\n disabled={page >= totalPages - 1 || loading}\n >\n Next\n </button>\n </div>\n </div>\n )}\n </div>\n );\n});\n\nexport function RadarrView({ active }: { active: boolean }): JSX.Element {\n const { push } = useToast();\n const {\n value: globalSearch,\n setValue: setGlobalSearch,\n register,\n clearHandler,\n } = useSearch();\n const { liveArr, setLiveArr } = useWebUI();\n\n const [instances, setInstances] = useState<ArrInfo[]>([]);\n const [selection, setSelection] = useState<string | \"aggregate\">(\"\");\n const [instanceData, setInstanceData] = useState<RadarrMoviesResponse | null>(null);\n const [instancePage, setInstancePage] = useState(0);\n const [instanceQuery, setInstanceQuery] = useState(\"\");\n const [instanceLoading, setInstanceLoading] = useState(false);\n const [lastUpdated, setLastUpdated] = useState<string | null>(null);\n const [instancePages, setInstancePages] = useState<Record<number, RadarrMovie[]>>({});\n const [instancePageSize, setInstancePageSize] = useState(RADARR_PAGE_SIZE);\n const [instanceTotalPages, setInstanceTotalPages] = useState(1);\n const instanceKeyRef = useRef<string>(\"\");\n const instancePagesRef = useRef<Record<number, RadarrMovie[]>>({});\n const globalSearchRef = useRef(globalSearch);\n const backendReadyWarnedRef = useRef(false);\n\n // Smart data sync for instance movies\n const instanceMovieSync = useDataSync<RadarrMovie>({\n getKey: (movie) => `${movie.title}-${movie.year}`,\n hashFields: ['title', 'year', 'hasFile', 'monitored', 'reason'],\n });\n\n const [aggRows, setAggRows] = useState<RadarrAggRow[]>([]);\n const [aggLoading, setAggLoading] = useState(false);\n const [aggPage, setAggPage] = useState(0);\n const [aggFilter, setAggFilter] = useState(\"\");\n const [aggUpdated, setAggUpdated] = useState<string | null>(null);\n\n // Smart data sync for aggregate movies\n const aggMovieSync = useDataSync<RadarrAggRow>({\n getKey: (movie) => `${movie.__instance}-${movie.title}-${movie.year}`,\n hashFields: ['__instance', 'title', 'year', 'hasFile', 'monitored', 'reason'],\n });\n const [aggSort, setAggSort] = useState<{\n key: RadarrAggSortKey;\n direction: \"asc\" | \"desc\";\n }>({ key: \"__instance\", direction: \"asc\" });\n const [onlyMissing, setOnlyMissing] = useState(false);\n const [reasonFilter, setReasonFilter] = useState<string>(\"all\");\n const [aggSummary, setAggSummary] = useState<{\n available: number;\n monitored: number;\n missing: number;\n total: number;\n }>({ available: 0, monitored: 0, missing: 0, total: 0 });\n\n const loadInstances = useCallback(async () => {\n try {\n const data = await getArrList();\n if (data.ready === false && !backendReadyWarnedRef.current) {\n backendReadyWarnedRef.current = true;\n push(\"Radarr backend is still initialising. Check the logs if this persists.\", \"info\");\n } else if (data.ready) {\n backendReadyWarnedRef.current = true;\n }\n const filtered = (data.arr || []).filter((arr) => arr.type === \"radarr\");\n setInstances(filtered);\n if (!filtered.length) {\n setSelection(\"aggregate\");\n setInstanceData(null);\n setAggRows([]);\n setAggSummary({ available: 0, monitored: 0, missing: 0, total: 0 });\n return;\n }\n if (selection === \"\") {\n // If only 1 instance, select it directly; otherwise use aggregate\n setSelection(filtered.length === 1 ? filtered[0].category : \"aggregate\");\n } else if (\n selection !== \"aggregate\" &&\n !filtered.some((arr) => arr.category === selection)\n ) {\n setSelection(filtered[0].category);\n }\n } catch (error) {\n push(\n error instanceof Error\n ? error.message\n : \"Unable to load Radarr instances\",\n \"error\"\n );\n }\n }, [push, selection]);\n\n const preloadRemainingPages = useCallback(\n async (\n category: string,\n query: string,\n pageSize: number,\n pages: number[],\n key: string\n ) => {\n if (!pages.length) return;\n try {\n const results: { page: number; movies: RadarrMovie[] }[] = [];\n for (const pg of pages) {\n const res = await getRadarrMovies(category, pg, pageSize, query);\n const resolved = res.page ?? pg;\n results.push({ page: resolved, movies: res.movies ?? [] });\n if (instanceKeyRef.current !== key) {\n return;\n }\n }\n if (instanceKeyRef.current !== key) return;\n\n // Smart diffing: only update pages that actually changed\n setInstancePages((prev) => {\n const next = { ...prev };\n let hasChanges = false;\n for (const { page, movies } of results) {\n // Use hash-based comparison for each page\n const syncResult = instanceMovieSync.syncData(movies);\n if (syncResult.hasChanges) {\n next[page] = syncResult.data;\n hasChanges = true;\n }\n }\n instancePagesRef.current = next;\n return hasChanges ? next : prev;\n });\n } catch (error) {\n push(\n error instanceof Error\n ? error.message\n : `Failed to load additional pages for ${category}`,\n \"error\"\n );\n }\n },\n [push]\n );\n\n const fetchInstance = useCallback(\n async (\n category: string,\n page: number,\n query: string,\n options: { preloadAll?: boolean; showLoading?: boolean } = {}\n ) => {\n const preloadAll = options.preloadAll !== false;\n const showLoading = options.showLoading ?? true;\n if (showLoading) {\n setInstanceLoading(true);\n }\n try {\n const key = `${category}::${query}`;\n const keyChanged = instanceKeyRef.current !== key;\n if (keyChanged) {\n instanceKeyRef.current = key;\n setInstancePages(() => {\n instancePagesRef.current = {};\n return {};\n });\n }\n const response = await getRadarrMovies(\n category,\n page,\n RADARR_PAGE_SIZE,\n query\n );\n setInstanceData(response);\n const resolvedPage = response.page ?? page;\n setInstancePage(resolvedPage);\n setInstanceQuery(query);\n const pageSize = response.page_size ?? RADARR_PAGE_SIZE;\n const totalItems = response.total ?? (response.movies ?? []).length;\n const totalPages = Math.max(1, Math.ceil((totalItems || 0) / pageSize));\n setInstancePageSize(pageSize);\n setInstanceTotalPages(totalPages);\n const movies = response.movies ?? [];\n const existingPages = keyChanged ? {} : instancePagesRef.current;\n\n // Smart diffing using hash-based change detection\n const syncResult = instanceMovieSync.syncData(movies);\n const moviesChanged = syncResult.hasChanges;\n\n if (keyChanged) {\n // Reset sync state on key change\n instanceMovieSync.reset();\n }\n\n if (keyChanged || moviesChanged) {\n setInstancePages((prev) => {\n const base = keyChanged ? {} : prev;\n const next = { ...base, [resolvedPage]: syncResult.data };\n instancePagesRef.current = next;\n return next;\n });\n setLastUpdated(new Date().toLocaleTimeString());\n }\n\n if (preloadAll) {\n const pagesToFetch: number[] = [];\n for (let i = 0; i < totalPages; i += 1) {\n if (i === resolvedPage) continue;\n if (!existingPages[i]) {\n pagesToFetch.push(i);\n }\n }\n void preloadRemainingPages(\n category,\n query,\n pageSize,\n pagesToFetch,\n key\n );\n }\n } catch (error) {\n push(\n error instanceof Error\n ? error.message\n : `Failed to load ${category} movies`,\n \"error\"\n );\n } finally {\n setInstanceLoading(false);\n }\n },\n [push, preloadRemainingPages]\n );\n\n const loadAggregate = useCallback(async (options?: { showLoading?: boolean }) => {\n if (!instances.length) {\n setAggRows([]);\n setAggSummary({ available: 0, monitored: 0, missing: 0, total: 0 });\n return;\n }\n const showLoading = options?.showLoading ?? true;\n if (showLoading) {\n setAggLoading(true);\n }\n try {\n const aggregated: RadarrAggRow[] = [];\n let totalAvailable = 0;\n let totalMonitored = 0;\n for (const inst of instances) {\n let page = 0;\n let counted = false;\n const label = inst.name || inst.category;\n while (page < 100) {\n const res = await getRadarrMovies(\n inst.category,\n page,\n RADARR_AGG_FETCH_SIZE,\n \"\"\n );\n if (!counted) {\n const counts = res.counts;\n if (counts) {\n totalAvailable += counts.available ?? 0;\n totalMonitored += counts.monitored ?? 0;\n }\n counted = true;\n }\n const movies = res.movies ?? [];\n movies.forEach((movie) => {\n aggregated.push({ ...movie, __instance: label });\n });\n if (!movies.length || movies.length < RADARR_AGG_FETCH_SIZE) break;\n page += 1;\n }\n }\n\n // Smart diffing using hash-based change detection\n const syncResult = aggMovieSync.syncData(aggregated);\n const rowsChanged = syncResult.hasChanges;\n\n if (rowsChanged) {\n setAggRows(syncResult.data);\n }\n\n const newSummary = {\n available: totalAvailable,\n monitored: totalMonitored,\n missing: aggregated.length - totalAvailable,\n total: aggregated.length,\n };\n\n const summaryChanged = (\n aggSummary.available !== newSummary.available ||\n aggSummary.monitored !== newSummary.monitored ||\n aggSummary.missing !== newSummary.missing ||\n aggSummary.total !== newSummary.total\n );\n\n if (summaryChanged) {\n setAggSummary(newSummary);\n }\n\n // Only reset page if filter changed, not on refresh\n if (aggFilter !== globalSearch) {\n setAggPage(0);\n setAggFilter(globalSearch);\n }\n\n // Only update timestamp if data actually changed\n if (rowsChanged || summaryChanged) {\n setAggUpdated(new Date().toLocaleTimeString());\n }\n } catch (error) {\n setAggRows([]);\n setAggSummary({ available: 0, monitored: 0, missing: 0, total: 0 });\n push(\n error instanceof Error\n ? error.message\n : \"Failed to load aggregated Radarr data\",\n \"error\"\n );\n } finally {\n setAggLoading(false);\n }\n }, [instances, globalSearch, push, aggFilter]);\n\n // LiveArr is now loaded via WebUIContext, no need to load config here\n\n useEffect(() => {\n if (!active) return;\n void loadInstances();\n }, [active, loadInstances]);\n\n useEffect(() => {\n if (!active) return;\n if (!selection || selection === \"aggregate\") return;\n instancePagesRef.current = {};\n setInstancePages({});\n setInstanceTotalPages(1);\n setInstancePage(0);\n const query = globalSearchRef.current;\n void fetchInstance(selection, 0, query, {\n preloadAll: true,\n showLoading: true,\n });\n }, [active, selection, fetchInstance]); // Removed onlyMissing to prevent refresh\n\n useEffect(() => {\n if (!active) return;\n if (selection !== \"aggregate\") return;\n void loadAggregate();\n }, [active, selection, loadAggregate]);\n\n useInterval(() => {\n if (selection === \"aggregate\" && liveArr) {\n void loadAggregate({ showLoading: false });\n }\n }, selection === \"aggregate\" && liveArr ? 1000 : null);\n\n useEffect(() => {\n if (!active) return;\n const handler = (term: string) => {\n if (selection === \"aggregate\") {\n setAggFilter(term);\n setAggPage(0);\n } else if (selection) {\n setInstancePage(0);\n void fetchInstance(selection, 0, term, {\n preloadAll: true,\n showLoading: true,\n });\n }\n };\n register(handler);\n return () => {\n clearHandler(handler);\n };\n }, [active, selection, register, clearHandler, fetchInstance]);\n\n useInterval(\n () => {\n if (selection && selection !== \"aggregate\") {\n const activeFilter = globalSearchRef.current?.trim?.() || \"\";\n if (activeFilter) {\n return;\n }\n void fetchInstance(selection, instancePage, instanceQuery, {\n preloadAll: false,\n showLoading: false,\n });\n }\n },\n active && selection && selection !== \"aggregate\" && liveArr ? 1000 : null\n );\n\n // Removed: Don't reset page when filter changes - preserve scroll position\n\n useEffect(() => {\n globalSearchRef.current = globalSearch;\n }, [globalSearch]);\n\n useEffect(() => {\n if (selection === \"aggregate\") {\n setAggFilter(globalSearch);\n }\n }, [selection, globalSearch]);\n\n const filteredAggRows = useMemo(() => {\n let rows = aggRows;\n if (aggFilter) {\n const q = aggFilter.toLowerCase();\n rows = rows.filter((row) => {\n const title = (row.title ?? \"\").toString().toLowerCase();\n const instance = (row.__instance ?? \"\").toLowerCase();\n return title.includes(q) || instance.includes(q);\n });\n }\n if (onlyMissing) {\n rows = rows.filter((row) => !row.hasFile);\n }\n if (reasonFilter !== \"all\") {\n if (reasonFilter === \"Not being searched\") {\n rows = rows.filter((row) => row.reason === \"Not being searched\" || !row.reason);\n } else {\n rows = rows.filter((row) => row.reason === reasonFilter);\n }\n }\n return rows;\n }, [aggRows, aggFilter, onlyMissing, reasonFilter]);\n\n const isAggFiltered = Boolean(aggFilter) || reasonFilter !== \"all\";\n\n const sortedAggRows = useMemo(() => {\n const list = [...filteredAggRows];\n const getValue = (row: RadarrAggRow, key: RadarrAggSortKey) => {\n switch (key) {\n case \"__instance\":\n return (row.__instance || \"\").toLowerCase();\n case \"title\":\n return (row.title || \"\").toLowerCase();\n case \"year\":\n return row.year ?? 0;\n case \"monitored\":\n return row.monitored ? 1 : 0;\n case \"hasFile\":\n return row.hasFile ? 1 : 0;\n default:\n return \"\";\n }\n };\n list.sort((a, b) => {\n const valueA = getValue(a, aggSort.key);\n const valueB = getValue(b, aggSort.key);\n let comparison = 0;\n if (typeof valueA === \"number\" && typeof valueB === \"number\") {\n comparison = valueA - valueB;\n } else if (typeof valueA === \"string\" && typeof valueB === \"string\") {\n comparison = valueA.localeCompare(valueB);\n } else {\n comparison = String(valueA).localeCompare(String(valueB));\n }\n return aggSort.direction === \"asc\" ? comparison : -comparison;\n });\n return list;\n }, [filteredAggRows, aggSort]);\n\n const aggPages = Math.max(\n 1,\n Math.ceil(sortedAggRows.length / RADARR_AGG_PAGE_SIZE)\n );\n const aggPageRows = useMemo(\n () => sortedAggRows.slice(\n aggPage * RADARR_AGG_PAGE_SIZE,\n aggPage * RADARR_AGG_PAGE_SIZE + RADARR_AGG_PAGE_SIZE\n ),\n [sortedAggRows, aggPage]\n );\n\n const allInstanceMovies = useMemo(() => {\n const pages = Object.keys(instancePages)\n .map(Number)\n .sort((a, b) => a - b);\n const rows: RadarrMovie[] = [];\n pages.forEach((pg) => {\n if (instancePages[pg]) {\n rows.push(...instancePages[pg]);\n }\n });\n return rows;\n }, [instancePages]);\n\n const handleRestart = useCallback(async () => {\n if (!selection || selection === \"aggregate\") return;\n try {\n await restartArr(selection);\n push(`Restarted ${selection}`, \"success\");\n } catch (error) {\n push(\n error instanceof Error ? error.message : `Failed to restart ${selection}`,\n \"error\"\n );\n }\n }, [selection, push]);\n\n const handleAggRefresh = useCallback(() => {\n void loadAggregate({ showLoading: true });\n }, [loadAggregate]);\n\n const handleAggSort = useCallback((key: RadarrAggSortKey) => {\n setAggSort((prev) =>\n prev.key === key\n ? {\n key,\n direction: prev.direction === \"asc\" ? \"desc\" : \"asc\",\n }\n : { key, direction: \"asc\" }\n );\n }, []);\n\n const handleInstanceRefresh = useCallback(() => {\n if (selection && selection !== \"aggregate\") {\n void fetchInstance(selection, instancePage, instanceQuery, {\n preloadAll: false,\n showLoading: true,\n });\n }\n }, [selection, instancePage, instanceQuery, fetchInstance]);\n\n const handleInstanceSelection = useCallback(\n (event: ChangeEvent<HTMLSelectElement>) => {\n const next = (event.target.value || \"aggregate\") as string | \"aggregate\";\n setSelection(next);\n if (next !== \"aggregate\") {\n setGlobalSearch(\"\");\n }\n },\n [setSelection, setGlobalSearch]\n );\n\n const isAggregate = selection === \"aggregate\";\n\n return (\n <section className=\"card\">\n <div className=\"card-header\">Radarr</div>\n <div className=\"card-body\">\n <div className=\"split\">\n <aside className=\"pane sidebar\">\n {instances.length > 1 && (\n <button\n className={`btn ${isAggregate ? \"active\" : \"\"}`}\n onClick={() => setSelection(\"aggregate\")}\n >\n All Radarr\n </button>\n )}\n {instances.map((inst) => (\n <button\n key={inst.category}\n className={`btn ghost ${\n selection === inst.category ? \"active\" : \"\"\n }`}\n onClick={() => {\n setSelection(inst.category);\n setGlobalSearch(\"\");\n }}\n >\n {inst.name || inst.category}\n </button>\n ))}\n </aside>\n <div className=\"pane\">\n <div className=\"field mobile-instance-select\">\n <label>Instance</label>\n <select\n value={selection || \"aggregate\"}\n onChange={handleInstanceSelection}\n disabled={!instances.length}\n >\n {instances.length > 1 && <option value=\"aggregate\">All Radarr</option>}\n {instances.map((inst) => (\n <option key={inst.category} value={inst.category}>\n {inst.name || inst.category}\n </option>\n ))}\n </select>\n </div>\n <div className=\"row\" style={{ alignItems: \"flex-end\", gap: \"12px\", flexWrap: \"wrap\" }}>\n <div className=\"col field\" style={{ flex: \"1 1 200px\" }}>\n <label>Search</label>\n <input\n placeholder=\"Filter movies\"\n value={globalSearch}\n onChange={(event) => setGlobalSearch(event.target.value)}\n />\n </div>\n <div className=\"field\" style={{ flex: \"0 0 auto\", minWidth: \"140px\" }}>\n <label>Status</label>\n <select\n onChange={(event) => {\n const value = event.target.value;\n setOnlyMissing(value === \"missing\");\n }}\n value={onlyMissing ? \"missing\" : \"all\"}\n >\n <option value=\"all\">All Movies</option>\n <option value=\"missing\">Missing Only</option>\n </select>\n </div>\n <div className=\"field\" style={{ flex: \"0 0 auto\", minWidth: \"140px\" }}>\n <label>Search Reason</label>\n <select\n onChange={(event) => setReasonFilter(event.target.value)}\n value={reasonFilter}\n >\n <option value=\"all\">All Reasons</option>\n <option value=\"Not being searched\">Not Being Searched</option>\n <option value=\"Missing\">Missing</option>\n <option value=\"Quality\">Quality</option>\n <option value=\"CustomFormat\">Custom Format</option>\n <option value=\"Upgrade\">Upgrade</option>\n </select>\n </div>\n </div>\n\n {isAggregate ? (\n <RadarrAggregateView\n loading={aggLoading}\n rows={aggPageRows}\n total={sortedAggRows.length}\n page={aggPage}\n totalPages={aggPages}\n onPageChange={setAggPage}\n onRefresh={handleAggRefresh}\n lastUpdated={aggUpdated}\n sort={aggSort}\n onSort={handleAggSort}\n summary={aggSummary}\n instanceCount={instances.length}\n isAggFiltered={isAggFiltered}\n />\n ) : (\n <RadarrInstanceView\n loading={instanceLoading}\n data={instanceData}\n page={instancePage}\n totalPages={instanceTotalPages}\n pageSize={instancePageSize}\n allMovies={allInstanceMovies}\n onlyMissing={onlyMissing}\n reasonFilter={reasonFilter}\n onPageChange={(page) => {\n setInstancePage(page);\n void fetchInstance(selection as string, page, instanceQuery, {\n preloadAll: true,\n });\n }}\n onRefresh={handleInstanceRefresh}\n onRestart={() => void handleRestart()}\n lastUpdated={lastUpdated}\n />\n )}\n </div>\n </div>\n </div>\n </section>\n );\n}\n","import {\n memo,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ChangeEvent,\n type JSX,\n} from \"react\";\nimport {\n getArrList,\n getSonarrSeries,\n restartArr,\n} from \"../api/client\";\nimport { StableTable } from \"../components/StableTable\";\nimport {\n useReactTable,\n getCoreRowModel,\n getSortedRowModel,\n getPaginationRowModel,\n getExpandedRowModel,\n flexRender,\n type ColumnDef,\n} from \"@tanstack/react-table\";\nimport type {\n ArrInfo,\n SonarrEpisode,\n SonarrSeriesEntry,\n SonarrSeriesResponse,\n SonarrSeason,\n} from \"../api/types\";\nimport { useToast } from \"../context/ToastContext\";\nimport { useSearch } from \"../context/SearchContext\";\nimport { useWebUI } from \"../context/WebUIContext\";\nimport { useInterval } from \"../hooks/useInterval\";\nimport { useDataSync } from \"../hooks/useDataSync\";\nimport { IconImage } from \"../components/IconImage\";\nimport RefreshIcon from \"../icons/refresh-arrow.svg\";\n\ninterface SonarrViewProps {\n active: boolean;\n}\n\ninterface SonarrAggRow {\n __instance: string;\n series: string;\n season: number | string;\n episode: number | string;\n title: string;\n monitored: boolean;\n hasFile: boolean;\n airDate: string;\n reason?: string | null;\n qualityProfileId?: number | null;\n qualityProfileName?: string | null;\n [key: string]: unknown;\n}\n\nconst SONARR_PAGE_SIZE = 25;\nconst SONARR_AGG_PAGE_SIZE = 50;\nconst SONARR_AGG_FETCH_SIZE = 200;\n\nfunction filterSeriesEntriesForMissing(seriesEntries: SonarrSeriesEntry[], onlyMissing: boolean): SonarrSeriesEntry[] {\n if (!onlyMissing) return seriesEntries;\n const result: SonarrSeriesEntry[] = [];\n for (const entry of seriesEntries) {\n const seasons = entry.seasons ?? {};\n const filteredSeasons: Record<string, SonarrSeason> = {};\n for (const [seasonNumber, season] of Object.entries(seasons)) {\n const episodes = (season.episodes ?? []).filter((episode) => !episode.hasFile);\n if (!episodes.length) continue;\n filteredSeasons[seasonNumber] = { ...season, episodes };\n }\n if (Object.keys(filteredSeasons).length === 0) continue;\n result.push({\n ...entry,\n seasons: filteredSeasons,\n });\n }\n return result;\n}\n\nfunction createFilteredSignature(seriesEntries: SonarrSeriesEntry[], onlyMissing: boolean): string {\n return JSON.stringify(filterSeriesEntriesForMissing(seriesEntries, onlyMissing));\n}\n\nexport function SonarrView({ active }: SonarrViewProps): JSX.Element {\n const { push } = useToast();\n const {\n value: globalSearch,\n setValue: setGlobalSearch,\n register,\n clearHandler,\n } = useSearch();\n const { liveArr, setLiveArr, groupSonarr, setGroupSonarr } = useWebUI();\n\n const [instances, setInstances] = useState<ArrInfo[]>([]);\n const [selection, setSelection] = useState<string | \"\">(\"\");\n const [instanceData, setInstanceData] =\n useState<SonarrSeriesResponse | null>(null);\n const [instancePage, setInstancePage] = useState(0);\n const [instanceQuery, setInstanceQuery] = useState(\"\");\n const [instanceLoading, setInstanceLoading] = useState(false);\n const [lastUpdated, setLastUpdated] = useState<string | null>(null);\n const [instancePages, setInstancePages] = useState<\n Record<number, SonarrSeriesEntry[]>\n >({});\n const instancePagesRef = useRef<Record<number, SonarrSeriesEntry[]>>({});\n const instanceDataRef = useRef<SonarrSeriesResponse | null>(null);\n const instanceKeyRef = useRef<string>(\"\");\n const [instancePageSize, setInstancePageSize] = useState(SONARR_PAGE_SIZE);\n const [instanceTotalPages, setInstanceTotalPages] = useState(1);\n const [instanceTotalItems, setInstanceTotalItems] = useState(0);\n const globalSearchRef = useRef(globalSearch);\n const backendReadyWarnedRef = useRef(false);\n const prevSelectionRef = useRef<string | \"\">(selection);\n\n const [aggRows, setAggRows] = useState<SonarrAggRow[]>([]);\n const [aggLoading, setAggLoading] = useState(false);\n const [aggPage, setAggPage] = useState(0);\n const [aggFilter, setAggFilter] = useState(\"\");\n const [aggUpdated, setAggUpdated] = useState<string | null>(null);\n\n // Smart data sync for aggregate episodes\n const aggEpisodeSync = useDataSync<SonarrAggRow>({\n getKey: (ep) => `${ep.__instance}-${ep.series}-${ep.season}-${ep.episode}`,\n hashFields: ['__instance', 'series', 'season', 'episode', 'title', 'hasFile', 'monitored', 'airDate', 'reason', 'qualityProfileId', 'qualityProfileName'],\n });\n\n const [onlyMissing, setOnlyMissing] = useState(false);\n const prevOnlyMissingRef = useRef(onlyMissing);\n const [reasonFilter, setReasonFilter] = useState<string>(\"all\");\n const [aggSummary, setAggSummary] = useState<{\n available: number;\n monitored: number;\n missing: number;\n total: number;\n }>({ available: 0, monitored: 0, missing: 0, total: 0 });\n\n // LiveArr and GroupSonarr are now loaded via WebUIContext, no need to load config here\n\n const loadInstances = useCallback(async () => {\n try {\n const data = await getArrList();\n if (data.ready === false && !backendReadyWarnedRef.current) {\n backendReadyWarnedRef.current = true;\n push(\"Sonarr backend is still initialising. Check the logs if this persists.\", \"info\");\n } else if (data.ready) {\n backendReadyWarnedRef.current = true;\n }\n const filtered = (data.arr || []).filter((arr) => arr.type === \"sonarr\");\n setInstances(filtered);\n if (!filtered.length) {\n setSelection(\"aggregate\");\n setInstanceData(null);\n setAggRows([]);\n setAggSummary({ available: 0, monitored: 0, missing: 0, total: 0 });\n return;\n }\n if (selection === \"\") {\n // If only 1 instance, select it directly; otherwise use aggregate\n setSelection(filtered.length === 1 ? filtered[0].category : \"aggregate\");\n } else if (\n selection !== \"aggregate\" &&\n !filtered.some((arr) => arr.category === selection)\n ) {\n setSelection(filtered[0].category);\n }\n } catch (error) {\n push(\n error instanceof Error\n ? error.message\n : \"Unable to load Sonarr instances\",\n \"error\"\n );\n }\n }, [push, selection]);\n\n const fetchInstance = useCallback(\n async (\n category: string,\n page: number,\n query: string,\n options: { preloadAll?: boolean; showLoading?: boolean; missingOnly?: boolean } = {}\n ) => {\n const { preloadAll = true, showLoading = true, missingOnly } = options;\n const useMissing = missingOnly ?? onlyMissing;\n if (showLoading) {\n setInstanceLoading(true);\n }\n try {\n const key = `${category}::${query}::${useMissing ? \"missing\" : \"all\"}`;\n const keyChanged = instanceKeyRef.current !== key;\n if (keyChanged) {\n instanceKeyRef.current = key;\n setInstancePages(() => {\n instancePagesRef.current = {};\n return {};\n });\n setInstanceTotalItems(0);\n setInstanceTotalPages(1);\n }\n const response = await getSonarrSeries(\n category,\n page,\n SONARR_PAGE_SIZE,\n query,\n { missingOnly: useMissing }\n );\n console.log(`[Sonarr Instance] Response for ${category} page ${page}:`, {\n total: response.total,\n page: response.page,\n page_size: response.page_size,\n series_count: response.series?.length ?? 0,\n counts: response.counts,\n missingOnly: useMissing,\n firstSeries: response.series?.[0] ? {\n title: response.series[0].series?.title,\n seasonsCount: Object.keys(response.series[0].seasons ?? {}).length,\n firstSeasonEpisodes: Object.values(response.series[0].seasons ?? {})[0]?.episodes?.length ?? 0\n } : null\n });\n const resolvedPage = response.page ?? page;\n const pageSize = response.page_size ?? SONARR_PAGE_SIZE;\n const totalItems = response.total ?? (response.series ?? []).length;\n const totalPages = Math.max(1, Math.ceil((totalItems || 0) / pageSize));\n const series = response.series ?? [];\n\n const prevPages = keyChanged ? {} : instancePagesRef.current;\n const nextPages = { ...prevPages, [resolvedPage]: series };\n const prevSignature = createFilteredSignature(prevPages[resolvedPage] ?? [], useMissing);\n const nextSignature = createFilteredSignature(series, useMissing);\n const shouldUpdateCurrentPage = keyChanged || prevSignature !== nextSignature;\n\n instancePagesRef.current = nextPages;\n if (shouldUpdateCurrentPage) {\n setInstancePages(nextPages);\n }\n\n setInstanceData((prev) => {\n const prevCounts = prev?.counts ?? null;\n const nextCounts = response.counts ?? null;\n const countsChanged =\n !prev ||\n prev.total !== response.total ||\n prev.page !== response.page ||\n prev.page_size !== response.page_size ||\n (prevCounts?.available ?? null) !== (nextCounts?.available ?? null) ||\n (prevCounts?.monitored ?? null) !== (nextCounts?.monitored ?? null) ||\n (prevCounts?.missing ?? null) !== (nextCounts?.missing ?? null);\n if (countsChanged || shouldUpdateCurrentPage) {\n instanceDataRef.current = response;\n return response;\n }\n return prev;\n });\n\n setInstancePage((prev) => (prev === resolvedPage ? prev : resolvedPage));\n setInstanceQuery((prev) => (prev === query ? prev : query));\n setInstancePageSize((prev) => (prev === pageSize ? prev : pageSize));\n setInstanceTotalPages((prev) => (prev === totalPages ? prev : totalPages));\n setInstanceTotalItems((prev) => (prev === totalItems ? prev : totalItems));\n\n if (shouldUpdateCurrentPage) {\n setLastUpdated(new Date().toLocaleTimeString());\n }\n\n if (preloadAll) {\n const pagesToFetch: number[] = [];\n for (let i = 0; i < totalPages; i += 1) {\n if (i === resolvedPage) continue;\n if (!nextPages[i]) {\n pagesToFetch.push(i);\n }\n }\n for (const targetPage of pagesToFetch) {\n try {\n const res = await getSonarrSeries(\n category,\n targetPage,\n pageSize,\n query,\n { missingOnly: useMissing }\n );\n if (instanceKeyRef.current !== key) {\n break;\n }\n const pageIndex = res.page ?? targetPage;\n const pageSeries = res.series ?? [];\n const currentPages = instancePagesRef.current;\n const prevSnapshot = createFilteredSignature(currentPages[pageIndex] ?? [], useMissing);\n const nextSnapshot = createFilteredSignature(pageSeries, useMissing);\n if (prevSnapshot === nextSnapshot) {\n instancePagesRef.current = { ...currentPages, [pageIndex]: pageSeries };\n continue;\n }\n setInstancePages((prev) => {\n const updated = { ...prev, [pageIndex]: pageSeries };\n instancePagesRef.current = updated;\n return updated;\n });\n } catch {\n break;\n }\n }\n }\n } catch (error) {\n push(\n error instanceof Error\n ? error.message\n : `Failed to load ${category} series`,\n \"error\"\n );\n } finally {\n if (showLoading) {\n setInstanceLoading(false);\n }\n }\n },\n [push, onlyMissing]\n );\n\n const loadAggregate = useCallback(async (options?: { showLoading?: boolean }) => {\n if (!instances.length) {\n setAggRows([]);\n setAggSummary({ available: 0, monitored: 0, missing: 0, total: 0 });\n return;\n }\n console.log(`[Sonarr Aggregate] Starting aggregation for ${instances.length} instances`);\n const showLoading = options?.showLoading ?? true;\n if (showLoading) {\n setAggLoading(true);\n }\n try {\n const aggregated: SonarrAggRow[] = [];\n let totalAvailable = 0;\n let totalMonitored = 0;\n let totalMissing = 0;\n for (const inst of instances) {\n let page = 0;\n let counted = false;\n const label = inst.name || inst.category;\n console.log(`[Sonarr Aggregate] Processing instance: ${label}`);\n while (page < 200) {\n const res = await getSonarrSeries(\n inst.category,\n page,\n SONARR_AGG_FETCH_SIZE,\n \"\",\n { missingOnly: onlyMissing }\n );\n console.log(`[Sonarr Aggregate] Response for ${label} page ${page}:`, {\n total: res.total,\n page: res.page,\n page_size: res.page_size,\n series_count: res.series?.length ?? 0,\n counts: res.counts,\n missingOnly: onlyMissing,\n firstSeries: res.series?.[0] ? {\n title: res.series[0].series?.title,\n seasonsCount: Object.keys(res.series[0].seasons ?? {}).length,\n firstSeasonEpisodes: Object.values(res.series[0].seasons ?? {})[0]?.episodes?.length ?? 0,\n firstEpisode: Object.values(res.series[0].seasons ?? {})[0]?.episodes?.[0]\n } : null\n });\n if (!counted) {\n const counts = res.counts;\n if (counts) {\n totalAvailable += counts.available ?? 0;\n totalMonitored += counts.monitored ?? 0;\n totalMissing += counts.missing ?? 0;\n }\n counted = true;\n }\n const series = res.series ?? [];\n let episodeCount = 0;\n series.forEach((entry: SonarrSeriesEntry) => {\n const seasonCount = Object.keys(entry.seasons ?? {}).length;\n let entryEpisodeCount = 0;\n Object.values(entry.seasons ?? {}).forEach(season => {\n entryEpisodeCount += (season.episodes ?? []).length;\n });\n episodeCount += entryEpisodeCount;\n });\n console.log(`[Sonarr Aggregate] Instance: ${label}, Page: ${page}, Series count: ${series.length}, Total episodes so far: ${aggregated.length}, Episodes in this response: ${episodeCount}`);\n series.forEach((entry: SonarrSeriesEntry) => {\n const title =\n (entry.series?.[\"title\"] as string | undefined) || \"\";\n const qualityProfileId = entry.series?.qualityProfileId ?? null;\n const qualityProfileName = entry.series?.qualityProfileName ?? null;\n Object.entries(entry.seasons ?? {}).forEach(\n ([seasonNumber, season]) => {\n (season.episodes ?? []).forEach((episode: SonarrEpisode) => {\n const episodeReason = (episode.reason as string | null | undefined) ?? null;\n aggregated.push({\n __instance: label,\n series: title,\n season: seasonNumber,\n episode: episode.episodeNumber ?? \"\",\n title: episode.title ?? \"\",\n monitored: !!episode.monitored,\n hasFile: !!episode.hasFile,\n airDate: episode.airDateUtc ?? \"\",\n reason: episodeReason,\n qualityProfileId,\n qualityProfileName,\n });\n });\n }\n );\n });\n if (!series.length || series.length < SONARR_AGG_FETCH_SIZE) {\n console.log(`[Sonarr Aggregate] Breaking pagination for ${label} - series.length=${series.length}`);\n break;\n }\n page += 1;\n }\n }\n\n // Smart diffing using hash-based change detection\n const syncResult = aggEpisodeSync.syncData(aggregated);\n const rowsChanged = syncResult.hasChanges;\n\n // Debug: Check what reason values we have\n const reasonCounts = new Map<string, number>();\n aggregated.forEach(ep => {\n const r = ep.reason || \"null/empty\";\n reasonCounts.set(r, (reasonCounts.get(r) || 0) + 1);\n });\n console.log(`[Sonarr Aggregate] Reason distribution:`, Object.fromEntries(reasonCounts));\n\n if (rowsChanged) {\n console.log(`[Sonarr Aggregate] Data changed, updating from ${aggRows.length} to ${aggregated.length} episodes`);\n setAggRows(syncResult.data);\n } else {\n console.log(`[Sonarr Aggregate] Data unchanged, skipping update`);\n }\n\n const newSummary = {\n available: totalAvailable,\n monitored: totalMonitored,\n missing: totalMissing,\n total: aggregated.length,\n };\n\n const summaryChanged = (\n aggSummary.available !== newSummary.available ||\n aggSummary.monitored !== newSummary.monitored ||\n aggSummary.missing !== newSummary.missing ||\n aggSummary.total !== newSummary.total\n );\n\n if (summaryChanged) {\n setAggSummary(newSummary);\n }\n\n // Only reset page if filter changed, not on refresh\n if (aggFilter !== globalSearch) {\n setAggPage(0);\n setAggFilter(globalSearch);\n }\n\n // Only update timestamp if data actually changed\n if (rowsChanged || summaryChanged) {\n setAggUpdated(new Date().toLocaleTimeString());\n }\n } catch (error) {\n setAggRows([]);\n setAggSummary({ available: 0, monitored: 0, missing: 0, total: 0 });\n push(\n error instanceof Error\n ? error.message\n : \"Failed to load aggregated Sonarr data\",\n \"error\"\n );\n } finally {\n setAggLoading(false);\n }\n }, [instances, globalSearch, push, onlyMissing, aggFilter]);\n\n useEffect(() => {\n if (!active) return;\n void loadInstances();\n }, [active, loadInstances]);\n\n useEffect(() => {\n if (!active) return;\n if (!selection || selection === \"aggregate\") return;\n\n const selectionChanged = prevSelectionRef.current !== selection;\n const onlyMissingChanged = prevOnlyMissingRef.current !== onlyMissing;\n\n // Reset page only when selection changes, not when filters change\n if (selectionChanged) {\n setInstancePage(0);\n prevSelectionRef.current = selection;\n }\n\n // Update ref for next comparison\n if (onlyMissingChanged) {\n prevOnlyMissingRef.current = onlyMissing;\n }\n\n // Fetch data: use page 0 if selection changed, current page otherwise\n const query = globalSearchRef.current;\n void fetchInstance(selection, selectionChanged ? 0 : instancePage, query, {\n preloadAll: true,\n showLoading: true,\n missingOnly: onlyMissing,\n });\n }, [active, selection, onlyMissing, fetchInstance, instancePage]);\n\n useEffect(() => {\n if (!active) return;\n if (selection !== \"aggregate\") return;\n void loadAggregate();\n }, [active, selection, loadAggregate]);\n\n useInterval(() => {\n if (selection === \"aggregate\" && liveArr) {\n void loadAggregate({ showLoading: false });\n }\n }, selection === \"aggregate\" && liveArr ? 1000 : null);\n\n useEffect(() => {\n if (!active) return;\n const handler = (term: string) => {\n if (selection === \"aggregate\") {\n setAggFilter(term);\n setAggPage(0);\n } else if (selection) {\n setInstancePage(0);\n void fetchInstance(selection, 0, term, {\n preloadAll: true,\n showLoading: true,\n missingOnly: onlyMissing,\n });\n }\n };\n register(handler);\n return () => clearHandler(handler);\n }, [active, selection, register, clearHandler, fetchInstance, onlyMissing]);\n\n useInterval(\n () => {\n if (selection && selection !== \"aggregate\") {\n const activeFilter = globalSearchRef.current?.trim?.() || \"\";\n if (activeFilter) {\n return;\n }\n void fetchInstance(selection, instancePage, instanceQuery, {\n preloadAll: false,\n showLoading: false,\n missingOnly: onlyMissing,\n });\n }\n },\n active && selection && selection !== \"aggregate\" && liveArr ? 1000 : null\n );\n\n useEffect(() => {\n globalSearchRef.current = globalSearch;\n }, [globalSearch]);\n\n useEffect(() => {\n if (selection === \"aggregate\") {\n setAggFilter(globalSearch);\n }\n }, [selection, globalSearch]);\n\n const filteredAggRows = useMemo(() => {\n let rows = aggRows;\n if (aggFilter) {\n const q = aggFilter.toLowerCase();\n rows = rows.filter((row) => {\n return (\n row.series.toLowerCase().includes(q) ||\n row.title.toLowerCase().includes(q) ||\n row.__instance.toLowerCase().includes(q)\n );\n });\n }\n if (onlyMissing) {\n rows = rows.filter((row) => !row.hasFile);\n }\n if (reasonFilter !== \"all\") {\n console.log(`[Sonarr Filter] Applying reason filter: \"${reasonFilter}\"`);\n const beforeFilterCount = rows.length;\n if (reasonFilter === \"Not being searched\") {\n rows = rows.filter((row) => row.reason === \"Not being searched\" || !row.reason);\n } else {\n rows = rows.filter((row) => row.reason === reasonFilter);\n }\n console.log(`[Sonarr Filter] Filtered from ${beforeFilterCount} to ${rows.length} episodes for reason \"${reasonFilter}\"`);\n if (rows.length < 10) {\n console.log(`[Sonarr Filter] Sample filtered rows:`, rows.slice(0, 5).map(r => ({ series: r.series, episode: r.episode, reason: r.reason })));\n }\n }\n return rows;\n }, [aggRows, aggFilter, onlyMissing, reasonFilter]);\n\n const isAggFiltered = Boolean(aggFilter) || onlyMissing || reasonFilter !== \"all\";\n\n const sortedAggRows = filteredAggRows;\n\n const aggPages = Math.max(\n 1,\n Math.ceil(sortedAggRows.length / SONARR_AGG_PAGE_SIZE)\n );\n const aggPageRows = useMemo(\n () => sortedAggRows.slice(\n aggPage * SONARR_AGG_PAGE_SIZE,\n aggPage * SONARR_AGG_PAGE_SIZE + SONARR_AGG_PAGE_SIZE\n ),\n [sortedAggRows, aggPage]\n );\n\n const currentSeries = instancePages[instancePage] ?? [];\n\n const allSeries = useMemo(() => {\n const pages = Object.keys(instancePages)\n .map(Number)\n .sort((a, b) => a - b);\n const rows: SonarrSeriesEntry[] = [];\n pages.forEach((pg) => {\n if (instancePages[pg]) {\n rows.push(...instancePages[pg]);\n }\n });\n return rows;\n }, [instancePages]);\n\n const handleRestart = useCallback(async () => {\n if (!selection || selection === \"aggregate\") return;\n try {\n await restartArr(selection);\n push(`Restarted ${selection}`, \"success\");\n } catch (error) {\n push(\n error instanceof Error ? error.message : `Failed to restart ${selection}`,\n \"error\"\n );\n }\n }, [selection, push]);\n\n const handleInstanceSelection = useCallback(\n (event: ChangeEvent<HTMLSelectElement>) => {\n const next = (event.target.value || \"aggregate\") as string | \"aggregate\";\n setSelection(next);\n if (next !== \"aggregate\") {\n setGlobalSearch(\"\");\n }\n },\n [setSelection, setGlobalSearch]\n );\n\n const isAggregate = selection === \"aggregate\";\n\n return (\n <section className=\"card\">\n <div className=\"card-header\">Sonarr</div>\n <div className=\"card-body\">\n <div className=\"split\">\n <aside className=\"pane sidebar\">\n {instances.length > 1 && (\n <button\n className={`btn ${isAggregate ? \"active\" : \"\"}`}\n onClick={() => setSelection(\"aggregate\")}\n >\n All Sonarr\n </button>\n )}\n {instances.map((inst) => (\n <button\n key={inst.category}\n className={`btn ghost ${\n selection === inst.category ? \"active\" : \"\"\n }`}\n onClick={() => {\n setSelection(inst.category);\n setGlobalSearch(\"\");\n }}\n >\n {inst.name || inst.category}\n </button>\n ))}\n </aside>\n <div className=\"pane\">\n <div className=\"field mobile-instance-select\">\n <label>Instance</label>\n <select\n value={selection || \"aggregate\"}\n onChange={handleInstanceSelection}\n disabled={!instances.length}\n >\n {instances.length > 1 && <option value=\"aggregate\">All Sonarr</option>}\n {instances.map((inst) => (\n <option key={inst.category} value={inst.category}>\n {inst.name || inst.category}\n </option>\n ))}\n </select>\n </div>\n <div className=\"row\" style={{ alignItems: \"flex-end\", gap: \"12px\", flexWrap: \"wrap\" }}>\n <div className=\"col field\" style={{ flex: \"1 1 200px\" }}>\n <label>Search</label>\n <input\n placeholder=\"Filter series or episodes\"\n value={globalSearch}\n onChange={(event) => setGlobalSearch(event.target.value)}\n />\n </div>\n <div className=\"field\" style={{ flex: \"0 0 auto\", minWidth: \"140px\" }}>\n <label>Status</label>\n <select\n onChange={(event) => {\n const value = event.target.value;\n const newMissingState = value === \"missing\";\n setOnlyMissing(newMissingState);\n // Trigger refetch when filter changes for instance views\n if (selection && selection !== \"aggregate\") {\n void fetchInstance(selection, 0, globalSearchRef.current || \"\", {\n preloadAll: true,\n showLoading: true,\n missingOnly: newMissingState,\n });\n }\n }}\n value={onlyMissing ? \"missing\" : \"all\"}\n >\n <option value=\"all\">All Episodes</option>\n <option value=\"missing\">Missing Only</option>\n </select>\n </div>\n <div className=\"field\" style={{ flex: \"0 0 auto\", minWidth: \"140px\" }}>\n <label>Search Reason</label>\n <select\n onChange={(event) => setReasonFilter(event.target.value)}\n value={reasonFilter}\n >\n <option value=\"all\">All Reasons</option>\n <option value=\"Not being searched\">Not Being Searched</option>\n <option value=\"Missing\">Missing</option>\n <option value=\"Quality\">Quality</option>\n <option value=\"CustomFormat\">Custom Format</option>\n <option value=\"Upgrade\">Upgrade</option>\n </select>\n </div>\n </div>\n\n {isAggregate ? (\n <SonarrAggregateView\n loading={aggLoading}\n rows={sortedAggRows}\n total={sortedAggRows.length}\n page={aggPage}\n totalPages={aggPages}\n onPageChange={setAggPage}\n onRefresh={() => void loadAggregate({ showLoading: true })}\n lastUpdated={aggUpdated}\n groupSonarr={groupSonarr}\n summary={aggSummary}\n instanceCount={instances.length}\n isAggFiltered={isAggFiltered}\n />\n ) : (\n <SonarrInstanceView\n loading={instanceLoading}\n counts={instanceData?.counts ?? null}\n series={groupSonarr ? currentSeries : allSeries}\n page={instancePage}\n pageSize={instancePageSize}\n totalPages={instanceTotalPages}\n totalItems={instanceTotalItems}\n onlyMissing={onlyMissing}\n reasonFilter={reasonFilter}\n onPageChange={(page) => {\n setInstancePage(page);\n void fetchInstance(selection as string, page, instanceQuery, {\n preloadAll: false,\n showLoading: true,\n missingOnly: onlyMissing,\n });\n }}\n onRestart={() => void handleRestart()}\n lastUpdated={lastUpdated}\n groupSonarr={groupSonarr}\n instances={instances}\n selection={selection as string}\n />\n )}\n </div>\n </div>\n </div>\n </section>\n );\n}\n\ninterface SonarrAggregateViewProps {\n loading: boolean;\n rows: SonarrAggRow[];\n total: number;\n page: number;\n totalPages: number;\n onPageChange: (page: number) => void;\n onRefresh: () => void;\n lastUpdated: string | null;\n groupSonarr: boolean;\n summary: { available: number; monitored: number; missing: number; total: number };\n instanceCount: number;\n isAggFiltered?: boolean;\n}\n\nfunction SonarrAggregateView({\n loading,\n rows,\n total,\n page,\n totalPages,\n onPageChange,\n onRefresh,\n lastUpdated,\n groupSonarr,\n summary,\n instanceCount,\n isAggFiltered = false,\n}: SonarrAggregateViewProps): JSX.Element {\n const prevRowsRef = useRef<SonarrAggRow[]>([]);\n const groupedDataCache = useRef<Array<{\n instance: string;\n series: string;\n qualityProfileId?: number | null;\n qualityProfileName?: string | null;\n subRows: Array<{\n seasonNumber: string;\n isSeason: boolean;\n subRows: Array<SonarrAggRow & { isEpisode: boolean }>;\n }>;\n }>>([]);\n const seriesGroupCache = useRef<Map<string, {\n instance: string;\n series: string;\n qualityProfileId?: number | null;\n qualityProfileName?: string | null;\n subRows: Array<{\n seasonNumber: string;\n isSeason: boolean;\n subRows: Array<SonarrAggRow & { isEpisode: boolean }>;\n }>;\n episodeKeys: Set<string>;\n }>>(new Map());\n\n // Create fully grouped data from all rows - only rebuild if rows actually changed\n const allGroupedData = useMemo(() => {\n // Quick reference check - if same array reference, return cached\n if (rows === prevRowsRef.current) {\n return groupedDataCache.current;\n }\n\n // Build instance > series > seasons map\n const instanceMap = new Map<string, Map<string, Map<string, SonarrAggRow[]>>>();\n\n rows.forEach(row => {\n const instance = row.__instance;\n const series = row.series;\n const season = String(row.season);\n\n if (!instanceMap.has(instance)) {\n instanceMap.set(instance, new Map());\n }\n const instanceSeriesMap = instanceMap.get(instance)!;\n\n if (!instanceSeriesMap.has(series)) {\n instanceSeriesMap.set(series, new Map());\n }\n const seasonMap = instanceSeriesMap.get(series)!;\n\n if (!seasonMap.has(season)) {\n seasonMap.set(season, []);\n }\n seasonMap.get(season)!.push(row);\n });\n\n const result: Array<{\n instance: string;\n series: string;\n qualityProfileId?: number | null;\n qualityProfileName?: string | null;\n subRows: Array<{\n seasonNumber: string;\n isSeason: boolean;\n subRows: Array<SonarrAggRow & { isEpisode: boolean }>;\n }>;\n }> = [];\n\n const newSeriesGroupCache = new Map<string, {\n instance: string;\n series: string;\n qualityProfileId?: number | null;\n qualityProfileName?: string | null;\n subRows: Array<{\n seasonNumber: string;\n isSeason: boolean;\n subRows: Array<SonarrAggRow & { isEpisode: boolean }>;\n }>;\n episodeKeys: Set<string>;\n }>();\n\n instanceMap.forEach((seriesMap, instance) => {\n seriesMap.forEach((seasonMap, series) => {\n const seriesKey = `${instance}-${series}`;\n\n // Build set of episode keys for this series\n const episodeKeys = new Set<string>();\n seasonMap.forEach((episodes, season) => {\n episodes.forEach(ep => {\n const episodeKey = `${season}-${ep.episode}`;\n episodeKeys.add(episodeKey);\n });\n });\n\n // Check if this series group is in cache and unchanged\n const cached = seriesGroupCache.current.get(seriesKey);\n if (cached && cached.episodeKeys.size === episodeKeys.size) {\n let unchanged = true;\n for (const key of episodeKeys) {\n if (!cached.episodeKeys.has(key)) {\n unchanged = false;\n break;\n }\n }\n if (unchanged) {\n // Reuse cached series group (prevents count flickering)\n result.push(cached);\n newSeriesGroupCache.set(seriesKey, cached);\n return;\n }\n }\n\n // Build new series group\n const firstEpisode = Array.from(seasonMap.values())[0]?.[0];\n console.log(`[Sonarr Grouped] Series: ${series}, QualityProfile: ${firstEpisode?.qualityProfileName}, FirstEpisode:`, firstEpisode);\n const seriesGroup = {\n instance,\n series,\n qualityProfileId: firstEpisode?.qualityProfileId,\n qualityProfileName: firstEpisode?.qualityProfileName,\n subRows: Array.from(seasonMap.entries()).map(([seasonNumber, episodes]) => ({\n seasonNumber,\n isSeason: true,\n subRows: episodes.map(ep => ({ ...ep, isEpisode: true }))\n })),\n episodeKeys,\n };\n result.push(seriesGroup);\n newSeriesGroupCache.set(seriesKey, seriesGroup);\n });\n });\n\n // Update caches\n prevRowsRef.current = rows;\n groupedDataCache.current = result;\n seriesGroupCache.current = newSeriesGroupCache;\n\n return result;\n }, [rows]);\n\n // For grouped view, paginate the series groups (not individual episodes)\n // For flat view, paginate the episode rows\n const groupedPageRows = useMemo(() => {\n const pageSize = 50;\n return allGroupedData.slice(page * pageSize, (page + 1) * pageSize);\n }, [allGroupedData, page]);\n\n const flatPageRows = useMemo(() => {\n const pageSize = 50;\n return rows.slice(page * pageSize, (page + 1) * pageSize);\n }, [rows, page]);\n\n const tableData = groupSonarr ? groupedPageRows : flatPageRows;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const groupedColumns = useMemo<ColumnDef<any>[]>(() => [\n {\n accessorKey: \"title\",\n header: \"Title\",\n cell: ({ row }) => {\n if (row.original.isEpisode) return row.original.title;\n if (row.original.isSeason) return `Season ${row.original.seasonNumber}`;\n // Series row - show series name, instance, and quality profile (like Lidarr)\n const parts = [row.original.series];\n if (row.original.instance) {\n parts.push(`(${row.original.instance})`);\n }\n if (row.original.qualityProfileName) {\n parts.push(`• ${row.original.qualityProfileName}`);\n }\n return parts.join(' ');\n }\n },\n {\n accessorKey: \"monitored\",\n header: \"Monitored\",\n cell: ({ row }) => {\n const monitored = row.original.isEpisode ? row.original.monitored : row.original.monitored;\n return (\n <span className={`track-status ${monitored ? 'available' : 'missing'}`}>\n {monitored ? '✓' : '✗'}\n </span>\n );\n }\n },\n {\n accessorKey: \"hasFile\",\n header: \"Has File\",\n cell: ({ row }) => {\n if (row.original.isEpisode) {\n const hasFile = row.original.hasFile;\n return (\n <span className={`track-status ${hasFile ? 'available' : 'missing'}`}>\n {hasFile ? '✓' : '✗'}\n </span>\n );\n }\n return null;\n }\n },\n {\n accessorKey: \"airDate\",\n header: \"Air Date\",\n cell: ({ row }) => {\n if (row.original.isEpisode) {\n return row.original.airDate || \"—\";\n }\n return null;\n }\n },\n ], []);\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const flatColumns = useMemo<ColumnDef<any>[]>(() => [\n ...(instanceCount > 1 ? [{\n accessorKey: \"__instance\",\n header: \"Instance\",\n }] : []),\n {\n accessorKey: \"series\",\n header: \"Series\",\n },\n {\n accessorKey: \"season\",\n header: \"Season\",\n },\n {\n accessorKey: \"episode\",\n header: \"Episode\",\n },\n {\n accessorKey: \"title\",\n header: \"Title\",\n },\n {\n accessorKey: \"monitored\",\n header: \"Monitored\",\n cell: ({ getValue }) => {\n const monitored = getValue() as boolean;\n return (\n <span className={`track-status ${monitored ? 'available' : 'missing'}`}>\n {monitored ? '✓' : '✗'}\n </span>\n );\n },\n },\n {\n accessorKey: \"hasFile\",\n header: \"Has File\",\n cell: ({ getValue }) => {\n const hasFile = getValue() as boolean;\n return (\n <span className={`track-status ${hasFile ? 'available' : 'missing'}`}>\n {hasFile ? '✓' : '✗'}\n </span>\n );\n },\n },\n {\n accessorKey: \"airDate\",\n header: \"Air Date\",\n cell: ({ getValue }) => getValue() || \"—\",\n },\n {\n accessorKey: \"qualityProfileName\",\n header: \"Quality Profile\",\n cell: ({ getValue }) => {\n const profileName = getValue() as string | null | undefined;\n return profileName || \"—\";\n },\n },\n {\n accessorKey: \"reason\",\n header: \"Reason\",\n cell: ({ getValue }) => {\n const reason = getValue() as string | null | undefined;\n if (!reason) return <span className=\"table-badge table-badge-reason\">Not being searched</span>;\n return <span className=\"table-badge table-badge-reason\">{reason}</span>;\n },\n },\n ], [instanceCount]);\n\n // Note: Quality profile is per-series, not per-episode\n // It would need to be fetched from the series data and added to each episode row\n\n const columns = groupSonarr ? groupedColumns : flatColumns;\n\n // eslint-disable-next-line react-hooks/incompatible-library\n const groupedTable = useReactTable({\n data: tableData,\n columns,\n getCoreRowModel: getCoreRowModel(),\n getExpandedRowModel: getExpandedRowModel(),\n });\n\n const flatTable = useReactTable({\n data: tableData,\n columns,\n getCoreRowModel: getCoreRowModel(),\n getSortedRowModel: getSortedRowModel(),\n getPaginationRowModel: getPaginationRowModel(),\n state: {\n pagination: {\n pageIndex: page,\n pageSize: 50,\n },\n },\n manualPagination: true,\n pageCount: totalPages,\n });\n\n const table = groupSonarr ? groupedTable : flatTable;\n\n const pageSize = 50;\n // For grouped view, paginate by series groups; for flat view, paginate by rows\n const effectiveTotalPages = groupSonarr\n ? Math.ceil(allGroupedData.length / pageSize)\n : Math.ceil(rows.length / pageSize);\n const safePage = Math.min(page, Math.max(0, effectiveTotalPages - 1));\n const totalItemsDisplay = groupSonarr\n ? `${allGroupedData.length} series`\n : rows.length.toLocaleString();\n\n return (\n <div className=\"stack animate-fade-in\">\n <div className=\"row\" style={{ justifyContent: \"space-between\" }}>\n <div className=\"hint\">\n Aggregated episodes across all instances{\" \"}\n {lastUpdated ? `(updated ${lastUpdated})` : \"\"}\n <br />\n <strong>Available:</strong>{\" \"}\n {summary.available.toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Monitored:</strong>{\" \"}\n {summary.monitored.toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Missing:</strong>{\" \"}\n {summary.missing.toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Total Episodes:</strong>{\" \"}\n {summary.total.toLocaleString(undefined, { maximumFractionDigits: 0 })}\n {isAggFiltered && rows.length < summary.total && (\n <>\n {\" \"}• <strong>Filtered:</strong>{\" \"}\n {rows.length.toLocaleString(undefined, { maximumFractionDigits: 0 })} of{\" \"}\n {summary.total.toLocaleString(undefined, { maximumFractionDigits: 0 })}\n </>\n )}\n </div>\n <button className=\"btn ghost\" onClick={onRefresh} disabled={loading}>\n <IconImage src={RefreshIcon} />\n Refresh\n </button>\n </div>\n {loading ? (\n <div className=\"loading\">\n <span className=\"spinner\" /> Loading Sonarr library…\n </div>\n ) : groupSonarr ? (\n <div className=\"sonarr-hierarchical-view\">\n {groupedPageRows.map((seriesGroup) => {\n console.log(`[Sonarr Render] Series: ${seriesGroup.series}, QualityProfile: ${seriesGroup.qualityProfileName}`);\n let episodeCount = 0;\n seriesGroup.subRows.forEach(season => {\n episodeCount += season.subRows.length;\n });\n return (\n <details key={`${seriesGroup.instance}-${seriesGroup.series}`} className=\"series-details\">\n <summary className=\"series-summary\">\n <span className=\"series-title\">{seriesGroup.series}</span>\n <span className=\"series-instance\">({seriesGroup.instance})</span>\n <span className=\"series-count\">({episodeCount} episodes)</span>\n {seriesGroup.qualityProfileName ? (\n <span className=\"series-quality\">• {seriesGroup.qualityProfileName}</span>\n ) : null}\n </summary>\n <div className=\"series-content\">\n {seriesGroup.subRows.map((season: typeof seriesGroup.subRows[number]) => (\n <details key={`${seriesGroup.instance}-${seriesGroup.series}-${season.seasonNumber}`} className=\"season-details\">\n <summary className=\"season-summary\">\n <span className=\"season-title\">Season {season.seasonNumber}</span>\n <span className=\"season-count\">({season.subRows.length} episodes)</span>\n </summary>\n <div className=\"season-content\">\n <div className=\"episodes-table-wrapper\">\n <table className=\"episodes-table\">\n <thead>\n <tr>\n <th>Episode</th>\n <th>Title</th>\n <th>Monitored</th>\n <th>Has File</th>\n <th>Air Date</th>\n <th>Reason</th>\n </tr>\n </thead>\n <tbody>\n {season.subRows.map((episode) => (\n <tr key={`${episode.__instance}-${episode.series}-${episode.season}-${episode.episode}`}>\n <td data-label=\"Episode\">{episode.episode}</td>\n <td data-label=\"Title\">{episode.title}</td>\n <td data-label=\"Monitored\">\n <span className={`track-status ${episode.monitored ? 'available' : 'missing'}`}>\n {episode.monitored ? '✓' : '✗'}\n </span>\n </td>\n <td data-label=\"Has File\">\n <span className={`track-status ${episode.hasFile ? 'available' : 'missing'}`}>\n {episode.hasFile ? '✓' : '✗'}\n </span>\n </td>\n <td data-label=\"Air Date\">{episode.airDate || \"—\"}</td>\n <td data-label=\"Reason\">{episode.reason ? <span className=\"table-badge table-badge-reason\">{episode.reason}</span> : <span className=\"table-badge table-badge-reason\">Not being searched</span>}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n </details>\n ))}\n </div>\n </details>\n );\n })}\n </div>\n ) : !loading && summary.total === 0 && instanceCount > 0 ? (\n <div className=\"hint\">\n <p>No episodes found in the database.</p>\n <p>The backend may still be initializing and syncing data from your Sonarr instances. Please check the logs or wait a few moments and refresh.</p>\n </div>\n ) : tableData.length ? (\n <div className=\"table-wrapper\">\n <table className=\"responsive-table\">\n <thead>\n <tr>\n {table.getFlatHeaders().map(header => (\n <th\n key={header.id}\n className={header.column.getCanSort() ? \"sortable\" : \"\"}\n onClick={header.column.getToggleSortingHandler()}\n >\n {header.isPlaceholder\n ? null\n : flexRender(\n header.column.columnDef.header,\n header.getContext()\n )}\n {header.column.getCanSort() && (\n <span className=\"sort-arrow\">\n {{\n asc: \"▲\",\n desc: \"▼\",\n }[header.column.getIsSorted() as string] ?? null}\n </span>\n )}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {table.getRowModel().rows.map(row => {\n const episode = row.original;\n const stableKey = `${episode.__instance}-${episode.series}-${episode.season}-${episode.episode}`;\n return (\n <tr key={stableKey}>\n {row.getVisibleCells().map(cell => (\n <td key={cell.id} data-label={cell.column.columnDef.header as string}>\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </td>\n ))}\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n ) : (\n <div className=\"hint\">No series found.</div>\n )}\n {tableData.length > 0 && (\n <div className=\"pagination\">\n <div>\n Page {safePage + 1} of {effectiveTotalPages} ({totalItemsDisplay} items ·\n page size {pageSize})\n </div>\n <div className=\"inline\">\n <button\n className=\"btn\"\n onClick={() => onPageChange(Math.max(0, safePage - 1))}\n disabled={safePage === 0 || loading}\n >\n Prev\n </button>\n <button\n className=\"btn\"\n onClick={() => onPageChange(Math.min(effectiveTotalPages - 1, safePage + 1))}\n disabled={safePage >= effectiveTotalPages - 1 || loading}\n >\n Next\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n\ninterface SonarrInstanceViewProps {\n loading: boolean;\n counts: { available: number; monitored: number; missing?: number } | null;\n series: SonarrSeriesEntry[];\n page: number;\n pageSize: number;\n totalPages: number;\n totalItems: number;\n onlyMissing: boolean;\n reasonFilter: string;\n onPageChange: (page: number) => void;\n onRestart: () => void;\n lastUpdated: string | null;\n groupSonarr: boolean;\n instances: ArrInfo[];\n selection: string;\n}\n\nfunction SonarrInstanceView({\n loading,\n counts,\n series,\n page,\n pageSize,\n totalPages,\n totalItems,\n onlyMissing,\n reasonFilter,\n onPageChange,\n onRestart,\n lastUpdated,\n groupSonarr,\n instances,\n selection,\n}: SonarrInstanceViewProps): JSX.Element {\n const safePage = Math.min(page, Math.max(0, totalPages - 1));\n\n // Separate pagination state for flat (episode) view\n const [flatPage, setFlatPage] = useState(0);\n const FLAT_PAGE_SIZE = 50;\n\n const prevSeriesRef = useRef<typeof series>([]);\n const episodeRowsCache = useRef<SonarrAggRow[]>([]);\n\n // Transform series to SonarrAggRow[] - only rebuild if series changed\n const episodeRows = useMemo(() => {\n // Quick reference check\n if (series === prevSeriesRef.current) {\n return episodeRowsCache.current;\n }\n\n const rows: SonarrAggRow[] = [];\n for (const entry of series) {\n const title = (entry.series?.[\"title\"] as string | undefined) || \"\";\n const qualityProfileId = entry.series?.qualityProfileId ?? null;\n const qualityProfileName = entry.series?.qualityProfileName ?? null;\n Object.entries(entry.seasons ?? {}).forEach(([seasonNumber, season]) => {\n (season.episodes ?? []).forEach((episode) => {\n rows.push({\n __instance: \"Instance\",\n series: title,\n season: seasonNumber,\n episode: episode.episodeNumber ?? \"\",\n title: episode.title ?? \"\",\n monitored: !!episode.monitored,\n hasFile: !!episode.hasFile,\n airDate: episode.airDateUtc ?? \"\",\n reason: (episode.reason as string | null | undefined) ?? null,\n qualityProfileId,\n qualityProfileName,\n });\n });\n });\n }\n\n prevSeriesRef.current = series;\n episodeRowsCache.current = rows;\n return rows;\n }, [series]);\n\n const filteredEpisodeRows = useMemo(() => {\n let rows = episodeRows;\n if (onlyMissing) {\n rows = rows.filter((row) => !row.hasFile);\n }\n if (reasonFilter !== \"all\") {\n console.log(`[Sonarr Instance Filter] Applying reason filter: \"${reasonFilter}\"`);\n const beforeFilterCount = rows.length;\n if (reasonFilter === \"Not being searched\") {\n rows = rows.filter((row) => row.reason === \"Not being searched\" || !row.reason);\n } else {\n rows = rows.filter((row) => row.reason === reasonFilter);\n }\n console.log(`[Sonarr Instance Filter] Filtered from ${beforeFilterCount} to ${rows.length} episodes for reason \"${reasonFilter}\"`);\n if (rows.length < 10) {\n console.log(`[Sonarr Instance Filter] Sample filtered rows:`, rows.slice(0, 5).map(r => ({ series: r.series, episode: r.episode, reason: r.reason })));\n }\n }\n return rows;\n }, [episodeRows, onlyMissing, reasonFilter]);\n\n // Reset flat page when filters change\n useEffect(() => {\n setFlatPage(0);\n }, [onlyMissing, reasonFilter]);\n\n const prevEpisodeRowsRef = useRef<SonarrAggRow[]>([]);\n const groupedTableDataCache = useRef<Array<{\n series: string;\n qualityProfileId?: number | null;\n qualityProfileName?: string | null;\n subRows: Array<{\n seasonNumber: string;\n isSeason: boolean;\n subRows: Array<SonarrAggRow & { isEpisode: boolean }>;\n }>;\n }>>([]);\n\n // Group for hierarchical view - only rebuild if filteredEpisodeRows changed\n const groupedTableData = useMemo(() => {\n // Quick reference check\n if (filteredEpisodeRows === prevEpisodeRowsRef.current) {\n return groupedTableDataCache.current;\n }\n\n const map = new Map<string, Map<string, SonarrAggRow[]>>();\n filteredEpisodeRows.forEach(row => {\n const seriesKey = row.series;\n if (!map.has(seriesKey)) map.set(seriesKey, new Map());\n const seasons = map.get(seriesKey)!;\n const seasonKey = String(row.season);\n if (!seasons.has(seasonKey)) seasons.set(seasonKey, []);\n seasons.get(seasonKey)!.push(row);\n });\n\n const result = Array.from(map.entries()).map(([seriesName, seasons]) => {\n // Get quality profile from first episode (all episodes in a series share the same profile)\n const firstEpisode = Array.from(seasons.values())[0]?.[0];\n return {\n series: seriesName,\n qualityProfileId: firstEpisode?.qualityProfileId,\n qualityProfileName: firstEpisode?.qualityProfileName,\n subRows: Array.from(seasons.entries()).map(([seasonNumber, episodes]) => ({\n seasonNumber,\n isSeason: true,\n subRows: episodes.map(ep => ({ ...ep, isEpisode: true }))\n }))\n };\n });\n\n prevEpisodeRowsRef.current = filteredEpisodeRows;\n groupedTableDataCache.current = result;\n return result;\n }, [filteredEpisodeRows]);\n\n const totalEpisodes = useMemo(() => episodeRows.length, [episodeRows]);\n const isFiltered = reasonFilter !== \"all\" || onlyMissing;\n const filteredCount = filteredEpisodeRows.length;\n\n // Pagination for flat view\n const flatTotalPages = Math.max(1, Math.ceil(filteredEpisodeRows.length / FLAT_PAGE_SIZE));\n const flatSafePage = Math.min(flatPage, Math.max(0, flatTotalPages - 1));\n const paginatedEpisodeRows = useMemo(() => {\n return filteredEpisodeRows.slice(flatSafePage * FLAT_PAGE_SIZE, (flatSafePage + 1) * FLAT_PAGE_SIZE);\n }, [filteredEpisodeRows, flatSafePage]);\n\n // Pagination for grouped view (paginate by series groups, not backend pages)\n const GROUPED_PAGE_SIZE = 50;\n const [groupedPage, setGroupedPage] = useState(0);\n const groupedTotalPages = Math.max(1, Math.ceil(groupedTableData.length / GROUPED_PAGE_SIZE));\n const groupedSafePage = Math.min(groupedPage, Math.max(0, groupedTotalPages - 1));\n const paginatedGroupedData = useMemo(() => {\n return groupedTableData.slice(groupedSafePage * GROUPED_PAGE_SIZE, (groupedSafePage + 1) * GROUPED_PAGE_SIZE);\n }, [groupedTableData, groupedSafePage]);\n\n // Reset grouped page when filters change\n useEffect(() => {\n setGroupedPage(0);\n }, [onlyMissing, reasonFilter]);\n\n return (\n <div className=\"stack animate-fade-in\">\n <div className=\"row\" style={{ justifyContent: \"space-between\" }}>\n <div className=\"hint\">\n {counts ? (\n <>\n <strong>Available:</strong>{\" \"}\n {counts.available.toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Monitored:</strong>{\" \"}\n {counts.monitored.toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Missing:</strong>{\" \"}\n {(counts.missing ?? 0).toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Total Episodes:</strong>{\" \"}\n {totalEpisodes.toLocaleString(undefined, { maximumFractionDigits: 0 })}\n {isFiltered && filteredCount < totalEpisodes && (\n <>\n {\" \"}• <strong>Filtered:</strong>{\" \"}\n {filteredCount.toLocaleString(undefined, { maximumFractionDigits: 0 })} of{\" \"}\n {totalEpisodes.toLocaleString(undefined, { maximumFractionDigits: 0 })}\n </>\n )}\n </>\n ) : (\n \"Loading series information...\"\n )}\n {lastUpdated ? ` (updated ${lastUpdated})` : \"\"}\n </div>\n <button className=\"btn ghost\" onClick={onRestart} disabled={loading}>\n <IconImage src={RefreshIcon} />\n Restart\n </button>\n </div>\n {loading ? (\n <div className=\"loading\">\n <span className=\"spinner\" /> Loading series…\n </div>\n ) : groupSonarr ? (\n <div className=\"sonarr-hierarchical-view\">\n {paginatedGroupedData.map((seriesGroup) => {\n let episodeCount = 0;\n seriesGroup.subRows.forEach(season => {\n episodeCount += season.subRows.length;\n });\n // Get instance name from selection\n const instanceName = instances.find(i => i.category === selection)?.name || selection;\n return (\n <details key={`${seriesGroup.series}`} className=\"series-details\">\n <summary className=\"series-summary\">\n <span className=\"series-title\">{seriesGroup.series}</span>\n <span className=\"series-instance\">({instanceName})</span>\n <span className=\"series-count\">({episodeCount} episodes)</span>\n {seriesGroup.qualityProfileName ? (\n <span className=\"series-quality\">• {seriesGroup.qualityProfileName}</span>\n ) : null}\n </summary>\n <div className=\"series-content\">\n {seriesGroup.subRows.map((season) => (\n <details key={`${seriesGroup.series}-${season.seasonNumber}`} className=\"season-details\">\n <summary className=\"season-summary\">\n <span className=\"season-title\">Season {season.seasonNumber}</span>\n <span className=\"season-count\">({season.subRows.length} episodes)</span>\n </summary>\n <div className=\"season-content\">\n <div className=\"episodes-table-wrapper\">\n <table className=\"episodes-table\">\n <thead>\n <tr>\n <th>Episode</th>\n <th>Title</th>\n <th>Monitored</th>\n <th>Has File</th>\n <th>Air Date</th>\n <th>Reason</th>\n </tr>\n </thead>\n <tbody>\n {season.subRows.map((episode: typeof season.subRows[number]) => (\n <tr key={`${episode.series}-${episode.season}-${episode.episode}`}>\n <td data-label=\"Episode\">{episode.episode}</td>\n <td data-label=\"Title\">{episode.title}</td>\n <td data-label=\"Monitored\">\n <span className={`track-status ${episode.monitored ? 'available' : 'missing'}`}>\n {episode.monitored ? '✓' : '✗'}\n </span>\n </td>\n <td data-label=\"Has File\">\n <span className={`track-status ${episode.hasFile ? 'available' : 'missing'}`}>\n {episode.hasFile ? '✓' : '✗'}\n </span>\n </td>\n <td data-label=\"Air Date\">{episode.airDate || \"—\"}</td>\n <td data-label=\"Reason\">{episode.reason ? <span className=\"table-badge table-badge-reason\">{episode.reason}</span> : <span className=\"table-badge table-badge-reason\">Not being searched</span>}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n </details>\n ))}\n </div>\n </details>\n );\n })}\n </div>\n ) : !loading && series.length > 0 && filteredEpisodeRows.length === 0 && episodeRows.length === 0 ? (\n <div className=\"hint\">\n <p>No episodes found for these series.</p>\n <p>The backend may still be syncing episode data from Sonarr. Please check the logs or wait a few moments and refresh.</p>\n </div>\n ) : !loading && series.length > 0 && filteredEpisodeRows.length === 0 && episodeRows.length > 0 ? (\n <div className=\"hint\">No episodes match the current filter.</div>\n ) : !groupSonarr && filteredEpisodeRows.length > 0 ? (\n <div className=\"table-wrapper\">\n <table className=\"responsive-table\">\n <thead>\n <tr>\n <th>Series</th>\n <th>Season</th>\n <th>Episode</th>\n <th>Title</th>\n <th>Monitored</th>\n <th>Has File</th>\n <th>Air Date</th>\n <th>Quality Profile</th>\n <th>Reason</th>\n </tr>\n </thead>\n <tbody>\n {paginatedEpisodeRows.map((row, idx) => (\n <tr key={`${row.series}-${row.season}-${row.episode}-${idx}`}>\n <td data-label=\"Series\">{row.series}</td>\n <td data-label=\"Season\">{row.season}</td>\n <td data-label=\"Episode\">{row.episode}</td>\n <td data-label=\"Title\">{row.title}</td>\n <td data-label=\"Monitored\">\n <span className={`track-status ${row.monitored ? 'available' : 'missing'}`}>\n {row.monitored ? '✓' : '✗'}\n </span>\n </td>\n <td data-label=\"Has File\">\n <span className={`track-status ${row.hasFile ? 'available' : 'missing'}`}>\n {row.hasFile ? '✓' : '✗'}\n </span>\n </td>\n <td data-label=\"Air Date\">{row.airDate || \"—\"}</td>\n <td data-label=\"Quality Profile\">{row.qualityProfileName || \"—\"}</td>\n <td data-label=\"Reason\">{row.reason ? <span className=\"table-badge table-badge-reason\">{row.reason}</span> : <span className=\"table-badge table-badge-reason\">Not being searched</span>}</td>\n </tr>\n ))}\n </tbody>\n </table>\n {flatTotalPages > 1 && (\n <div className=\"pagination\">\n <div>\n Page {flatSafePage + 1} of {flatTotalPages} ({filteredEpisodeRows.length.toLocaleString()} episodes · page size {FLAT_PAGE_SIZE})\n </div>\n <div className=\"inline\">\n <button\n className=\"btn\"\n onClick={() => setFlatPage(Math.max(0, flatSafePage - 1))}\n disabled={flatSafePage === 0 || loading}\n >\n Prev\n </button>\n <button\n className=\"btn\"\n onClick={() => setFlatPage(Math.min(flatTotalPages - 1, flatSafePage + 1))}\n disabled={flatSafePage >= flatTotalPages - 1 || loading}\n >\n Next\n </button>\n </div>\n </div>\n )}\n </div>\n ) : (\n <div className=\"hint\">No series found.</div>\n )}\n {groupSonarr && groupedTableData.length > 0 && (\n <div className=\"pagination\">\n <div>\n Page {groupedSafePage + 1} of {groupedTotalPages} ({groupedTableData.length.toLocaleString()} series · page size {GROUPED_PAGE_SIZE})\n </div>\n <div className=\"inline\">\n <button\n className=\"btn\"\n onClick={() => setGroupedPage(Math.max(0, groupedSafePage - 1))}\n disabled={groupedSafePage === 0 || loading}\n >\n Prev\n </button>\n <button\n className=\"btn\"\n onClick={() => setGroupedPage(Math.min(groupedTotalPages - 1, groupedSafePage + 1))}\n disabled={groupedSafePage >= groupedTotalPages - 1 || loading}\n >\n Next\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ChangeEvent,\n type JSX,\n} from \"react\";\nimport {\n getArrList,\n getLidarrAlbums,\n restartArr,\n} from \"../api/client\";\nimport {\n useReactTable,\n getCoreRowModel,\n getSortedRowModel,\n flexRender,\n type ColumnDef,\n} from \"@tanstack/react-table\";\nimport type {\n ArrInfo,\n LidarrAlbum,\n LidarrAlbumEntry,\n LidarrAlbumsResponse,\n} from \"../api/types\";\nimport { useToast } from \"../context/ToastContext\";\nimport { useSearch } from \"../context/SearchContext\";\nimport { useWebUI } from \"../context/WebUIContext\";\nimport { useInterval } from \"../hooks/useInterval\";\nimport { useDataSync } from \"../hooks/useDataSync\";\nimport { IconImage } from \"../components/IconImage\";\nimport RefreshIcon from \"../icons/refresh-arrow.svg\";\nimport RestartIcon from \"../icons/refresh-arrow.svg\";\n\ninterface LidarrAggRow extends LidarrAlbumEntry {\n __instance: string;\n [key: string]: unknown;\n}\n\ninterface LidarrTrackRow {\n __instance: string;\n artistName: string;\n albumTitle: string;\n trackNumber: number;\n title: string;\n duration?: number;\n hasFile: boolean;\n monitored: boolean;\n reason?: string | null;\n qualityProfileId?: number | null;\n qualityProfileName?: string | null;\n [key: string]: unknown;\n}\n\n\n\nconst LIDARR_PAGE_SIZE = 50;\nconst LIDARR_AGG_FETCH_SIZE = 500;\n\ninterface LidarrAggregateViewProps {\n loading: boolean;\n rows: LidarrAggRow[];\n trackRows: LidarrTrackRow[];\n page: number;\n onPageChange: (page: number) => void;\n onRefresh: () => void;\n lastUpdated: string | null;\n summary: { available: number; monitored: number; missing: number; total: number };\n instanceCount: number;\n groupLidarr: boolean;\n isAggFiltered?: boolean;\n}\n\nfunction LidarrAggregateView({\n loading,\n rows,\n trackRows,\n page,\n onPageChange,\n onRefresh,\n lastUpdated,\n summary,\n instanceCount,\n groupLidarr,\n isAggFiltered = false,\n}: LidarrAggregateViewProps): JSX.Element {\n const prevRowsRef = useRef<LidarrAggRow[]>([]);\n const groupedDataCache = useRef<Array<{\n instance: string;\n artist: string;\n qualityProfileId?: number | null;\n qualityProfileName?: string | null;\n albums: LidarrAggRow[];\n }>>([]);\n const artistGroupCache = useRef<Map<string, {\n instance: string;\n artist: string;\n qualityProfileId?: number | null;\n qualityProfileName?: string | null;\n albums: LidarrAggRow[];\n albumKeys: Set<string>;\n }>>(new Map());\n\n // Create grouped data structure: instance > artist > albums - only rebuild if rows actually changed\n const groupedData = useMemo(() => {\n // Quick reference check - if same array reference, return cached\n if (rows === prevRowsRef.current) {\n return groupedDataCache.current;\n }\n\n // Build instance > artist > albums map\n const instanceMap = new Map<string, Map<string, LidarrAggRow[]>>();\n\n rows.forEach(row => {\n const instance = row.__instance;\n const artist = (row.album?.[\"artistName\"] as string | undefined) || \"Unknown Artist\";\n\n if (!instanceMap.has(instance)) {\n instanceMap.set(instance, new Map());\n }\n const artistMap = instanceMap.get(instance)!;\n\n if (!artistMap.has(artist)) {\n artistMap.set(artist, []);\n }\n artistMap.get(artist)!.push(row);\n });\n\n const result: Array<{\n instance: string;\n artist: string;\n qualityProfileId?: number | null;\n qualityProfileName?: string | null;\n albums: LidarrAggRow[];\n }> = [];\n\n const newArtistGroupCache = new Map<string, {\n instance: string;\n artist: string;\n qualityProfileId?: number | null;\n qualityProfileName?: string | null;\n albums: LidarrAggRow[];\n albumKeys: Set<string>;\n }>();\n\n instanceMap.forEach((artistMap, instance) => {\n artistMap.forEach((albums, artist) => {\n const artistKey = `${instance}-${artist}`;\n\n // Build set of album keys for this artist\n const albumKeys = new Set<string>();\n albums.forEach(album => {\n const albumData = album.album as Record<string, unknown>;\n const albumKey = `${albumData?.[\"title\"]}`;\n albumKeys.add(albumKey);\n });\n\n // Check if this artist group is in cache and unchanged\n const cached = artistGroupCache.current.get(artistKey);\n if (cached && cached.albumKeys.size === albumKeys.size) {\n let unchanged = true;\n for (const key of albumKeys) {\n if (!cached.albumKeys.has(key)) {\n unchanged = false;\n break;\n }\n }\n if (unchanged) {\n // Reuse cached artist group (prevents count flickering)\n result.push(cached);\n newArtistGroupCache.set(artistKey, cached);\n return;\n }\n }\n\n // Build new artist group\n const firstAlbum = albums[0];\n const albumData = firstAlbum?.album as Record<string, unknown> | undefined;\n const artistGroup = {\n instance,\n artist,\n qualityProfileId: (albumData?.[\"qualityProfileId\"] as number | null | undefined) ?? null,\n qualityProfileName: (albumData?.[\"qualityProfileName\"] as string | null | undefined) ?? null,\n albums,\n albumKeys,\n };\n result.push(artistGroup);\n newArtistGroupCache.set(artistKey, artistGroup);\n });\n });\n\n // Update caches\n prevRowsRef.current = rows;\n groupedDataCache.current = result;\n artistGroupCache.current = newArtistGroupCache;\n\n return result;\n }, [rows]);\n\n // For grouped view, paginate the artist groups (not individual albums)\n // For flat view, paginate the album rows\n const groupedPageRows = useMemo(() => {\n const pageSize = 50;\n return groupedData.slice(page * pageSize, (page + 1) * pageSize);\n }, [groupedData, page]);\n\n const flatPageRows = useMemo(() => {\n const pageSize = 50;\n const start = page * pageSize;\n const end = start + pageSize;\n return trackRows.slice(start, end);\n }, [trackRows, page]);\n\n const flatColumns = useMemo<ColumnDef<LidarrTrackRow>[]>(\n () => [\n ...(instanceCount > 1 ? [{\n accessorKey: \"__instance\",\n header: \"Instance\",\n size: 120,\n }] : []),\n {\n accessorKey: \"artistName\",\n header: \"Artist\",\n size: 150,\n },\n {\n accessorKey: \"albumTitle\",\n header: \"Album\",\n size: 150,\n },\n {\n accessorKey: \"trackNumber\",\n header: \"#\",\n size: 50,\n },\n {\n accessorKey: \"title\",\n header: \"Track\",\n },\n {\n accessorKey: \"duration\",\n header: \"Duration\",\n cell: (info) => {\n const dur = info.getValue() as number | undefined;\n if (!dur) return <span className=\"hint\">—</span>;\n return `${Math.floor(dur / 60)}:${String(dur % 60).padStart(2, '0')}`;\n },\n size: 80,\n },\n {\n accessorKey: \"monitored\",\n header: \"Monitored\",\n cell: (info) => {\n const monitored = info.getValue() as boolean;\n return (\n <span className={`track-status ${monitored ? 'available' : 'missing'}`}>\n {monitored ? '✓' : '✗'}\n </span>\n );\n },\n size: 100,\n },\n {\n accessorKey: \"hasFile\",\n header: \"Has File\",\n cell: (info) => {\n const hasFile = info.getValue() as boolean;\n return (\n <span className={`track-status ${hasFile ? 'available' : 'missing'}`}>\n {hasFile ? '✓' : '✗'}\n </span>\n );\n },\n size: 100,\n },\n {\n accessorKey: \"qualityProfileName\",\n header: \"Quality Profile\",\n cell: (info) => {\n const profileName = info.getValue() as string | null | undefined;\n return profileName || \"—\";\n },\n size: 150,\n },\n {\n accessorKey: \"reason\",\n header: \"Reason\",\n cell: (info) => {\n const reason = info.getValue() as string | null | undefined;\n if (!reason) return <span className=\"table-badge table-badge-reason\">Not being searched</span>;\n return <span className=\"table-badge table-badge-reason\">{reason}</span>;\n },\n size: 120,\n },\n ],\n [instanceCount]\n );\n\n const flatTable = useReactTable({\n data: flatPageRows,\n columns: flatColumns,\n getCoreRowModel: getCoreRowModel(),\n });\n\n return (\n <div className=\"stack animate-fade-in\">\n <div className=\"row\" style={{ justifyContent: \"space-between\" }}>\n <div className=\"hint\">\n Aggregated albums across all instances{\" \"}\n {lastUpdated ? `(updated ${lastUpdated})` : \"\"}\n <br />\n <strong>Available:</strong>{\" \"}\n {summary.available.toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Monitored:</strong>{\" \"}\n {summary.monitored.toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Missing:</strong>{\" \"}\n {summary.missing.toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Total:</strong>{\" \"}\n {summary.total.toLocaleString(undefined, { maximumFractionDigits: 0 })}\n {isAggFiltered && (groupLidarr ? rows.length : trackRows.length) < summary.total && (\n <>\n {\" \"}• <strong>Filtered:</strong>{\" \"}\n {(groupLidarr ? rows.length : trackRows.length).toLocaleString(undefined, { maximumFractionDigits: 0 })} of{\" \"}\n {summary.total.toLocaleString(undefined, { maximumFractionDigits: 0 })}\n </>\n )}\n </div>\n <button className=\"btn ghost\" onClick={onRefresh} disabled={loading}>\n <IconImage src={RefreshIcon} />\n Refresh\n </button>\n </div>\n\n {loading ? (\n <div className=\"loading\">\n <span className=\"spinner\" /> Loading Lidarr library…\n </div>\n ) : groupLidarr ? (\n <div className=\"lidarr-hierarchical-view\">\n {groupedPageRows.map((artistGroup) => (\n <details key={`${artistGroup.instance}-${artistGroup.artist}`} className=\"artist-details\">\n <summary className=\"artist-summary\">\n <span className=\"artist-title\">{artistGroup.artist}</span>\n <span className=\"artist-instance\">({artistGroup.instance})</span>\n <span className=\"artist-count\">({artistGroup.albums.length} albums)</span>\n {artistGroup.qualityProfileName ? (\n <span className=\"artist-quality\">• {artistGroup.qualityProfileName}</span>\n ) : null}\n </summary>\n <div className=\"artist-content\">\n {artistGroup.albums.map((albumEntry) => {\n const albumData = albumEntry.album as Record<string, unknown>;\n const albumTitle = (albumData?.[\"title\"] as string | undefined) || \"Unknown Album\";\n const albumId = (albumData?.[\"id\"] as number | undefined) || 0;\n const artistName = (albumData?.[\"artistName\"] as string | undefined) || \"\";\n const releaseDate = albumData?.[\"releaseDate\"] as string | undefined;\n const monitored = albumData?.[\"monitored\"] as boolean | undefined;\n const hasFile = albumData?.[\"hasFile\"] as boolean | undefined;\n const reason = albumData?.[\"reason\"] as string | null | undefined;\n const tracks = albumEntry.tracks || [];\n const totals = albumEntry.totals;\n\n return (\n <details key={`${albumEntry.__instance}-${artistName}-${albumTitle}`} className=\"album-details\">\n <summary className=\"album-summary\">\n <span className=\"album-title\">{albumTitle}</span>\n {releaseDate && (\n <span className=\"album-date\">{new Date(releaseDate).toLocaleDateString()}</span>\n )}\n {tracks && tracks.length > 0 && (\n <span className=\"album-track-count\">({totals.available || 0}/{totals.monitored || tracks.length} tracks)</span>\n )}\n <span className={`album-status ${hasFile ? 'has-file' : 'missing'}`}>\n {hasFile ? '✓' : '✗'}\n </span>\n </summary>\n <div className=\"album-content\">\n {tracks && tracks.length > 0 ? (\n <div className=\"tracks-table-wrapper\">\n <table className=\"tracks-table\">\n <thead>\n <tr>\n <th>#</th>\n <th>Title</th>\n <th>Duration</th>\n <th>Has File</th>\n <th>Reason</th>\n </tr>\n </thead>\n <tbody>\n {tracks.map((track) => (\n <tr key={`${albumId}-${track.id}`} className={track.hasFile ? 'track-available' : 'track-missing'}>\n <td data-label=\"#\">{track.trackNumber}</td>\n <td data-label=\"Title\">{track.title}</td>\n <td data-label=\"Duration\">{track.duration ? `${Math.floor(track.duration / 60)}:${String(track.duration % 60).padStart(2, '0')}` : '—'}</td>\n <td data-label=\"Has File\">\n <span className={`track-status ${track.hasFile ? 'available' : 'missing'}`}>\n {track.hasFile ? '✓' : '✗'}\n </span>\n </td>\n <td data-label=\"Reason\">\n {reason ? (\n <span className=\"table-badge table-badge-reason\">{reason}</span>\n ) : (\n <span className=\"table-badge table-badge-reason\">Not being searched</span>\n )}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n ) : (\n <div className=\"album-info\">\n <p>\n <strong>Monitored:</strong> {monitored ? 'Yes' : 'No'}\n {' | '}\n <strong>Has File:</strong> {hasFile ? 'Yes' : 'No'}\n </p>\n <p>\n <strong>Reason:</strong>{' '}\n {reason ? (\n <span className=\"table-badge table-badge-reason\">{reason}</span>\n ) : (\n <span className=\"table-badge table-badge-reason\">Not being searched</span>\n )}\n </p>\n </div>\n )}\n </div>\n </details>\n );\n })}\n </div>\n </details>\n ))}\n </div>\n ) : trackRows.length ? (\n <div className=\"table-wrapper\">\n <table className=\"responsive-table\">\n <thead>\n {flatTable.getHeaderGroups().map((headerGroup) => (\n <tr key={headerGroup.id}>\n {headerGroup.headers.map((header) => (\n <th key={header.id}>\n {header.isPlaceholder\n ? null\n : flexRender(\n header.column.columnDef.header,\n header.getContext()\n )}\n </th>\n ))}\n </tr>\n ))}\n </thead>\n <tbody>\n {flatTable.getRowModel().rows.map((row) => {\n const track = row.original;\n const stableKey = `${track.__instance}-${track.artistName}-${track.albumTitle}-${track.trackNumber}`;\n return (\n <tr key={stableKey}>\n {row.getVisibleCells().map((cell) => (\n <td key={cell.id} data-label={String(cell.column.columnDef.header)}>\n {flexRender(\n cell.column.columnDef.cell,\n cell.getContext()\n )}\n </td>\n ))}\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n ) : (\n <div className=\"hint\">No tracks found.</div>\n )}\n\n {(groupLidarr ? groupedPageRows.length > 0 : flatPageRows.length > 0) && (\n <div className=\"pagination\">\n <div>\n {groupLidarr ? (\n <>Page {page + 1} of {Math.ceil(groupedData.length / 50)} ({groupedData.length} artists · page size 50)</>\n ) : (\n <>Page {page + 1} of {Math.ceil(trackRows.length / 50)} ({trackRows.length.toLocaleString()} tracks · page size 50)</>\n )}\n </div>\n <div className=\"inline\">\n <button\n className=\"btn\"\n onClick={() => onPageChange(Math.max(0, page - 1))}\n disabled={page === 0 || loading}\n >\n Prev\n </button>\n <button\n className=\"btn\"\n onClick={() => onPageChange(Math.min((groupLidarr ? Math.ceil(groupedData.length / 50) : Math.ceil(trackRows.length / 50)) - 1, page + 1))}\n disabled={page >= (groupLidarr ? Math.ceil(groupedData.length / 50) : Math.ceil(trackRows.length / 50)) - 1 || loading}\n >\n Next\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n\ninterface LidarrInstanceViewProps {\n loading: boolean;\n data: LidarrAlbumsResponse | null;\n page: number;\n totalPages: number;\n pageSize: number;\n allAlbums: LidarrAlbumEntry[];\n onlyMissing: boolean;\n reasonFilter: string;\n onPageChange: (page: number) => void;\n onRestart: () => void;\n lastUpdated: string | null;\n groupLidarr: boolean;\n instances: ArrInfo[];\n selection: string;\n}\n\nfunction LidarrInstanceView({\n loading,\n data,\n page,\n totalPages,\n pageSize,\n allAlbums,\n onlyMissing,\n reasonFilter,\n onPageChange,\n onRestart,\n lastUpdated,\n groupLidarr,\n instances,\n selection,\n}: LidarrInstanceViewProps): JSX.Element {\n // Separate pagination state for flat (album) view\n const [flatPage, setFlatPage] = useState(0);\n const FLAT_PAGE_SIZE = 50;\n\n const filteredAlbums = useMemo(() => {\n let albums = allAlbums;\n if (onlyMissing) {\n albums = albums.filter((entry) => {\n const albumData = entry.album as Record<string, unknown>;\n return !(albumData?.[\"hasFile\"] as boolean | undefined);\n });\n }\n return albums;\n }, [allAlbums, onlyMissing]);\n\n const reasonFilteredAlbums = useMemo(() => {\n if (reasonFilter === \"all\") return filteredAlbums;\n if (reasonFilter === \"Not being searched\") {\n return filteredAlbums.filter((entry) => {\n const albumData = entry.album as Record<string, unknown>;\n return albumData?.[\"reason\"] === \"Not being searched\" || !albumData?.[\"reason\"];\n });\n }\n return filteredAlbums.filter((entry) => {\n const albumData = entry.album as Record<string, unknown>;\n return albumData?.[\"reason\"] === reasonFilter;\n });\n }, [filteredAlbums, reasonFilter]);\n\n const totalAlbums = useMemo(() => allAlbums.length, [allAlbums]);\n const isFiltered = reasonFilter !== \"all\" || onlyMissing;\n const filteredCount = reasonFilteredAlbums.length;\n\n // Count total tracks for instance view\n const totalTracks = useMemo(() => {\n let count = 0;\n allAlbums.forEach(entry => {\n const tracks = entry.tracks || [];\n count += tracks.length;\n });\n return count;\n }, [allAlbums]);\n\n const filteredTracks = useMemo(() => {\n let count = 0;\n reasonFilteredAlbums.forEach(entry => {\n const tracks = entry.tracks || [];\n count += tracks.length;\n });\n return count;\n }, [reasonFilteredAlbums]);\n\n // Reset flat page when filters change\n useEffect(() => {\n setFlatPage(0);\n }, [onlyMissing, reasonFilter]);\n\n const prevFilteredAlbumsRef = useRef<LidarrAlbumEntry[]>([]);\n const groupedAlbumsCache = useRef<Array<{\n artist: string;\n albums: LidarrAlbumEntry[];\n qualityProfileName?: string | null;\n }>>([]);\n\n // Group albums by artist for hierarchical view - only rebuild if filtered albums changed\n const groupedAlbums = useMemo(() => {\n // Quick reference check\n if (reasonFilteredAlbums === prevFilteredAlbumsRef.current) {\n return groupedAlbumsCache.current;\n }\n\n const artistMap = new Map<string, LidarrAlbumEntry[]>();\n reasonFilteredAlbums.forEach(albumEntry => {\n const albumData = albumEntry.album as Record<string, unknown>;\n const artist = (albumData?.[\"artistName\"] as string | undefined) || \"Unknown Artist\";\n if (!artistMap.has(artist)) {\n artistMap.set(artist, []);\n }\n artistMap.get(artist)!.push(albumEntry);\n });\n\n const result = Array.from(artistMap.entries()).map(([artist, albums]) => {\n // Get quality profile from first album (all albums by same artist typically share quality profile)\n const firstAlbum = albums[0]?.album as Record<string, unknown> | undefined;\n const qualityProfileName = (firstAlbum?.[\"qualityProfileName\"] as string | null | undefined) ?? null;\n return {\n artist,\n albums,\n qualityProfileName,\n };\n });\n\n prevFilteredAlbumsRef.current = reasonFilteredAlbums;\n groupedAlbumsCache.current = result;\n return result;\n }, [reasonFilteredAlbums]);\n\n const columns = useMemo<ColumnDef<LidarrAlbumEntry>[]>(\n () => [\n {\n id: \"title\",\n header: \"Album\",\n cell: (info) => {\n const albumData = info.row.original.album as Record<string, unknown>;\n return (albumData?.[\"title\"] as string | undefined) || \"Unknown Album\";\n },\n },\n {\n id: \"artistName\",\n header: \"Artist\",\n cell: (info) => {\n const albumData = info.row.original.album as Record<string, unknown>;\n return (albumData?.[\"artistName\"] as string | undefined) || \"Unknown Artist\";\n },\n size: 150,\n },\n {\n id: \"releaseDate\",\n header: \"Release Date\",\n cell: (info) => {\n const albumData = info.row.original.album as Record<string, unknown>;\n const date = albumData?.[\"releaseDate\"] as string | undefined;\n if (!date) return <span className=\"hint\">—</span>;\n return new Date(date).toLocaleDateString();\n },\n size: 120,\n },\n {\n id: \"monitored\",\n header: \"Monitored\",\n cell: (info) => {\n const albumData = info.row.original.album as Record<string, unknown>;\n const monitored = albumData?.[\"monitored\"] as boolean | undefined;\n return (\n <span className={`track-status ${monitored ? 'available' : 'missing'}`}>\n {monitored ? '✓' : '✗'}\n </span>\n );\n },\n size: 100,\n },\n {\n id: \"hasFile\",\n header: \"Has File\",\n cell: (info) => {\n const albumData = info.row.original.album as Record<string, unknown>;\n const hasFile = albumData?.[\"hasFile\"] as boolean | undefined;\n return (\n <span className={`track-status ${hasFile ? 'available' : 'missing'}`}>\n {hasFile ? '✓' : '✗'}\n </span>\n );\n },\n size: 100,\n },\n {\n id: \"qualityProfileName\",\n header: \"Quality Profile\",\n cell: (info) => {\n const albumData = info.row.original.album as Record<string, unknown>;\n const profileName = albumData?.[\"qualityProfileName\"] as string | null | undefined;\n return profileName || \"—\";\n },\n size: 150,\n },\n {\n id: \"reason\",\n header: \"Reason\",\n cell: (info) => {\n const albumData = info.row.original.album as Record<string, unknown>;\n const reason = albumData?.[\"reason\"] as string | null | undefined;\n if (!reason) return <span className=\"table-badge table-badge-reason\">Not being searched</span>;\n return <span className=\"table-badge table-badge-reason\">{reason}</span>;\n },\n size: 120,\n },\n ],\n []\n );\n\n // Pagination for flat view\n const flatTotalPages = Math.max(1, Math.ceil(reasonFilteredAlbums.length / FLAT_PAGE_SIZE));\n const flatSafePage = Math.min(flatPage, Math.max(0, flatTotalPages - 1));\n const paginatedAlbums = useMemo(() => {\n return reasonFilteredAlbums.slice(flatSafePage * FLAT_PAGE_SIZE, (flatSafePage + 1) * FLAT_PAGE_SIZE);\n }, [reasonFilteredAlbums, flatSafePage]);\n\n // Pagination for grouped view (paginate by artist groups, not backend pages)\n const GROUPED_PAGE_SIZE = 50;\n const [groupedPage, setGroupedPage] = useState(0);\n const groupedTotalPages = Math.max(1, Math.ceil(groupedAlbums.length / GROUPED_PAGE_SIZE));\n const groupedSafePage = Math.min(groupedPage, Math.max(0, groupedTotalPages - 1));\n const paginatedGroupedAlbums = useMemo(() => {\n return groupedAlbums.slice(groupedSafePage * GROUPED_PAGE_SIZE, (groupedSafePage + 1) * GROUPED_PAGE_SIZE);\n }, [groupedAlbums, groupedSafePage]);\n\n // Reset grouped page when filters change\n useEffect(() => {\n setGroupedPage(0);\n }, [onlyMissing, reasonFilter]);\n\n const table = useReactTable({\n data: paginatedAlbums,\n columns,\n getCoreRowModel: getCoreRowModel(),\n getSortedRowModel: getSortedRowModel(),\n });\n\n return (\n <div className=\"stack animate-fade-in\">\n <div className=\"row\" style={{ justifyContent: \"space-between\" }}>\n <div className=\"hint\">\n {data?.counts ? (\n <>\n <strong>Available:</strong>{\" \"}\n {(data.counts.available ?? 0).toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Monitored:</strong>{\" \"}\n {(data.counts.monitored ?? 0).toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Missing:</strong>{\" \"}\n {((data.counts.monitored ?? 0) - (data.counts.available ?? 0)).toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Total:</strong>{\" \"}\n {totalAlbums.toLocaleString(undefined, { maximumFractionDigits: 0 })}\n {isFiltered && filteredCount < totalAlbums && (\n <>\n {\" \"}• <strong>Filtered:</strong>{\" \"}\n {filteredCount.toLocaleString(undefined, { maximumFractionDigits: 0 })} of{\" \"}\n {totalAlbums.toLocaleString(undefined, { maximumFractionDigits: 0 })}\n </>\n )}\n </>\n ) : (\n \"Loading album information...\"\n )}\n {lastUpdated ? ` (updated ${lastUpdated})` : \"\"}\n </div>\n <button className=\"btn ghost\" onClick={onRestart} disabled={loading}>\n <IconImage src={RestartIcon} />\n Restart\n </button>\n </div>\n\n {loading ? (\n <div className=\"loading\">\n <span className=\"spinner\" /> Loading…\n </div>\n ) : groupLidarr ? (\n <div className=\"lidarr-hierarchical-view\">\n {paginatedGroupedAlbums.map((artistGroup) => {\n // Get instance name from selection\n const instanceName = instances.find(i => i.category === selection)?.name || selection;\n return (\n <details key={artistGroup.artist} className=\"artist-details\">\n <summary className=\"artist-summary\">\n <span className=\"artist-title\">{artistGroup.artist}</span>\n <span className=\"artist-instance\">({instanceName})</span>\n <span className=\"artist-count\">({artistGroup.albums.length} albums)</span>\n {artistGroup.qualityProfileName ? (\n <span className=\"artist-quality\">• {artistGroup.qualityProfileName}</span>\n ) : null}\n </summary>\n <div className=\"artist-content\">\n {artistGroup.albums.map((albumEntry) => {\n const albumData = albumEntry.album as Record<string, unknown>;\n const albumTitle = (albumData?.[\"title\"] as string | undefined) || \"Unknown Album\";\n const albumId = (albumData?.[\"id\"] as number | undefined) || 0;\n const artistName = (albumData?.[\"artistName\"] as string | undefined) || \"\";\n const releaseDate = albumData?.[\"releaseDate\"] as string | undefined;\n const monitored = albumData?.[\"monitored\"] as boolean | undefined;\n const hasFile = albumData?.[\"hasFile\"] as boolean | undefined;\n const reason = albumData?.[\"reason\"] as string | null | undefined;\n const tracks = albumEntry.tracks || [];\n const totals = albumEntry.totals;\n\n return (\n <details key={`${artistName}-${albumTitle}`} className=\"album-details\">\n <summary className=\"album-summary\">\n <span className=\"album-title\">{albumTitle}</span>\n {releaseDate && (\n <span className=\"album-date\">{new Date(releaseDate).toLocaleDateString()}</span>\n )}\n {tracks && tracks.length > 0 && (\n <span className=\"album-track-count\">({totals.available || 0}/{totals.monitored || tracks.length} tracks)</span>\n )}\n <span className={`album-status ${hasFile ? 'has-file' : 'missing'}`}>\n {hasFile ? '✓' : '✗'}\n </span>\n </summary>\n <div className=\"album-content\">\n {tracks && tracks.length > 0 ? (\n <div className=\"tracks-table-wrapper\">\n <table className=\"tracks-table\">\n <thead>\n <tr>\n <th>#</th>\n <th>Title</th>\n <th>Duration</th>\n <th>Has File</th>\n <th>Reason</th>\n </tr>\n </thead>\n <tbody>\n {tracks.map((track) => (\n <tr key={`${albumId}-${track.id}`} className={track.hasFile ? 'track-available' : 'track-missing'}>\n <td data-label=\"#\">{track.trackNumber}</td>\n <td data-label=\"Title\">{track.title}</td>\n <td data-label=\"Duration\">{track.duration ? `${Math.floor(track.duration / 60)}:${String(track.duration % 60).padStart(2, '0')}` : '—'}</td>\n <td data-label=\"Has File\">\n <span className={`track-status ${track.hasFile ? 'available' : 'missing'}`}>\n {track.hasFile ? '✓' : '✗'}\n </span>\n </td>\n <td data-label=\"Reason\">\n {reason ? (\n <span className=\"table-badge table-badge-reason\">{reason}</span>\n ) : (\n <span className=\"table-badge table-badge-reason\">Not being searched</span>\n )}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n ) : (\n <div className=\"album-info\">\n <p>\n <strong>Monitored:</strong> {monitored ? 'Yes' : 'No'}\n {' | '}\n <strong>Has File:</strong> {hasFile ? 'Yes' : 'No'}\n </p>\n <p>\n <strong>Reason:</strong>{' '}\n {reason ? (\n <span className=\"table-badge table-badge-reason\">{reason}</span>\n ) : (\n <span className=\"table-badge table-badge-reason\">Not being searched</span>\n )}\n </p>\n </div>\n )}\n </div>\n </details>\n );\n })}\n </div>\n </details>\n );\n })}\n </div>\n ) : !groupLidarr && allAlbums.length ? (\n <div className=\"table-wrapper\">\n <table className=\"responsive-table\">\n <thead>\n {table.getHeaderGroups().map((headerGroup) => (\n <tr key={headerGroup.id}>\n {headerGroup.headers.map((header) => (\n <th key={header.id}>\n {header.isPlaceholder\n ? null\n : flexRender(\n header.column.columnDef.header,\n header.getContext()\n )}\n </th>\n ))}\n </tr>\n ))}\n </thead>\n <tbody>\n {table.getRowModel().rows.map((row) => {\n const albumEntry = row.original;\n const albumData = albumEntry.album as Record<string, unknown>;\n const title = (albumData?.[\"title\"] as string | undefined) || \"Unknown\";\n const artistName = (albumData?.[\"artistName\"] as string | undefined) || \"Unknown\";\n const stableKey = `${title}-${artistName}`;\n return (\n <tr key={stableKey}>\n {row.getVisibleCells().map((cell) => (\n <td key={cell.id} data-label={String(cell.column.columnDef.header)}>\n {flexRender(\n cell.column.columnDef.cell,\n cell.getContext()\n )}\n </td>\n ))}\n </tr>\n );\n })}\n </tbody>\n </table>\n {flatTotalPages > 1 && (\n <div className=\"pagination\">\n <div>\n Page {flatSafePage + 1} of {flatTotalPages} ({reasonFilteredAlbums.length.toLocaleString()} albums · page size {FLAT_PAGE_SIZE})\n </div>\n <div className=\"inline\">\n <button\n className=\"btn\"\n onClick={() => setFlatPage(Math.max(0, flatSafePage - 1))}\n disabled={flatSafePage === 0 || loading}\n >\n Prev\n </button>\n <button\n className=\"btn\"\n onClick={() => setFlatPage(Math.min(flatTotalPages - 1, flatSafePage + 1))}\n disabled={flatSafePage >= flatTotalPages - 1 || loading}\n >\n Next\n </button>\n </div>\n </div>\n )}\n </div>\n ) : (\n <div className=\"hint\">No albums found.</div>\n )}\n\n {groupLidarr && groupedAlbums.length > 0 && (\n <div className=\"pagination\">\n <div>\n Page {groupedSafePage + 1} of {groupedTotalPages} ({groupedAlbums.length.toLocaleString()} artists · page size {GROUPED_PAGE_SIZE})\n </div>\n <div className=\"inline\">\n <button\n className=\"btn\"\n onClick={() => setGroupedPage(Math.max(0, groupedSafePage - 1))}\n disabled={groupedSafePage === 0 || loading}\n >\n Prev\n </button>\n <button\n className=\"btn\"\n onClick={() => setGroupedPage(Math.min(groupedTotalPages - 1, groupedSafePage + 1))}\n disabled={groupedSafePage >= groupedTotalPages - 1 || loading}\n >\n Next\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport function LidarrView({ active }: { active: boolean }): JSX.Element {\n const { push } = useToast();\n const {\n value: globalSearch,\n setValue: setGlobalSearch,\n register,\n clearHandler,\n } = useSearch();\n const { liveArr, groupLidarr } = useWebUI();\n\n const [instances, setInstances] = useState<ArrInfo[]>([]);\n const [selection, setSelection] = useState<string | \"\">(\"\");\n const [instanceData, setInstanceData] = useState<LidarrAlbumsResponse | null>(null);\n const [instancePage, setInstancePage] = useState(0);\n const [instanceQuery, setInstanceQuery] = useState(\"\");\n const [instanceLoading, setInstanceLoading] = useState(false);\n const [lastUpdated, setLastUpdated] = useState<string | null>(null);\n const [instancePages, setInstancePages] = useState<Record<number, LidarrAlbumEntry[]>>({});\n const [instancePageSize, setInstancePageSize] = useState(LIDARR_PAGE_SIZE);\n const [instanceTotalPages, setInstanceTotalPages] = useState(1);\n const instanceKeyRef = useRef<string>(\"\");\n const instancePagesRef = useRef<Record<number, LidarrAlbumEntry[]>>({});\n const globalSearchRef = useRef(globalSearch);\n const backendReadyWarnedRef = useRef(false);\n const prevSelectionRef = useRef<string | \"\">(selection);\n\n // Smart data sync for instance albums\n const instanceAlbumSync = useDataSync<LidarrAlbumEntry>({\n getKey: (album) => {\n const albumData = album.album as Record<string, unknown>;\n const artistName = (albumData?.[\"artistName\"] as string | undefined) || \"\";\n const title = (albumData?.[\"title\"] as string | undefined) || \"\";\n return `${artistName}-${title}`;\n },\n hashFields: ['album', 'tracks', 'totals'],\n });\n\n const [aggRows, setAggRows] = useState<LidarrAggRow[]>([]);\n const [aggTrackRows, setAggTrackRows] = useState<LidarrTrackRow[]>([]);\n const [aggLoading, setAggLoading] = useState(false);\n const [aggPage, setAggPage] = useState(0);\n const [aggFilter, setAggFilter] = useState(\"\");\n const [aggUpdated, setAggUpdated] = useState<string | null>(null);\n\n // Smart data sync for aggregate albums\n const aggAlbumSync = useDataSync<LidarrAggRow>({\n getKey: (album) => {\n const albumData = album.album as Record<string, unknown>;\n const artistName = (albumData?.[\"artistName\"] as string | undefined) || \"\";\n const title = (albumData?.[\"title\"] as string | undefined) || \"\";\n return `${album.__instance}-${artistName}-${title}`;\n },\n hashFields: ['__instance', 'album', 'tracks', 'totals'],\n });\n\n // Smart data sync for track rows\n const aggTrackSync = useDataSync<LidarrTrackRow>({\n getKey: (track) => `${track.__instance}-${track.artistName}-${track.albumTitle}-${track.trackNumber}`,\n hashFields: ['__instance', 'artistName', 'albumTitle', 'trackNumber', 'title', 'hasFile', 'monitored', 'reason'],\n });\n const [onlyMissing, setOnlyMissing] = useState(false);\n const [reasonFilter, setReasonFilter] = useState<string>(\"all\");\n const [aggSummary, setAggSummary] = useState<{\n available: number;\n monitored: number;\n missing: number;\n total: number;\n }>({ available: 0, monitored: 0, missing: 0, total: 0 });\n\n const loadInstances = useCallback(async () => {\n try {\n const data = await getArrList();\n if (data.ready === false && !backendReadyWarnedRef.current) {\n backendReadyWarnedRef.current = true;\n push(\"Lidarr backend is still initialising. Check the logs if this persists.\", \"info\");\n } else if (data.ready) {\n backendReadyWarnedRef.current = true;\n }\n const filtered = (data.arr || []).filter((arr) => arr.type === \"lidarr\");\n setInstances(filtered);\n if (!filtered.length) {\n setSelection(\"aggregate\");\n setInstanceData(null);\n setAggRows([]);\n setAggSummary({ available: 0, monitored: 0, missing: 0, total: 0 });\n return;\n }\n if (selection === \"\") {\n // If only 1 instance, select it directly; otherwise use aggregate\n setSelection(filtered.length === 1 ? filtered[0].category : \"aggregate\");\n } else if (\n selection !== \"aggregate\" &&\n !filtered.some((arr) => arr.category === selection)\n ) {\n setSelection(filtered[0].category);\n }\n } catch (error) {\n push(\n error instanceof Error\n ? error.message\n : \"Unable to load Lidarr instances\",\n \"error\"\n );\n }\n }, [push, selection]);\n\n const preloadRemainingPages = useCallback(\n async (\n category: string,\n query: string,\n pageSize: number,\n pages: number[],\n key: string\n ) => {\n if (!pages.length) return;\n try {\n const results: { page: number; albums: LidarrAlbumEntry[] }[] = [];\n for (const pg of pages) {\n const res = await getLidarrAlbums(category, pg, pageSize, query);\n const resolved = res.page ?? pg;\n results.push({ page: resolved, albums: res.albums ?? [] });\n if (instanceKeyRef.current !== key) {\n return;\n }\n }\n if (instanceKeyRef.current !== key) return;\n\n // Smart diffing: only update pages that actually changed\n setInstancePages((prev) => {\n const next = { ...prev };\n let hasChanges = false;\n for (const { page, albums } of results) {\n // Use hash-based comparison for each page\n const syncResult = instanceAlbumSync.syncData(albums);\n if (syncResult.hasChanges) {\n next[page] = syncResult.data;\n hasChanges = true;\n }\n }\n instancePagesRef.current = next;\n return hasChanges ? next : prev;\n });\n } catch (error) {\n push(\n error instanceof Error\n ? error.message\n : `Failed to load additional pages for ${category}`,\n \"error\"\n );\n }\n },\n [push]\n );\n\n const fetchInstance = useCallback(\n async (\n category: string,\n page: number,\n query: string,\n options: { preloadAll?: boolean; showLoading?: boolean } = {}\n ) => {\n const preloadAll = options.preloadAll !== false;\n const showLoading = options.showLoading ?? true;\n if (showLoading) {\n setInstanceLoading(true);\n }\n try {\n const key = `${category}::${query}`;\n const keyChanged = instanceKeyRef.current !== key;\n if (keyChanged) {\n instanceKeyRef.current = key;\n setInstancePages(() => {\n instancePagesRef.current = {};\n return {};\n });\n }\n const response = await getLidarrAlbums(\n category,\n page,\n LIDARR_PAGE_SIZE,\n query\n );\n setInstanceData(response);\n const resolvedPage = response.page ?? page;\n setInstancePage(resolvedPage);\n setInstanceQuery(query);\n const pageSize = response.page_size ?? LIDARR_PAGE_SIZE;\n const totalItems = response.total ?? (response.albums ?? []).length;\n const totalPages = Math.max(1, Math.ceil((totalItems || 0) / pageSize));\n setInstancePageSize(pageSize);\n setInstanceTotalPages(totalPages);\n const albums = response.albums ?? [];\n const existingPages = keyChanged ? {} : instancePagesRef.current;\n\n // Smart diffing using hash-based change detection\n const syncResult = instanceAlbumSync.syncData(albums);\n const albumsChanged = syncResult.hasChanges;\n\n if (keyChanged) {\n // Reset sync state on key change\n instanceAlbumSync.reset();\n }\n\n if (keyChanged || albumsChanged) {\n setInstancePages((prev) => {\n const base = keyChanged ? {} : prev;\n const next = { ...base, [resolvedPage]: syncResult.data };\n instancePagesRef.current = next;\n return next;\n });\n setLastUpdated(new Date().toLocaleTimeString());\n }\n\n if (preloadAll) {\n const pagesToFetch: number[] = [];\n for (let i = 0; i < totalPages; i += 1) {\n if (i === resolvedPage) continue;\n if (!existingPages[i]) {\n pagesToFetch.push(i);\n }\n }\n void preloadRemainingPages(\n category,\n query,\n pageSize,\n pagesToFetch,\n key\n );\n }\n } catch (error) {\n push(\n error instanceof Error\n ? error.message\n : `Failed to load ${category} albums`,\n \"error\"\n );\n } finally {\n setInstanceLoading(false);\n }\n },\n [push, preloadRemainingPages]\n );\n\n const loadAggregate = useCallback(async (options?: { showLoading?: boolean }) => {\n if (!instances.length) {\n setAggRows([]);\n setAggSummary({ available: 0, monitored: 0, missing: 0, total: 0 });\n return;\n }\n const showLoading = options?.showLoading ?? true;\n if (showLoading) {\n setAggLoading(true);\n }\n try {\n const aggregated: LidarrAggRow[] = [];\n let totalAvailable = 0;\n let totalMonitored = 0;\n for (const inst of instances) {\n let page = 0;\n let counted = false;\n const label = inst.name || inst.category;\n while (page < 100) {\n const res = await getLidarrAlbums(\n inst.category,\n page,\n LIDARR_AGG_FETCH_SIZE,\n \"\"\n );\n\n console.log(\"=== Lidarr API Response ===\");\n console.log(\"Instance:\", inst.category);\n console.log(\"Response:\", res);\n console.log(\"Albums count:\", res.albums?.length);\n if (res.albums && res.albums.length > 0) {\n console.log(\"First album entry:\", res.albums[0]);\n console.log(\"First album.album:\", res.albums[0].album);\n console.log(\"First album.totals:\", res.albums[0].totals);\n console.log(\"First album.tracks:\", res.albums[0].tracks);\n }\n console.log(\"=========================\");\n\n if (!counted) {\n const counts = res.counts;\n if (counts) {\n totalAvailable += counts.available ?? 0;\n totalMonitored += counts.monitored ?? 0;\n }\n counted = true;\n }\n const albumEntries = res.albums ?? [];\n albumEntries.forEach((entry) => {\n aggregated.push({ ...entry, __instance: label });\n });\n if (!albumEntries.length || albumEntries.length < LIDARR_AGG_FETCH_SIZE) break;\n page += 1;\n }\n }\n\n // Flatten tracks from all albums for flat mode\n const trackRows: LidarrTrackRow[] = [];\n aggregated.forEach((albumEntry) => {\n const albumData = albumEntry.album as Record<string, unknown>;\n const artistName = (albumData?.[\"artistName\"] as string | undefined) || \"Unknown Artist\";\n const albumTitle = (albumData?.[\"title\"] as string | undefined) || \"Unknown Album\";\n const reason = albumData?.[\"reason\"] as string | null | undefined;\n const qualityProfileId = albumData?.[\"qualityProfileId\"] as number | null | undefined;\n const qualityProfileName = albumData?.[\"qualityProfileName\"] as string | null | undefined;\n const tracks = albumEntry.tracks || [];\n\n if (tracks && tracks.length > 0) {\n tracks.forEach((track) => {\n trackRows.push({\n __instance: albumEntry.__instance,\n artistName,\n albumTitle,\n trackNumber: track.trackNumber || 0,\n title: track.title || \"Unknown Track\",\n duration: track.duration,\n hasFile: track.hasFile || false,\n monitored: track.monitored || false,\n reason,\n qualityProfileId,\n qualityProfileName,\n });\n });\n }\n });\n\n // Smart diffing using hash-based change detection\n const albumSyncResult = aggAlbumSync.syncData(aggregated);\n const rowsChanged = albumSyncResult.hasChanges;\n\n const trackSyncResult = aggTrackSync.syncData(trackRows);\n const trackRowsChanged = trackSyncResult.hasChanges;\n\n if (rowsChanged) {\n setAggRows(albumSyncResult.data);\n }\n\n if (trackRowsChanged) {\n setAggTrackRows(trackSyncResult.data);\n }\n\n const newSummary = groupLidarr\n ? {\n available: totalAvailable,\n monitored: totalMonitored,\n missing: aggregated.length - totalAvailable,\n total: aggregated.length,\n }\n : {\n available: trackRows.filter(t => t.hasFile).length,\n monitored: trackRows.filter(t => t.monitored).length,\n missing: trackRows.filter(t => !t.hasFile).length,\n total: trackRows.length,\n };\n\n const summaryChanged = (\n aggSummary.available !== newSummary.available ||\n aggSummary.monitored !== newSummary.monitored ||\n aggSummary.missing !== newSummary.missing ||\n aggSummary.total !== newSummary.total\n );\n\n if (summaryChanged) {\n setAggSummary(newSummary);\n }\n\n // Only reset page if filter changed, not on refresh\n if (aggFilter !== globalSearch) {\n setAggPage(0);\n setAggFilter(globalSearch);\n }\n\n // Only update timestamp if data actually changed\n if (rowsChanged || summaryChanged) {\n setAggUpdated(new Date().toLocaleTimeString());\n }\n } catch (error) {\n setAggRows([]);\n setAggSummary({ available: 0, monitored: 0, missing: 0, total: 0 });\n push(\n error instanceof Error\n ? error.message\n : \"Failed to load aggregated Lidarr data\",\n \"error\"\n );\n } finally {\n setAggLoading(false);\n }\n }, [instances, globalSearch, push, aggFilter, groupLidarr]);\n\n // LiveArr is now loaded via WebUIContext, no need to load config here\n\n useEffect(() => {\n if (!active) return;\n void loadInstances();\n }, [active, loadInstances]);\n\n useEffect(() => {\n if (!active) return;\n if (!selection || selection === \"aggregate\") return;\n\n const selectionChanged = prevSelectionRef.current !== selection;\n\n // Reset page and cache only when selection changes\n if (selectionChanged) {\n instancePagesRef.current = {};\n setInstancePages({});\n setInstanceTotalPages(1);\n setInstancePage(0);\n prevSelectionRef.current = selection;\n }\n\n // Fetch data: use page 0 if selection changed, current page otherwise\n const query = globalSearchRef.current;\n void fetchInstance(selection, selectionChanged ? 0 : instancePage, query, {\n preloadAll: true,\n showLoading: true,\n });\n }, [active, selection, fetchInstance, instancePage]);\n\n useEffect(() => {\n if (!active) return;\n if (selection !== \"aggregate\") return;\n void loadAggregate();\n }, [active, selection, loadAggregate]);\n\n useInterval(() => {\n if (selection === \"aggregate\" && liveArr) {\n void loadAggregate({ showLoading: false });\n }\n }, selection === \"aggregate\" && liveArr ? 1000 : null);\n\n useEffect(() => {\n if (!active) return;\n const handler = (term: string) => {\n if (selection === \"aggregate\") {\n setAggFilter(term);\n setAggPage(0);\n } else if (selection) {\n setInstancePage(0);\n void fetchInstance(selection, 0, term, {\n preloadAll: true,\n showLoading: true,\n });\n }\n };\n register(handler);\n return () => {\n clearHandler(handler);\n };\n }, [active, selection, register, clearHandler, fetchInstance]);\n\n useInterval(\n () => {\n if (selection && selection !== \"aggregate\") {\n const activeFilter = globalSearchRef.current?.trim?.() || \"\";\n if (activeFilter) {\n return;\n }\n void fetchInstance(selection, instancePage, instanceQuery, {\n preloadAll: false,\n showLoading: false,\n });\n }\n },\n active && selection && selection !== \"aggregate\" && liveArr ? 1000 : null\n );\n\n // Removed: Don't reset page when filter changes - preserve scroll position\n\n useEffect(() => {\n globalSearchRef.current = globalSearch;\n }, [globalSearch]);\n\n useEffect(() => {\n if (selection === \"aggregate\") {\n setAggFilter(globalSearch);\n }\n }, [selection, globalSearch]);\n\n const filteredAggRows = useMemo(() => {\n let rows = aggRows;\n if (aggFilter) {\n const q = aggFilter.toLowerCase();\n rows = rows.filter((row) => {\n const albumData = row.album as Record<string, unknown>;\n const title = ((albumData?.[\"title\"] as string | undefined) ?? \"\").toString().toLowerCase();\n const artist = ((albumData?.[\"artistName\"] as string | undefined) ?? \"\").toString().toLowerCase();\n const instance = (row.__instance ?? \"\").toLowerCase();\n return title.includes(q) || artist.includes(q) || instance.includes(q);\n });\n }\n if (onlyMissing) {\n rows = rows.filter((row) => {\n const albumData = row.album as Record<string, unknown>;\n return !(albumData?.[\"hasFile\"] as boolean | undefined);\n });\n }\n if (reasonFilter !== \"all\") {\n if (reasonFilter === \"Not being searched\") {\n rows = rows.filter((row) => {\n const albumData = row.album as Record<string, unknown>;\n return albumData?.[\"reason\"] === \"Not being searched\" || !albumData?.[\"reason\"];\n });\n } else {\n rows = rows.filter((row) => {\n const albumData = row.album as Record<string, unknown>;\n return albumData?.[\"reason\"] === reasonFilter;\n });\n }\n }\n return rows;\n }, [aggRows, aggFilter, onlyMissing, reasonFilter]);\n\n const isAggFiltered = Boolean(aggFilter) || reasonFilter !== \"all\";\n\n const filteredAggTrackRows = useMemo(() => {\n let rows = aggTrackRows;\n if (aggFilter) {\n const q = aggFilter.toLowerCase();\n rows = rows.filter((row) => {\n return (\n row.artistName.toLowerCase().includes(q) ||\n row.albumTitle.toLowerCase().includes(q) ||\n row.title.toLowerCase().includes(q) ||\n row.__instance.toLowerCase().includes(q)\n );\n });\n }\n if (onlyMissing) {\n rows = rows.filter((row) => !row.hasFile);\n }\n if (reasonFilter !== \"all\") {\n if (reasonFilter === \"Not being searched\") {\n rows = rows.filter((row) => row.reason === \"Not being searched\" || !row.reason);\n } else {\n rows = rows.filter((row) => row.reason === reasonFilter);\n }\n }\n return rows;\n }, [aggTrackRows, aggFilter, onlyMissing, reasonFilter]);\n\n const allInstanceAlbums = useMemo(() => {\n const pages = Object.keys(instancePages)\n .map(Number)\n .sort((a, b) => a - b);\n const rows: LidarrAlbumEntry[] = [];\n pages.forEach((pg) => {\n if (instancePages[pg]) {\n rows.push(...instancePages[pg]);\n }\n });\n return rows;\n }, [instancePages]);\n\n const currentPageAlbums = useMemo(() => {\n return instancePages[instancePage] ?? [];\n }, [instancePages, instancePage]);\n\n const handleRestart = useCallback(async () => {\n if (!selection || selection === \"aggregate\") return;\n try {\n await restartArr(selection);\n push(`Restarted ${selection}`, \"success\");\n } catch (error) {\n push(\n error instanceof Error ? error.message : `Failed to restart ${selection}`,\n \"error\"\n );\n }\n }, [selection, push]);\n\n const handleInstanceSelection = useCallback(\n (event: ChangeEvent<HTMLSelectElement>) => {\n const next = (event.target.value || \"aggregate\") as string | \"aggregate\";\n setSelection(next);\n if (next !== \"aggregate\") {\n setGlobalSearch(\"\");\n }\n },\n [setSelection, setGlobalSearch]\n );\n\n const isAggregate = selection === \"aggregate\";\n\n return (\n <section className=\"card\">\n <div className=\"card-header\">Lidarr</div>\n <div className=\"card-body\">\n <div className=\"split\">\n <aside className=\"pane sidebar\">\n {instances.length > 1 && (\n <button\n className={`btn ${isAggregate ? \"active\" : \"\"}`}\n onClick={() => setSelection(\"aggregate\")}\n >\n All Lidarr\n </button>\n )}\n {instances.map((inst) => (\n <button\n key={inst.category}\n className={`btn ghost ${\n selection === inst.category ? \"active\" : \"\"\n }`}\n onClick={() => {\n setSelection(inst.category);\n setGlobalSearch(\"\");\n }}\n >\n {inst.name || inst.category}\n </button>\n ))}\n </aside>\n <div className=\"pane\">\n <div className=\"field mobile-instance-select\">\n <label>Instance</label>\n <select\n value={selection || \"aggregate\"}\n onChange={handleInstanceSelection}\n disabled={!instances.length}\n >\n {instances.length > 1 && <option value=\"aggregate\">All Lidarr</option>}\n {instances.map((inst) => (\n <option key={inst.category} value={inst.category}>\n {inst.name || inst.category}\n </option>\n ))}\n </select>\n </div>\n <div className=\"row\" style={{ alignItems: \"flex-end\", gap: \"12px\", flexWrap: \"wrap\" }}>\n <div className=\"col field\" style={{ flex: \"1 1 200px\" }}>\n <label>Search</label>\n <input\n placeholder=\"Filter albums\"\n value={globalSearch}\n onChange={(event) => setGlobalSearch(event.target.value)}\n />\n </div>\n <div className=\"field\" style={{ flex: \"0 0 auto\", minWidth: \"140px\" }}>\n <label>Status</label>\n <select\n onChange={(event) => {\n const value = event.target.value;\n setOnlyMissing(value === \"missing\");\n }}\n value={onlyMissing ? \"missing\" : \"all\"}\n >\n <option value=\"all\">All Albums</option>\n <option value=\"missing\">Missing Only</option>\n </select>\n </div>\n <div className=\"field\" style={{ flex: \"0 0 auto\", minWidth: \"140px\" }}>\n <label>Search Reason</label>\n <select\n onChange={(event) => setReasonFilter(event.target.value)}\n value={reasonFilter}\n >\n <option value=\"all\">All Reasons</option>\n <option value=\"Not being searched\">Not Being Searched</option>\n <option value=\"Missing\">Missing</option>\n <option value=\"Quality\">Quality</option>\n <option value=\"CustomFormat\">Custom Format</option>\n <option value=\"Upgrade\">Upgrade</option>\n </select>\n </div>\n </div>\n\n {isAggregate ? (\n <LidarrAggregateView\n loading={aggLoading}\n rows={filteredAggRows}\n trackRows={filteredAggTrackRows}\n page={aggPage}\n onPageChange={setAggPage}\n onRefresh={() => void loadAggregate({ showLoading: true })}\n lastUpdated={aggUpdated}\n summary={aggSummary}\n instanceCount={instances.length}\n groupLidarr={groupLidarr}\n isAggFiltered={isAggFiltered}\n />\n ) : (\n <LidarrInstanceView\n loading={instanceLoading}\n data={instanceData}\n page={instancePage}\n totalPages={instanceTotalPages}\n pageSize={instancePageSize}\n allAlbums={groupLidarr ? currentPageAlbums : allInstanceAlbums}\n onlyMissing={onlyMissing}\n reasonFilter={reasonFilter}\n onPageChange={(page) => {\n setInstancePage(page);\n void fetchInstance(selection as string, page, instanceQuery, {\n preloadAll: true,\n });\n }}\n onRestart={() => void handleRestart()}\n lastUpdated={lastUpdated}\n groupLidarr={groupLidarr}\n instances={instances}\n selection={selection as string}\n />\n )}\n </div>\n </div>\n </div>\n </section>\n );\n}\n","import { type JSX } from \"react\";\nimport { RadarrView } from \"./RadarrView\";\nimport { SonarrView } from \"./SonarrView\";\nimport { LidarrView } from \"./LidarrView\";\n\ninterface ArrViewProps {\n type: \"radarr\" | \"sonarr\" | \"lidarr\";\n active: boolean;\n}\n\nexport function ArrView({ type, active }: ArrViewProps): JSX.Element {\n if (type === \"radarr\") {\n return <RadarrView active={active} />;\n }\n if (type === \"lidarr\") {\n return <LidarrView active={active} />;\n }\n return <SonarrView active={active} />;\n}\n"],"names":["StableTableInner","data","columns","getRowKey","table","useReactTable","getCoreRowModel","jsxs","jsx","headerGroup","header","flexRender","row","stableKey","cell","StableTable","memo","prevProps","nextProps","fnv1aHash","str","hash","i","createItemHash","item","fields","values","field","value","detectChanges","existing","incoming","getKey","hashFields","added","updated","removed","seenIds","id","existingItem","existingHash","unchanged","hasChanges","mergeChanges","changes","newById","newByHash","newIds","index","denormalize","createEmptyNormalized","useDataSync","options","normalizedRef","useRef","lastUpdate","setLastUpdate","useState","syncData","useCallback","newData","merged","getData","reset","RADARR_PAGE_SIZE","RADARR_AGG_PAGE_SIZE","RADARR_AGG_FETCH_SIZE","RadarrAggregateView","loading","rows","total","page","totalPages","onPageChange","onRefresh","lastUpdated","sort","onSort","summary","instanceCount","isAggFiltered","useMemo","info","monitored","hasFile","reason","Fragment","IconImage","RefreshIcon","movie","RadarrInstanceView","pageSize","allMovies","onlyMissing","reasonFilter","onRestart","filteredMovies","movies","m","reasonFilteredMovies","totalMovies","isFiltered","filteredCount","getSortedRowModel","RestartIcon","RadarrView","active","push","useToast","globalSearch","setGlobalSearch","register","clearHandler","useSearch","liveArr","setLiveArr","useWebUI","instances","setInstances","selection","setSelection","instanceData","setInstanceData","instancePage","setInstancePage","instanceQuery","setInstanceQuery","instanceLoading","setInstanceLoading","setLastUpdated","instancePages","setInstancePages","instancePageSize","setInstancePageSize","instanceTotalPages","setInstanceTotalPages","instanceKeyRef","instancePagesRef","globalSearchRef","backendReadyWarnedRef","instanceMovieSync","aggRows","setAggRows","aggLoading","setAggLoading","aggPage","setAggPage","aggFilter","setAggFilter","aggUpdated","setAggUpdated","aggMovieSync","aggSort","setAggSort","setOnlyMissing","setReasonFilter","aggSummary","setAggSummary","loadInstances","getArrList","filtered","arr","error","preloadRemainingPages","category","query","pages","key","results","pg","res","getRadarrMovies","resolved","prev","next","syncResult","fetchInstance","preloadAll","keyChanged","response","resolvedPage","totalItems","existingPages","moviesChanged","pagesToFetch","loadAggregate","aggregated","totalAvailable","totalMonitored","inst","counted","label","counts","rowsChanged","newSummary","summaryChanged","useEffect","useInterval","handler","term","filteredAggRows","q","title","instance","sortedAggRows","list","getValue","a","b","valueA","valueB","comparison","aggPages","aggPageRows","allInstanceMovies","handleRestart","restartArr","handleAggRefresh","handleAggSort","handleInstanceRefresh","handleInstanceSelection","event","isAggregate","SONARR_PAGE_SIZE","SONARR_AGG_PAGE_SIZE","SONARR_AGG_FETCH_SIZE","filterSeriesEntriesForMissing","seriesEntries","result","entry","seasons","filteredSeasons","seasonNumber","season","episodes","episode","createFilteredSignature","SonarrView","groupSonarr","setGroupSonarr","instanceDataRef","instanceTotalItems","setInstanceTotalItems","prevSelectionRef","aggEpisodeSync","ep","prevOnlyMissingRef","showLoading","missingOnly","useMissing","getSonarrSeries","series","prevPages","nextPages","prevSignature","nextSignature","shouldUpdateCurrentPage","prevCounts","nextCounts","targetPage","pageIndex","pageSeries","currentPages","prevSnapshot","nextSnapshot","totalMissing","episodeCount","seasonCount","entryEpisodeCount","qualityProfileId","qualityProfileName","episodeReason","reasonCounts","r","selectionChanged","onlyMissingChanged","beforeFilterCount","currentSeries","allSeries","newMissingState","SonarrAggregateView","SonarrInstanceView","prevRowsRef","groupedDataCache","seriesGroupCache","allGroupedData","instanceMap","instanceSeriesMap","seasonMap","newSeriesGroupCache","seriesMap","seriesKey","episodeKeys","episodeKey","cached","firstEpisode","seriesGroup","groupedPageRows","flatPageRows","tableData","groupedColumns","parts","flatColumns","groupedTable","getExpandedRowModel","flatTable","getPaginationRowModel","effectiveTotalPages","safePage","totalItemsDisplay","flatPage","setFlatPage","FLAT_PAGE_SIZE","prevSeriesRef","episodeRowsCache","episodeRows","filteredEpisodeRows","prevEpisodeRowsRef","groupedTableDataCache","groupedTableData","map","seasonKey","seriesName","totalEpisodes","flatTotalPages","flatSafePage","paginatedEpisodeRows","GROUPED_PAGE_SIZE","groupedPage","setGroupedPage","groupedTotalPages","groupedSafePage","paginatedGroupedData","instanceName","idx","LIDARR_PAGE_SIZE","LIDARR_AGG_FETCH_SIZE","LidarrAggregateView","trackRows","groupLidarr","artistGroupCache","groupedData","artist","artistMap","newArtistGroupCache","albums","artistKey","albumKeys","album","albumKey","albumData","artistGroup","start","end","dur","albumEntry","albumTitle","albumId","artistName","releaseDate","tracks","totals","track","LidarrInstanceView","allAlbums","filteredAlbums","reasonFilteredAlbums","totalAlbums","count","prevFilteredAlbumsRef","groupedAlbumsCache","groupedAlbums","date","paginatedAlbums","paginatedGroupedAlbums","LidarrView","instanceAlbumSync","aggTrackRows","setAggTrackRows","aggAlbumSync","aggTrackSync","getLidarrAlbums","albumsChanged","albumEntries","albumSyncResult","trackSyncResult","trackRowsChanged","t","filteredAggTrackRows","allInstanceAlbums","currentPageAlbums","ArrView","type"],"mappings":"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"}
1
+ {"version":3,"file":"ArrView.js","sources":["../../../webui/src/components/StableTable.tsx","../../../webui/src/utils/dataSync.ts","../../../webui/src/hooks/useDataSync.ts","../../../webui/src/pages/RadarrView.tsx","../../../webui/src/pages/SonarrView.tsx","../../../webui/src/pages/LidarrView.tsx","../../../webui/src/pages/ArrView.tsx"],"sourcesContent":["import { memo } from \"react\";\nimport {\n useReactTable,\n getCoreRowModel,\n flexRender,\n type ColumnDef,\n} from \"@tanstack/react-table\";\n\ninterface StableTableProps<TData> {\n data: TData[];\n columns: ColumnDef<TData, unknown>[];\n getRowKey?: (row: TData) => string;\n}\n\nfunction StableTableInner<TData>({ data, columns, getRowKey }: StableTableProps<TData>) {\n const table = useReactTable({\n data,\n columns,\n getCoreRowModel: getCoreRowModel(),\n });\n\n return (\n <div className=\"table-wrapper\">\n <table className=\"responsive-table\">\n <thead>\n {table.getHeaderGroups().map((headerGroup) => (\n <tr key={headerGroup.id}>\n {headerGroup.headers.map((header) => (\n <th key={header.id}>\n {header.isPlaceholder\n ? null\n : flexRender(\n header.column.columnDef.header,\n header.getContext()\n )}\n </th>\n ))}\n </tr>\n ))}\n </thead>\n <tbody>\n {table.getRowModel().rows.map((row) => {\n const stableKey = getRowKey ? getRowKey(row.original) : row.id;\n return (\n <tr key={stableKey}>\n {row.getVisibleCells().map((cell) => (\n <td key={cell.id} data-label={String(cell.column.columnDef.header)}>\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </td>\n ))}\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n );\n}\n\nexport const StableTable = memo(StableTableInner, (prevProps, nextProps) => {\n // Only re-render if data reference changed\n return prevProps.data === nextProps.data && prevProps.columns === nextProps.columns;\n}) as typeof StableTableInner;\n","/**\n * Data synchronization utilities for efficient change detection and incremental updates\n */\n\n/**\n * Fast hash function using FNV-1a algorithm\n */\nfunction fnv1aHash(str: string): string {\n let hash = 2166136261;\n for (let i = 0; i < str.length; i++) {\n hash ^= str.charCodeAt(i);\n hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);\n }\n return (hash >>> 0).toString(36);\n}\n\n/**\n * Generic interface for items that can be hashed\n */\nexport interface Hashable {\n [key: string]: unknown;\n}\n\n/**\n * Result of change detection\n */\nexport interface ChangeDetectionResult<T> {\n added: T[];\n updated: T[];\n removed: string[];\n unchanged: number;\n hasChanges: boolean;\n}\n\n/**\n * Normalized data structure for efficient lookups\n */\nexport interface NormalizedData<T> {\n byId: Map<string, T>;\n byHash: Map<string, string>;\n allIds: string[];\n lastUpdate: number;\n}\n\n/**\n * Create hash from item based on specified fields\n */\nexport function createItemHash<T extends Hashable>(\n item: T,\n fields: (keyof T)[]\n): string {\n const values = fields.map(field => {\n const value = item[field];\n if (value === null || value === undefined) return '';\n if (typeof value === 'boolean') return value ? '1' : '0';\n if (typeof value === 'object') return JSON.stringify(value);\n return String(value);\n });\n return fnv1aHash(values.join('|'));\n}\n\n/**\n * Detect changes between existing and incoming data\n */\nexport function detectChanges<T extends Hashable>(\n existing: NormalizedData<T>,\n incoming: T[],\n getKey: (item: T) => string,\n hashFields: (keyof T)[]\n): ChangeDetectionResult<T> {\n const added: T[] = [];\n const updated: T[] = [];\n const removed: string[] = [];\n const seenIds = new Set<string>();\n\n // Check incoming items\n for (const item of incoming) {\n const id = getKey(item);\n const hash = createItemHash(item, hashFields);\n seenIds.add(id);\n\n const existingItem = existing.byId.get(id);\n const existingHash = existing.byHash.get(id);\n\n if (!existingItem) {\n // New item\n added.push(item);\n } else if (existingHash !== hash) {\n // Item exists but data changed\n updated.push(item);\n }\n }\n\n // Find removed items\n for (const id of existing.allIds) {\n if (!seenIds.has(id)) {\n removed.push(id);\n }\n }\n\n const unchanged = incoming.length - added.length - updated.length;\n const hasChanges = added.length > 0 || updated.length > 0 || removed.length > 0;\n\n return { added, updated, removed, unchanged, hasChanges };\n}\n\n/**\n * Merge changes into normalized data\n */\nexport function mergeChanges<T extends Hashable>(\n existing: NormalizedData<T>,\n changes: ChangeDetectionResult<T>,\n getKey: (item: T) => string,\n hashFields: (keyof T)[]\n): NormalizedData<T> {\n if (!changes.hasChanges) {\n return existing;\n }\n\n const newById = new Map(existing.byId);\n const newByHash = new Map(existing.byHash);\n const newIds = [...existing.allIds];\n\n // Add new items\n for (const item of changes.added) {\n const id = getKey(item);\n const hash = createItemHash(item, hashFields);\n newById.set(id, item);\n newByHash.set(id, hash);\n newIds.push(id);\n }\n\n // Update existing items\n for (const item of changes.updated) {\n const id = getKey(item);\n const hash = createItemHash(item, hashFields);\n newById.set(id, item);\n newByHash.set(id, hash);\n }\n\n // Remove deleted items\n for (const id of changes.removed) {\n newById.delete(id);\n newByHash.delete(id);\n const index = newIds.indexOf(id);\n if (index !== -1) {\n newIds.splice(index, 1);\n }\n }\n\n return {\n byId: newById,\n byHash: newByHash,\n allIds: newIds,\n lastUpdate: Date.now(),\n };\n}\n\n/**\n * Convert normalized data to array\n */\nexport function denormalize<T>(data: NormalizedData<T>): T[] {\n return data.allIds.map(id => data.byId.get(id)!).filter(Boolean);\n}\n\n/**\n * Create normalized data from array\n */\nexport function normalize<T extends Hashable>(\n items: T[],\n getKey: (item: T) => string,\n hashFields: (keyof T)[]\n): NormalizedData<T> {\n const byId = new Map<string, T>();\n const byHash = new Map<string, string>();\n const allIds: string[] = [];\n\n for (const item of items) {\n const id = getKey(item);\n const hash = createItemHash(item, hashFields);\n byId.set(id, item);\n byHash.set(id, hash);\n allIds.push(id);\n }\n\n return {\n byId,\n byHash,\n allIds,\n lastUpdate: Date.now(),\n };\n}\n\n/**\n * Create empty normalized data\n */\nexport function createEmptyNormalized<T>(): NormalizedData<T> {\n return {\n byId: new Map(),\n byHash: new Map(),\n allIds: [],\n lastUpdate: 0,\n };\n}\n\n/**\n * Check if two arrays have the same content (order-independent)\n * Uses fast hash comparison instead of deep equality\n */\nexport function arraysEqual<T extends Hashable>(\n a: T[],\n b: T[],\n getKey: (item: T) => string,\n hashFields: (keyof T)[]\n): boolean {\n if (a.length !== b.length) return false;\n\n const aHashes = new Map<string, string>();\n for (const item of a) {\n const id = getKey(item);\n const hash = createItemHash(item, hashFields);\n aHashes.set(id, hash);\n }\n\n for (const item of b) {\n const id = getKey(item);\n const hash = createItemHash(item, hashFields);\n if (aHashes.get(id) !== hash) return false;\n }\n\n return true;\n}\n","import { useCallback, useRef, useState } from \"react\";\nimport {\n type NormalizedData,\n type ChangeDetectionResult,\n type Hashable,\n createEmptyNormalized,\n detectChanges,\n mergeChanges,\n denormalize,\n} from \"../utils/dataSync\";\n\nexport interface DataSyncOptions<T extends Hashable> {\n getKey: (item: T) => string;\n hashFields: (keyof T)[];\n}\n\nexport interface DataSyncResult<T extends Hashable> {\n data: T[];\n hasChanges: boolean;\n changes: ChangeDetectionResult<T> | null;\n lastUpdate: number;\n}\n\n/**\n * Hook for managing incremental data synchronization\n * Automatically detects changes and prevents unnecessary re-renders\n */\nexport function useDataSync<T extends Hashable>(\n options: DataSyncOptions<T>\n): {\n syncData: (newData: T[]) => DataSyncResult<T>;\n getData: () => T[];\n reset: () => void;\n lastUpdate: number;\n} {\n const { getKey, hashFields } = options;\n\n const normalizedRef = useRef<NormalizedData<T>>(createEmptyNormalized<T>());\n const [lastUpdate, setLastUpdate] = useState(0);\n\n const syncData = useCallback(\n (newData: T[]): DataSyncResult<T> => {\n const changes = detectChanges(\n normalizedRef.current,\n newData,\n getKey,\n hashFields\n );\n\n if (!changes.hasChanges) {\n // No changes detected, return existing data\n return {\n data: denormalize(normalizedRef.current),\n hasChanges: false,\n changes: null,\n lastUpdate: normalizedRef.current.lastUpdate,\n };\n }\n\n // Merge changes into normalized data\n const merged = mergeChanges(\n normalizedRef.current,\n changes,\n getKey,\n hashFields\n );\n\n normalizedRef.current = merged;\n setLastUpdate(merged.lastUpdate);\n\n return {\n data: denormalize(merged),\n hasChanges: true,\n changes,\n lastUpdate: merged.lastUpdate,\n };\n },\n [getKey, hashFields]\n );\n\n const getData = useCallback((): T[] => {\n return denormalize(normalizedRef.current);\n }, []);\n\n const reset = useCallback(() => {\n normalizedRef.current = createEmptyNormalized<T>();\n setLastUpdate(0);\n }, []);\n\n return {\n syncData,\n getData,\n reset,\n lastUpdate,\n };\n}\n","import {\n memo,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ChangeEvent,\n type JSX,\n} from \"react\";\nimport {\n getArrList,\n getRadarrMovies,\n restartArr,\n} from \"../api/client\";\nimport { StableTable } from \"../components/StableTable\";\nimport {\n useReactTable,\n getCoreRowModel,\n getSortedRowModel,\n flexRender,\n type ColumnDef,\n} from \"@tanstack/react-table\";\nimport type {\n ArrInfo,\n RadarrMovie,\n RadarrMoviesResponse,\n} from \"../api/types\";\nimport { useToast } from \"../context/ToastContext\";\nimport { useSearch } from \"../context/SearchContext\";\nimport { useWebUI } from \"../context/WebUIContext\";\nimport { useInterval } from \"../hooks/useInterval\";\nimport { useDataSync } from \"../hooks/useDataSync\";\nimport { IconImage } from \"../components/IconImage\";\nimport RefreshIcon from \"../icons/refresh-arrow.svg\";\nimport RestartIcon from \"../icons/refresh-arrow.svg\";\n\ninterface RadarrAggRow extends RadarrMovie {\n __instance: string;\n [key: string]: unknown;\n}\n\ntype RadarrSortKey = \"title\" | \"year\" | \"monitored\" | \"hasFile\";\ntype RadarrAggSortKey = \"__instance\" | RadarrSortKey;\n\nconst RADARR_PAGE_SIZE = 50;\nconst RADARR_AGG_PAGE_SIZE = 50;\nconst RADARR_AGG_FETCH_SIZE = 500;\n\ninterface RadarrAggregateViewProps {\n loading: boolean;\n rows: RadarrAggRow[];\n total: number;\n page: number;\n totalPages: number;\n onPageChange: (page: number) => void;\n onRefresh: () => void;\n lastUpdated: string | null;\n sort: { key: RadarrAggSortKey; direction: \"asc\" | \"desc\" };\n onSort: (key: RadarrAggSortKey) => void;\n summary: { available: number; monitored: number; missing: number; total: number };\n instanceCount: number;\n isAggFiltered?: boolean;\n}\n\nconst RadarrAggregateView = memo(function RadarrAggregateView({\n loading,\n rows,\n total,\n page,\n totalPages,\n onPageChange,\n onRefresh,\n lastUpdated,\n summary,\n instanceCount,\n isAggFiltered = false,\n}: RadarrAggregateViewProps): JSX.Element {\n const columns = useMemo<ColumnDef<RadarrAggRow>[]>(\n () => [\n ...(instanceCount > 1 ? [{\n accessorKey: \"__instance\",\n header: \"Instance\",\n size: 150,\n }] : []),\n {\n accessorKey: \"title\",\n header: \"Title\",\n cell: (info) => info.getValue(),\n },\n {\n accessorKey: \"year\",\n header: \"Year\",\n size: 80,\n },\n {\n accessorKey: \"monitored\",\n header: \"Monitored\",\n cell: (info) => {\n const monitored = info.getValue() as boolean;\n return (\n <span className={`track-status ${monitored ? 'available' : 'missing'}`}>\n {monitored ? '✓' : '✗'}\n </span>\n );\n },\n size: 100,\n },\n {\n accessorKey: \"hasFile\",\n header: \"Has File\",\n cell: (info) => {\n const hasFile = info.getValue() as boolean;\n return (\n <span className={`track-status ${hasFile ? 'available' : 'missing'}`}>\n {hasFile ? '✓' : '✗'}\n </span>\n );\n },\n size: 100,\n },\n {\n accessorKey: \"qualityProfileName\",\n header: \"Quality Profile\",\n cell: (info) => {\n const profileName = info.getValue() as string | null | undefined;\n return profileName || \"—\";\n },\n size: 150,\n },\n {\n accessorKey: \"reason\",\n header: \"Reason\",\n cell: (info) => {\n const reason = info.getValue() as string | null;\n if (!reason) return <span className=\"table-badge table-badge-reason\">Not being searched</span>;\n return <span className=\"table-badge table-badge-reason\">{reason}</span>;\n },\n size: 120,\n },\n ],\n [instanceCount]\n );\n\n return (\n <div className=\"stack animate-fade-in\">\n <div className=\"row\" style={{ justifyContent: \"space-between\" }}>\n <div className=\"hint\">\n Aggregated movies across all instances{\" \"}\n {lastUpdated ? `(updated ${lastUpdated})` : \"\"}\n <br />\n <strong>Available:</strong>{\" \"}\n {summary.available.toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Monitored:</strong>{\" \"}\n {summary.monitored.toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Missing:</strong>{\" \"}\n {summary.missing.toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Total:</strong>{\" \"}\n {summary.total.toLocaleString(undefined, { maximumFractionDigits: 0 })}\n {isAggFiltered && total < summary.total && (\n <>\n {\" \"}• <strong>Filtered:</strong>{\" \"}\n {total.toLocaleString(undefined, { maximumFractionDigits: 0 })} of{\" \"}\n {summary.total.toLocaleString(undefined, { maximumFractionDigits: 0 })}\n </>\n )}\n </div>\n <button className=\"btn ghost\" onClick={onRefresh} disabled={loading}>\n <IconImage src={RefreshIcon} />\n Refresh\n </button>\n </div>\n\n {loading ? (\n <div className=\"loading\">\n <span className=\"spinner\" /> Loading Radarr library…\n </div>\n ) : total ? (\n <StableTable\n data={rows}\n columns={columns}\n getRowKey={(movie) => `${movie.__instance}-${movie.title}-${movie.year}`}\n />\n ) : (\n <div className=\"hint\">No movies found.</div>\n )}\n\n {total > 0 && (\n <div className=\"pagination\">\n <div>\n Page {page + 1} of {totalPages} ({total.toLocaleString()} items · page size{\" \"}\n {RADARR_AGG_PAGE_SIZE})\n </div>\n <div className=\"inline\">\n <button\n className=\"btn\"\n onClick={() => onPageChange(Math.max(0, page - 1))}\n disabled={page === 0 || loading}\n >\n Prev\n </button>\n <button\n className=\"btn\"\n onClick={() => onPageChange(Math.min(totalPages - 1, page + 1))}\n disabled={page >= totalPages - 1 || loading}\n >\n Next\n </button>\n </div>\n </div>\n )}\n </div>\n );\n});\n\ninterface RadarrInstanceViewProps {\n loading: boolean;\n data: RadarrMoviesResponse | null;\n page: number;\n totalPages: number;\n pageSize: number;\n allMovies: RadarrMovie[];\n onlyMissing: boolean;\n reasonFilter: string;\n onPageChange: (page: number) => void;\n onRefresh: () => void;\n onRestart: () => void;\n lastUpdated: string | null;\n}\n\nconst RadarrInstanceView = memo(function RadarrInstanceView({\n loading,\n data,\n page,\n totalPages,\n pageSize,\n allMovies,\n onlyMissing,\n reasonFilter,\n onPageChange,\n onRestart,\n lastUpdated,\n}: RadarrInstanceViewProps): JSX.Element {\n const filteredMovies = useMemo(() => {\n let movies = allMovies;\n if (onlyMissing) {\n movies = movies.filter((m) => !m.hasFile);\n }\n return movies;\n }, [allMovies, onlyMissing]);\n\n const reasonFilteredMovies = useMemo(() => {\n if (reasonFilter === \"all\") return filteredMovies;\n if (reasonFilter === \"Not being searched\") {\n return filteredMovies.filter((m) => m.reason === \"Not being searched\" || !m.reason);\n }\n return filteredMovies.filter((m) => m.reason === reasonFilter);\n }, [filteredMovies, reasonFilter]);\n\n const totalMovies = useMemo(() => allMovies.length, [allMovies]);\n const isFiltered = reasonFilter !== \"all\" || onlyMissing;\n const filteredCount = reasonFilteredMovies.length;\n\n const columns = useMemo<ColumnDef<RadarrMovie>[]>(\n () => [\n {\n accessorKey: \"title\",\n header: \"Title\",\n cell: (info) => info.getValue(),\n },\n {\n accessorKey: \"year\",\n header: \"Year\",\n size: 80,\n },\n {\n accessorKey: \"monitored\",\n header: \"Monitored\",\n cell: (info) => {\n const monitored = info.getValue() as boolean;\n return (\n <span className={`track-status ${monitored ? 'available' : 'missing'}`}>\n {monitored ? '✓' : '✗'}\n </span>\n );\n },\n size: 100,\n },\n {\n accessorKey: \"hasFile\",\n header: \"Has File\",\n cell: (info) => {\n const hasFile = info.getValue() as boolean;\n return (\n <span className={`track-status ${hasFile ? 'available' : 'missing'}`}>\n {hasFile ? '✓' : '✗'}\n </span>\n );\n },\n size: 100,\n },\n {\n accessorKey: \"qualityProfileName\",\n header: \"Quality Profile\",\n cell: (info) => {\n const profileName = info.getValue() as string | null | undefined;\n return profileName || \"—\";\n },\n size: 150,\n },\n {\n accessorKey: \"reason\",\n header: \"Reason\",\n cell: (info) => {\n const reason = info.getValue() as string | null;\n if (!reason) return <span className=\"table-badge table-badge-reason\">Not being searched</span>;\n return <span className=\"table-badge table-badge-reason\">{reason}</span>;\n },\n size: 120,\n },\n ],\n []\n );\n\n const table = useReactTable({\n data: reasonFilteredMovies.slice(page * pageSize, page * pageSize + pageSize),\n columns,\n getCoreRowModel: getCoreRowModel(),\n getSortedRowModel: getSortedRowModel(),\n });\n\n return (\n <div className=\"stack animate-fade-in\">\n <div className=\"row\" style={{ justifyContent: \"space-between\" }}>\n <div className=\"hint\">\n {data?.counts ? (\n <>\n <strong>Available:</strong>{\" \"}\n {(data.counts.available ?? 0).toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Monitored:</strong>{\" \"}\n {(data.counts.monitored ?? 0).toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Missing:</strong>{\" \"}\n {((data.counts.monitored ?? 0) - (data.counts.available ?? 0)).toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Total:</strong>{\" \"}\n {totalMovies.toLocaleString(undefined, { maximumFractionDigits: 0 })}\n {isFiltered && filteredCount < totalMovies && (\n <>\n {\" \"}• <strong>Filtered:</strong>{\" \"}\n {filteredCount.toLocaleString(undefined, { maximumFractionDigits: 0 })} of{\" \"}\n {totalMovies.toLocaleString(undefined, { maximumFractionDigits: 0 })}\n </>\n )}\n </>\n ) : (\n \"Loading movie information...\"\n )}\n {lastUpdated ? ` (updated ${lastUpdated})` : \"\"}\n </div>\n <button className=\"btn ghost\" onClick={onRestart} disabled={loading}>\n <IconImage src={RestartIcon} />\n Restart\n </button>\n </div>\n\n {loading ? (\n <div className=\"loading\">\n <span className=\"spinner\" /> Loading…\n </div>\n ) : allMovies.length ? (\n <div className=\"table-wrapper\">\n <table className=\"responsive-table\">\n <thead>\n {table.getHeaderGroups().map((headerGroup) => (\n <tr key={headerGroup.id}>\n {headerGroup.headers.map((header) => (\n <th key={header.id}>\n {header.isPlaceholder\n ? null\n : flexRender(\n header.column.columnDef.header,\n header.getContext()\n )}\n </th>\n ))}\n </tr>\n ))}\n </thead>\n <tbody>\n {table.getRowModel().rows.map((row) => {\n const movie = row.original;\n const stableKey = `${movie.title}-${movie.year}`;\n return (\n <tr key={stableKey}>\n {row.getVisibleCells().map((cell) => (\n <td key={cell.id} data-label={String(cell.column.columnDef.header)}>\n {flexRender(\n cell.column.columnDef.cell,\n cell.getContext()\n )}\n </td>\n ))}\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n ) : (\n <div className=\"hint\">No movies found.</div>\n )}\n\n {reasonFilteredMovies.length > pageSize && (\n <div className=\"pagination\">\n <div>\n Page {page + 1} of {totalPages} ({reasonFilteredMovies.length.toLocaleString()} items · page size{\" \"}\n {pageSize})\n </div>\n <div className=\"inline\">\n <button\n className=\"btn\"\n onClick={() => onPageChange(Math.max(0, page - 1))}\n disabled={page === 0 || loading}\n >\n Prev\n </button>\n <button\n className=\"btn\"\n onClick={() => onPageChange(Math.min(totalPages - 1, page + 1))}\n disabled={page >= totalPages - 1 || loading}\n >\n Next\n </button>\n </div>\n </div>\n )}\n </div>\n );\n});\n\nexport function RadarrView({ active }: { active: boolean }): JSX.Element {\n const { push } = useToast();\n const {\n value: globalSearch,\n setValue: setGlobalSearch,\n register,\n clearHandler,\n } = useSearch();\n const { liveArr } = useWebUI();\n\n const [instances, setInstances] = useState<ArrInfo[]>([]);\n const [selection, setSelection] = useState<string | \"aggregate\">(\"\");\n const [instanceData, setInstanceData] = useState<RadarrMoviesResponse | null>(null);\n const [instancePage, setInstancePage] = useState(0);\n const [instanceQuery, setInstanceQuery] = useState(\"\");\n const [instanceLoading, setInstanceLoading] = useState(false);\n const [lastUpdated, setLastUpdated] = useState<string | null>(null);\n const [instancePages, setInstancePages] = useState<Record<number, RadarrMovie[]>>({});\n const [instancePageSize, setInstancePageSize] = useState(RADARR_PAGE_SIZE);\n const [instanceTotalPages, setInstanceTotalPages] = useState(1);\n const instanceKeyRef = useRef<string>(\"\");\n const instancePagesRef = useRef<Record<number, RadarrMovie[]>>({});\n const globalSearchRef = useRef(globalSearch);\n const backendReadyWarnedRef = useRef(false);\n\n // Smart data sync for instance movies\n const instanceMovieSync = useDataSync<RadarrMovie>({\n getKey: (movie) => `${movie.title}-${movie.year}`,\n hashFields: ['title', 'year', 'hasFile', 'monitored', 'reason'],\n });\n\n const [aggRows, setAggRows] = useState<RadarrAggRow[]>([]);\n const [aggLoading, setAggLoading] = useState(false);\n const [aggPage, setAggPage] = useState(0);\n const [aggFilter, setAggFilter] = useState(\"\");\n const [aggUpdated, setAggUpdated] = useState<string | null>(null);\n\n // Smart data sync for aggregate movies\n const aggMovieSync = useDataSync<RadarrAggRow>({\n getKey: (movie) => `${movie.__instance}-${movie.title}-${movie.year}`,\n hashFields: ['__instance', 'title', 'year', 'hasFile', 'monitored', 'reason'],\n });\n const [aggSort, setAggSort] = useState<{\n key: RadarrAggSortKey;\n direction: \"asc\" | \"desc\";\n }>({ key: \"__instance\", direction: \"asc\" });\n const [onlyMissing, setOnlyMissing] = useState(false);\n const [reasonFilter, setReasonFilter] = useState<string>(\"all\");\n const [aggSummary, setAggSummary] = useState<{\n available: number;\n monitored: number;\n missing: number;\n total: number;\n }>({ available: 0, monitored: 0, missing: 0, total: 0 });\n\n const loadInstances = useCallback(async () => {\n try {\n const data = await getArrList();\n if (data.ready === false && !backendReadyWarnedRef.current) {\n backendReadyWarnedRef.current = true;\n push(\"Radarr backend is still initialising. Check the logs if this persists.\", \"info\");\n } else if (data.ready) {\n backendReadyWarnedRef.current = true;\n }\n const filtered = (data.arr || []).filter((arr) => arr.type === \"radarr\");\n setInstances(filtered);\n if (!filtered.length) {\n setSelection(\"aggregate\");\n setInstanceData(null);\n setAggRows([]);\n setAggSummary({ available: 0, monitored: 0, missing: 0, total: 0 });\n return;\n }\n if (selection === \"\") {\n // If only 1 instance, select it directly; otherwise use aggregate\n setSelection(filtered.length === 1 ? filtered[0].category : \"aggregate\");\n } else if (\n selection !== \"aggregate\" &&\n !filtered.some((arr) => arr.category === selection)\n ) {\n setSelection(filtered[0].category);\n }\n } catch (error) {\n push(\n error instanceof Error\n ? error.message\n : \"Unable to load Radarr instances\",\n \"error\"\n );\n }\n }, [push, selection]);\n\n const preloadRemainingPages = useCallback(\n async (\n category: string,\n query: string,\n pageSize: number,\n pages: number[],\n key: string\n ) => {\n if (!pages.length) return;\n try {\n const results: { page: number; movies: RadarrMovie[] }[] = [];\n for (const pg of pages) {\n const res = await getRadarrMovies(category, pg, pageSize, query);\n const resolved = res.page ?? pg;\n results.push({ page: resolved, movies: res.movies ?? [] });\n if (instanceKeyRef.current !== key) {\n return;\n }\n }\n if (instanceKeyRef.current !== key) return;\n\n // Smart diffing: only update pages that actually changed\n setInstancePages((prev) => {\n const next = { ...prev };\n let hasChanges = false;\n for (const { page, movies } of results) {\n // Use hash-based comparison for each page\n const syncResult = instanceMovieSync.syncData(movies);\n if (syncResult.hasChanges) {\n next[page] = syncResult.data;\n hasChanges = true;\n }\n }\n instancePagesRef.current = next;\n return hasChanges ? next : prev;\n });\n } catch (error) {\n push(\n error instanceof Error\n ? error.message\n : `Failed to load additional pages for ${category}`,\n \"error\"\n );\n }\n },\n [push]\n );\n\n const fetchInstance = useCallback(\n async (\n category: string,\n page: number,\n query: string,\n options: { preloadAll?: boolean; showLoading?: boolean } = {}\n ) => {\n const preloadAll = options.preloadAll !== false;\n const showLoading = options.showLoading ?? true;\n if (showLoading) {\n setInstanceLoading(true);\n }\n try {\n const key = `${category}::${query}`;\n const keyChanged = instanceKeyRef.current !== key;\n if (keyChanged) {\n instanceKeyRef.current = key;\n setInstancePages(() => {\n instancePagesRef.current = {};\n return {};\n });\n }\n const response = await getRadarrMovies(\n category,\n page,\n RADARR_PAGE_SIZE,\n query\n );\n setInstanceData(response);\n const resolvedPage = response.page ?? page;\n setInstancePage(resolvedPage);\n setInstanceQuery(query);\n const pageSize = response.page_size ?? RADARR_PAGE_SIZE;\n const totalItems = response.total ?? (response.movies ?? []).length;\n const totalPages = Math.max(1, Math.ceil((totalItems || 0) / pageSize));\n setInstancePageSize(pageSize);\n setInstanceTotalPages(totalPages);\n const movies = response.movies ?? [];\n const existingPages = keyChanged ? {} : instancePagesRef.current;\n\n // Smart diffing using hash-based change detection\n const syncResult = instanceMovieSync.syncData(movies);\n const moviesChanged = syncResult.hasChanges;\n\n if (keyChanged) {\n // Reset sync state on key change\n instanceMovieSync.reset();\n }\n\n if (keyChanged || moviesChanged) {\n setInstancePages((prev) => {\n const base = keyChanged ? {} : prev;\n const next = { ...base, [resolvedPage]: syncResult.data };\n instancePagesRef.current = next;\n return next;\n });\n setLastUpdated(new Date().toLocaleTimeString());\n }\n\n if (preloadAll) {\n const pagesToFetch: number[] = [];\n for (let i = 0; i < totalPages; i += 1) {\n if (i === resolvedPage) continue;\n if (!existingPages[i]) {\n pagesToFetch.push(i);\n }\n }\n void preloadRemainingPages(\n category,\n query,\n pageSize,\n pagesToFetch,\n key\n );\n }\n } catch (error) {\n push(\n error instanceof Error\n ? error.message\n : `Failed to load ${category} movies`,\n \"error\"\n );\n } finally {\n setInstanceLoading(false);\n }\n },\n [push, preloadRemainingPages]\n );\n\n const loadAggregate = useCallback(async (options?: { showLoading?: boolean }) => {\n if (!instances.length) {\n setAggRows([]);\n setAggSummary({ available: 0, monitored: 0, missing: 0, total: 0 });\n return;\n }\n const showLoading = options?.showLoading ?? true;\n if (showLoading) {\n setAggLoading(true);\n }\n try {\n const aggregated: RadarrAggRow[] = [];\n let totalAvailable = 0;\n let totalMonitored = 0;\n for (const inst of instances) {\n let page = 0;\n let counted = false;\n const label = inst.name || inst.category;\n while (page < 100) {\n const res = await getRadarrMovies(\n inst.category,\n page,\n RADARR_AGG_FETCH_SIZE,\n \"\"\n );\n if (!counted) {\n const counts = res.counts;\n if (counts) {\n totalAvailable += counts.available ?? 0;\n totalMonitored += counts.monitored ?? 0;\n }\n counted = true;\n }\n const movies = res.movies ?? [];\n movies.forEach((movie) => {\n aggregated.push({ ...movie, __instance: label });\n });\n if (!movies.length || movies.length < RADARR_AGG_FETCH_SIZE) break;\n page += 1;\n }\n }\n\n // Smart diffing using hash-based change detection\n const syncResult = aggMovieSync.syncData(aggregated);\n const rowsChanged = syncResult.hasChanges;\n\n if (rowsChanged) {\n setAggRows(syncResult.data);\n }\n\n const newSummary = {\n available: totalAvailable,\n monitored: totalMonitored,\n missing: aggregated.length - totalAvailable,\n total: aggregated.length,\n };\n\n const summaryChanged = (\n aggSummary.available !== newSummary.available ||\n aggSummary.monitored !== newSummary.monitored ||\n aggSummary.missing !== newSummary.missing ||\n aggSummary.total !== newSummary.total\n );\n\n if (summaryChanged) {\n setAggSummary(newSummary);\n }\n\n // Only reset page if filter changed, not on refresh\n if (aggFilter !== globalSearch) {\n setAggPage(0);\n setAggFilter(globalSearch);\n }\n\n // Only update timestamp if data actually changed\n if (rowsChanged || summaryChanged) {\n setAggUpdated(new Date().toLocaleTimeString());\n }\n } catch (error) {\n setAggRows([]);\n setAggSummary({ available: 0, monitored: 0, missing: 0, total: 0 });\n push(\n error instanceof Error\n ? error.message\n : \"Failed to load aggregated Radarr data\",\n \"error\"\n );\n } finally {\n setAggLoading(false);\n }\n }, [instances, globalSearch, push, aggFilter]);\n\n // LiveArr is now loaded via WebUIContext, no need to load config here\n\n useEffect(() => {\n if (!active) return;\n void loadInstances();\n }, [active, loadInstances]);\n\n useEffect(() => {\n if (!active) return;\n if (!selection || selection === \"aggregate\") return;\n instancePagesRef.current = {};\n setInstancePages({});\n setInstanceTotalPages(1);\n setInstancePage(0);\n const query = globalSearchRef.current;\n void fetchInstance(selection, 0, query, {\n preloadAll: true,\n showLoading: true,\n });\n }, [active, selection, fetchInstance]); // Removed onlyMissing to prevent refresh\n\n useEffect(() => {\n if (!active) return;\n if (selection !== \"aggregate\") return;\n void loadAggregate();\n }, [active, selection, loadAggregate]);\n\n useInterval(() => {\n if (selection === \"aggregate\" && liveArr) {\n void loadAggregate({ showLoading: false });\n }\n }, selection === \"aggregate\" && liveArr ? 1000 : null);\n\n useEffect(() => {\n if (!active) return;\n const handler = (term: string) => {\n if (selection === \"aggregate\") {\n setAggFilter(term);\n setAggPage(0);\n } else if (selection) {\n setInstancePage(0);\n void fetchInstance(selection, 0, term, {\n preloadAll: true,\n showLoading: true,\n });\n }\n };\n register(handler);\n return () => {\n clearHandler(handler);\n };\n }, [active, selection, register, clearHandler, fetchInstance]);\n\n useInterval(\n () => {\n if (selection && selection !== \"aggregate\") {\n const activeFilter = globalSearchRef.current?.trim?.() || \"\";\n if (activeFilter) {\n return;\n }\n void fetchInstance(selection, instancePage, instanceQuery, {\n preloadAll: false,\n showLoading: false,\n });\n }\n },\n active && selection && selection !== \"aggregate\" && liveArr ? 1000 : null\n );\n\n // Removed: Don't reset page when filter changes - preserve scroll position\n\n useEffect(() => {\n globalSearchRef.current = globalSearch;\n }, [globalSearch]);\n\n useEffect(() => {\n if (selection === \"aggregate\") {\n setAggFilter(globalSearch);\n }\n }, [selection, globalSearch]);\n\n const filteredAggRows = useMemo(() => {\n let rows = aggRows;\n if (aggFilter) {\n const q = aggFilter.toLowerCase();\n rows = rows.filter((row) => {\n const title = (row.title ?? \"\").toString().toLowerCase();\n const instance = (row.__instance ?? \"\").toLowerCase();\n return title.includes(q) || instance.includes(q);\n });\n }\n if (onlyMissing) {\n rows = rows.filter((row) => !row.hasFile);\n }\n if (reasonFilter !== \"all\") {\n if (reasonFilter === \"Not being searched\") {\n rows = rows.filter((row) => row.reason === \"Not being searched\" || !row.reason);\n } else {\n rows = rows.filter((row) => row.reason === reasonFilter);\n }\n }\n return rows;\n }, [aggRows, aggFilter, onlyMissing, reasonFilter]);\n\n const isAggFiltered = Boolean(aggFilter) || reasonFilter !== \"all\";\n\n const sortedAggRows = useMemo(() => {\n const list = [...filteredAggRows];\n const getValue = (row: RadarrAggRow, key: RadarrAggSortKey) => {\n switch (key) {\n case \"__instance\":\n return (row.__instance || \"\").toLowerCase();\n case \"title\":\n return (row.title || \"\").toLowerCase();\n case \"year\":\n return row.year ?? 0;\n case \"monitored\":\n return row.monitored ? 1 : 0;\n case \"hasFile\":\n return row.hasFile ? 1 : 0;\n default:\n return \"\";\n }\n };\n list.sort((a, b) => {\n const valueA = getValue(a, aggSort.key);\n const valueB = getValue(b, aggSort.key);\n let comparison = 0;\n if (typeof valueA === \"number\" && typeof valueB === \"number\") {\n comparison = valueA - valueB;\n } else if (typeof valueA === \"string\" && typeof valueB === \"string\") {\n comparison = valueA.localeCompare(valueB);\n } else {\n comparison = String(valueA).localeCompare(String(valueB));\n }\n return aggSort.direction === \"asc\" ? comparison : -comparison;\n });\n return list;\n }, [filteredAggRows, aggSort]);\n\n const aggPages = Math.max(\n 1,\n Math.ceil(sortedAggRows.length / RADARR_AGG_PAGE_SIZE)\n );\n const aggPageRows = useMemo(\n () => sortedAggRows.slice(\n aggPage * RADARR_AGG_PAGE_SIZE,\n aggPage * RADARR_AGG_PAGE_SIZE + RADARR_AGG_PAGE_SIZE\n ),\n [sortedAggRows, aggPage]\n );\n\n const allInstanceMovies = useMemo(() => {\n const pages = Object.keys(instancePages)\n .map(Number)\n .sort((a, b) => a - b);\n const rows: RadarrMovie[] = [];\n pages.forEach((pg) => {\n if (instancePages[pg]) {\n rows.push(...instancePages[pg]);\n }\n });\n return rows;\n }, [instancePages]);\n\n const handleRestart = useCallback(async () => {\n if (!selection || selection === \"aggregate\") return;\n try {\n await restartArr(selection);\n push(`Restarted ${selection}`, \"success\");\n } catch (error) {\n push(\n error instanceof Error ? error.message : `Failed to restart ${selection}`,\n \"error\"\n );\n }\n }, [selection, push]);\n\n const handleAggRefresh = useCallback(() => {\n void loadAggregate({ showLoading: true });\n }, [loadAggregate]);\n\n const handleAggSort = useCallback((key: RadarrAggSortKey) => {\n setAggSort((prev) =>\n prev.key === key\n ? {\n key,\n direction: prev.direction === \"asc\" ? \"desc\" : \"asc\",\n }\n : { key, direction: \"asc\" }\n );\n }, []);\n\n const handleInstanceRefresh = useCallback(() => {\n if (selection && selection !== \"aggregate\") {\n void fetchInstance(selection, instancePage, instanceQuery, {\n preloadAll: false,\n showLoading: true,\n });\n }\n }, [selection, instancePage, instanceQuery, fetchInstance]);\n\n const handleInstanceSelection = useCallback(\n (event: ChangeEvent<HTMLSelectElement>) => {\n const next = (event.target.value || \"aggregate\") as string | \"aggregate\";\n setSelection(next);\n if (next !== \"aggregate\") {\n setGlobalSearch(\"\");\n }\n },\n [setSelection, setGlobalSearch]\n );\n\n const isAggregate = selection === \"aggregate\";\n\n return (\n <section className=\"card\">\n <div className=\"card-header\">Radarr</div>\n <div className=\"card-body\">\n <div className=\"split\">\n <aside className=\"pane sidebar\">\n {instances.length > 1 && (\n <button\n className={`btn ${isAggregate ? \"active\" : \"\"}`}\n onClick={() => setSelection(\"aggregate\")}\n >\n All Radarr\n </button>\n )}\n {instances.map((inst) => (\n <button\n key={inst.category}\n className={`btn ghost ${\n selection === inst.category ? \"active\" : \"\"\n }`}\n onClick={() => {\n setSelection(inst.category);\n setGlobalSearch(\"\");\n }}\n >\n {inst.name || inst.category}\n </button>\n ))}\n </aside>\n <div className=\"pane\">\n <div className=\"field mobile-instance-select\">\n <label>Instance</label>\n <select\n value={selection || \"aggregate\"}\n onChange={handleInstanceSelection}\n disabled={!instances.length}\n >\n {instances.length > 1 && <option value=\"aggregate\">All Radarr</option>}\n {instances.map((inst) => (\n <option key={inst.category} value={inst.category}>\n {inst.name || inst.category}\n </option>\n ))}\n </select>\n </div>\n <div className=\"row\" style={{ alignItems: \"flex-end\", gap: \"12px\", flexWrap: \"wrap\" }}>\n <div className=\"col field\" style={{ flex: \"1 1 200px\" }}>\n <label>Search</label>\n <input\n placeholder=\"Filter movies\"\n value={globalSearch}\n onChange={(event) => setGlobalSearch(event.target.value)}\n />\n </div>\n <div className=\"field\" style={{ flex: \"0 0 auto\", minWidth: \"140px\" }}>\n <label>Status</label>\n <select\n onChange={(event) => {\n const value = event.target.value;\n setOnlyMissing(value === \"missing\");\n }}\n value={onlyMissing ? \"missing\" : \"all\"}\n >\n <option value=\"all\">All Movies</option>\n <option value=\"missing\">Missing Only</option>\n </select>\n </div>\n <div className=\"field\" style={{ flex: \"0 0 auto\", minWidth: \"140px\" }}>\n <label>Search Reason</label>\n <select\n onChange={(event) => setReasonFilter(event.target.value)}\n value={reasonFilter}\n >\n <option value=\"all\">All Reasons</option>\n <option value=\"Not being searched\">Not Being Searched</option>\n <option value=\"Missing\">Missing</option>\n <option value=\"Quality\">Quality</option>\n <option value=\"CustomFormat\">Custom Format</option>\n <option value=\"Upgrade\">Upgrade</option>\n </select>\n </div>\n </div>\n\n {isAggregate ? (\n <RadarrAggregateView\n loading={aggLoading}\n rows={aggPageRows}\n total={sortedAggRows.length}\n page={aggPage}\n totalPages={aggPages}\n onPageChange={setAggPage}\n onRefresh={handleAggRefresh}\n lastUpdated={aggUpdated}\n sort={aggSort}\n onSort={handleAggSort}\n summary={aggSummary}\n instanceCount={instances.length}\n isAggFiltered={isAggFiltered}\n />\n ) : (\n <RadarrInstanceView\n loading={instanceLoading}\n data={instanceData}\n page={instancePage}\n totalPages={instanceTotalPages}\n pageSize={instancePageSize}\n allMovies={allInstanceMovies}\n onlyMissing={onlyMissing}\n reasonFilter={reasonFilter}\n onPageChange={(page) => {\n setInstancePage(page);\n void fetchInstance(selection as string, page, instanceQuery, {\n preloadAll: true,\n });\n }}\n onRefresh={handleInstanceRefresh}\n onRestart={() => void handleRestart()}\n lastUpdated={lastUpdated}\n />\n )}\n </div>\n </div>\n </div>\n </section>\n );\n}\n","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ChangeEvent,\n type JSX,\n} from \"react\";\nimport {\n getArrList,\n getSonarrSeries,\n restartArr,\n} from \"../api/client\";\nimport {\n useReactTable,\n getCoreRowModel,\n getSortedRowModel,\n getPaginationRowModel,\n getExpandedRowModel,\n flexRender,\n type ColumnDef,\n} from \"@tanstack/react-table\";\nimport type {\n ArrInfo,\n SonarrEpisode,\n SonarrSeriesEntry,\n SonarrSeriesResponse,\n SonarrSeason,\n} from \"../api/types\";\nimport { useToast } from \"../context/ToastContext\";\nimport { useSearch } from \"../context/SearchContext\";\nimport { useWebUI } from \"../context/WebUIContext\";\nimport { useInterval } from \"../hooks/useInterval\";\nimport { useDataSync } from \"../hooks/useDataSync\";\nimport { IconImage } from \"../components/IconImage\";\nimport RefreshIcon from \"../icons/refresh-arrow.svg\";\n\ninterface SonarrViewProps {\n active: boolean;\n}\n\ninterface SonarrAggRow {\n __instance: string;\n series: string;\n season: number | string;\n episode: number | string;\n title: string;\n monitored: boolean;\n hasFile: boolean;\n airDate: string;\n reason?: string | null;\n qualityProfileId?: number | null;\n qualityProfileName?: string | null;\n [key: string]: unknown;\n}\n\nconst SONARR_PAGE_SIZE = 25;\nconst SONARR_AGG_PAGE_SIZE = 50;\nconst SONARR_AGG_FETCH_SIZE = 200;\n\nfunction filterSeriesEntriesForMissing(seriesEntries: SonarrSeriesEntry[], onlyMissing: boolean): SonarrSeriesEntry[] {\n if (!onlyMissing) return seriesEntries;\n const result: SonarrSeriesEntry[] = [];\n for (const entry of seriesEntries) {\n const seasons = entry.seasons ?? {};\n const filteredSeasons: Record<string, SonarrSeason> = {};\n for (const [seasonNumber, season] of Object.entries(seasons)) {\n const episodes = (season.episodes ?? []).filter((episode) => !episode.hasFile);\n if (!episodes.length) continue;\n filteredSeasons[seasonNumber] = { ...season, episodes };\n }\n if (Object.keys(filteredSeasons).length === 0) continue;\n result.push({\n ...entry,\n seasons: filteredSeasons,\n });\n }\n return result;\n}\n\nfunction createFilteredSignature(seriesEntries: SonarrSeriesEntry[], onlyMissing: boolean): string {\n return JSON.stringify(filterSeriesEntriesForMissing(seriesEntries, onlyMissing));\n}\n\nexport function SonarrView({ active }: SonarrViewProps): JSX.Element {\n const { push } = useToast();\n const {\n value: globalSearch,\n setValue: setGlobalSearch,\n register,\n clearHandler,\n } = useSearch();\n const { liveArr, groupSonarr } = useWebUI();\n\n const [instances, setInstances] = useState<ArrInfo[]>([]);\n const [selection, setSelection] = useState<string | \"\">(\"\");\n const [instanceData, setInstanceData] =\n useState<SonarrSeriesResponse | null>(null);\n const [instancePage, setInstancePage] = useState(0);\n const [instanceQuery, setInstanceQuery] = useState(\"\");\n const [instanceLoading, setInstanceLoading] = useState(false);\n const [lastUpdated, setLastUpdated] = useState<string | null>(null);\n const [instancePages, setInstancePages] = useState<\n Record<number, SonarrSeriesEntry[]>\n >({});\n const instancePagesRef = useRef<Record<number, SonarrSeriesEntry[]>>({});\n const instanceDataRef = useRef<SonarrSeriesResponse | null>(null);\n const instanceKeyRef = useRef<string>(\"\");\n const [instancePageSize, setInstancePageSize] = useState(SONARR_PAGE_SIZE);\n const [instanceTotalPages, setInstanceTotalPages] = useState(1);\n const [instanceTotalItems, setInstanceTotalItems] = useState(0);\n const globalSearchRef = useRef(globalSearch);\n const backendReadyWarnedRef = useRef(false);\n const prevSelectionRef = useRef<string | \"\">(selection);\n\n const [aggRows, setAggRows] = useState<SonarrAggRow[]>([]);\n const [aggLoading, setAggLoading] = useState(false);\n const [aggPage, setAggPage] = useState(0);\n const [aggFilter, setAggFilter] = useState(\"\");\n const [aggUpdated, setAggUpdated] = useState<string | null>(null);\n\n // Smart data sync for aggregate episodes\n const aggEpisodeSync = useDataSync<SonarrAggRow>({\n getKey: (ep) => `${ep.__instance}-${ep.series}-${ep.season}-${ep.episode}`,\n hashFields: ['__instance', 'series', 'season', 'episode', 'title', 'hasFile', 'monitored', 'airDate', 'reason', 'qualityProfileId', 'qualityProfileName'],\n });\n\n const [onlyMissing, setOnlyMissing] = useState(false);\n const prevOnlyMissingRef = useRef(onlyMissing);\n const [reasonFilter, setReasonFilter] = useState<string>(\"all\");\n const [aggSummary, setAggSummary] = useState<{\n available: number;\n monitored: number;\n missing: number;\n total: number;\n }>({ available: 0, monitored: 0, missing: 0, total: 0 });\n\n // LiveArr and GroupSonarr are now loaded via WebUIContext, no need to load config here\n\n const loadInstances = useCallback(async () => {\n try {\n const data = await getArrList();\n if (data.ready === false && !backendReadyWarnedRef.current) {\n backendReadyWarnedRef.current = true;\n push(\"Sonarr backend is still initialising. Check the logs if this persists.\", \"info\");\n } else if (data.ready) {\n backendReadyWarnedRef.current = true;\n }\n const filtered = (data.arr || []).filter((arr) => arr.type === \"sonarr\");\n setInstances(filtered);\n if (!filtered.length) {\n setSelection(\"aggregate\");\n setInstanceData(null);\n setAggRows([]);\n setAggSummary({ available: 0, monitored: 0, missing: 0, total: 0 });\n return;\n }\n if (selection === \"\") {\n // If only 1 instance, select it directly; otherwise use aggregate\n setSelection(filtered.length === 1 ? filtered[0].category : \"aggregate\");\n } else if (\n selection !== \"aggregate\" &&\n !filtered.some((arr) => arr.category === selection)\n ) {\n setSelection(filtered[0].category);\n }\n } catch (error) {\n push(\n error instanceof Error\n ? error.message\n : \"Unable to load Sonarr instances\",\n \"error\"\n );\n }\n }, [push, selection]);\n\n const fetchInstance = useCallback(\n async (\n category: string,\n page: number,\n query: string,\n options: { preloadAll?: boolean; showLoading?: boolean; missingOnly?: boolean } = {}\n ) => {\n const { preloadAll = true, showLoading = true, missingOnly } = options;\n const useMissing = missingOnly ?? onlyMissing;\n if (showLoading) {\n setInstanceLoading(true);\n }\n try {\n const key = `${category}::${query}::${useMissing ? \"missing\" : \"all\"}`;\n const keyChanged = instanceKeyRef.current !== key;\n if (keyChanged) {\n instanceKeyRef.current = key;\n setInstancePages(() => {\n instancePagesRef.current = {};\n return {};\n });\n setInstanceTotalItems(0);\n setInstanceTotalPages(1);\n }\n const response = await getSonarrSeries(\n category,\n page,\n SONARR_PAGE_SIZE,\n query,\n { missingOnly: useMissing }\n );\n console.log(`[Sonarr Instance] Response for ${category} page ${page}:`, {\n total: response.total,\n page: response.page,\n page_size: response.page_size,\n series_count: response.series?.length ?? 0,\n counts: response.counts,\n missingOnly: useMissing,\n firstSeries: response.series?.[0] ? {\n title: response.series[0].series?.title,\n seasonsCount: Object.keys(response.series[0].seasons ?? {}).length,\n firstSeasonEpisodes: Object.values(response.series[0].seasons ?? {})[0]?.episodes?.length ?? 0\n } : null\n });\n const resolvedPage = response.page ?? page;\n const pageSize = response.page_size ?? SONARR_PAGE_SIZE;\n const totalItems = response.total ?? (response.series ?? []).length;\n const totalPages = Math.max(1, Math.ceil((totalItems || 0) / pageSize));\n const series = response.series ?? [];\n\n const prevPages = keyChanged ? {} : instancePagesRef.current;\n const nextPages = { ...prevPages, [resolvedPage]: series };\n const prevSignature = createFilteredSignature(prevPages[resolvedPage] ?? [], useMissing);\n const nextSignature = createFilteredSignature(series, useMissing);\n const shouldUpdateCurrentPage = keyChanged || prevSignature !== nextSignature;\n\n instancePagesRef.current = nextPages;\n if (shouldUpdateCurrentPage) {\n setInstancePages(nextPages);\n }\n\n setInstanceData((prev) => {\n const prevCounts = prev?.counts ?? null;\n const nextCounts = response.counts ?? null;\n const countsChanged =\n !prev ||\n prev.total !== response.total ||\n prev.page !== response.page ||\n prev.page_size !== response.page_size ||\n (prevCounts?.available ?? null) !== (nextCounts?.available ?? null) ||\n (prevCounts?.monitored ?? null) !== (nextCounts?.monitored ?? null) ||\n (prevCounts?.missing ?? null) !== (nextCounts?.missing ?? null);\n if (countsChanged || shouldUpdateCurrentPage) {\n instanceDataRef.current = response;\n return response;\n }\n return prev;\n });\n\n setInstancePage((prev) => (prev === resolvedPage ? prev : resolvedPage));\n setInstanceQuery((prev) => (prev === query ? prev : query));\n setInstancePageSize((prev) => (prev === pageSize ? prev : pageSize));\n setInstanceTotalPages((prev) => (prev === totalPages ? prev : totalPages));\n setInstanceTotalItems((prev) => (prev === totalItems ? prev : totalItems));\n\n if (shouldUpdateCurrentPage) {\n setLastUpdated(new Date().toLocaleTimeString());\n }\n\n if (preloadAll) {\n const pagesToFetch: number[] = [];\n for (let i = 0; i < totalPages; i += 1) {\n if (i === resolvedPage) continue;\n if (!nextPages[i]) {\n pagesToFetch.push(i);\n }\n }\n for (const targetPage of pagesToFetch) {\n try {\n const res = await getSonarrSeries(\n category,\n targetPage,\n pageSize,\n query,\n { missingOnly: useMissing }\n );\n if (instanceKeyRef.current !== key) {\n break;\n }\n const pageIndex = res.page ?? targetPage;\n const pageSeries = res.series ?? [];\n const currentPages = instancePagesRef.current;\n const prevSnapshot = createFilteredSignature(currentPages[pageIndex] ?? [], useMissing);\n const nextSnapshot = createFilteredSignature(pageSeries, useMissing);\n if (prevSnapshot === nextSnapshot) {\n instancePagesRef.current = { ...currentPages, [pageIndex]: pageSeries };\n continue;\n }\n setInstancePages((prev) => {\n const updated = { ...prev, [pageIndex]: pageSeries };\n instancePagesRef.current = updated;\n return updated;\n });\n } catch {\n break;\n }\n }\n }\n } catch (error) {\n push(\n error instanceof Error\n ? error.message\n : `Failed to load ${category} series`,\n \"error\"\n );\n } finally {\n if (showLoading) {\n setInstanceLoading(false);\n }\n }\n },\n [push, onlyMissing]\n );\n\n const loadAggregate = useCallback(async (options?: { showLoading?: boolean }) => {\n if (!instances.length) {\n setAggRows([]);\n setAggSummary({ available: 0, monitored: 0, missing: 0, total: 0 });\n return;\n }\n console.log(`[Sonarr Aggregate] Starting aggregation for ${instances.length} instances`);\n const showLoading = options?.showLoading ?? true;\n if (showLoading) {\n setAggLoading(true);\n }\n try {\n const aggregated: SonarrAggRow[] = [];\n let totalAvailable = 0;\n let totalMonitored = 0;\n let totalMissing = 0;\n for (const inst of instances) {\n let page = 0;\n let counted = false;\n const label = inst.name || inst.category;\n console.log(`[Sonarr Aggregate] Processing instance: ${label}`);\n while (page < 200) {\n const res = await getSonarrSeries(\n inst.category,\n page,\n SONARR_AGG_FETCH_SIZE,\n \"\",\n { missingOnly: onlyMissing }\n );\n console.log(`[Sonarr Aggregate] Response for ${label} page ${page}:`, {\n total: res.total,\n page: res.page,\n page_size: res.page_size,\n series_count: res.series?.length ?? 0,\n counts: res.counts,\n missingOnly: onlyMissing,\n firstSeries: res.series?.[0] ? {\n title: res.series[0].series?.title,\n seasonsCount: Object.keys(res.series[0].seasons ?? {}).length,\n firstSeasonEpisodes: Object.values(res.series[0].seasons ?? {})[0]?.episodes?.length ?? 0,\n firstEpisode: Object.values(res.series[0].seasons ?? {})[0]?.episodes?.[0]\n } : null\n });\n if (!counted) {\n const counts = res.counts;\n if (counts) {\n totalAvailable += counts.available ?? 0;\n totalMonitored += counts.monitored ?? 0;\n totalMissing += counts.missing ?? 0;\n }\n counted = true;\n }\n const series = res.series ?? [];\n let episodeCount = 0;\n series.forEach((entry: SonarrSeriesEntry) => {\n // const seasonCount = Object.keys(entry.seasons ?? {}).length;\n let entryEpisodeCount = 0;\n Object.values(entry.seasons ?? {}).forEach(season => {\n entryEpisodeCount += (season.episodes ?? []).length;\n });\n episodeCount += entryEpisodeCount;\n });\n console.log(`[Sonarr Aggregate] Instance: ${label}, Page: ${page}, Series count: ${series.length}, Total episodes so far: ${aggregated.length}, Episodes in this response: ${episodeCount}`);\n series.forEach((entry: SonarrSeriesEntry) => {\n const title =\n (entry.series?.[\"title\"] as string | undefined) || \"\";\n const qualityProfileId = entry.series?.qualityProfileId ?? null;\n const qualityProfileName = entry.series?.qualityProfileName ?? null;\n Object.entries(entry.seasons ?? {}).forEach(\n ([seasonNumber, season]) => {\n (season.episodes ?? []).forEach((episode: SonarrEpisode) => {\n const episodeReason = (episode.reason as string | null | undefined) ?? null;\n aggregated.push({\n __instance: label,\n series: title,\n season: seasonNumber,\n episode: episode.episodeNumber ?? \"\",\n title: episode.title ?? \"\",\n monitored: !!episode.monitored,\n hasFile: !!episode.hasFile,\n airDate: episode.airDateUtc ?? \"\",\n reason: episodeReason,\n qualityProfileId,\n qualityProfileName,\n });\n });\n }\n );\n });\n if (!series.length || series.length < SONARR_AGG_FETCH_SIZE) {\n console.log(`[Sonarr Aggregate] Breaking pagination for ${label} - series.length=${series.length}`);\n break;\n }\n page += 1;\n }\n }\n\n // Smart diffing using hash-based change detection\n const syncResult = aggEpisodeSync.syncData(aggregated);\n const rowsChanged = syncResult.hasChanges;\n\n // Debug: Check what reason values we have\n const reasonCounts = new Map<string, number>();\n aggregated.forEach(ep => {\n const r = ep.reason || \"null/empty\";\n reasonCounts.set(r, (reasonCounts.get(r) || 0) + 1);\n });\n console.log(`[Sonarr Aggregate] Reason distribution:`, Object.fromEntries(reasonCounts));\n\n if (rowsChanged) {\n console.log(`[Sonarr Aggregate] Data changed, updating from ${aggRows.length} to ${aggregated.length} episodes`);\n setAggRows(syncResult.data);\n } else {\n console.log(`[Sonarr Aggregate] Data unchanged, skipping update`);\n }\n\n const newSummary = {\n available: totalAvailable,\n monitored: totalMonitored,\n missing: totalMissing,\n total: aggregated.length,\n };\n\n const summaryChanged = (\n aggSummary.available !== newSummary.available ||\n aggSummary.monitored !== newSummary.monitored ||\n aggSummary.missing !== newSummary.missing ||\n aggSummary.total !== newSummary.total\n );\n\n if (summaryChanged) {\n setAggSummary(newSummary);\n }\n\n // Only reset page if filter changed, not on refresh\n if (aggFilter !== globalSearch) {\n setAggPage(0);\n setAggFilter(globalSearch);\n }\n\n // Only update timestamp if data actually changed\n if (rowsChanged || summaryChanged) {\n setAggUpdated(new Date().toLocaleTimeString());\n }\n } catch (error) {\n setAggRows([]);\n setAggSummary({ available: 0, monitored: 0, missing: 0, total: 0 });\n push(\n error instanceof Error\n ? error.message\n : \"Failed to load aggregated Sonarr data\",\n \"error\"\n );\n } finally {\n setAggLoading(false);\n }\n }, [instances, globalSearch, push, onlyMissing, aggFilter]);\n\n useEffect(() => {\n if (!active) return;\n void loadInstances();\n }, [active, loadInstances]);\n\n useEffect(() => {\n if (!active) return;\n if (!selection || selection === \"aggregate\") return;\n\n const selectionChanged = prevSelectionRef.current !== selection;\n const onlyMissingChanged = prevOnlyMissingRef.current !== onlyMissing;\n\n // Reset page only when selection changes, not when filters change\n if (selectionChanged) {\n setInstancePage(0);\n prevSelectionRef.current = selection;\n }\n\n // Update ref for next comparison\n if (onlyMissingChanged) {\n prevOnlyMissingRef.current = onlyMissing;\n }\n\n // Fetch data: use page 0 if selection changed, current page otherwise\n const query = globalSearchRef.current;\n void fetchInstance(selection, selectionChanged ? 0 : instancePage, query, {\n preloadAll: true,\n showLoading: true,\n missingOnly: onlyMissing,\n });\n }, [active, selection, onlyMissing, fetchInstance, instancePage]);\n\n useEffect(() => {\n if (!active) return;\n if (selection !== \"aggregate\") return;\n void loadAggregate();\n }, [active, selection, loadAggregate]);\n\n useInterval(() => {\n if (selection === \"aggregate\" && liveArr) {\n void loadAggregate({ showLoading: false });\n }\n }, selection === \"aggregate\" && liveArr ? 1000 : null);\n\n useEffect(() => {\n if (!active) return;\n const handler = (term: string) => {\n if (selection === \"aggregate\") {\n setAggFilter(term);\n setAggPage(0);\n } else if (selection) {\n setInstancePage(0);\n void fetchInstance(selection, 0, term, {\n preloadAll: true,\n showLoading: true,\n missingOnly: onlyMissing,\n });\n }\n };\n register(handler);\n return () => clearHandler(handler);\n }, [active, selection, register, clearHandler, fetchInstance, onlyMissing]);\n\n useInterval(\n () => {\n if (selection && selection !== \"aggregate\") {\n const activeFilter = globalSearchRef.current?.trim?.() || \"\";\n if (activeFilter) {\n return;\n }\n void fetchInstance(selection, instancePage, instanceQuery, {\n preloadAll: false,\n showLoading: false,\n missingOnly: onlyMissing,\n });\n }\n },\n active && selection && selection !== \"aggregate\" && liveArr ? 1000 : null\n );\n\n useEffect(() => {\n globalSearchRef.current = globalSearch;\n }, [globalSearch]);\n\n useEffect(() => {\n if (selection === \"aggregate\") {\n setAggFilter(globalSearch);\n }\n }, [selection, globalSearch]);\n\n const filteredAggRows = useMemo(() => {\n let rows = aggRows;\n if (aggFilter) {\n const q = aggFilter.toLowerCase();\n rows = rows.filter((row) => {\n return (\n row.series.toLowerCase().includes(q) ||\n row.title.toLowerCase().includes(q) ||\n row.__instance.toLowerCase().includes(q)\n );\n });\n }\n if (onlyMissing) {\n rows = rows.filter((row) => !row.hasFile);\n }\n if (reasonFilter !== \"all\") {\n console.log(`[Sonarr Filter] Applying reason filter: \"${reasonFilter}\"`);\n const beforeFilterCount = rows.length;\n if (reasonFilter === \"Not being searched\") {\n rows = rows.filter((row) => row.reason === \"Not being searched\" || !row.reason);\n } else {\n rows = rows.filter((row) => row.reason === reasonFilter);\n }\n console.log(`[Sonarr Filter] Filtered from ${beforeFilterCount} to ${rows.length} episodes for reason \"${reasonFilter}\"`);\n if (rows.length < 10) {\n console.log(`[Sonarr Filter] Sample filtered rows:`, rows.slice(0, 5).map(r => ({ series: r.series, episode: r.episode, reason: r.reason })));\n }\n }\n return rows;\n }, [aggRows, aggFilter, onlyMissing, reasonFilter]);\n\n const isAggFiltered = Boolean(aggFilter) || onlyMissing || reasonFilter !== \"all\";\n\n const sortedAggRows = filteredAggRows;\n\n const aggPages = Math.max(\n 1,\n Math.ceil(sortedAggRows.length / SONARR_AGG_PAGE_SIZE)\n );\n // Paginated rows (for potential future use)\n // const aggPageRows = useMemo(\n // () => sortedAggRows.slice(\n // aggPage * SONARR_AGG_PAGE_SIZE,\n // aggPage * SONARR_AGG_PAGE_SIZE + SONARR_AGG_PAGE_SIZE\n // ),\n // [sortedAggRows, aggPage]\n // );\n\n const currentSeries = instancePages[instancePage] ?? [];\n\n const allSeries = useMemo(() => {\n const pages = Object.keys(instancePages)\n .map(Number)\n .sort((a, b) => a - b);\n const rows: SonarrSeriesEntry[] = [];\n pages.forEach((pg) => {\n if (instancePages[pg]) {\n rows.push(...instancePages[pg]);\n }\n });\n return rows;\n }, [instancePages]);\n\n const handleRestart = useCallback(async () => {\n if (!selection || selection === \"aggregate\") return;\n try {\n await restartArr(selection);\n push(`Restarted ${selection}`, \"success\");\n } catch (error) {\n push(\n error instanceof Error ? error.message : `Failed to restart ${selection}`,\n \"error\"\n );\n }\n }, [selection, push]);\n\n const handleInstanceSelection = useCallback(\n (event: ChangeEvent<HTMLSelectElement>) => {\n const next = (event.target.value || \"aggregate\") as string | \"aggregate\";\n setSelection(next);\n if (next !== \"aggregate\") {\n setGlobalSearch(\"\");\n }\n },\n [setSelection, setGlobalSearch]\n );\n\n const isAggregate = selection === \"aggregate\";\n\n return (\n <section className=\"card\">\n <div className=\"card-header\">Sonarr</div>\n <div className=\"card-body\">\n <div className=\"split\">\n <aside className=\"pane sidebar\">\n {instances.length > 1 && (\n <button\n className={`btn ${isAggregate ? \"active\" : \"\"}`}\n onClick={() => setSelection(\"aggregate\")}\n >\n All Sonarr\n </button>\n )}\n {instances.map((inst) => (\n <button\n key={inst.category}\n className={`btn ghost ${\n selection === inst.category ? \"active\" : \"\"\n }`}\n onClick={() => {\n setSelection(inst.category);\n setGlobalSearch(\"\");\n }}\n >\n {inst.name || inst.category}\n </button>\n ))}\n </aside>\n <div className=\"pane\">\n <div className=\"field mobile-instance-select\">\n <label>Instance</label>\n <select\n value={selection || \"aggregate\"}\n onChange={handleInstanceSelection}\n disabled={!instances.length}\n >\n {instances.length > 1 && <option value=\"aggregate\">All Sonarr</option>}\n {instances.map((inst) => (\n <option key={inst.category} value={inst.category}>\n {inst.name || inst.category}\n </option>\n ))}\n </select>\n </div>\n <div className=\"row\" style={{ alignItems: \"flex-end\", gap: \"12px\", flexWrap: \"wrap\" }}>\n <div className=\"col field\" style={{ flex: \"1 1 200px\" }}>\n <label>Search</label>\n <input\n placeholder=\"Filter series or episodes\"\n value={globalSearch}\n onChange={(event) => setGlobalSearch(event.target.value)}\n />\n </div>\n <div className=\"field\" style={{ flex: \"0 0 auto\", minWidth: \"140px\" }}>\n <label>Status</label>\n <select\n onChange={(event) => {\n const value = event.target.value;\n const newMissingState = value === \"missing\";\n setOnlyMissing(newMissingState);\n // Trigger refetch when filter changes for instance views\n if (selection && selection !== \"aggregate\") {\n void fetchInstance(selection, 0, globalSearchRef.current || \"\", {\n preloadAll: true,\n showLoading: true,\n missingOnly: newMissingState,\n });\n }\n }}\n value={onlyMissing ? \"missing\" : \"all\"}\n >\n <option value=\"all\">All Episodes</option>\n <option value=\"missing\">Missing Only</option>\n </select>\n </div>\n <div className=\"field\" style={{ flex: \"0 0 auto\", minWidth: \"140px\" }}>\n <label>Search Reason</label>\n <select\n onChange={(event) => setReasonFilter(event.target.value)}\n value={reasonFilter}\n >\n <option value=\"all\">All Reasons</option>\n <option value=\"Not being searched\">Not Being Searched</option>\n <option value=\"Missing\">Missing</option>\n <option value=\"Quality\">Quality</option>\n <option value=\"CustomFormat\">Custom Format</option>\n <option value=\"Upgrade\">Upgrade</option>\n </select>\n </div>\n </div>\n\n {isAggregate ? (\n <SonarrAggregateView\n loading={aggLoading}\n rows={sortedAggRows}\n total={sortedAggRows.length}\n page={aggPage}\n totalPages={aggPages}\n onPageChange={setAggPage}\n onRefresh={() => void loadAggregate({ showLoading: true })}\n lastUpdated={aggUpdated}\n groupSonarr={groupSonarr}\n summary={aggSummary}\n instanceCount={instances.length}\n isAggFiltered={isAggFiltered}\n />\n ) : (\n <SonarrInstanceView\n loading={instanceLoading}\n counts={instanceData?.counts ?? null}\n series={groupSonarr ? currentSeries : allSeries}\n page={instancePage}\n pageSize={instancePageSize}\n totalPages={instanceTotalPages}\n totalItems={instanceTotalItems}\n onlyMissing={onlyMissing}\n reasonFilter={reasonFilter}\n onPageChange={(page) => {\n setInstancePage(page);\n void fetchInstance(selection as string, page, instanceQuery, {\n preloadAll: false,\n showLoading: true,\n missingOnly: onlyMissing,\n });\n }}\n onRestart={() => void handleRestart()}\n lastUpdated={lastUpdated}\n groupSonarr={groupSonarr}\n instances={instances}\n selection={selection as string}\n />\n )}\n </div>\n </div>\n </div>\n </section>\n );\n}\n\ninterface SonarrAggregateViewProps {\n loading: boolean;\n rows: SonarrAggRow[];\n total: number;\n page: number;\n totalPages: number;\n onPageChange: (page: number) => void;\n onRefresh: () => void;\n lastUpdated: string | null;\n groupSonarr: boolean;\n summary: { available: number; monitored: number; missing: number; total: number };\n instanceCount: number;\n isAggFiltered?: boolean;\n}\n\nfunction SonarrAggregateView({\n loading,\n rows,\n page,\n totalPages,\n onPageChange,\n onRefresh,\n lastUpdated,\n groupSonarr,\n summary,\n instanceCount,\n isAggFiltered = false,\n}: SonarrAggregateViewProps): JSX.Element {\n const prevRowsRef = useRef<SonarrAggRow[]>([]);\n const groupedDataCache = useRef<Array<{\n instance: string;\n series: string;\n qualityProfileId?: number | null;\n qualityProfileName?: string | null;\n subRows: Array<{\n seasonNumber: string;\n isSeason: boolean;\n subRows: Array<SonarrAggRow & { isEpisode: boolean }>;\n }>;\n }>>([]);\n const seriesGroupCache = useRef<Map<string, {\n instance: string;\n series: string;\n qualityProfileId?: number | null;\n qualityProfileName?: string | null;\n subRows: Array<{\n seasonNumber: string;\n isSeason: boolean;\n subRows: Array<SonarrAggRow & { isEpisode: boolean }>;\n }>;\n episodeKeys: Set<string>;\n }>>(new Map());\n\n // Create fully grouped data from all rows - only rebuild if rows actually changed\n const allGroupedData = useMemo(() => {\n // Quick reference check - if same array reference, return cached\n if (rows === prevRowsRef.current) {\n return groupedDataCache.current;\n }\n\n // Build instance > series > seasons map\n const instanceMap = new Map<string, Map<string, Map<string, SonarrAggRow[]>>>();\n\n rows.forEach(row => {\n const instance = row.__instance;\n const series = row.series;\n const season = String(row.season);\n\n if (!instanceMap.has(instance)) {\n instanceMap.set(instance, new Map());\n }\n const instanceSeriesMap = instanceMap.get(instance)!;\n\n if (!instanceSeriesMap.has(series)) {\n instanceSeriesMap.set(series, new Map());\n }\n const seasonMap = instanceSeriesMap.get(series)!;\n\n if (!seasonMap.has(season)) {\n seasonMap.set(season, []);\n }\n seasonMap.get(season)!.push(row);\n });\n\n const result: Array<{\n instance: string;\n series: string;\n qualityProfileId?: number | null;\n qualityProfileName?: string | null;\n subRows: Array<{\n seasonNumber: string;\n isSeason: boolean;\n subRows: Array<SonarrAggRow & { isEpisode: boolean }>;\n }>;\n }> = [];\n\n const newSeriesGroupCache = new Map<string, {\n instance: string;\n series: string;\n qualityProfileId?: number | null;\n qualityProfileName?: string | null;\n subRows: Array<{\n seasonNumber: string;\n isSeason: boolean;\n subRows: Array<SonarrAggRow & { isEpisode: boolean }>;\n }>;\n episodeKeys: Set<string>;\n }>();\n\n instanceMap.forEach((seriesMap, instance) => {\n seriesMap.forEach((seasonMap, series) => {\n const seriesKey = `${instance}-${series}`;\n\n // Build set of episode keys for this series\n const episodeKeys = new Set<string>();\n seasonMap.forEach((episodes, season) => {\n episodes.forEach(ep => {\n const episodeKey = `${season}-${ep.episode}`;\n episodeKeys.add(episodeKey);\n });\n });\n\n // Check if this series group is in cache and unchanged\n const cached = seriesGroupCache.current.get(seriesKey);\n if (cached && cached.episodeKeys.size === episodeKeys.size) {\n let unchanged = true;\n for (const key of episodeKeys) {\n if (!cached.episodeKeys.has(key)) {\n unchanged = false;\n break;\n }\n }\n if (unchanged) {\n // Reuse cached series group (prevents count flickering)\n result.push(cached);\n newSeriesGroupCache.set(seriesKey, cached);\n return;\n }\n }\n\n // Build new series group\n const firstEpisode = Array.from(seasonMap.values())[0]?.[0];\n console.log(`[Sonarr Grouped] Series: ${series}, QualityProfile: ${firstEpisode?.qualityProfileName}, FirstEpisode:`, firstEpisode);\n const seriesGroup = {\n instance,\n series,\n qualityProfileId: firstEpisode?.qualityProfileId,\n qualityProfileName: firstEpisode?.qualityProfileName,\n subRows: Array.from(seasonMap.entries()).map(([seasonNumber, episodes]) => ({\n seasonNumber,\n isSeason: true,\n subRows: episodes.map(ep => ({ ...ep, isEpisode: true }))\n })),\n episodeKeys,\n };\n result.push(seriesGroup);\n newSeriesGroupCache.set(seriesKey, seriesGroup);\n });\n });\n\n // Update caches\n prevRowsRef.current = rows;\n groupedDataCache.current = result;\n seriesGroupCache.current = newSeriesGroupCache;\n\n return result;\n }, [rows]);\n\n // For grouped view, paginate the series groups (not individual episodes)\n // For flat view, paginate the episode rows\n const groupedPageRows = useMemo(() => {\n const pageSize = 50;\n return allGroupedData.slice(page * pageSize, (page + 1) * pageSize);\n }, [allGroupedData, page]);\n\n const flatPageRows = useMemo(() => {\n const pageSize = 50;\n return rows.slice(page * pageSize, (page + 1) * pageSize);\n }, [rows, page]);\n\n const tableData = groupSonarr ? groupedPageRows : flatPageRows;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const groupedColumns = useMemo<ColumnDef<any>[]>(() => [\n {\n accessorKey: \"title\",\n header: \"Title\",\n cell: ({ row }) => {\n if (row.original.isEpisode) return row.original.title;\n if (row.original.isSeason) return `Season ${row.original.seasonNumber}`;\n // Series row - show series name, instance, and quality profile (like Lidarr)\n const parts = [row.original.series];\n if (row.original.instance) {\n parts.push(`(${row.original.instance})`);\n }\n if (row.original.qualityProfileName) {\n parts.push(`• ${row.original.qualityProfileName}`);\n }\n return parts.join(' ');\n }\n },\n {\n accessorKey: \"monitored\",\n header: \"Monitored\",\n cell: ({ row }) => {\n const monitored = row.original.isEpisode ? row.original.monitored : row.original.monitored;\n return (\n <span className={`track-status ${monitored ? 'available' : 'missing'}`}>\n {monitored ? '✓' : '✗'}\n </span>\n );\n }\n },\n {\n accessorKey: \"hasFile\",\n header: \"Has File\",\n cell: ({ row }) => {\n if (row.original.isEpisode) {\n const hasFile = row.original.hasFile;\n return (\n <span className={`track-status ${hasFile ? 'available' : 'missing'}`}>\n {hasFile ? '✓' : '✗'}\n </span>\n );\n }\n return null;\n }\n },\n {\n accessorKey: \"airDate\",\n header: \"Air Date\",\n cell: ({ row }) => {\n if (row.original.isEpisode) {\n return row.original.airDate || \"—\";\n }\n return null;\n }\n },\n ], []);\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const flatColumns = useMemo<ColumnDef<any>[]>(() => [\n ...(instanceCount > 1 ? [{\n accessorKey: \"__instance\",\n header: \"Instance\",\n }] : []),\n {\n accessorKey: \"series\",\n header: \"Series\",\n },\n {\n accessorKey: \"season\",\n header: \"Season\",\n },\n {\n accessorKey: \"episode\",\n header: \"Episode\",\n },\n {\n accessorKey: \"title\",\n header: \"Title\",\n },\n {\n accessorKey: \"monitored\",\n header: \"Monitored\",\n cell: ({ getValue }) => {\n const monitored = getValue() as boolean;\n return (\n <span className={`track-status ${monitored ? 'available' : 'missing'}`}>\n {monitored ? '✓' : '✗'}\n </span>\n );\n },\n },\n {\n accessorKey: \"hasFile\",\n header: \"Has File\",\n cell: ({ getValue }) => {\n const hasFile = getValue() as boolean;\n return (\n <span className={`track-status ${hasFile ? 'available' : 'missing'}`}>\n {hasFile ? '✓' : '✗'}\n </span>\n );\n },\n },\n {\n accessorKey: \"airDate\",\n header: \"Air Date\",\n cell: ({ getValue }) => getValue() || \"—\",\n },\n {\n accessorKey: \"qualityProfileName\",\n header: \"Quality Profile\",\n cell: ({ getValue }) => {\n const profileName = getValue() as string | null | undefined;\n return profileName || \"—\";\n },\n },\n {\n accessorKey: \"reason\",\n header: \"Reason\",\n cell: ({ getValue }) => {\n const reason = getValue() as string | null | undefined;\n if (!reason) return <span className=\"table-badge table-badge-reason\">Not being searched</span>;\n return <span className=\"table-badge table-badge-reason\">{reason}</span>;\n },\n },\n ], [instanceCount]);\n\n // Note: Quality profile is per-series, not per-episode\n // It would need to be fetched from the series data and added to each episode row\n\n const columns = groupSonarr ? groupedColumns : flatColumns;\n\n // eslint-disable-next-line react-hooks/incompatible-library\n const groupedTable = useReactTable({\n data: tableData,\n columns,\n getCoreRowModel: getCoreRowModel(),\n getExpandedRowModel: getExpandedRowModel(),\n });\n\n const flatTable = useReactTable({\n data: tableData,\n columns,\n getCoreRowModel: getCoreRowModel(),\n getSortedRowModel: getSortedRowModel(),\n getPaginationRowModel: getPaginationRowModel(),\n state: {\n pagination: {\n pageIndex: page,\n pageSize: 50,\n },\n },\n manualPagination: true,\n pageCount: totalPages,\n });\n\n const table = groupSonarr ? groupedTable : flatTable;\n\n const pageSize = 50;\n // For grouped view, paginate by series groups; for flat view, paginate by rows\n const effectiveTotalPages = groupSonarr\n ? Math.ceil(allGroupedData.length / pageSize)\n : Math.ceil(rows.length / pageSize);\n const safePage = Math.min(page, Math.max(0, effectiveTotalPages - 1));\n const totalItemsDisplay = groupSonarr\n ? `${allGroupedData.length} series`\n : rows.length.toLocaleString();\n\n return (\n <div className=\"stack animate-fade-in\">\n <div className=\"row\" style={{ justifyContent: \"space-between\" }}>\n <div className=\"hint\">\n Aggregated episodes across all instances{\" \"}\n {lastUpdated ? `(updated ${lastUpdated})` : \"\"}\n <br />\n <strong>Available:</strong>{\" \"}\n {summary.available.toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Monitored:</strong>{\" \"}\n {summary.monitored.toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Missing:</strong>{\" \"}\n {summary.missing.toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Total Episodes:</strong>{\" \"}\n {summary.total.toLocaleString(undefined, { maximumFractionDigits: 0 })}\n {isAggFiltered && rows.length < summary.total && (\n <>\n {\" \"}• <strong>Filtered:</strong>{\" \"}\n {rows.length.toLocaleString(undefined, { maximumFractionDigits: 0 })} of{\" \"}\n {summary.total.toLocaleString(undefined, { maximumFractionDigits: 0 })}\n </>\n )}\n </div>\n <button className=\"btn ghost\" onClick={onRefresh} disabled={loading}>\n <IconImage src={RefreshIcon} />\n Refresh\n </button>\n </div>\n {loading ? (\n <div className=\"loading\">\n <span className=\"spinner\" /> Loading Sonarr library…\n </div>\n ) : groupSonarr ? (\n <div className=\"sonarr-hierarchical-view\">\n {groupedPageRows.map((seriesGroup) => {\n console.log(`[Sonarr Render] Series: ${seriesGroup.series}, QualityProfile: ${seriesGroup.qualityProfileName}`);\n let episodeCount = 0;\n seriesGroup.subRows.forEach(season => {\n episodeCount += season.subRows.length;\n });\n return (\n <details key={`${seriesGroup.instance}-${seriesGroup.series}`} className=\"series-details\">\n <summary className=\"series-summary\">\n <span className=\"series-title\">{seriesGroup.series}</span>\n <span className=\"series-instance\">({seriesGroup.instance})</span>\n <span className=\"series-count\">({episodeCount} episodes)</span>\n {seriesGroup.qualityProfileName ? (\n <span className=\"series-quality\">• {seriesGroup.qualityProfileName}</span>\n ) : null}\n </summary>\n <div className=\"series-content\">\n {seriesGroup.subRows.map((season: typeof seriesGroup.subRows[number]) => (\n <details key={`${seriesGroup.instance}-${seriesGroup.series}-${season.seasonNumber}`} className=\"season-details\">\n <summary className=\"season-summary\">\n <span className=\"season-title\">Season {season.seasonNumber}</span>\n <span className=\"season-count\">({season.subRows.length} episodes)</span>\n </summary>\n <div className=\"season-content\">\n <div className=\"episodes-table-wrapper\">\n <table className=\"episodes-table\">\n <thead>\n <tr>\n <th>Episode</th>\n <th>Title</th>\n <th>Monitored</th>\n <th>Has File</th>\n <th>Air Date</th>\n <th>Reason</th>\n </tr>\n </thead>\n <tbody>\n {season.subRows.map((episode) => (\n <tr key={`${episode.__instance}-${episode.series}-${episode.season}-${episode.episode}`}>\n <td data-label=\"Episode\">{episode.episode}</td>\n <td data-label=\"Title\">{episode.title}</td>\n <td data-label=\"Monitored\">\n <span className={`track-status ${episode.monitored ? 'available' : 'missing'}`}>\n {episode.monitored ? '✓' : '✗'}\n </span>\n </td>\n <td data-label=\"Has File\">\n <span className={`track-status ${episode.hasFile ? 'available' : 'missing'}`}>\n {episode.hasFile ? '✓' : '✗'}\n </span>\n </td>\n <td data-label=\"Air Date\">{episode.airDate || \"—\"}</td>\n <td data-label=\"Reason\">{episode.reason ? <span className=\"table-badge table-badge-reason\">{episode.reason}</span> : <span className=\"table-badge table-badge-reason\">Not being searched</span>}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n </details>\n ))}\n </div>\n </details>\n );\n })}\n </div>\n ) : !loading && summary.total === 0 && instanceCount > 0 ? (\n <div className=\"hint\">\n <p>No episodes found in the database.</p>\n <p>The backend may still be initializing and syncing data from your Sonarr instances. Please check the logs or wait a few moments and refresh.</p>\n </div>\n ) : tableData.length ? (\n <div className=\"table-wrapper\">\n <table className=\"responsive-table\">\n <thead>\n <tr>\n {table.getFlatHeaders().map(header => (\n <th\n key={header.id}\n className={header.column.getCanSort() ? \"sortable\" : \"\"}\n onClick={header.column.getToggleSortingHandler()}\n >\n {header.isPlaceholder\n ? null\n : flexRender(\n header.column.columnDef.header,\n header.getContext()\n )}\n {header.column.getCanSort() && (\n <span className=\"sort-arrow\">\n {{\n asc: \"▲\",\n desc: \"▼\",\n }[header.column.getIsSorted() as string] ?? null}\n </span>\n )}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {table.getRowModel().rows.map(row => {\n const episode = row.original;\n const stableKey = `${episode.__instance}-${episode.series}-${episode.season}-${episode.episode}`;\n return (\n <tr key={stableKey}>\n {row.getVisibleCells().map(cell => (\n <td key={cell.id} data-label={cell.column.columnDef.header as string}>\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </td>\n ))}\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n ) : (\n <div className=\"hint\">No series found.</div>\n )}\n {tableData.length > 0 && (\n <div className=\"pagination\">\n <div>\n Page {safePage + 1} of {effectiveTotalPages} ({totalItemsDisplay} items ·\n page size {pageSize})\n </div>\n <div className=\"inline\">\n <button\n className=\"btn\"\n onClick={() => onPageChange(Math.max(0, safePage - 1))}\n disabled={safePage === 0 || loading}\n >\n Prev\n </button>\n <button\n className=\"btn\"\n onClick={() => onPageChange(Math.min(effectiveTotalPages - 1, safePage + 1))}\n disabled={safePage >= effectiveTotalPages - 1 || loading}\n >\n Next\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n\ninterface SonarrInstanceViewProps {\n loading: boolean;\n counts: { available: number; monitored: number; missing?: number } | null;\n series: SonarrSeriesEntry[];\n page: number;\n pageSize: number;\n totalPages: number;\n totalItems: number;\n onlyMissing: boolean;\n reasonFilter: string;\n onPageChange: (page: number) => void;\n onRestart: () => void;\n lastUpdated: string | null;\n groupSonarr: boolean;\n instances: ArrInfo[];\n selection: string;\n}\n\nfunction SonarrInstanceView({\n loading,\n counts,\n series,\n page,\n pageSize,\n totalPages,\n totalItems,\n onlyMissing,\n reasonFilter,\n onPageChange,\n onRestart,\n lastUpdated,\n groupSonarr,\n instances,\n selection,\n}: SonarrInstanceViewProps): JSX.Element {\n\n // Separate pagination state for flat (episode) view\n const [flatPage, setFlatPage] = useState(0);\n const FLAT_PAGE_SIZE = 50;\n\n // Transform series to SonarrAggRow[] - rebuild when series changes\n const episodeRows = useMemo(() => {\n const rows: SonarrAggRow[] = [];\n for (const entry of series) {\n const title = (entry.series?.[\"title\"] as string | undefined) || \"\";\n const qualityProfileId = entry.series?.qualityProfileId ?? null;\n const qualityProfileName = entry.series?.qualityProfileName ?? null;\n Object.entries(entry.seasons ?? {}).forEach(([seasonNumber, season]) => {\n (season.episodes ?? []).forEach((episode) => {\n rows.push({\n __instance: \"Instance\",\n series: title,\n season: seasonNumber,\n episode: episode.episodeNumber ?? \"\",\n title: episode.title ?? \"\",\n monitored: !!episode.monitored,\n hasFile: !!episode.hasFile,\n airDate: episode.airDateUtc ?? \"\",\n reason: (episode.reason as string | null | undefined) ?? null,\n qualityProfileId,\n qualityProfileName,\n });\n });\n });\n }\n\n return rows;\n }, [series]);\n\n const filteredEpisodeRows = useMemo(() => {\n let rows = episodeRows;\n if (onlyMissing) {\n rows = rows.filter((row) => !row.hasFile);\n }\n if (reasonFilter !== \"all\") {\n console.log(`[Sonarr Instance Filter] Applying reason filter: \"${reasonFilter}\"`);\n const beforeFilterCount = rows.length;\n if (reasonFilter === \"Not being searched\") {\n rows = rows.filter((row) => row.reason === \"Not being searched\" || !row.reason);\n } else {\n rows = rows.filter((row) => row.reason === reasonFilter);\n }\n console.log(`[Sonarr Instance Filter] Filtered from ${beforeFilterCount} to ${rows.length} episodes for reason \"${reasonFilter}\"`);\n if (rows.length < 10) {\n console.log(`[Sonarr Instance Filter] Sample filtered rows:`, rows.slice(0, 5).map(r => ({ series: r.series, episode: r.episode, reason: r.reason })));\n }\n }\n return rows;\n }, [episodeRows, onlyMissing, reasonFilter]);\n\n // Reset flat page when filters change\n useEffect(() => {\n const timer = setTimeout(() => setFlatPage(0), 0);\n return () => clearTimeout(timer);\n }, [onlyMissing, reasonFilter]);\n\n // Group for hierarchical view - rebuild when filteredEpisodeRows changes\n const groupedTableData = useMemo(() => {\n const map = new Map<string, Map<string, SonarrAggRow[]>>();\n filteredEpisodeRows.forEach(row => {\n const seriesKey = row.series;\n if (!map.has(seriesKey)) map.set(seriesKey, new Map());\n const seasons = map.get(seriesKey)!;\n const seasonKey = String(row.season);\n if (!seasons.has(seasonKey)) seasons.set(seasonKey, []);\n seasons.get(seasonKey)!.push(row);\n });\n\n const result = Array.from(map.entries()).map(([seriesName, seasons]) => {\n // Get quality profile from first episode (all episodes in a series share the same profile)\n const firstEpisode = Array.from(seasons.values())[0]?.[0];\n return {\n series: seriesName,\n qualityProfileId: firstEpisode?.qualityProfileId,\n qualityProfileName: firstEpisode?.qualityProfileName,\n subRows: Array.from(seasons.entries()).map(([seasonNumber, episodes]) => ({\n seasonNumber,\n isSeason: true,\n subRows: episodes.map(ep => ({ ...ep, isEpisode: true }))\n }))\n };\n });\n\n return result;\n }, [filteredEpisodeRows]);\n\n const totalEpisodes = useMemo(() => episodeRows.length, [episodeRows]);\n const isFiltered = reasonFilter !== \"all\" || onlyMissing;\n const filteredCount = filteredEpisodeRows.length;\n\n // Pagination for flat view\n const flatTotalPages = Math.max(1, Math.ceil(filteredEpisodeRows.length / FLAT_PAGE_SIZE));\n const flatSafePage = Math.min(flatPage, Math.max(0, flatTotalPages - 1));\n const paginatedEpisodeRows = useMemo(() => {\n return filteredEpisodeRows.slice(flatSafePage * FLAT_PAGE_SIZE, (flatSafePage + 1) * FLAT_PAGE_SIZE);\n }, [filteredEpisodeRows, flatSafePage]);\n\n // Pagination for grouped view (paginate by series groups, not backend pages)\n const GROUPED_PAGE_SIZE = 50;\n const [groupedPage, setGroupedPage] = useState(0);\n const groupedTotalPages = Math.max(1, Math.ceil(groupedTableData.length / GROUPED_PAGE_SIZE));\n const groupedSafePage = Math.min(groupedPage, Math.max(0, groupedTotalPages - 1));\n const paginatedGroupedData = useMemo(() => {\n return groupedTableData.slice(groupedSafePage * GROUPED_PAGE_SIZE, (groupedSafePage + 1) * GROUPED_PAGE_SIZE);\n }, [groupedTableData, groupedSafePage]);\n\n // Reset grouped page when filters change\n useEffect(() => {\n const timer = setTimeout(() => setGroupedPage(0), 0);\n return () => clearTimeout(timer);\n }, [onlyMissing, reasonFilter]);\n\n return (\n <div className=\"stack animate-fade-in\">\n <div className=\"row\" style={{ justifyContent: \"space-between\" }}>\n <div className=\"hint\">\n {counts ? (\n <>\n <strong>Available:</strong>{\" \"}\n {counts.available.toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Monitored:</strong>{\" \"}\n {counts.monitored.toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Missing:</strong>{\" \"}\n {(counts.missing ?? 0).toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Total Episodes:</strong>{\" \"}\n {totalEpisodes.toLocaleString(undefined, { maximumFractionDigits: 0 })}\n {isFiltered && filteredCount < totalEpisodes && (\n <>\n {\" \"}• <strong>Filtered:</strong>{\" \"}\n {filteredCount.toLocaleString(undefined, { maximumFractionDigits: 0 })} of{\" \"}\n {totalEpisodes.toLocaleString(undefined, { maximumFractionDigits: 0 })}\n </>\n )}\n </>\n ) : (\n \"Loading series information...\"\n )}\n {lastUpdated ? ` (updated ${lastUpdated})` : \"\"}\n </div>\n <button className=\"btn ghost\" onClick={onRestart} disabled={loading}>\n <IconImage src={RefreshIcon} />\n Restart\n </button>\n </div>\n {loading ? (\n <div className=\"loading\">\n <span className=\"spinner\" /> Loading series…\n </div>\n ) : groupSonarr ? (\n <div className=\"sonarr-hierarchical-view\">\n {paginatedGroupedData.map((seriesGroup) => {\n let episodeCount = 0;\n seriesGroup.subRows.forEach(season => {\n episodeCount += season.subRows.length;\n });\n // Get instance name from selection\n const instanceName = instances.find(i => i.category === selection)?.name || selection;\n return (\n <details key={`${seriesGroup.series}`} className=\"series-details\">\n <summary className=\"series-summary\">\n <span className=\"series-title\">{seriesGroup.series}</span>\n <span className=\"series-instance\">({instanceName})</span>\n <span className=\"series-count\">({episodeCount} episodes)</span>\n {seriesGroup.qualityProfileName ? (\n <span className=\"series-quality\">• {seriesGroup.qualityProfileName}</span>\n ) : null}\n </summary>\n <div className=\"series-content\">\n {seriesGroup.subRows.map((season) => (\n <details key={`${seriesGroup.series}-${season.seasonNumber}`} className=\"season-details\">\n <summary className=\"season-summary\">\n <span className=\"season-title\">Season {season.seasonNumber}</span>\n <span className=\"season-count\">({season.subRows.length} episodes)</span>\n </summary>\n <div className=\"season-content\">\n <div className=\"episodes-table-wrapper\">\n <table className=\"episodes-table\">\n <thead>\n <tr>\n <th>Episode</th>\n <th>Title</th>\n <th>Monitored</th>\n <th>Has File</th>\n <th>Air Date</th>\n <th>Reason</th>\n </tr>\n </thead>\n <tbody>\n {season.subRows.map((episode: typeof season.subRows[number]) => (\n <tr key={`${episode.series}-${episode.season}-${episode.episode}`}>\n <td data-label=\"Episode\">{episode.episode}</td>\n <td data-label=\"Title\">{episode.title}</td>\n <td data-label=\"Monitored\">\n <span className={`track-status ${episode.monitored ? 'available' : 'missing'}`}>\n {episode.monitored ? '✓' : '✗'}\n </span>\n </td>\n <td data-label=\"Has File\">\n <span className={`track-status ${episode.hasFile ? 'available' : 'missing'}`}>\n {episode.hasFile ? '✓' : '✗'}\n </span>\n </td>\n <td data-label=\"Air Date\">{episode.airDate || \"—\"}</td>\n <td data-label=\"Reason\">{episode.reason ? <span className=\"table-badge table-badge-reason\">{episode.reason}</span> : <span className=\"table-badge table-badge-reason\">Not being searched</span>}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n </details>\n ))}\n </div>\n </details>\n );\n })}\n </div>\n ) : !loading && series.length > 0 && filteredEpisodeRows.length === 0 && episodeRows.length === 0 ? (\n <div className=\"hint\">\n <p>No episodes found for these series.</p>\n <p>The backend may still be syncing episode data from Sonarr. Please check the logs or wait a few moments and refresh.</p>\n </div>\n ) : !loading && series.length > 0 && filteredEpisodeRows.length === 0 && episodeRows.length > 0 ? (\n <div className=\"hint\">No episodes match the current filter.</div>\n ) : !groupSonarr && filteredEpisodeRows.length > 0 ? (\n <div className=\"table-wrapper\">\n <table className=\"responsive-table\">\n <thead>\n <tr>\n <th>Series</th>\n <th>Season</th>\n <th>Episode</th>\n <th>Title</th>\n <th>Monitored</th>\n <th>Has File</th>\n <th>Air Date</th>\n <th>Quality Profile</th>\n <th>Reason</th>\n </tr>\n </thead>\n <tbody>\n {paginatedEpisodeRows.map((row, idx) => (\n <tr key={`${row.series}-${row.season}-${row.episode}-${idx}`}>\n <td data-label=\"Series\">{row.series}</td>\n <td data-label=\"Season\">{row.season}</td>\n <td data-label=\"Episode\">{row.episode}</td>\n <td data-label=\"Title\">{row.title}</td>\n <td data-label=\"Monitored\">\n <span className={`track-status ${row.monitored ? 'available' : 'missing'}`}>\n {row.monitored ? '✓' : '✗'}\n </span>\n </td>\n <td data-label=\"Has File\">\n <span className={`track-status ${row.hasFile ? 'available' : 'missing'}`}>\n {row.hasFile ? '✓' : '✗'}\n </span>\n </td>\n <td data-label=\"Air Date\">{row.airDate || \"—\"}</td>\n <td data-label=\"Quality Profile\">{row.qualityProfileName || \"—\"}</td>\n <td data-label=\"Reason\">{row.reason ? <span className=\"table-badge table-badge-reason\">{row.reason}</span> : <span className=\"table-badge table-badge-reason\">Not being searched</span>}</td>\n </tr>\n ))}\n </tbody>\n </table>\n {flatTotalPages > 1 && (\n <div className=\"pagination\">\n <div>\n Page {flatSafePage + 1} of {flatTotalPages} ({filteredEpisodeRows.length.toLocaleString()} episodes · page size {FLAT_PAGE_SIZE})\n </div>\n <div className=\"inline\">\n <button\n className=\"btn\"\n onClick={() => setFlatPage(Math.max(0, flatSafePage - 1))}\n disabled={flatSafePage === 0 || loading}\n >\n Prev\n </button>\n <button\n className=\"btn\"\n onClick={() => setFlatPage(Math.min(flatTotalPages - 1, flatSafePage + 1))}\n disabled={flatSafePage >= flatTotalPages - 1 || loading}\n >\n Next\n </button>\n </div>\n </div>\n )}\n </div>\n ) : (\n <div className=\"hint\">No series found.</div>\n )}\n {groupSonarr && groupedTableData.length > 0 && (\n <div className=\"pagination\">\n <div>\n Page {groupedSafePage + 1} of {groupedTotalPages} ({groupedTableData.length.toLocaleString()} series · page size {GROUPED_PAGE_SIZE})\n </div>\n <div className=\"inline\">\n <button\n className=\"btn\"\n onClick={() => setGroupedPage(Math.max(0, groupedSafePage - 1))}\n disabled={groupedSafePage === 0 || loading}\n >\n Prev\n </button>\n <button\n className=\"btn\"\n onClick={() => setGroupedPage(Math.min(groupedTotalPages - 1, groupedSafePage + 1))}\n disabled={groupedSafePage >= groupedTotalPages - 1 || loading}\n >\n Next\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ChangeEvent,\n type JSX,\n} from \"react\";\nimport {\n getArrList,\n getLidarrAlbums,\n restartArr,\n} from \"../api/client\";\nimport {\n useReactTable,\n getCoreRowModel,\n getSortedRowModel,\n flexRender,\n type ColumnDef,\n} from \"@tanstack/react-table\";\nimport type {\n ArrInfo,\n LidarrAlbumEntry,\n LidarrAlbumsResponse,\n} from \"../api/types\";\nimport { useToast } from \"../context/ToastContext\";\nimport { useSearch } from \"../context/SearchContext\";\nimport { useWebUI } from \"../context/WebUIContext\";\nimport { useInterval } from \"../hooks/useInterval\";\nimport { useDataSync } from \"../hooks/useDataSync\";\nimport { IconImage } from \"../components/IconImage\";\nimport RefreshIcon from \"../icons/refresh-arrow.svg\";\nimport RestartIcon from \"../icons/refresh-arrow.svg\";\n\ninterface LidarrAggRow extends LidarrAlbumEntry {\n __instance: string;\n [key: string]: unknown;\n}\n\ninterface LidarrTrackRow {\n __instance: string;\n artistName: string;\n albumTitle: string;\n trackNumber: number;\n title: string;\n duration?: number;\n hasFile: boolean;\n monitored: boolean;\n reason?: string | null;\n qualityProfileId?: number | null;\n qualityProfileName?: string | null;\n [key: string]: unknown;\n}\n\n\n\nconst LIDARR_PAGE_SIZE = 50;\nconst LIDARR_AGG_FETCH_SIZE = 500;\n\ninterface LidarrAggregateViewProps {\n loading: boolean;\n rows: LidarrAggRow[];\n trackRows: LidarrTrackRow[];\n page: number;\n onPageChange: (page: number) => void;\n onRefresh: () => void;\n lastUpdated: string | null;\n summary: { available: number; monitored: number; missing: number; total: number };\n instanceCount: number;\n groupLidarr: boolean;\n isAggFiltered?: boolean;\n}\n\nfunction LidarrAggregateView({\n loading,\n rows,\n trackRows,\n page,\n onPageChange,\n onRefresh,\n lastUpdated,\n summary,\n instanceCount,\n groupLidarr,\n isAggFiltered = false,\n}: LidarrAggregateViewProps): JSX.Element {\n const prevRowsRef = useRef<LidarrAggRow[]>([]);\n const groupedDataCache = useRef<Array<{\n instance: string;\n artist: string;\n qualityProfileId?: number | null;\n qualityProfileName?: string | null;\n albums: LidarrAggRow[];\n }>>([]);\n const artistGroupCache = useRef<Map<string, {\n instance: string;\n artist: string;\n qualityProfileId?: number | null;\n qualityProfileName?: string | null;\n albums: LidarrAggRow[];\n albumKeys: Set<string>;\n }>>(new Map());\n\n // Create grouped data structure: instance > artist > albums - only rebuild if rows actually changed\n const groupedData = useMemo(() => {\n // Quick reference check - if same array reference, return cached\n if (rows === prevRowsRef.current) {\n return groupedDataCache.current;\n }\n\n // Build instance > artist > albums map\n const instanceMap = new Map<string, Map<string, LidarrAggRow[]>>();\n\n rows.forEach(row => {\n const instance = row.__instance;\n const artist = (row.album?.[\"artistName\"] as string | undefined) || \"Unknown Artist\";\n\n if (!instanceMap.has(instance)) {\n instanceMap.set(instance, new Map());\n }\n const artistMap = instanceMap.get(instance)!;\n\n if (!artistMap.has(artist)) {\n artistMap.set(artist, []);\n }\n artistMap.get(artist)!.push(row);\n });\n\n const result: Array<{\n instance: string;\n artist: string;\n qualityProfileId?: number | null;\n qualityProfileName?: string | null;\n albums: LidarrAggRow[];\n }> = [];\n\n const newArtistGroupCache = new Map<string, {\n instance: string;\n artist: string;\n qualityProfileId?: number | null;\n qualityProfileName?: string | null;\n albums: LidarrAggRow[];\n albumKeys: Set<string>;\n }>();\n\n instanceMap.forEach((artistMap, instance) => {\n artistMap.forEach((albums, artist) => {\n const artistKey = `${instance}-${artist}`;\n\n // Build set of album keys for this artist\n const albumKeys = new Set<string>();\n albums.forEach(album => {\n const albumData = album.album as Record<string, unknown>;\n const albumKey = `${albumData?.[\"title\"]}`;\n albumKeys.add(albumKey);\n });\n\n // Check if this artist group is in cache and unchanged\n const cached = artistGroupCache.current.get(artistKey);\n if (cached && cached.albumKeys.size === albumKeys.size) {\n let unchanged = true;\n for (const key of albumKeys) {\n if (!cached.albumKeys.has(key)) {\n unchanged = false;\n break;\n }\n }\n if (unchanged) {\n // Reuse cached artist group (prevents count flickering)\n result.push(cached);\n newArtistGroupCache.set(artistKey, cached);\n return;\n }\n }\n\n // Build new artist group\n const firstAlbum = albums[0];\n const albumData = firstAlbum?.album as Record<string, unknown> | undefined;\n const artistGroup = {\n instance,\n artist,\n qualityProfileId: (albumData?.[\"qualityProfileId\"] as number | null | undefined) ?? null,\n qualityProfileName: (albumData?.[\"qualityProfileName\"] as string | null | undefined) ?? null,\n albums,\n albumKeys,\n };\n result.push(artistGroup);\n newArtistGroupCache.set(artistKey, artistGroup);\n });\n });\n\n // Update caches\n prevRowsRef.current = rows;\n groupedDataCache.current = result;\n artistGroupCache.current = newArtistGroupCache;\n\n return result;\n }, [rows]);\n\n // For grouped view, paginate the artist groups (not individual albums)\n // For flat view, paginate the album rows\n const groupedPageRows = useMemo(() => {\n const pageSize = 50;\n return groupedData.slice(page * pageSize, (page + 1) * pageSize);\n }, [groupedData, page]);\n\n const flatPageRows = useMemo(() => {\n const pageSize = 50;\n const start = page * pageSize;\n const end = start + pageSize;\n return trackRows.slice(start, end);\n }, [trackRows, page]);\n\n const flatColumns = useMemo<ColumnDef<LidarrTrackRow>[]>(\n () => [\n ...(instanceCount > 1 ? [{\n accessorKey: \"__instance\",\n header: \"Instance\",\n size: 120,\n }] : []),\n {\n accessorKey: \"artistName\",\n header: \"Artist\",\n size: 150,\n },\n {\n accessorKey: \"albumTitle\",\n header: \"Album\",\n size: 150,\n },\n {\n accessorKey: \"trackNumber\",\n header: \"#\",\n size: 50,\n },\n {\n accessorKey: \"title\",\n header: \"Track\",\n },\n {\n accessorKey: \"duration\",\n header: \"Duration\",\n cell: (info) => {\n const dur = info.getValue() as number | undefined;\n if (!dur) return <span className=\"hint\">—</span>;\n return `${Math.floor(dur / 60)}:${String(dur % 60).padStart(2, '0')}`;\n },\n size: 80,\n },\n {\n accessorKey: \"monitored\",\n header: \"Monitored\",\n cell: (info) => {\n const monitored = info.getValue() as boolean;\n return (\n <span className={`track-status ${monitored ? 'available' : 'missing'}`}>\n {monitored ? '✓' : '✗'}\n </span>\n );\n },\n size: 100,\n },\n {\n accessorKey: \"hasFile\",\n header: \"Has File\",\n cell: (info) => {\n const hasFile = info.getValue() as boolean;\n return (\n <span className={`track-status ${hasFile ? 'available' : 'missing'}`}>\n {hasFile ? '✓' : '✗'}\n </span>\n );\n },\n size: 100,\n },\n {\n accessorKey: \"qualityProfileName\",\n header: \"Quality Profile\",\n cell: (info) => {\n const profileName = info.getValue() as string | null | undefined;\n return profileName || \"—\";\n },\n size: 150,\n },\n {\n accessorKey: \"reason\",\n header: \"Reason\",\n cell: (info) => {\n const reason = info.getValue() as string | null | undefined;\n if (!reason) return <span className=\"table-badge table-badge-reason\">Not being searched</span>;\n return <span className=\"table-badge table-badge-reason\">{reason}</span>;\n },\n size: 120,\n },\n ],\n [instanceCount]\n );\n\n const flatTable = useReactTable({\n data: flatPageRows,\n columns: flatColumns,\n getCoreRowModel: getCoreRowModel(),\n });\n\n return (\n <div className=\"stack animate-fade-in\">\n <div className=\"row\" style={{ justifyContent: \"space-between\" }}>\n <div className=\"hint\">\n Aggregated albums across all instances{\" \"}\n {lastUpdated ? `(updated ${lastUpdated})` : \"\"}\n <br />\n <strong>Available:</strong>{\" \"}\n {summary.available.toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Monitored:</strong>{\" \"}\n {summary.monitored.toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Missing:</strong>{\" \"}\n {summary.missing.toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Total:</strong>{\" \"}\n {summary.total.toLocaleString(undefined, { maximumFractionDigits: 0 })}\n {isAggFiltered && (groupLidarr ? rows.length : trackRows.length) < summary.total && (\n <>\n {\" \"}• <strong>Filtered:</strong>{\" \"}\n {(groupLidarr ? rows.length : trackRows.length).toLocaleString(undefined, { maximumFractionDigits: 0 })} of{\" \"}\n {summary.total.toLocaleString(undefined, { maximumFractionDigits: 0 })}\n </>\n )}\n </div>\n <button className=\"btn ghost\" onClick={onRefresh} disabled={loading}>\n <IconImage src={RefreshIcon} />\n Refresh\n </button>\n </div>\n\n {loading ? (\n <div className=\"loading\">\n <span className=\"spinner\" /> Loading Lidarr library…\n </div>\n ) : groupLidarr ? (\n <div className=\"lidarr-hierarchical-view\">\n {groupedPageRows.map((artistGroup) => (\n <details key={`${artistGroup.instance}-${artistGroup.artist}`} className=\"artist-details\">\n <summary className=\"artist-summary\">\n <span className=\"artist-title\">{artistGroup.artist}</span>\n <span className=\"artist-instance\">({artistGroup.instance})</span>\n <span className=\"artist-count\">({artistGroup.albums.length} albums)</span>\n {artistGroup.qualityProfileName ? (\n <span className=\"artist-quality\">• {artistGroup.qualityProfileName}</span>\n ) : null}\n </summary>\n <div className=\"artist-content\">\n {artistGroup.albums.map((albumEntry) => {\n const albumData = albumEntry.album as Record<string, unknown>;\n const albumTitle = (albumData?.[\"title\"] as string | undefined) || \"Unknown Album\";\n const albumId = (albumData?.[\"id\"] as number | undefined) || 0;\n const artistName = (albumData?.[\"artistName\"] as string | undefined) || \"\";\n const releaseDate = albumData?.[\"releaseDate\"] as string | undefined;\n const monitored = albumData?.[\"monitored\"] as boolean | undefined;\n const hasFile = albumData?.[\"hasFile\"] as boolean | undefined;\n const reason = albumData?.[\"reason\"] as string | null | undefined;\n const tracks = albumEntry.tracks || [];\n const totals = albumEntry.totals;\n\n return (\n <details key={`${albumEntry.__instance}-${artistName}-${albumTitle}`} className=\"album-details\">\n <summary className=\"album-summary\">\n <span className=\"album-title\">{albumTitle}</span>\n {releaseDate && (\n <span className=\"album-date\">{new Date(releaseDate).toLocaleDateString()}</span>\n )}\n {tracks && tracks.length > 0 && (\n <span className=\"album-track-count\">({totals.available || 0}/{totals.monitored || tracks.length} tracks)</span>\n )}\n <span className={`album-status ${hasFile ? 'has-file' : 'missing'}`}>\n {hasFile ? '✓' : '✗'}\n </span>\n </summary>\n <div className=\"album-content\">\n {tracks && tracks.length > 0 ? (\n <div className=\"tracks-table-wrapper\">\n <table className=\"tracks-table\">\n <thead>\n <tr>\n <th>#</th>\n <th>Title</th>\n <th>Duration</th>\n <th>Has File</th>\n <th>Reason</th>\n </tr>\n </thead>\n <tbody>\n {tracks.map((track) => (\n <tr key={`${albumId}-${track.id}`} className={track.hasFile ? 'track-available' : 'track-missing'}>\n <td data-label=\"#\">{track.trackNumber}</td>\n <td data-label=\"Title\">{track.title}</td>\n <td data-label=\"Duration\">{track.duration ? `${Math.floor(track.duration / 60)}:${String(track.duration % 60).padStart(2, '0')}` : '—'}</td>\n <td data-label=\"Has File\">\n <span className={`track-status ${track.hasFile ? 'available' : 'missing'}`}>\n {track.hasFile ? '✓' : '✗'}\n </span>\n </td>\n <td data-label=\"Reason\">\n {reason ? (\n <span className=\"table-badge table-badge-reason\">{reason}</span>\n ) : (\n <span className=\"table-badge table-badge-reason\">Not being searched</span>\n )}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n ) : (\n <div className=\"album-info\">\n <p>\n <strong>Monitored:</strong> {monitored ? 'Yes' : 'No'}\n {' | '}\n <strong>Has File:</strong> {hasFile ? 'Yes' : 'No'}\n </p>\n <p>\n <strong>Reason:</strong>{' '}\n {reason ? (\n <span className=\"table-badge table-badge-reason\">{reason}</span>\n ) : (\n <span className=\"table-badge table-badge-reason\">Not being searched</span>\n )}\n </p>\n </div>\n )}\n </div>\n </details>\n );\n })}\n </div>\n </details>\n ))}\n </div>\n ) : trackRows.length ? (\n <div className=\"table-wrapper\">\n <table className=\"responsive-table\">\n <thead>\n {flatTable.getHeaderGroups().map((headerGroup) => (\n <tr key={headerGroup.id}>\n {headerGroup.headers.map((header) => (\n <th key={header.id}>\n {header.isPlaceholder\n ? null\n : flexRender(\n header.column.columnDef.header,\n header.getContext()\n )}\n </th>\n ))}\n </tr>\n ))}\n </thead>\n <tbody>\n {flatTable.getRowModel().rows.map((row) => {\n const track = row.original;\n const stableKey = `${track.__instance}-${track.artistName}-${track.albumTitle}-${track.trackNumber}`;\n return (\n <tr key={stableKey}>\n {row.getVisibleCells().map((cell) => (\n <td key={cell.id} data-label={String(cell.column.columnDef.header)}>\n {flexRender(\n cell.column.columnDef.cell,\n cell.getContext()\n )}\n </td>\n ))}\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n ) : (\n <div className=\"hint\">No tracks found.</div>\n )}\n\n {(groupLidarr ? groupedPageRows.length > 0 : flatPageRows.length > 0) && (\n <div className=\"pagination\">\n <div>\n {groupLidarr ? (\n <>Page {page + 1} of {Math.ceil(groupedData.length / 50)} ({groupedData.length} artists · page size 50)</>\n ) : (\n <>Page {page + 1} of {Math.ceil(trackRows.length / 50)} ({trackRows.length.toLocaleString()} tracks · page size 50)</>\n )}\n </div>\n <div className=\"inline\">\n <button\n className=\"btn\"\n onClick={() => onPageChange(Math.max(0, page - 1))}\n disabled={page === 0 || loading}\n >\n Prev\n </button>\n <button\n className=\"btn\"\n onClick={() => onPageChange(Math.min((groupLidarr ? Math.ceil(groupedData.length / 50) : Math.ceil(trackRows.length / 50)) - 1, page + 1))}\n disabled={page >= (groupLidarr ? Math.ceil(groupedData.length / 50) : Math.ceil(trackRows.length / 50)) - 1 || loading}\n >\n Next\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n\ninterface LidarrInstanceViewProps {\n loading: boolean;\n data: LidarrAlbumsResponse | null;\n page: number;\n totalPages: number;\n pageSize: number;\n allAlbums: LidarrAlbumEntry[];\n onlyMissing: boolean;\n reasonFilter: string;\n onPageChange: (page: number) => void;\n onRestart: () => void;\n lastUpdated: string | null;\n groupLidarr: boolean;\n instances: ArrInfo[];\n selection: string;\n}\n\nfunction LidarrInstanceView({\n loading,\n data,\n allAlbums,\n onlyMissing,\n reasonFilter,\n onRestart,\n lastUpdated,\n groupLidarr,\n instances,\n selection,\n}: LidarrInstanceViewProps): JSX.Element {\n // Separate pagination state for flat (album) view\n const [flatPage, setFlatPage] = useState(0);\n const FLAT_PAGE_SIZE = 50;\n\n const filteredAlbums = useMemo(() => {\n let albums = allAlbums;\n if (onlyMissing) {\n albums = albums.filter((entry) => {\n const albumData = entry.album as Record<string, unknown>;\n return !(albumData?.[\"hasFile\"] as boolean | undefined);\n });\n }\n return albums;\n }, [allAlbums, onlyMissing]);\n\n const reasonFilteredAlbums = useMemo(() => {\n if (reasonFilter === \"all\") return filteredAlbums;\n if (reasonFilter === \"Not being searched\") {\n return filteredAlbums.filter((entry) => {\n const albumData = entry.album as Record<string, unknown>;\n return albumData?.[\"reason\"] === \"Not being searched\" || !albumData?.[\"reason\"];\n });\n }\n return filteredAlbums.filter((entry) => {\n const albumData = entry.album as Record<string, unknown>;\n return albumData?.[\"reason\"] === reasonFilter;\n });\n }, [filteredAlbums, reasonFilter]);\n\n const totalAlbums = useMemo(() => allAlbums.length, [allAlbums]);\n const isFiltered = reasonFilter !== \"all\" || onlyMissing;\n const filteredCount = reasonFilteredAlbums.length;\n\n // Count total tracks for instance view\n // Track counts (for potential future use)\n // const totalTracks = useMemo(() => {\n // let count = 0;\n // allAlbums.forEach(entry => {\n // const tracks = entry.tracks || [];\n // count += tracks.length;\n // });\n // return count;\n // }, [allAlbums]);\n\n // const filteredTracks = useMemo(() => {\n // let count = 0;\n // reasonFilteredAlbums.forEach(entry => {\n // const tracks = entry.tracks || [];\n // count += tracks.length;\n // });\n // return count;\n // }, [reasonFilteredAlbums]);\n\n // Reset flat page when filters change\n useEffect(() => {\n setFlatPage(0);\n }, [onlyMissing, reasonFilter]);\n\n const prevFilteredAlbumsRef = useRef<LidarrAlbumEntry[]>([]);\n const groupedAlbumsCache = useRef<Array<{\n artist: string;\n albums: LidarrAlbumEntry[];\n qualityProfileName?: string | null;\n }>>([]);\n\n // Group albums by artist for hierarchical view - only rebuild if filtered albums changed\n const groupedAlbums = useMemo(() => {\n // Quick reference check\n if (reasonFilteredAlbums === prevFilteredAlbumsRef.current) {\n return groupedAlbumsCache.current;\n }\n\n const artistMap = new Map<string, LidarrAlbumEntry[]>();\n reasonFilteredAlbums.forEach(albumEntry => {\n const albumData = albumEntry.album as Record<string, unknown>;\n const artist = (albumData?.[\"artistName\"] as string | undefined) || \"Unknown Artist\";\n if (!artistMap.has(artist)) {\n artistMap.set(artist, []);\n }\n artistMap.get(artist)!.push(albumEntry);\n });\n\n const result = Array.from(artistMap.entries()).map(([artist, albums]) => {\n // Get quality profile from first album (all albums by same artist typically share quality profile)\n const firstAlbum = albums[0]?.album as Record<string, unknown> | undefined;\n const qualityProfileName = (firstAlbum?.[\"qualityProfileName\"] as string | null | undefined) ?? null;\n return {\n artist,\n albums,\n qualityProfileName,\n };\n });\n\n prevFilteredAlbumsRef.current = reasonFilteredAlbums;\n groupedAlbumsCache.current = result;\n return result;\n }, [reasonFilteredAlbums]);\n\n const columns = useMemo<ColumnDef<LidarrAlbumEntry>[]>(\n () => [\n {\n id: \"title\",\n header: \"Album\",\n cell: (info) => {\n const albumData = info.row.original.album as Record<string, unknown>;\n return (albumData?.[\"title\"] as string | undefined) || \"Unknown Album\";\n },\n },\n {\n id: \"artistName\",\n header: \"Artist\",\n cell: (info) => {\n const albumData = info.row.original.album as Record<string, unknown>;\n return (albumData?.[\"artistName\"] as string | undefined) || \"Unknown Artist\";\n },\n size: 150,\n },\n {\n id: \"releaseDate\",\n header: \"Release Date\",\n cell: (info) => {\n const albumData = info.row.original.album as Record<string, unknown>;\n const date = albumData?.[\"releaseDate\"] as string | undefined;\n if (!date) return <span className=\"hint\">—</span>;\n return new Date(date).toLocaleDateString();\n },\n size: 120,\n },\n {\n id: \"monitored\",\n header: \"Monitored\",\n cell: (info) => {\n const albumData = info.row.original.album as Record<string, unknown>;\n const monitored = albumData?.[\"monitored\"] as boolean | undefined;\n return (\n <span className={`track-status ${monitored ? 'available' : 'missing'}`}>\n {monitored ? '✓' : '✗'}\n </span>\n );\n },\n size: 100,\n },\n {\n id: \"hasFile\",\n header: \"Has File\",\n cell: (info) => {\n const albumData = info.row.original.album as Record<string, unknown>;\n const hasFile = albumData?.[\"hasFile\"] as boolean | undefined;\n return (\n <span className={`track-status ${hasFile ? 'available' : 'missing'}`}>\n {hasFile ? '✓' : '✗'}\n </span>\n );\n },\n size: 100,\n },\n {\n id: \"qualityProfileName\",\n header: \"Quality Profile\",\n cell: (info) => {\n const albumData = info.row.original.album as Record<string, unknown>;\n const profileName = albumData?.[\"qualityProfileName\"] as string | null | undefined;\n return profileName || \"—\";\n },\n size: 150,\n },\n {\n id: \"reason\",\n header: \"Reason\",\n cell: (info) => {\n const albumData = info.row.original.album as Record<string, unknown>;\n const reason = albumData?.[\"reason\"] as string | null | undefined;\n if (!reason) return <span className=\"table-badge table-badge-reason\">Not being searched</span>;\n return <span className=\"table-badge table-badge-reason\">{reason}</span>;\n },\n size: 120,\n },\n ],\n []\n );\n\n // Pagination for flat view\n const flatTotalPages = Math.max(1, Math.ceil(reasonFilteredAlbums.length / FLAT_PAGE_SIZE));\n const flatSafePage = Math.min(flatPage, Math.max(0, flatTotalPages - 1));\n const paginatedAlbums = useMemo(() => {\n return reasonFilteredAlbums.slice(flatSafePage * FLAT_PAGE_SIZE, (flatSafePage + 1) * FLAT_PAGE_SIZE);\n }, [reasonFilteredAlbums, flatSafePage]);\n\n // Pagination for grouped view (paginate by artist groups, not backend pages)\n const GROUPED_PAGE_SIZE = 50;\n const [groupedPage, setGroupedPage] = useState(0);\n const groupedTotalPages = Math.max(1, Math.ceil(groupedAlbums.length / GROUPED_PAGE_SIZE));\n const groupedSafePage = Math.min(groupedPage, Math.max(0, groupedTotalPages - 1));\n const paginatedGroupedAlbums = useMemo(() => {\n return groupedAlbums.slice(groupedSafePage * GROUPED_PAGE_SIZE, (groupedSafePage + 1) * GROUPED_PAGE_SIZE);\n }, [groupedAlbums, groupedSafePage]);\n\n // Reset grouped page when filters change\n useEffect(() => {\n setGroupedPage(0);\n }, [onlyMissing, reasonFilter]);\n\n const table = useReactTable({\n data: paginatedAlbums,\n columns,\n getCoreRowModel: getCoreRowModel(),\n getSortedRowModel: getSortedRowModel(),\n });\n\n return (\n <div className=\"stack animate-fade-in\">\n <div className=\"row\" style={{ justifyContent: \"space-between\" }}>\n <div className=\"hint\">\n {data?.counts ? (\n <>\n <strong>Available:</strong>{\" \"}\n {(data.counts.available ?? 0).toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Monitored:</strong>{\" \"}\n {(data.counts.monitored ?? 0).toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Missing:</strong>{\" \"}\n {((data.counts.monitored ?? 0) - (data.counts.available ?? 0)).toLocaleString(undefined, { maximumFractionDigits: 0 })} •{\" \"}\n <strong>Total:</strong>{\" \"}\n {totalAlbums.toLocaleString(undefined, { maximumFractionDigits: 0 })}\n {isFiltered && filteredCount < totalAlbums && (\n <>\n {\" \"}• <strong>Filtered:</strong>{\" \"}\n {filteredCount.toLocaleString(undefined, { maximumFractionDigits: 0 })} of{\" \"}\n {totalAlbums.toLocaleString(undefined, { maximumFractionDigits: 0 })}\n </>\n )}\n </>\n ) : (\n \"Loading album information...\"\n )}\n {lastUpdated ? ` (updated ${lastUpdated})` : \"\"}\n </div>\n <button className=\"btn ghost\" onClick={onRestart} disabled={loading}>\n <IconImage src={RestartIcon} />\n Restart\n </button>\n </div>\n\n {loading ? (\n <div className=\"loading\">\n <span className=\"spinner\" /> Loading…\n </div>\n ) : groupLidarr ? (\n <div className=\"lidarr-hierarchical-view\">\n {paginatedGroupedAlbums.map((artistGroup) => {\n // Get instance name from selection\n const instanceName = instances.find(i => i.category === selection)?.name || selection;\n return (\n <details key={artistGroup.artist} className=\"artist-details\">\n <summary className=\"artist-summary\">\n <span className=\"artist-title\">{artistGroup.artist}</span>\n <span className=\"artist-instance\">({instanceName})</span>\n <span className=\"artist-count\">({artistGroup.albums.length} albums)</span>\n {artistGroup.qualityProfileName ? (\n <span className=\"artist-quality\">• {artistGroup.qualityProfileName}</span>\n ) : null}\n </summary>\n <div className=\"artist-content\">\n {artistGroup.albums.map((albumEntry) => {\n const albumData = albumEntry.album as Record<string, unknown>;\n const albumTitle = (albumData?.[\"title\"] as string | undefined) || \"Unknown Album\";\n const albumId = (albumData?.[\"id\"] as number | undefined) || 0;\n const artistName = (albumData?.[\"artistName\"] as string | undefined) || \"\";\n const releaseDate = albumData?.[\"releaseDate\"] as string | undefined;\n const monitored = albumData?.[\"monitored\"] as boolean | undefined;\n const hasFile = albumData?.[\"hasFile\"] as boolean | undefined;\n const reason = albumData?.[\"reason\"] as string | null | undefined;\n const tracks = albumEntry.tracks || [];\n const totals = albumEntry.totals;\n\n return (\n <details key={`${artistName}-${albumTitle}`} className=\"album-details\">\n <summary className=\"album-summary\">\n <span className=\"album-title\">{albumTitle}</span>\n {releaseDate && (\n <span className=\"album-date\">{new Date(releaseDate).toLocaleDateString()}</span>\n )}\n {tracks && tracks.length > 0 && (\n <span className=\"album-track-count\">({totals.available || 0}/{totals.monitored || tracks.length} tracks)</span>\n )}\n <span className={`album-status ${hasFile ? 'has-file' : 'missing'}`}>\n {hasFile ? '✓' : '✗'}\n </span>\n </summary>\n <div className=\"album-content\">\n {tracks && tracks.length > 0 ? (\n <div className=\"tracks-table-wrapper\">\n <table className=\"tracks-table\">\n <thead>\n <tr>\n <th>#</th>\n <th>Title</th>\n <th>Duration</th>\n <th>Has File</th>\n <th>Reason</th>\n </tr>\n </thead>\n <tbody>\n {tracks.map((track) => (\n <tr key={`${albumId}-${track.id}`} className={track.hasFile ? 'track-available' : 'track-missing'}>\n <td data-label=\"#\">{track.trackNumber}</td>\n <td data-label=\"Title\">{track.title}</td>\n <td data-label=\"Duration\">{track.duration ? `${Math.floor(track.duration / 60)}:${String(track.duration % 60).padStart(2, '0')}` : '—'}</td>\n <td data-label=\"Has File\">\n <span className={`track-status ${track.hasFile ? 'available' : 'missing'}`}>\n {track.hasFile ? '✓' : '✗'}\n </span>\n </td>\n <td data-label=\"Reason\">\n {reason ? (\n <span className=\"table-badge table-badge-reason\">{reason}</span>\n ) : (\n <span className=\"table-badge table-badge-reason\">Not being searched</span>\n )}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n ) : (\n <div className=\"album-info\">\n <p>\n <strong>Monitored:</strong> {monitored ? 'Yes' : 'No'}\n {' | '}\n <strong>Has File:</strong> {hasFile ? 'Yes' : 'No'}\n </p>\n <p>\n <strong>Reason:</strong>{' '}\n {reason ? (\n <span className=\"table-badge table-badge-reason\">{reason}</span>\n ) : (\n <span className=\"table-badge table-badge-reason\">Not being searched</span>\n )}\n </p>\n </div>\n )}\n </div>\n </details>\n );\n })}\n </div>\n </details>\n );\n })}\n </div>\n ) : !groupLidarr && allAlbums.length ? (\n <div className=\"table-wrapper\">\n <table className=\"responsive-table\">\n <thead>\n {table.getHeaderGroups().map((headerGroup) => (\n <tr key={headerGroup.id}>\n {headerGroup.headers.map((header) => (\n <th key={header.id}>\n {header.isPlaceholder\n ? null\n : flexRender(\n header.column.columnDef.header,\n header.getContext()\n )}\n </th>\n ))}\n </tr>\n ))}\n </thead>\n <tbody>\n {table.getRowModel().rows.map((row) => {\n const albumEntry = row.original;\n const albumData = albumEntry.album as Record<string, unknown>;\n const title = (albumData?.[\"title\"] as string | undefined) || \"Unknown\";\n const artistName = (albumData?.[\"artistName\"] as string | undefined) || \"Unknown\";\n const stableKey = `${title}-${artistName}`;\n return (\n <tr key={stableKey}>\n {row.getVisibleCells().map((cell) => (\n <td key={cell.id} data-label={String(cell.column.columnDef.header)}>\n {flexRender(\n cell.column.columnDef.cell,\n cell.getContext()\n )}\n </td>\n ))}\n </tr>\n );\n })}\n </tbody>\n </table>\n {flatTotalPages > 1 && (\n <div className=\"pagination\">\n <div>\n Page {flatSafePage + 1} of {flatTotalPages} ({reasonFilteredAlbums.length.toLocaleString()} albums · page size {FLAT_PAGE_SIZE})\n </div>\n <div className=\"inline\">\n <button\n className=\"btn\"\n onClick={() => setFlatPage(Math.max(0, flatSafePage - 1))}\n disabled={flatSafePage === 0 || loading}\n >\n Prev\n </button>\n <button\n className=\"btn\"\n onClick={() => setFlatPage(Math.min(flatTotalPages - 1, flatSafePage + 1))}\n disabled={flatSafePage >= flatTotalPages - 1 || loading}\n >\n Next\n </button>\n </div>\n </div>\n )}\n </div>\n ) : (\n <div className=\"hint\">No albums found.</div>\n )}\n\n {groupLidarr && groupedAlbums.length > 0 && (\n <div className=\"pagination\">\n <div>\n Page {groupedSafePage + 1} of {groupedTotalPages} ({groupedAlbums.length.toLocaleString()} artists · page size {GROUPED_PAGE_SIZE})\n </div>\n <div className=\"inline\">\n <button\n className=\"btn\"\n onClick={() => setGroupedPage(Math.max(0, groupedSafePage - 1))}\n disabled={groupedSafePage === 0 || loading}\n >\n Prev\n </button>\n <button\n className=\"btn\"\n onClick={() => setGroupedPage(Math.min(groupedTotalPages - 1, groupedSafePage + 1))}\n disabled={groupedSafePage >= groupedTotalPages - 1 || loading}\n >\n Next\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport function LidarrView({ active }: { active: boolean }): JSX.Element {\n const { push } = useToast();\n const {\n value: globalSearch,\n setValue: setGlobalSearch,\n register,\n clearHandler,\n } = useSearch();\n const { liveArr, groupLidarr } = useWebUI();\n\n const [instances, setInstances] = useState<ArrInfo[]>([]);\n const [selection, setSelection] = useState<string | \"\">(\"\");\n const [instanceData, setInstanceData] = useState<LidarrAlbumsResponse | null>(null);\n const [instancePage, setInstancePage] = useState(0);\n const [instanceQuery, setInstanceQuery] = useState(\"\");\n const [instanceLoading, setInstanceLoading] = useState(false);\n const [lastUpdated, setLastUpdated] = useState<string | null>(null);\n const [instancePages, setInstancePages] = useState<Record<number, LidarrAlbumEntry[]>>({});\n const [instancePageSize, setInstancePageSize] = useState(LIDARR_PAGE_SIZE);\n const [instanceTotalPages, setInstanceTotalPages] = useState(1);\n const instanceKeyRef = useRef<string>(\"\");\n const instancePagesRef = useRef<Record<number, LidarrAlbumEntry[]>>({});\n const globalSearchRef = useRef(globalSearch);\n const backendReadyWarnedRef = useRef(false);\n const prevSelectionRef = useRef<string | \"\">(selection);\n\n // Smart data sync for instance albums\n const instanceAlbumSync = useDataSync<LidarrAlbumEntry>({\n getKey: (album) => {\n const albumData = album.album as Record<string, unknown>;\n const artistName = (albumData?.[\"artistName\"] as string | undefined) || \"\";\n const title = (albumData?.[\"title\"] as string | undefined) || \"\";\n return `${artistName}-${title}`;\n },\n hashFields: ['album', 'tracks', 'totals'],\n });\n\n const [aggRows, setAggRows] = useState<LidarrAggRow[]>([]);\n const [aggTrackRows, setAggTrackRows] = useState<LidarrTrackRow[]>([]);\n const [aggLoading, setAggLoading] = useState(false);\n const [aggPage, setAggPage] = useState(0);\n const [aggFilter, setAggFilter] = useState(\"\");\n const [aggUpdated, setAggUpdated] = useState<string | null>(null);\n\n // Smart data sync for aggregate albums\n const aggAlbumSync = useDataSync<LidarrAggRow>({\n getKey: (album) => {\n const albumData = album.album as Record<string, unknown>;\n const artistName = (albumData?.[\"artistName\"] as string | undefined) || \"\";\n const title = (albumData?.[\"title\"] as string | undefined) || \"\";\n return `${album.__instance}-${artistName}-${title}`;\n },\n hashFields: ['__instance', 'album', 'tracks', 'totals'],\n });\n\n // Smart data sync for track rows\n const aggTrackSync = useDataSync<LidarrTrackRow>({\n getKey: (track) => `${track.__instance}-${track.artistName}-${track.albumTitle}-${track.trackNumber}`,\n hashFields: ['__instance', 'artistName', 'albumTitle', 'trackNumber', 'title', 'hasFile', 'monitored', 'reason'],\n });\n const [onlyMissing, setOnlyMissing] = useState(false);\n const [reasonFilter, setReasonFilter] = useState<string>(\"all\");\n const [aggSummary, setAggSummary] = useState<{\n available: number;\n monitored: number;\n missing: number;\n total: number;\n }>({ available: 0, monitored: 0, missing: 0, total: 0 });\n\n const loadInstances = useCallback(async () => {\n try {\n const data = await getArrList();\n if (data.ready === false && !backendReadyWarnedRef.current) {\n backendReadyWarnedRef.current = true;\n push(\"Lidarr backend is still initialising. Check the logs if this persists.\", \"info\");\n } else if (data.ready) {\n backendReadyWarnedRef.current = true;\n }\n const filtered = (data.arr || []).filter((arr) => arr.type === \"lidarr\");\n setInstances(filtered);\n if (!filtered.length) {\n setSelection(\"aggregate\");\n setInstanceData(null);\n setAggRows([]);\n setAggSummary({ available: 0, monitored: 0, missing: 0, total: 0 });\n return;\n }\n if (selection === \"\") {\n // If only 1 instance, select it directly; otherwise use aggregate\n setSelection(filtered.length === 1 ? filtered[0].category : \"aggregate\");\n } else if (\n selection !== \"aggregate\" &&\n !filtered.some((arr) => arr.category === selection)\n ) {\n setSelection(filtered[0].category);\n }\n } catch (error) {\n push(\n error instanceof Error\n ? error.message\n : \"Unable to load Lidarr instances\",\n \"error\"\n );\n }\n }, [push, selection]);\n\n const preloadRemainingPages = useCallback(\n async (\n category: string,\n query: string,\n pageSize: number,\n pages: number[],\n key: string\n ) => {\n if (!pages.length) return;\n try {\n const results: { page: number; albums: LidarrAlbumEntry[] }[] = [];\n for (const pg of pages) {\n const res = await getLidarrAlbums(category, pg, pageSize, query);\n const resolved = res.page ?? pg;\n results.push({ page: resolved, albums: res.albums ?? [] });\n if (instanceKeyRef.current !== key) {\n return;\n }\n }\n if (instanceKeyRef.current !== key) return;\n\n // Smart diffing: only update pages that actually changed\n setInstancePages((prev) => {\n const next = { ...prev };\n let hasChanges = false;\n for (const { page, albums } of results) {\n // Use hash-based comparison for each page\n const syncResult = instanceAlbumSync.syncData(albums);\n if (syncResult.hasChanges) {\n next[page] = syncResult.data;\n hasChanges = true;\n }\n }\n instancePagesRef.current = next;\n return hasChanges ? next : prev;\n });\n } catch (error) {\n push(\n error instanceof Error\n ? error.message\n : `Failed to load additional pages for ${category}`,\n \"error\"\n );\n }\n },\n [push]\n );\n\n const fetchInstance = useCallback(\n async (\n category: string,\n page: number,\n query: string,\n options: { preloadAll?: boolean; showLoading?: boolean } = {}\n ) => {\n const preloadAll = options.preloadAll !== false;\n const showLoading = options.showLoading ?? true;\n if (showLoading) {\n setInstanceLoading(true);\n }\n try {\n const key = `${category}::${query}`;\n const keyChanged = instanceKeyRef.current !== key;\n if (keyChanged) {\n instanceKeyRef.current = key;\n setInstancePages(() => {\n instancePagesRef.current = {};\n return {};\n });\n }\n const response = await getLidarrAlbums(\n category,\n page,\n LIDARR_PAGE_SIZE,\n query\n );\n setInstanceData(response);\n const resolvedPage = response.page ?? page;\n setInstancePage(resolvedPage);\n setInstanceQuery(query);\n const pageSize = response.page_size ?? LIDARR_PAGE_SIZE;\n const totalItems = response.total ?? (response.albums ?? []).length;\n const totalPages = Math.max(1, Math.ceil((totalItems || 0) / pageSize));\n setInstancePageSize(pageSize);\n setInstanceTotalPages(totalPages);\n const albums = response.albums ?? [];\n const existingPages = keyChanged ? {} : instancePagesRef.current;\n\n // Smart diffing using hash-based change detection\n const syncResult = instanceAlbumSync.syncData(albums);\n const albumsChanged = syncResult.hasChanges;\n\n if (keyChanged) {\n // Reset sync state on key change\n instanceAlbumSync.reset();\n }\n\n if (keyChanged || albumsChanged) {\n setInstancePages((prev) => {\n const base = keyChanged ? {} : prev;\n const next = { ...base, [resolvedPage]: syncResult.data };\n instancePagesRef.current = next;\n return next;\n });\n setLastUpdated(new Date().toLocaleTimeString());\n }\n\n if (preloadAll) {\n const pagesToFetch: number[] = [];\n for (let i = 0; i < totalPages; i += 1) {\n if (i === resolvedPage) continue;\n if (!existingPages[i]) {\n pagesToFetch.push(i);\n }\n }\n void preloadRemainingPages(\n category,\n query,\n pageSize,\n pagesToFetch,\n key\n );\n }\n } catch (error) {\n push(\n error instanceof Error\n ? error.message\n : `Failed to load ${category} albums`,\n \"error\"\n );\n } finally {\n setInstanceLoading(false);\n }\n },\n [push, preloadRemainingPages]\n );\n\n const loadAggregate = useCallback(async (options?: { showLoading?: boolean }) => {\n if (!instances.length) {\n setAggRows([]);\n setAggSummary({ available: 0, monitored: 0, missing: 0, total: 0 });\n return;\n }\n const showLoading = options?.showLoading ?? true;\n if (showLoading) {\n setAggLoading(true);\n }\n try {\n const aggregated: LidarrAggRow[] = [];\n let totalAvailable = 0;\n let totalMonitored = 0;\n for (const inst of instances) {\n let page = 0;\n let counted = false;\n const label = inst.name || inst.category;\n while (page < 100) {\n const res = await getLidarrAlbums(\n inst.category,\n page,\n LIDARR_AGG_FETCH_SIZE,\n \"\"\n );\n\n console.log(\"=== Lidarr API Response ===\");\n console.log(\"Instance:\", inst.category);\n console.log(\"Response:\", res);\n console.log(\"Albums count:\", res.albums?.length);\n if (res.albums && res.albums.length > 0) {\n console.log(\"First album entry:\", res.albums[0]);\n console.log(\"First album.album:\", res.albums[0].album);\n console.log(\"First album.totals:\", res.albums[0].totals);\n console.log(\"First album.tracks:\", res.albums[0].tracks);\n }\n console.log(\"=========================\");\n\n if (!counted) {\n const counts = res.counts;\n if (counts) {\n totalAvailable += counts.available ?? 0;\n totalMonitored += counts.monitored ?? 0;\n }\n counted = true;\n }\n const albumEntries = res.albums ?? [];\n albumEntries.forEach((entry) => {\n aggregated.push({ ...entry, __instance: label });\n });\n if (!albumEntries.length || albumEntries.length < LIDARR_AGG_FETCH_SIZE) break;\n page += 1;\n }\n }\n\n // Flatten tracks from all albums for flat mode\n const trackRows: LidarrTrackRow[] = [];\n aggregated.forEach((albumEntry) => {\n const albumData = albumEntry.album as Record<string, unknown>;\n const artistName = (albumData?.[\"artistName\"] as string | undefined) || \"Unknown Artist\";\n const albumTitle = (albumData?.[\"title\"] as string | undefined) || \"Unknown Album\";\n const reason = albumData?.[\"reason\"] as string | null | undefined;\n const qualityProfileId = albumData?.[\"qualityProfileId\"] as number | null | undefined;\n const qualityProfileName = albumData?.[\"qualityProfileName\"] as string | null | undefined;\n const tracks = albumEntry.tracks || [];\n\n if (tracks && tracks.length > 0) {\n tracks.forEach((track) => {\n trackRows.push({\n __instance: albumEntry.__instance,\n artistName,\n albumTitle,\n trackNumber: track.trackNumber || 0,\n title: track.title || \"Unknown Track\",\n duration: track.duration,\n hasFile: track.hasFile || false,\n monitored: track.monitored || false,\n reason,\n qualityProfileId,\n qualityProfileName,\n });\n });\n }\n });\n\n // Smart diffing using hash-based change detection\n const albumSyncResult = aggAlbumSync.syncData(aggregated);\n const rowsChanged = albumSyncResult.hasChanges;\n\n const trackSyncResult = aggTrackSync.syncData(trackRows);\n const trackRowsChanged = trackSyncResult.hasChanges;\n\n if (rowsChanged) {\n setAggRows(albumSyncResult.data);\n }\n\n if (trackRowsChanged) {\n setAggTrackRows(trackSyncResult.data);\n }\n\n const newSummary = groupLidarr\n ? {\n available: totalAvailable,\n monitored: totalMonitored,\n missing: aggregated.length - totalAvailable,\n total: aggregated.length,\n }\n : {\n available: trackRows.filter(t => t.hasFile).length,\n monitored: trackRows.filter(t => t.monitored).length,\n missing: trackRows.filter(t => !t.hasFile).length,\n total: trackRows.length,\n };\n\n const summaryChanged = (\n aggSummary.available !== newSummary.available ||\n aggSummary.monitored !== newSummary.monitored ||\n aggSummary.missing !== newSummary.missing ||\n aggSummary.total !== newSummary.total\n );\n\n if (summaryChanged) {\n setAggSummary(newSummary);\n }\n\n // Only reset page if filter changed, not on refresh\n if (aggFilter !== globalSearch) {\n setAggPage(0);\n setAggFilter(globalSearch);\n }\n\n // Only update timestamp if data actually changed\n if (rowsChanged || summaryChanged) {\n setAggUpdated(new Date().toLocaleTimeString());\n }\n } catch (error) {\n setAggRows([]);\n setAggSummary({ available: 0, monitored: 0, missing: 0, total: 0 });\n push(\n error instanceof Error\n ? error.message\n : \"Failed to load aggregated Lidarr data\",\n \"error\"\n );\n } finally {\n setAggLoading(false);\n }\n }, [instances, globalSearch, push, aggFilter, groupLidarr]);\n\n // LiveArr is now loaded via WebUIContext, no need to load config here\n\n useEffect(() => {\n if (!active) return;\n void loadInstances();\n }, [active, loadInstances]);\n\n useEffect(() => {\n if (!active) return;\n if (!selection || selection === \"aggregate\") return;\n\n const selectionChanged = prevSelectionRef.current !== selection;\n\n // Reset page and cache only when selection changes\n if (selectionChanged) {\n instancePagesRef.current = {};\n setInstancePages({});\n setInstanceTotalPages(1);\n setInstancePage(0);\n prevSelectionRef.current = selection;\n }\n\n // Fetch data: use page 0 if selection changed, current page otherwise\n const query = globalSearchRef.current;\n void fetchInstance(selection, selectionChanged ? 0 : instancePage, query, {\n preloadAll: true,\n showLoading: true,\n });\n }, [active, selection, fetchInstance, instancePage]);\n\n useEffect(() => {\n if (!active) return;\n if (selection !== \"aggregate\") return;\n void loadAggregate();\n }, [active, selection, loadAggregate]);\n\n useInterval(() => {\n if (selection === \"aggregate\" && liveArr) {\n void loadAggregate({ showLoading: false });\n }\n }, selection === \"aggregate\" && liveArr ? 1000 : null);\n\n useEffect(() => {\n if (!active) return;\n const handler = (term: string) => {\n if (selection === \"aggregate\") {\n setAggFilter(term);\n setAggPage(0);\n } else if (selection) {\n setInstancePage(0);\n void fetchInstance(selection, 0, term, {\n preloadAll: true,\n showLoading: true,\n });\n }\n };\n register(handler);\n return () => {\n clearHandler(handler);\n };\n }, [active, selection, register, clearHandler, fetchInstance]);\n\n useInterval(\n () => {\n if (selection && selection !== \"aggregate\") {\n const activeFilter = globalSearchRef.current?.trim?.() || \"\";\n if (activeFilter) {\n return;\n }\n void fetchInstance(selection, instancePage, instanceQuery, {\n preloadAll: false,\n showLoading: false,\n });\n }\n },\n active && selection && selection !== \"aggregate\" && liveArr ? 1000 : null\n );\n\n // Removed: Don't reset page when filter changes - preserve scroll position\n\n useEffect(() => {\n globalSearchRef.current = globalSearch;\n }, [globalSearch]);\n\n useEffect(() => {\n if (selection === \"aggregate\") {\n setAggFilter(globalSearch);\n }\n }, [selection, globalSearch]);\n\n const filteredAggRows = useMemo(() => {\n let rows = aggRows;\n if (aggFilter) {\n const q = aggFilter.toLowerCase();\n rows = rows.filter((row) => {\n const albumData = row.album as Record<string, unknown>;\n const title = ((albumData?.[\"title\"] as string | undefined) ?? \"\").toString().toLowerCase();\n const artist = ((albumData?.[\"artistName\"] as string | undefined) ?? \"\").toString().toLowerCase();\n const instance = (row.__instance ?? \"\").toLowerCase();\n return title.includes(q) || artist.includes(q) || instance.includes(q);\n });\n }\n if (onlyMissing) {\n rows = rows.filter((row) => {\n const albumData = row.album as Record<string, unknown>;\n return !(albumData?.[\"hasFile\"] as boolean | undefined);\n });\n }\n if (reasonFilter !== \"all\") {\n if (reasonFilter === \"Not being searched\") {\n rows = rows.filter((row) => {\n const albumData = row.album as Record<string, unknown>;\n return albumData?.[\"reason\"] === \"Not being searched\" || !albumData?.[\"reason\"];\n });\n } else {\n rows = rows.filter((row) => {\n const albumData = row.album as Record<string, unknown>;\n return albumData?.[\"reason\"] === reasonFilter;\n });\n }\n }\n return rows;\n }, [aggRows, aggFilter, onlyMissing, reasonFilter]);\n\n const isAggFiltered = Boolean(aggFilter) || reasonFilter !== \"all\";\n\n const filteredAggTrackRows = useMemo(() => {\n let rows = aggTrackRows;\n if (aggFilter) {\n const q = aggFilter.toLowerCase();\n rows = rows.filter((row) => {\n return (\n row.artistName.toLowerCase().includes(q) ||\n row.albumTitle.toLowerCase().includes(q) ||\n row.title.toLowerCase().includes(q) ||\n row.__instance.toLowerCase().includes(q)\n );\n });\n }\n if (onlyMissing) {\n rows = rows.filter((row) => !row.hasFile);\n }\n if (reasonFilter !== \"all\") {\n if (reasonFilter === \"Not being searched\") {\n rows = rows.filter((row) => row.reason === \"Not being searched\" || !row.reason);\n } else {\n rows = rows.filter((row) => row.reason === reasonFilter);\n }\n }\n return rows;\n }, [aggTrackRows, aggFilter, onlyMissing, reasonFilter]);\n\n const allInstanceAlbums = useMemo(() => {\n const pages = Object.keys(instancePages)\n .map(Number)\n .sort((a, b) => a - b);\n const rows: LidarrAlbumEntry[] = [];\n pages.forEach((pg) => {\n if (instancePages[pg]) {\n rows.push(...instancePages[pg]);\n }\n });\n return rows;\n }, [instancePages]);\n\n const currentPageAlbums = useMemo(() => {\n return instancePages[instancePage] ?? [];\n }, [instancePages, instancePage]);\n\n const handleRestart = useCallback(async () => {\n if (!selection || selection === \"aggregate\") return;\n try {\n await restartArr(selection);\n push(`Restarted ${selection}`, \"success\");\n } catch (error) {\n push(\n error instanceof Error ? error.message : `Failed to restart ${selection}`,\n \"error\"\n );\n }\n }, [selection, push]);\n\n const handleInstanceSelection = useCallback(\n (event: ChangeEvent<HTMLSelectElement>) => {\n const next = (event.target.value || \"aggregate\") as string | \"aggregate\";\n setSelection(next);\n if (next !== \"aggregate\") {\n setGlobalSearch(\"\");\n }\n },\n [setSelection, setGlobalSearch]\n );\n\n const isAggregate = selection === \"aggregate\";\n\n return (\n <section className=\"card\">\n <div className=\"card-header\">Lidarr</div>\n <div className=\"card-body\">\n <div className=\"split\">\n <aside className=\"pane sidebar\">\n {instances.length > 1 && (\n <button\n className={`btn ${isAggregate ? \"active\" : \"\"}`}\n onClick={() => setSelection(\"aggregate\")}\n >\n All Lidarr\n </button>\n )}\n {instances.map((inst) => (\n <button\n key={inst.category}\n className={`btn ghost ${\n selection === inst.category ? \"active\" : \"\"\n }`}\n onClick={() => {\n setSelection(inst.category);\n setGlobalSearch(\"\");\n }}\n >\n {inst.name || inst.category}\n </button>\n ))}\n </aside>\n <div className=\"pane\">\n <div className=\"field mobile-instance-select\">\n <label>Instance</label>\n <select\n value={selection || \"aggregate\"}\n onChange={handleInstanceSelection}\n disabled={!instances.length}\n >\n {instances.length > 1 && <option value=\"aggregate\">All Lidarr</option>}\n {instances.map((inst) => (\n <option key={inst.category} value={inst.category}>\n {inst.name || inst.category}\n </option>\n ))}\n </select>\n </div>\n <div className=\"row\" style={{ alignItems: \"flex-end\", gap: \"12px\", flexWrap: \"wrap\" }}>\n <div className=\"col field\" style={{ flex: \"1 1 200px\" }}>\n <label>Search</label>\n <input\n placeholder=\"Filter albums\"\n value={globalSearch}\n onChange={(event) => setGlobalSearch(event.target.value)}\n />\n </div>\n <div className=\"field\" style={{ flex: \"0 0 auto\", minWidth: \"140px\" }}>\n <label>Status</label>\n <select\n onChange={(event) => {\n const value = event.target.value;\n setOnlyMissing(value === \"missing\");\n }}\n value={onlyMissing ? \"missing\" : \"all\"}\n >\n <option value=\"all\">All Albums</option>\n <option value=\"missing\">Missing Only</option>\n </select>\n </div>\n <div className=\"field\" style={{ flex: \"0 0 auto\", minWidth: \"140px\" }}>\n <label>Search Reason</label>\n <select\n onChange={(event) => setReasonFilter(event.target.value)}\n value={reasonFilter}\n >\n <option value=\"all\">All Reasons</option>\n <option value=\"Not being searched\">Not Being Searched</option>\n <option value=\"Missing\">Missing</option>\n <option value=\"Quality\">Quality</option>\n <option value=\"CustomFormat\">Custom Format</option>\n <option value=\"Upgrade\">Upgrade</option>\n </select>\n </div>\n </div>\n\n {isAggregate ? (\n <LidarrAggregateView\n loading={aggLoading}\n rows={filteredAggRows}\n trackRows={filteredAggTrackRows}\n page={aggPage}\n onPageChange={setAggPage}\n onRefresh={() => void loadAggregate({ showLoading: true })}\n lastUpdated={aggUpdated}\n summary={aggSummary}\n instanceCount={instances.length}\n groupLidarr={groupLidarr}\n isAggFiltered={isAggFiltered}\n />\n ) : (\n <LidarrInstanceView\n loading={instanceLoading}\n data={instanceData}\n page={instancePage}\n totalPages={instanceTotalPages}\n pageSize={instancePageSize}\n allAlbums={groupLidarr ? currentPageAlbums : allInstanceAlbums}\n onlyMissing={onlyMissing}\n reasonFilter={reasonFilter}\n onPageChange={(page) => {\n setInstancePage(page);\n void fetchInstance(selection as string, page, instanceQuery, {\n preloadAll: true,\n });\n }}\n onRestart={() => void handleRestart()}\n lastUpdated={lastUpdated}\n groupLidarr={groupLidarr}\n instances={instances}\n selection={selection as string}\n />\n )}\n </div>\n </div>\n </div>\n </section>\n );\n}\n","import { type JSX } from \"react\";\nimport { RadarrView } from \"./RadarrView\";\nimport { SonarrView } from \"./SonarrView\";\nimport { LidarrView } from \"./LidarrView\";\n\ninterface ArrViewProps {\n type: \"radarr\" | \"sonarr\" | \"lidarr\";\n active: boolean;\n}\n\nexport function ArrView({ type, active }: ArrViewProps): JSX.Element {\n if (type === \"radarr\") {\n return <RadarrView active={active} />;\n }\n if (type === \"lidarr\") {\n return <LidarrView active={active} />;\n }\n return <SonarrView active={active} />;\n}\n"],"names":["StableTableInner","data","columns","getRowKey","table","useReactTable","getCoreRowModel","jsxs","jsx","headerGroup","header","flexRender","row","stableKey","cell","StableTable","memo","prevProps","nextProps","fnv1aHash","str","hash","i","createItemHash","item","fields","values","field","value","detectChanges","existing","incoming","getKey","hashFields","added","updated","removed","seenIds","id","existingItem","existingHash","unchanged","hasChanges","mergeChanges","changes","newById","newByHash","newIds","index","denormalize","createEmptyNormalized","useDataSync","options","normalizedRef","useRef","lastUpdate","setLastUpdate","useState","syncData","useCallback","newData","merged","getData","reset","RADARR_PAGE_SIZE","RADARR_AGG_PAGE_SIZE","RADARR_AGG_FETCH_SIZE","RadarrAggregateView","loading","rows","total","page","totalPages","onPageChange","onRefresh","lastUpdated","summary","instanceCount","isAggFiltered","useMemo","info","monitored","hasFile","reason","Fragment","IconImage","RefreshIcon","movie","RadarrInstanceView","pageSize","allMovies","onlyMissing","reasonFilter","onRestart","filteredMovies","movies","m","reasonFilteredMovies","totalMovies","isFiltered","filteredCount","getSortedRowModel","RestartIcon","RadarrView","active","push","useToast","globalSearch","setGlobalSearch","register","clearHandler","useSearch","liveArr","useWebUI","instances","setInstances","selection","setSelection","instanceData","setInstanceData","instancePage","setInstancePage","instanceQuery","setInstanceQuery","instanceLoading","setInstanceLoading","setLastUpdated","instancePages","setInstancePages","instancePageSize","setInstancePageSize","instanceTotalPages","setInstanceTotalPages","instanceKeyRef","instancePagesRef","globalSearchRef","backendReadyWarnedRef","instanceMovieSync","aggRows","setAggRows","aggLoading","setAggLoading","aggPage","setAggPage","aggFilter","setAggFilter","aggUpdated","setAggUpdated","aggMovieSync","aggSort","setAggSort","setOnlyMissing","setReasonFilter","aggSummary","setAggSummary","loadInstances","getArrList","filtered","arr","error","preloadRemainingPages","category","query","pages","key","results","pg","res","getRadarrMovies","resolved","prev","next","syncResult","fetchInstance","preloadAll","keyChanged","response","resolvedPage","totalItems","existingPages","moviesChanged","pagesToFetch","loadAggregate","aggregated","totalAvailable","totalMonitored","inst","counted","label","counts","rowsChanged","newSummary","summaryChanged","useEffect","useInterval","handler","term","filteredAggRows","q","title","instance","sortedAggRows","list","getValue","a","b","valueA","valueB","comparison","aggPages","aggPageRows","allInstanceMovies","handleRestart","restartArr","handleAggRefresh","handleAggSort","handleInstanceRefresh","handleInstanceSelection","event","isAggregate","SONARR_PAGE_SIZE","SONARR_AGG_PAGE_SIZE","SONARR_AGG_FETCH_SIZE","filterSeriesEntriesForMissing","seriesEntries","result","entry","seasons","filteredSeasons","seasonNumber","season","episodes","episode","createFilteredSignature","SonarrView","groupSonarr","instanceDataRef","instanceTotalItems","setInstanceTotalItems","prevSelectionRef","aggEpisodeSync","ep","prevOnlyMissingRef","showLoading","missingOnly","useMissing","getSonarrSeries","series","prevPages","nextPages","prevSignature","nextSignature","shouldUpdateCurrentPage","prevCounts","nextCounts","targetPage","pageIndex","pageSeries","currentPages","prevSnapshot","nextSnapshot","totalMissing","episodeCount","entryEpisodeCount","qualityProfileId","qualityProfileName","episodeReason","reasonCounts","r","selectionChanged","onlyMissingChanged","beforeFilterCount","currentSeries","allSeries","newMissingState","SonarrAggregateView","SonarrInstanceView","prevRowsRef","groupedDataCache","seriesGroupCache","allGroupedData","instanceMap","instanceSeriesMap","seasonMap","newSeriesGroupCache","seriesMap","seriesKey","episodeKeys","episodeKey","cached","firstEpisode","seriesGroup","groupedPageRows","flatPageRows","tableData","groupedColumns","parts","flatColumns","groupedTable","getExpandedRowModel","flatTable","getPaginationRowModel","effectiveTotalPages","safePage","totalItemsDisplay","flatPage","setFlatPage","FLAT_PAGE_SIZE","episodeRows","filteredEpisodeRows","timer","groupedTableData","map","seasonKey","seriesName","totalEpisodes","flatTotalPages","flatSafePage","paginatedEpisodeRows","GROUPED_PAGE_SIZE","groupedPage","setGroupedPage","groupedTotalPages","groupedSafePage","paginatedGroupedData","instanceName","idx","LIDARR_PAGE_SIZE","LIDARR_AGG_FETCH_SIZE","LidarrAggregateView","trackRows","groupLidarr","artistGroupCache","groupedData","artist","artistMap","newArtistGroupCache","albums","artistKey","albumKeys","album","albumKey","albumData","artistGroup","start","end","dur","albumEntry","albumTitle","albumId","artistName","releaseDate","tracks","totals","track","LidarrInstanceView","allAlbums","filteredAlbums","reasonFilteredAlbums","totalAlbums","prevFilteredAlbumsRef","groupedAlbumsCache","groupedAlbums","date","paginatedAlbums","paginatedGroupedAlbums","LidarrView","instanceAlbumSync","aggTrackRows","setAggTrackRows","aggAlbumSync","aggTrackSync","getLidarrAlbums","albumsChanged","albumEntries","albumSyncResult","trackSyncResult","trackRowsChanged","t","filteredAggTrackRows","allInstanceAlbums","currentPageAlbums","ArrView","type"],"mappings":"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"}