qBitrr2 5.5.3__py3-none-any.whl → 5.5.6__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.
qBitrr/bundled_data.py CHANGED
@@ -1,5 +1,5 @@
1
- version = "5.5.3"
2
- git_hash = "0af67a21"
1
+ version = "5.5.6"
2
+ git_hash = "addcf902"
3
3
  license_text = (
4
4
  "Licence can be found on:\n\nhttps://github.com/Feramance/qBitrr/blob/master/LICENSE"
5
5
  )
qBitrr/db_lock.py CHANGED
@@ -6,6 +6,7 @@ from contextlib import contextmanager
6
6
  from pathlib import Path
7
7
  from typing import Iterator
8
8
 
9
+ from qBitrr.db_recovery import checkpoint_wal, repair_database
9
10
  from qBitrr.home_path import APPDATA_FOLDER
10
11
 
11
12
  if os.name == "nt": # pragma: no cover - platform specific
@@ -99,6 +100,8 @@ def with_database_retry(
99
100
  - sqlite3.IntegrityError (data constraint violations)
100
101
  - sqlite3.ProgrammingError (SQL syntax errors)
101
102
 
103
+ On detecting database corruption, attempts automatic recovery before retrying.
104
+
102
105
  Args:
103
106
  func: Callable to execute (should take no arguments)
104
107
  retries: Maximum number of retry attempts (default: 5)
@@ -118,6 +121,8 @@ def with_database_retry(
118
121
  import time
119
122
 
120
123
  attempt = 0
124
+ corruption_recovery_attempted = False
125
+
121
126
  while True:
122
127
  try:
123
128
  return func()
@@ -128,6 +133,61 @@ def with_database_retry(
128
133
  if "syntax" in error_msg or "constraint" in error_msg:
129
134
  raise
130
135
 
136
+ # Detect corruption and attempt recovery (only once)
137
+ if not corruption_recovery_attempted and (
138
+ "disk image is malformed" in error_msg
139
+ or "database disk image is malformed" in error_msg
140
+ or "database corruption" in error_msg
141
+ ):
142
+ corruption_recovery_attempted = True
143
+ if logger:
144
+ logger.error(
145
+ "Database corruption detected: %s. Attempting automatic recovery...",
146
+ e,
147
+ )
148
+
149
+ recovery_succeeded = False
150
+ try:
151
+ db_path = APPDATA_FOLDER / "qbitrr.db"
152
+
153
+ # Step 1: Try WAL checkpoint (least invasive)
154
+ if logger:
155
+ logger.info("Attempting WAL checkpoint...")
156
+ if checkpoint_wal(db_path, logger):
157
+ if logger:
158
+ logger.info("WAL checkpoint successful - retrying operation")
159
+ recovery_succeeded = True
160
+ else:
161
+ # Step 2: Try full repair (more invasive)
162
+ if logger:
163
+ logger.warning(
164
+ "WAL checkpoint failed - attempting full database repair..."
165
+ )
166
+ if repair_database(db_path, backup=True, logger_override=logger):
167
+ if logger:
168
+ logger.info("Database repair successful - retrying operation")
169
+ recovery_succeeded = True
170
+
171
+ except Exception as recovery_error:
172
+ if logger:
173
+ logger.error(
174
+ "Database recovery error: %s",
175
+ recovery_error,
176
+ )
177
+
178
+ if recovery_succeeded:
179
+ # Reset attempt counter after successful recovery
180
+ attempt = 0
181
+ time.sleep(1) # Brief pause before retry
182
+ continue
183
+
184
+ # If we reach here, recovery failed - log and continue with normal retry
185
+ if logger:
186
+ logger.critical(
187
+ "Automatic database recovery failed. "
188
+ "Manual intervention may be required. Attempting normal retry..."
189
+ )
190
+
131
191
  attempt += 1
132
192
  if attempt >= retries:
133
193
  if logger:
@@ -161,16 +221,18 @@ class ResilientSqliteDatabase:
161
221
  (specifically when setting PRAGMAs), before query-level retry logic can help.
162
222
  """
163
223
 
164
- def __init__(self, database, max_retries=5, backoff=0.5):
224
+ def __init__(self, database, max_retries=5, backoff=0.5, logger=None):
165
225
  """
166
226
  Args:
167
227
  database: Peewee SqliteDatabase instance to wrap
168
228
  max_retries: Maximum connection retry attempts
169
229
  backoff: Initial backoff delay in seconds
230
+ logger: Optional logger instance for logging recovery attempts
170
231
  """
171
232
  self._db = database
172
233
  self._max_retries = max_retries
173
234
  self._backoff = backoff
235
+ self._logger = logger
174
236
 
175
237
  def __getattr__(self, name):
176
238
  """Delegate all attribute access to the wrapped database."""
@@ -194,6 +256,7 @@ class ResilientSqliteDatabase:
194
256
 
195
257
  last_error = None
196
258
  delay = self._backoff
259
+ corruption_recovery_attempted = False
197
260
 
198
261
  for attempt in range(1, self._max_retries + 1):
199
262
  try:
@@ -201,8 +264,77 @@ class ResilientSqliteDatabase:
201
264
  except (OperationalError, DatabaseError, sqlite3.OperationalError) as e:
202
265
  error_msg = str(e).lower()
203
266
 
204
- # Only retry on transient I/O errors
205
- if "disk i/o error" in error_msg or "database is locked" in error_msg:
267
+ # Detect corruption and attempt recovery (only once)
268
+ if not corruption_recovery_attempted and (
269
+ "disk image is malformed" in error_msg
270
+ or "database disk image is malformed" in error_msg
271
+ or "database corruption" in error_msg
272
+ ):
273
+ corruption_recovery_attempted = True
274
+ if self._logger:
275
+ self._logger.error(
276
+ "Database corruption detected during connection: %s. "
277
+ "Attempting automatic recovery...",
278
+ e,
279
+ )
280
+
281
+ recovery_succeeded = False
282
+ try:
283
+ db_path = APPDATA_FOLDER / "qbitrr.db"
284
+
285
+ # Close current connection if any
286
+ try:
287
+ if not self._db.is_closed():
288
+ self._db.close()
289
+ except Exception:
290
+ pass # Ignore errors closing corrupted connection
291
+
292
+ # Step 1: Try WAL checkpoint
293
+ if self._logger:
294
+ self._logger.info("Attempting WAL checkpoint...")
295
+ if checkpoint_wal(db_path, self._logger):
296
+ if self._logger:
297
+ self._logger.info(
298
+ "WAL checkpoint successful - retrying connection"
299
+ )
300
+ recovery_succeeded = True
301
+ else:
302
+ # Step 2: Try full repair
303
+ if self._logger:
304
+ self._logger.warning(
305
+ "WAL checkpoint failed - attempting full database repair..."
306
+ )
307
+ if repair_database(db_path, backup=True, logger_override=self._logger):
308
+ if self._logger:
309
+ self._logger.info(
310
+ "Database repair successful - retrying connection"
311
+ )
312
+ recovery_succeeded = True
313
+
314
+ except Exception as recovery_error:
315
+ if self._logger:
316
+ self._logger.error(
317
+ "Database recovery error: %s",
318
+ recovery_error,
319
+ )
320
+
321
+ if recovery_succeeded:
322
+ time.sleep(1)
323
+ continue
324
+
325
+ # Recovery failed - log and continue with normal retry
326
+ if self._logger:
327
+ self._logger.critical(
328
+ "Automatic database recovery failed. "
329
+ "Manual intervention may be required."
330
+ )
331
+
332
+ # Retry on transient I/O errors
333
+ if (
334
+ "disk i/o error" in error_msg
335
+ or "database is locked" in error_msg
336
+ or "disk image is malformed" in error_msg
337
+ ):
206
338
  last_error = e
207
339
 
208
340
  if attempt < self._max_retries:
@@ -1,2 +1,2 @@
1
- import{u as qe,f as es,h as ss,i as as,k as Ve,l as ts,j as e,I as Je,R as Ge,m as Ue}from"./app.js";import{r as a,u as Le,f as pe,g as Pe,a as ns,b as cs,c as ds}from"./table.js";import{u as Ie}from"./useInterval.js";import"./vendor.js";const Ye=50,Se=50,Be=500;function gs({loading:d,rows:c,total:m,page:f,totalPages:R,onPageChange:M,onRefresh:L,lastUpdated:I,sort:p,onSort:P,summary:i}){const g=a.useMemo(()=>[{accessorKey:"__instance",header:"Instance",size:150},{accessorKey:"title",header:"Title",cell:o=>o.getValue()},{accessorKey:"year",header:"Year",size:80},{accessorKey:"monitored",header:"Monitored",cell:o=>o.getValue()?e.jsx("span",{className:"table-badge",children:"Yes"}):e.jsx("span",{children:"No"}),size:100},{accessorKey:"hasFile",header:"Has File",cell:o=>o.getValue()?e.jsx("span",{className:"table-badge",children:"Yes"}):e.jsx("span",{children:"No"}),size:100},{accessorKey:"reason",header:"Reason",cell:o=>{const v=o.getValue();return v?e.jsx("span",{className:"table-badge table-badge-reason",children:v}):e.jsx("span",{className:"hint",children:"—"})},size:120}],[]),n=Le({data:c,columns:g,getCoreRowModel:Pe()});return e.jsxs("div",{className:"stack animate-fade-in",children:[e.jsxs("div",{className:"row",style:{justifyContent:"space-between"},children:[e.jsxs("div",{className:"hint",children:["Aggregated movies across all instances"," ",I?`(updated ${I})`:"",e.jsx("br",{}),e.jsx("strong",{children:"Available:"})," ",i.available.toLocaleString(void 0,{maximumFractionDigits:0})," •"," ",e.jsx("strong",{children:"Monitored:"})," ",i.monitored.toLocaleString(void 0,{maximumFractionDigits:0})," •"," ",e.jsx("strong",{children:"Missing:"})," ",i.missing.toLocaleString(void 0,{maximumFractionDigits:0})," •"," ",e.jsx("strong",{children:"Total:"})," ",i.total.toLocaleString(void 0,{maximumFractionDigits:0})]}),e.jsxs("button",{className:"btn ghost",onClick:L,disabled:d,children:[e.jsx(Je,{src:Ge}),"Refresh"]})]}),d?e.jsxs("div",{className:"loading",children:[e.jsx("span",{className:"spinner"})," Loading Radarr library…"]}):m?e.jsx("div",{className:"table-wrapper",children:e.jsxs("table",{className:"responsive-table",children:[e.jsx("thead",{children:n.getHeaderGroups().map(o=>e.jsx("tr",{children:o.headers.map(v=>e.jsx("th",{className:v.column.getCanSort()?"sortable":"",onClick:()=>{const h=v.id;P(h)},children:v.isPlaceholder?null:pe(v.column.columnDef.header,v.getContext())},v.id))},o.id))}),e.jsx("tbody",{children:n.getRowModel().rows.map(o=>{const v=o.original,h=`${v.__instance}-${v.title}-${v.year}`;return e.jsx("tr",{children:o.getVisibleCells().map(x=>e.jsx("td",{children:pe(x.column.columnDef.cell,x.getContext())},x.id))},h)})})]})}):e.jsx("div",{className:"hint",children:"No movies found."}),m>0&&e.jsxs("div",{className:"pagination",children:[e.jsxs("div",{children:["Page ",f+1," of ",R," (",m.toLocaleString()," items · page size"," ",Se,")"]}),e.jsxs("div",{className:"inline",children:[e.jsx("button",{className:"btn",onClick:()=>M(Math.max(0,f-1)),disabled:f===0||d,children:"Prev"}),e.jsx("button",{className:"btn",onClick:()=>M(Math.min(R-1,f+1)),disabled:f>=R-1||d,children:"Next"})]})]})]})}function hs({loading:d,data:c,page:m,totalPages:f,pageSize:R,allMovies:M,onlyMissing:L,reasonFilter:I,onPageChange:p,onRestart:P,lastUpdated:i}){const g=a.useMemo(()=>{let h=M;return L&&(h=h.filter(x=>!x.hasFile)),h},[M,L]),n=a.useMemo(()=>I==="all"?g:I==="none"?g.filter(h=>!h.reason):g.filter(h=>h.reason===I),[g,I]),o=a.useMemo(()=>[{accessorKey:"title",header:"Title",cell:h=>h.getValue()},{accessorKey:"year",header:"Year",size:80},{accessorKey:"monitored",header:"Monitored",cell:h=>h.getValue()?e.jsx("span",{className:"table-badge",children:"Yes"}):e.jsx("span",{children:"No"}),size:100},{accessorKey:"hasFile",header:"Has File",cell:h=>h.getValue()?e.jsx("span",{className:"table-badge",children:"Yes"}):e.jsx("span",{children:"No"}),size:100},{accessorKey:"reason",header:"Reason",cell:h=>{const x=h.getValue();return x?e.jsx("span",{className:"table-badge table-badge-reason",children:x}):e.jsx("span",{className:"hint",children:"—"})},size:120}],[]),v=Le({data:n.slice(m*R,m*R+R),columns:o,getCoreRowModel:Pe(),getSortedRowModel:ns()});return e.jsxs("div",{className:"stack animate-fade-in",children:[e.jsxs("div",{className:"row",style:{justifyContent:"space-between"},children:[e.jsxs("div",{className:"hint",children:[c?.counts?`Available: ${c.counts.available??0} • Monitored: ${c.counts.monitored??0}`:"",i?` (updated ${i})`:""]}),e.jsxs("button",{className:"btn ghost",onClick:P,disabled:d,children:[e.jsx(Je,{src:Ge}),"Restart"]})]}),d?e.jsxs("div",{className:"loading",children:[e.jsx("span",{className:"spinner"})," Loading…"]}):M.length?e.jsx("div",{className:"table-wrapper",children:e.jsxs("table",{className:"responsive-table",children:[e.jsx("thead",{children:v.getHeaderGroups().map(h=>e.jsx("tr",{children:h.headers.map(x=>e.jsx("th",{children:x.isPlaceholder?null:pe(x.column.columnDef.header,x.getContext())},x.id))},h.id))}),e.jsx("tbody",{children:v.getRowModel().rows.map(h=>{const x=h.original,G=`${x.title}-${x.year}`;return e.jsx("tr",{children:h.getVisibleCells().map(W=>e.jsx("td",{children:pe(W.column.columnDef.cell,W.getContext())},W.id))},G)})})]})}):e.jsx("div",{className:"hint",children:"No movies found."}),n.length>R&&e.jsxs("div",{className:"pagination",children:[e.jsxs("div",{children:["Page ",m+1," of ",f," (",n.length.toLocaleString()," items · page size"," ",R,")"]}),e.jsxs("div",{className:"inline",children:[e.jsx("button",{className:"btn",onClick:()=>p(Math.max(0,m-1)),disabled:m===0||d,children:"Prev"}),e.jsx("button",{className:"btn",onClick:()=>p(Math.min(f-1,m+1)),disabled:m>=f-1||d,children:"Next"})]})]})]})}function us({active:d}){const{push:c}=qe(),{value:m,setValue:f,register:R,clearHandler:M}=es(),{liveArr:L,setLiveArr:I}=ss(),[p,P]=a.useState([]),[i,g]=a.useState("aggregate"),[n,o]=a.useState(null),[v,h]=a.useState(0),[x,G]=a.useState(""),[W,ie]=a.useState(!1),[re,X]=a.useState(null),[V,se]=a.useState({}),[l,E]=a.useState(Ye),[y,_]=a.useState(1),D=a.useRef(""),K=a.useRef({}),Y=a.useRef(m),H=a.useRef(!1),[le,ue]=a.useState([]),[ye,oe]=a.useState(!1),[ce,me]=a.useState(0),[q,ve]=a.useState(""),[Re,Ne]=a.useState(null),[ee,xe]=a.useState({key:"__instance",direction:"asc"}),[ae,_e]=a.useState(!1),[te,O]=a.useState("all"),[ke,Q]=a.useState({available:0,monitored:0,missing:0,total:0}),Me=a.useCallback(async()=>{try{const t=await as();t.ready===!1&&!H.current?(H.current=!0,c("Radarr backend is still initialising. Check the logs if this persists.","info")):t.ready&&(H.current=!0);const s=(t.arr||[]).filter(r=>r.type==="radarr");if(P(s),!s.length){g("aggregate"),o(null),ue([]),Q({available:0,monitored:0,missing:0,total:0});return}i===""?g("aggregate"):i!=="aggregate"&&!s.some(r=>r.category===i)&&g(s[0].category)}catch(t){c(t instanceof Error?t.message:"Unable to load Radarr instances","error")}},[c,i]),Ae=a.useCallback(async(t,s,r,u,N)=>{if(u.length)try{const $=[];for(const j of u){const b=await Ve(t,j,r,s),S=b.page??j;if($.push({page:S,movies:b.movies??[]}),D.current!==N)return}if(D.current!==N)return;se(j=>{const b={...j};let S=!1;for(const{page:C,movies:F}of $){const w=j[C]??[];JSON.stringify(w)!==JSON.stringify(F)&&(b[C]=F,S=!0)}return K.current=b,S?b:j})}catch($){c($ instanceof Error?$.message:`Failed to load additional pages for ${t}`,"error")}},[c]),J=a.useCallback(async(t,s,r,u={})=>{const N=u.preloadAll!==!1;(u.showLoading??!0)&&ie(!0);try{const j=`${t}::${r}`,b=D.current!==j;b&&(D.current=j,se(()=>(K.current={},{})));const S=await Ve(t,s,Ye,r);o(S);const C=S.page??s;h(C),G(r);const F=S.page_size??Ye,w=S.total??(S.movies??[]).length,T=Math.max(1,Math.ceil((w||0)/F));E(F),_(T);const k=S.movies??[],ge=b?{}:K.current,he=K.current[C]??[],je=JSON.stringify(he)!==JSON.stringify(k);if((b||je)&&(se(z=>{const we={...b?{}:z,[C]:k};return K.current=we,we}),X(new Date().toLocaleTimeString())),N){const z=[];for(let B=0;B<T;B+=1)B!==C&&(ge[B]||z.push(B));Ae(t,r,F,z,j)}}catch(j){c(j instanceof Error?j.message:`Failed to load ${t} movies`,"error")}finally{ie(!1)}},[c,Ae]),de=a.useCallback(async()=>{if(!p.length){ue([]),Q({available:0,monitored:0,missing:0,total:0});return}oe(!0);try{const t=[];let s=0,r=0;for(const N of p){let $=0,j=!1;const b=N.name||N.category;for(;$<100;){const S=await Ve(N.category,$,Be,"");if(!j){const F=S.counts;F&&(s+=F.available??0,r+=F.monitored??0),j=!0}const C=S.movies??[];if(C.forEach(F=>{t.push({...F,__instance:b})}),!C.length||C.length<Be)break;$+=1}}ue(N=>{const $=JSON.stringify(N),j=JSON.stringify(t);return $===j?N:t});const u={available:s,monitored:r,missing:t.length-s,total:t.length};Q(N=>N.available===u.available&&N.monitored===u.monitored&&N.missing===u.missing&&N.total===u.total?N:u),q!==m&&(me(0),ve(m)),Ne(new Date().toLocaleTimeString())}catch(t){ue([]),Q({available:0,monitored:0,missing:0,total:0}),c(t instanceof Error?t.message:"Failed to load aggregated Radarr data","error")}finally{oe(!1)}},[p,m,c]);a.useEffect(()=>{d&&Me()},[d,Me]),a.useEffect(()=>{if(!d||!i||i==="aggregate")return;K.current={},se({}),_(1),h(0);const t=Y.current;J(i,0,t,{preloadAll:!0,showLoading:!0})},[d,i,J]),a.useEffect(()=>{d&&i==="aggregate"&&de()},[d,i,de]),Ie(()=>{i==="aggregate"&&L&&de()},i==="aggregate"&&L?1e4:null),a.useEffect(()=>{if(!d)return;const t=s=>{i==="aggregate"?(ve(s),me(0)):i&&(h(0),J(i,0,s,{preloadAll:!0,showLoading:!0}))};return R(t),()=>{M(t)}},[d,i,R,M,J]),Ie(()=>{if(i&&i!=="aggregate"){if(Y.current?.trim?.()||"")return;J(i,v,x,{preloadAll:!1,showLoading:!1})}},d&&i&&i!=="aggregate"&&L?1e3:null),a.useEffect(()=>{Y.current=m},[m]),a.useEffect(()=>{i==="aggregate"&&ve(m)},[i,m]);const Z=a.useMemo(()=>{let t=le;if(q){const s=q.toLowerCase();t=t.filter(r=>{const u=(r.title??"").toString().toLowerCase(),N=(r.__instance??"").toLowerCase();return u.includes(s)||N.includes(s)})}return ae&&(t=t.filter(s=>!s.hasFile)),te!=="all"&&(te==="none"?t=t.filter(s=>!s.reason):t=t.filter(s=>s.reason===te)),t},[le,q,ae,te]),ne=a.useMemo(()=>{const t=[...Z],s=(r,u)=>{switch(u){case"__instance":return(r.__instance||"").toLowerCase();case"title":return(r.title||"").toLowerCase();case"year":return r.year??0;case"monitored":return r.monitored?1:0;case"hasFile":return r.hasFile?1:0;default:return""}};return t.sort((r,u)=>{const N=s(r,ee.key),$=s(u,ee.key);let j=0;return typeof N=="number"&&typeof $=="number"?j=N-$:typeof N=="string"&&typeof $=="string"?j=N.localeCompare($):j=String(N).localeCompare(String($)),ee.direction==="asc"?j:-j}),t},[Z,ee]),We=Math.max(1,Math.ceil(ne.length/Se)),fe=ne.slice(ce*Se,ce*Se+Se),De=a.useMemo(()=>{const t=Object.keys(V).map(Number).sort((r,u)=>r-u),s=[];return t.forEach(r=>{V[r]&&s.push(...V[r])}),s},[V]),Ke=a.useCallback(async()=>{if(!(!i||i==="aggregate"))try{await ts(i),c(`Restarted ${i}`,"success")}catch(t){c(t instanceof Error?t.message:`Failed to restart ${i}`,"error")}},[i,c]),Te=a.useCallback(t=>{const s=t.target.value||"aggregate";g(s),s!=="aggregate"&&f("")},[g,f]),Ce=i==="aggregate";return e.jsxs("section",{className:"card",children:[e.jsx("div",{className:"card-header",children:"Radarr"}),e.jsx("div",{className:"card-body",children:e.jsxs("div",{className:"split",children:[e.jsxs("aside",{className:"pane sidebar",children:[e.jsx("button",{className:`btn ${Ce?"active":""}`,onClick:()=>g("aggregate"),children:"All Radarr"}),p.map(t=>e.jsx("button",{className:`btn ghost ${i===t.category?"active":""}`,onClick:()=>{g(t.category),f("")},children:t.name||t.category},t.category))]}),e.jsxs("div",{className:"pane",children:[e.jsxs("div",{className:"field mobile-instance-select",children:[e.jsx("label",{children:"Instance"}),e.jsxs("select",{value:i||"aggregate",onChange:Te,disabled:!p.length,children:[e.jsx("option",{value:"aggregate",children:"All Radarr"}),p.map(t=>e.jsx("option",{value:t.category,children:t.name||t.category},t.category))]})]}),e.jsxs("div",{className:"row",style:{alignItems:"flex-end",gap:"12px",flexWrap:"wrap"},children:[e.jsxs("div",{className:"col field",style:{flex:"1 1 200px"},children:[e.jsx("label",{children:"Search"}),e.jsx("input",{placeholder:"Filter movies",value:m,onChange:t=>f(t.target.value)})]}),e.jsxs("div",{className:"field",style:{flex:"0 0 auto",minWidth:"140px"},children:[e.jsx("label",{children:"Status"}),e.jsxs("select",{onChange:t=>{const s=t.target.value;_e(s==="missing")},value:ae?"missing":"all",children:[e.jsx("option",{value:"all",children:"All Movies"}),e.jsx("option",{value:"missing",children:"Missing Only"})]})]}),e.jsxs("div",{className:"field",style:{flex:"0 0 auto",minWidth:"140px"},children:[e.jsx("label",{children:"Search Reason"}),e.jsxs("select",{onChange:t=>O(t.target.value),value:te,children:[e.jsx("option",{value:"all",children:"All Reasons"}),e.jsx("option",{value:"none",children:"Not Being Searched"}),e.jsx("option",{value:"Missing",children:"Missing"}),e.jsx("option",{value:"Quality",children:"Quality"}),e.jsx("option",{value:"CustomFormat",children:"Custom Format"}),e.jsx("option",{value:"Upgrade",children:"Upgrade"}),e.jsx("option",{value:"Scheduled search",children:"Scheduled Search"})]})]})]}),Ce?e.jsx(gs,{loading:ye,rows:fe,total:ne.length,page:ce,totalPages:We,onPageChange:me,onRefresh:()=>void de(),lastUpdated:Re,sort:ee,onSort:t=>xe(s=>s.key===t?{key:t,direction:s.direction==="asc"?"desc":"asc"}:{key:t,direction:"asc"}),summary:ke}):e.jsx(hs,{loading:W,data:n,page:v,totalPages:y,pageSize:l,allMovies:De,onlyMissing:ae,reasonFilter:te,onPageChange:t=>{h(t),J(i,t,x,{preloadAll:!0})},onRestart:()=>void Ke(),lastUpdated:re})]})]})})]})}const He=25,Fe=50,Xe=200;function ms(d,c){if(!c)return d;const m=[];for(const f of d){const R=f.seasons??{},M={};for(const[L,I]of Object.entries(R)){const p=(I.episodes??[]).filter(P=>!P.hasFile);p.length&&(M[L]={...I,episodes:p})}Object.keys(M).length!==0&&m.push({...f,seasons:M})}return m}function Ee(d,c){return JSON.stringify(ms(d,c))}function xs({active:d}){const{push:c}=qe(),{value:m,setValue:f,register:R,clearHandler:M}=es(),{liveArr:L,setLiveArr:I,groupSonarr:p,setGroupSonarr:P}=ss(),[i,g]=a.useState([]),[n,o]=a.useState("aggregate"),[v,h]=a.useState(null),[x,G]=a.useState(0),[W,ie]=a.useState(""),[re,X]=a.useState(!1),[V,se]=a.useState(null),[l,E]=a.useState({}),y=a.useRef({}),_=a.useRef(null),D=a.useRef(""),[K,Y]=a.useState(He),[H,le]=a.useState(1),[ue,ye]=a.useState(0),oe=a.useRef(m),ce=a.useRef(!1),[me,q]=a.useState([]),[ve,Re]=a.useState(!1),[Ne,ee]=a.useState(0),[xe,ae]=a.useState(""),[_e,te]=a.useState(null),[O,ke]=a.useState(!1),[Q,Me]=a.useState("all"),[Ae,J]=a.useState({available:0,monitored:0,missing:0,total:0}),de=a.useCallback(async()=>{try{const s=await as();s.ready===!1&&!ce.current?(ce.current=!0,c("Sonarr backend is still initialising. Check the logs if this persists.","info")):s.ready&&(ce.current=!0);const r=(s.arr||[]).filter(u=>u.type==="sonarr");if(g(r),!r.length){o("aggregate"),h(null),q([]),J({available:0,monitored:0,missing:0,total:0});return}n===""?o("aggregate"):n!=="aggregate"&&!r.some(u=>u.category===n)&&o(r[0].category)}catch(s){c(s instanceof Error?s.message:"Unable to load Sonarr instances","error")}},[c,n]),Z=a.useCallback(async(s,r,u,N={})=>{const{preloadAll:$=!0,showLoading:j=!0,missingOnly:b}=N,S=b??O;j&&X(!0);try{const C=`${s}::${u}::${S?"missing":"all"}`,F=D.current!==C;F&&(D.current=C,E(()=>(y.current={},{})),ye(0),le(1));const w=await Ue(s,r,He,u,{missingOnly:S}),T=w.page??r,k=w.page_size??He,ge=w.total??(w.series??[]).length,he=Math.max(1,Math.ceil((ge||0)/k)),je=w.series??[],z=F?{}:y.current,B={...z,[T]:je},we=Ee(z[T]??[],S),is=Ee(je,S),Oe=F||we!==is;if(y.current=B,Oe&&E(B),h(A=>{const U=A?.counts??null,be=w.counts??null;return!A||A.total!==w.total||A.page!==w.page||A.page_size!==w.page_size||(U?.available??null)!==(be?.available??null)||(U?.monitored??null)!==(be?.monitored??null)||(U?.missing??null)!==(be?.missing??null)||Oe?(_.current=w,w):A}),G(A=>A===T?A:T),ie(A=>A===u?A:u),Y(A=>A===k?A:k),le(A=>A===he?A:he),ye(A=>A===ge?A:ge),Oe&&se(new Date().toLocaleTimeString()),$){const A=[];for(let U=0;U<he;U+=1)U!==T&&(B[U]||A.push(U));for(const U of A)try{const be=await Ue(s,U,k,u,{missingOnly:S});if(D.current!==C)break;const $e=be.page??U,ze=be.series??[],Qe=y.current,rs=Ee(Qe[$e]??[],S),ls=Ee(ze,S);if(rs===ls){y.current={...Qe,[$e]:ze};continue}E(os=>{const Ze={...os,[$e]:ze};return y.current=Ze,Ze})}catch{break}}}catch(C){c(C instanceof Error?C.message:`Failed to load ${s} series`,"error")}finally{j&&X(!1)}},[c,O]),ne=a.useCallback(async()=>{if(!i.length){q([]),J({available:0,monitored:0,missing:0,total:0});return}console.log(`[Sonarr Aggregate] Starting aggregation for ${i.length} instances`),Re(!0);try{const s=[];let r=0,u=0,N=0;for(const b of i){let S=0,C=!1;const F=b.name||b.category;for(console.log(`[Sonarr Aggregate] Processing instance: ${F}`);S<200;){const w=await Ue(b.category,S,Xe,"",{missingOnly:O});if(console.log(`[Sonarr Aggregate] Response for ${F} page ${S}:`,{total:w.total,page:w.page,page_size:w.page_size,series_count:w.series?.length??0,counts:w.counts}),!C){const k=w.counts;k&&(r+=k.available??0,u+=k.monitored??0,N+=k.missing??0),C=!0}const T=w.series??[];if(console.log(`[Sonarr Aggregate] Instance: ${F}, Page: ${S}, Series count: ${T.length}, Total episodes so far: ${s.length}`),T.forEach(k=>{const ge=k.series?.title||"";Object.entries(k.seasons??{}).forEach(([he,je])=>{(je.episodes??[]).forEach(z=>{s.push({__instance:F,series:ge,season:he,episode:z.episodeNumber??"",title:z.title??"",monitored:!!z.monitored,hasFile:!!z.hasFile,airDate:z.airDateUtc??""})})})}),!T.length||T.length<Xe){console.log(`[Sonarr Aggregate] Breaking pagination for ${F} - series.length=${T.length}`);break}S+=1}}const $=new Set(s.map(b=>`${b.__instance}::${b.series}`)).size;console.log("[Sonarr Aggregate] Aggregation complete:",{totalEpisodes:s.length,uniqueSeries:$,instances:i.length}),q(b=>{const S=JSON.stringify(b),C=JSON.stringify(s);return S===C?(console.log("[Sonarr Aggregate] Data unchanged, skipping update"),b):(console.log(`[Sonarr Aggregate] Data changed, updating from ${b.length} to ${s.length} episodes`),s)});const j={available:r,monitored:u,missing:N,total:s.length};J(b=>b.available===j.available&&b.monitored===j.monitored&&b.missing===j.missing&&b.total===j.total?b:j),xe!==m&&(ee(0),ae(m)),te(new Date().toLocaleTimeString())}catch(s){q([]),J({available:0,monitored:0,missing:0,total:0}),c(s instanceof Error?s.message:"Failed to load aggregated Sonarr data","error")}finally{Re(!1)}},[i,m,c,O]);a.useEffect(()=>{d&&de()},[d,de]),a.useEffect(()=>{if(!d||!n||n==="aggregate")return;G(0);const s=oe.current;Z(n,0,s,{preloadAll:!0,showLoading:!0,missingOnly:O})},[d,n,Z]),a.useEffect(()=>{d&&n==="aggregate"&&ne()},[d,n,ne]),Ie(()=>{n==="aggregate"&&L&&ne()},n==="aggregate"&&L?1e4:null),a.useEffect(()=>{if(!d)return;const s=r=>{n==="aggregate"?(ae(r),ee(0)):n&&(G(0),Z(n,0,r,{preloadAll:!0,showLoading:!0,missingOnly:O}))};return R(s),()=>M(s)},[d,n,R,M,Z,O]),Ie(()=>{if(n&&n!=="aggregate"){if(oe.current?.trim?.()||"")return;Z(n,x,W,{preloadAll:!1,showLoading:!1,missingOnly:O})}},d&&n&&n!=="aggregate"&&L?1e3:null),a.useEffect(()=>{oe.current=m},[m]),a.useEffect(()=>{n==="aggregate"&&ae(m)},[n,m]);const fe=a.useMemo(()=>{let s=me;if(xe){const r=xe.toLowerCase();s=s.filter(u=>u.series.toLowerCase().includes(r)||u.title.toLowerCase().includes(r)||u.__instance.toLowerCase().includes(r))}return Q!=="all"&&(Q==="none"?s=s.filter(r=>!r.reason):s=s.filter(r=>r.reason===Q)),s},[me,xe,Q]),De=Math.max(1,Math.ceil(fe.length/Fe));fe.slice(Ne*Fe,Ne*Fe+Fe);const Ke=l[x]??[],Te=a.useCallback(async()=>{if(!(!n||n==="aggregate"))try{await ts(n),c(`Restarted ${n}`,"success")}catch(s){c(s instanceof Error?s.message:`Failed to restart ${n}`,"error")}},[n,c]),Ce=a.useCallback(s=>{const r=s.target.value||"aggregate";o(r),r!=="aggregate"&&f("")},[o,f]),t=n==="aggregate";return e.jsxs("section",{className:"card",children:[e.jsx("div",{className:"card-header",children:"Sonarr"}),e.jsx("div",{className:"card-body",children:e.jsxs("div",{className:"split",children:[e.jsxs("aside",{className:"pane sidebar",children:[e.jsx("button",{className:`btn ${t?"active":""}`,onClick:()=>o("aggregate"),children:"All Sonarr"}),i.map(s=>e.jsx("button",{className:`btn ghost ${n===s.category?"active":""}`,onClick:()=>{o(s.category),f("")},children:s.name||s.category},s.category))]}),e.jsxs("div",{className:"pane",children:[e.jsxs("div",{className:"field mobile-instance-select",children:[e.jsx("label",{children:"Instance"}),e.jsxs("select",{value:n||"aggregate",onChange:Ce,disabled:!i.length,children:[e.jsx("option",{value:"aggregate",children:"All Sonarr"}),i.map(s=>e.jsx("option",{value:s.category,children:s.name||s.category},s.category))]})]}),e.jsxs("div",{className:"row",style:{alignItems:"flex-end",gap:"12px",flexWrap:"wrap"},children:[e.jsxs("div",{className:"col field",style:{flex:"1 1 200px"},children:[e.jsx("label",{children:"Search"}),e.jsx("input",{placeholder:"Filter series or episodes",value:m,onChange:s=>f(s.target.value)})]}),e.jsxs("div",{className:"field",style:{flex:"0 0 auto",minWidth:"140px"},children:[e.jsx("label",{children:"Status"}),e.jsxs("select",{onChange:s=>{const u=s.target.value==="missing";ke(u),n&&n!=="aggregate"&&Z(n,0,oe.current||"",{preloadAll:!0,showLoading:!0,missingOnly:u})},value:O?"missing":"all",children:[e.jsx("option",{value:"all",children:"All Episodes"}),e.jsx("option",{value:"missing",children:"Missing Only"})]})]}),e.jsxs("div",{className:"field",style:{flex:"0 0 auto",minWidth:"140px"},children:[e.jsx("label",{children:"Search Reason"}),e.jsxs("select",{onChange:s=>Me(s.target.value),value:Q,children:[e.jsx("option",{value:"all",children:"All Reasons"}),e.jsx("option",{value:"none",children:"Not Being Searched"}),e.jsx("option",{value:"Missing",children:"Missing"}),e.jsx("option",{value:"Quality",children:"Quality"}),e.jsx("option",{value:"CustomFormat",children:"Custom Format"}),e.jsx("option",{value:"Upgrade",children:"Upgrade"}),e.jsx("option",{value:"Scheduled search",children:"Scheduled Search"})]})]})]}),t?e.jsx(fs,{loading:ve,rows:fe,total:fe.length,page:Ne,totalPages:De,onPageChange:ee,onRefresh:()=>void ne(),lastUpdated:_e,groupSonarr:p,summary:Ae}):e.jsx(js,{loading:re,counts:v?.counts??null,series:Ke,page:x,pageSize:K,totalPages:H,totalItems:ue,onlyMissing:O,onPageChange:s=>{G(s),Z(n,s,W,{preloadAll:!1,showLoading:!0,missingOnly:O})},onRestart:()=>void Te(),lastUpdated:V,groupSonarr:p})]})]})})]})}function fs({loading:d,rows:c,total:m,page:f,totalPages:R,onPageChange:M,onRefresh:L,lastUpdated:I,groupSonarr:p,summary:P}){const i=a.useMemo(()=>{const l=new Map;c.forEach(y=>{const _=y.__instance,D=y.series,K=String(y.season);l.has(_)||l.set(_,new Map);const Y=l.get(_);Y.has(D)||Y.set(D,new Map);const H=Y.get(D);H.has(K)||H.set(K,[]),H.get(K).push(y)});const E=[];return l.forEach((y,_)=>{y.forEach((D,K)=>{E.push({instance:_,series:K,subRows:Array.from(D.entries()).map(([Y,H])=>({seasonNumber:Y,isSeason:!0,subRows:H.map(le=>({...le,isEpisode:!0}))}))})})}),E},[c]),g=a.useMemo(()=>i.slice(f*50,(f+1)*50),[i,f]),n=a.useMemo(()=>c.slice(f*50,(f+1)*50),[c,f]),o=p?g:n,v=a.useMemo(()=>[{accessorKey:"title",header:"Title",cell:({row:l})=>l.original.isEpisode?l.original.title:l.original.isSeason?`Season ${l.original.seasonNumber}`:l.original.series},{accessorKey:"monitored",header:"Monitored",cell:({row:l})=>{const E=(l.original.isEpisode,l.original.monitored);return e.jsx("span",{className:"table-badge",children:E?"Yes":"No"})}},{accessorKey:"hasFile",header:"Has File",cell:({row:l})=>l.original.isEpisode?e.jsx("span",{className:"table-badge",children:l.original.hasFile?"Yes":"No"}):null},{accessorKey:"airDate",header:"Air Date",cell:({row:l})=>l.original.isEpisode?l.original.airDate||"—":null}],[]),h=a.useMemo(()=>[{accessorKey:"__instance",header:"Instance"},{accessorKey:"series",header:"Series"},{accessorKey:"season",header:"Season"},{accessorKey:"episode",header:"Episode"},{accessorKey:"title",header:"Title"},{accessorKey:"monitored",header:"Monitored",cell:({getValue:l})=>e.jsx("span",{className:"table-badge",children:l()?"Yes":"No"})},{accessorKey:"hasFile",header:"Has File",cell:({getValue:l})=>e.jsx("span",{className:"table-badge",children:l()?"Yes":"No"})},{accessorKey:"airDate",header:"Air Date",cell:({getValue:l})=>l()||"—"}],[]),x=p?v:h,G=Le({data:o,columns:x,getCoreRowModel:Pe(),getExpandedRowModel:cs()}),W=Le({data:o,columns:x,getCoreRowModel:Pe(),getSortedRowModel:ns(),getPaginationRowModel:ds(),state:{pagination:{pageIndex:f,pageSize:50}},manualPagination:!0,pageCount:R}),ie=p?G:W,re=50,X=Math.ceil(p?i.length/re:c.length/re),V=Math.min(f,Math.max(0,X-1)),se=p?`${i.length} series`:c.length.toLocaleString();return e.jsxs("div",{className:"stack animate-fade-in",children:[e.jsxs("div",{className:"row",style:{justifyContent:"space-between"},children:[e.jsxs("div",{className:"hint",children:["Aggregated episodes across all instances"," ",I?`(updated ${I})`:"",e.jsx("br",{}),e.jsx("strong",{children:"Available:"})," ",P.available.toLocaleString(void 0,{maximumFractionDigits:0})," •"," ",e.jsx("strong",{children:"Monitored:"})," ",P.monitored.toLocaleString(void 0,{maximumFractionDigits:0})," •"," ",e.jsx("strong",{children:"Missing:"})," ",P.missing.toLocaleString(void 0,{maximumFractionDigits:0})," •"," ",e.jsx("strong",{children:"Total Episodes:"})," ",P.total.toLocaleString(void 0,{maximumFractionDigits:0})]}),e.jsxs("button",{className:"btn ghost",onClick:L,disabled:d,children:[e.jsx(Je,{src:Ge}),"Refresh"]})]}),d?e.jsxs("div",{className:"loading",children:[e.jsx("span",{className:"spinner"})," Loading Sonarr library…"]}):p?e.jsx("div",{className:"sonarr-hierarchical-view",children:g.map(l=>e.jsxs("details",{className:"series-details",children:[e.jsxs("summary",{className:"series-summary",children:[e.jsx("span",{className:"series-title",children:l.series}),e.jsxs("span",{className:"series-instance",children:["(",l.instance,")"]})]}),e.jsx("div",{className:"series-content",children:l.subRows.map(E=>e.jsxs("details",{className:"season-details",children:[e.jsxs("summary",{className:"season-summary",children:[e.jsxs("span",{className:"season-title",children:["Season ",E.seasonNumber]}),e.jsxs("span",{className:"season-count",children:["(",E.subRows.length," episodes)"]})]}),e.jsx("div",{className:"season-content",children:e.jsx("div",{className:"episodes-table-wrapper",children:e.jsxs("table",{className:"episodes-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Episode"}),e.jsx("th",{children:"Title"}),e.jsx("th",{children:"Monitored"}),e.jsx("th",{children:"Has File"}),e.jsx("th",{children:"Air Date"}),e.jsx("th",{children:"Reason"})]})}),e.jsx("tbody",{children:E.subRows.map(y=>e.jsxs("tr",{children:[e.jsx("td",{children:y.episode}),e.jsx("td",{children:y.title}),e.jsx("td",{children:e.jsx("span",{className:"table-badge",children:y.monitored?"Yes":"No"})}),e.jsx("td",{children:e.jsx("span",{className:"table-badge",children:y.hasFile?"Yes":"No"})}),e.jsx("td",{children:y.airDate||"—"}),e.jsx("td",{children:y.reason?e.jsx("span",{className:"table-badge table-badge-reason",children:y.reason}):e.jsx("span",{className:"hint",children:"—"})})]},`${y.__instance}-${y.series}-${y.season}-${y.episode}`))})]})})})]},`${l.instance}-${l.series}-${E.seasonNumber}`))})]},`${l.instance}-${l.series}`))}):o.length?e.jsx("div",{className:"table-wrapper",children:e.jsxs("table",{className:"responsive-table",children:[e.jsx("thead",{children:e.jsx("tr",{children:ie.getFlatHeaders().map(l=>e.jsxs("th",{className:l.column.getCanSort()?"sortable":"",onClick:l.column.getToggleSortingHandler(),children:[l.isPlaceholder?null:pe(l.column.columnDef.header,l.getContext()),l.column.getCanSort()&&e.jsx("span",{className:"sort-arrow",children:{asc:"▲",desc:"▼"}[l.column.getIsSorted()]??null})]},l.id))})}),e.jsx("tbody",{children:ie.getRowModel().rows.map(l=>{const E=l.original,y=`${E.__instance}-${E.series}-${E.season}-${E.episode}`;return e.jsx("tr",{children:l.getVisibleCells().map(_=>e.jsx("td",{"data-label":_.column.columnDef.header,children:pe(_.column.columnDef.cell,_.getContext())},_.id))},y)})})]})}):e.jsx("div",{className:"hint",children:"No series found."}),o.length>0&&e.jsxs("div",{className:"pagination",children:[e.jsxs("div",{children:["Page ",V+1," of ",X," (",se," items · page size ",re,")"]}),e.jsxs("div",{className:"inline",children:[e.jsx("button",{className:"btn",onClick:()=>M(Math.max(0,V-1)),disabled:V===0||d,children:"Prev"}),e.jsx("button",{className:"btn",onClick:()=>M(Math.min(X-1,V+1)),disabled:V>=X-1||d,children:"Next"})]})]})]})}function js({loading:d,counts:c,series:m,page:f,pageSize:R,totalPages:M,onPageChange:L,groupSonarr:I}){const p=Math.min(f,Math.max(0,M-1)),P=a.useMemo(()=>{const g=[];for(const n of m){const o=n.series?.title||"";Object.entries(n.seasons??{}).forEach(([v,h])=>{(h.episodes??[]).forEach(x=>{g.push({__instance:"Instance",series:o,season:v,episode:x.episodeNumber??"",title:x.title??"",monitored:!!x.monitored,hasFile:!!x.hasFile,airDate:x.airDateUtc??""})})})}return g},[m]),i=a.useMemo(()=>{const g=new Map;return P.forEach(n=>{const o=n.series;g.has(o)||g.set(o,new Map);const v=g.get(o),h=String(n.season);v.has(h)||v.set(h,[]),v.get(h).push(n)}),Array.from(g.entries()).map(([n,o])=>({series:n,subRows:Array.from(o.entries()).map(([v,h])=>({seasonNumber:v,isSeason:!0,subRows:h.map(x=>({...x,isEpisode:!0}))}))}))},[P]);return e.jsxs("div",{className:"stack animate-fade-in",children:[e.jsx("div",{className:"row",style:{justifyContent:"space-between"},children:e.jsx("div",{className:"hint",children:c?e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"Available:"})," ",c.available.toLocaleString()," •"," ",e.jsx("strong",{children:"Monitored:"})," ",c.monitored.toLocaleString()," •"," ",e.jsx("strong",{children:"Missing:"})," ",c.missing?.toLocaleString()??0]}):"Loading series information..."})}),d?e.jsxs("div",{className:"loading",children:[e.jsx("span",{className:"spinner"})," Loading series…"]}):I?e.jsx("div",{className:"sonarr-hierarchical-view",children:i.map(g=>e.jsxs("details",{className:"series-details",children:[e.jsx("summary",{className:"series-summary",children:e.jsx("span",{className:"series-title",children:g.series})}),e.jsx("div",{className:"series-content",children:g.subRows.map(n=>e.jsxs("details",{className:"season-details",children:[e.jsxs("summary",{className:"season-summary",children:[e.jsxs("span",{className:"season-title",children:["Season ",n.seasonNumber]}),e.jsxs("span",{className:"season-count",children:["(",n.subRows.length," episodes)"]})]}),e.jsx("div",{className:"season-content",children:e.jsx("div",{className:"episodes-table-wrapper",children:e.jsxs("table",{className:"episodes-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Episode"}),e.jsx("th",{children:"Title"}),e.jsx("th",{children:"Monitored"}),e.jsx("th",{children:"Has File"}),e.jsx("th",{children:"Air Date"}),e.jsx("th",{children:"Reason"})]})}),e.jsx("tbody",{children:n.subRows.map(o=>e.jsxs("tr",{children:[e.jsx("td",{children:o.episode}),e.jsx("td",{children:o.title}),e.jsx("td",{children:e.jsx("span",{className:"table-badge",children:o.monitored?"Yes":"No"})}),e.jsx("td",{children:e.jsx("span",{className:"table-badge",children:o.hasFile?"Yes":"No"})}),e.jsx("td",{children:o.airDate||"—"}),e.jsx("td",{children:o.reason?e.jsx("span",{className:"table-badge table-badge-reason",children:o.reason}):e.jsx("span",{className:"hint",children:"—"})})]},`${o.series}-${o.season}-${o.episode}`))})]})})})]},`${g.series}-${n.seasonNumber}`))})]},`${g.series}`))}):P.length?e.jsxs("div",{className:"table-wrapper",children:[e.jsxs("table",{className:"responsive-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Series"}),e.jsx("th",{children:"Season"}),e.jsx("th",{children:"Episode"}),e.jsx("th",{children:"Title"}),e.jsx("th",{children:"Monitored"}),e.jsx("th",{children:"Has File"}),e.jsx("th",{children:"Air Date"}),e.jsx("th",{children:"Reason"})]})}),e.jsx("tbody",{children:P.slice(p*R,p*R+R).map((g,n)=>e.jsxs("tr",{children:[e.jsx("td",{children:g.series}),e.jsx("td",{children:g.season}),e.jsx("td",{children:g.episode}),e.jsx("td",{children:g.title}),e.jsx("td",{children:e.jsx("span",{className:"table-badge",children:g.monitored?"Yes":"No"})}),e.jsx("td",{children:e.jsx("span",{className:"table-badge",children:g.hasFile?"Yes":"No"})}),e.jsx("td",{children:g.airDate||"—"}),e.jsx("td",{children:g.reason?e.jsx("span",{className:"table-badge table-badge-reason",children:g.reason}):e.jsx("span",{className:"hint",children:"—"})})]},`${g.series}-${g.season}-${g.episode}-${n}`))})]}),e.jsxs("div",{className:"pagination",children:[e.jsxs("div",{children:["Page ",p+1," of ",M," (",P.length.toLocaleString()," items · page size ",R,")"]}),e.jsxs("div",{className:"inline",children:[e.jsx("button",{className:"btn",onClick:()=>L(Math.max(0,p-1)),disabled:p===0||d,children:"Prev"}),e.jsx("button",{className:"btn",onClick:()=>L(Math.min(M-1,p+1)),disabled:p>=M-1||d,children:"Next"})]})]})]}):e.jsx("div",{className:"hint",children:"No series found."})]})}function Ss({type:d,active:c}){return d==="radarr"?e.jsx(us,{active:c}):e.jsx(xs,{active:c})}export{Ss as ArrView};
1
+ import{j as e,u as is,h as rs,i as os,k as cs,l as Je,m as ds,I as qe,R as Ue,n as Xe,o as es}from"./app.js";import{r as a,u as ze,g as Te,f as Pe,a as gs,b as vs,c as ys}from"./table.js";import{u as Ke}from"./useInterval.js";import"./vendor.js";function Ss({data:r,columns:t,getRowKey:u}){const h=ze({data:r,columns:t,getCoreRowModel:Te()});return e.jsx("div",{className:"table-wrapper",children:e.jsxs("table",{className:"responsive-table",children:[e.jsx("thead",{children:h.getHeaderGroups().map(y=>e.jsx("tr",{children:y.headers.map(v=>e.jsx("th",{children:v.isPlaceholder?null:Pe(v.column.columnDef.header,v.getContext())},v.id))},y.id))}),e.jsx("tbody",{children:h.getRowModel().rows.map(y=>{const v=u?u(y.original):y.id;return e.jsx("tr",{children:y.getVisibleCells().map(F=>e.jsx("td",{"data-label":String(F.column.columnDef.header),children:Pe(F.column.columnDef.cell,F.getContext())},F.id))},v)})})]})})}const Rs=a.memo(Ss,(r,t)=>r.data===t.data&&r.columns===t.columns);function Cs(r){let t=2166136261;for(let u=0;u<r.length;u++)t^=r.charCodeAt(u),t+=(t<<1)+(t<<4)+(t<<7)+(t<<8)+(t<<24);return(t>>>0).toString(36)}function ls(r,t){const u=t.map(h=>{const y=r[h];return y==null?"":typeof y=="boolean"?y?"1":"0":typeof y=="object"?JSON.stringify(y):String(y)});return Cs(u.join("|"))}function ws(r,t,u,h){const y=[],v=[],F=[],N=new Set;for(const n of t){const M=u(n),b=ls(n,h);N.add(M);const B=r.byId.get(M),K=r.byHash.get(M);B?K!==b&&v.push(n):y.push(n)}for(const n of r.allIds)N.has(n)||F.push(n);const m=t.length-y.length-v.length,T=y.length>0||v.length>0||F.length>0;return{added:y,updated:v,removed:F,unchanged:m,hasChanges:T}}function Fs(r,t,u,h){if(!t.hasChanges)return r;const y=new Map(r.byId),v=new Map(r.byHash),F=[...r.allIds];for(const N of t.added){const m=u(N),T=ls(N,h);y.set(m,N),v.set(m,T),F.push(m)}for(const N of t.updated){const m=u(N),T=ls(N,h);y.set(m,N),v.set(m,T)}for(const N of t.removed){y.delete(N),v.delete(N);const m=F.indexOf(N);m!==-1&&F.splice(m,1)}return{byId:y,byHash:v,allIds:F,lastUpdate:Date.now()}}function ss(r){return r.allIds.map(t=>r.byId.get(t)).filter(Boolean)}function ms(){return{byId:new Map,byHash:new Map,allIds:[],lastUpdate:0}}function _e(r){const{getKey:t,hashFields:u}=r,h=a.useRef(ms()),[y,v]=a.useState(0),F=a.useCallback(T=>{const n=ws(h.current,T,t,u);if(!n.hasChanges)return{data:ss(h.current),hasChanges:!1,changes:null,lastUpdate:h.current.lastUpdate};const M=Fs(h.current,n,t,u);return h.current=M,v(M.lastUpdate),{data:ss(M),hasChanges:!0,changes:n,lastUpdate:M.lastUpdate}},[t,u]),N=a.useCallback(()=>ss(h.current),[]),m=a.useCallback(()=>{h.current=ms(),v(0)},[]);return{syncData:F,getData:N,reset:m,lastUpdate:y}}const as=50,Be=50,fs=500,Ms=a.memo(function({loading:t,rows:u,total:h,page:y,totalPages:v,onPageChange:F,onRefresh:N,lastUpdated:m,sort:T,onSort:n,summary:M,instanceCount:b,isAggFiltered:B=!1}){const K=a.useMemo(()=>[...b>1?[{accessorKey:"__instance",header:"Instance",size:150}]:[],{accessorKey:"title",header:"Title",cell:A=>A.getValue()},{accessorKey:"year",header:"Year",size:80},{accessorKey:"monitored",header:"Monitored",cell:A=>{const L=A.getValue();return e.jsx("span",{className:`track-status ${L?"available":"missing"}`,children:L?"✓":"✗"})},size:100},{accessorKey:"hasFile",header:"Has File",cell:A=>{const L=A.getValue();return e.jsx("span",{className:`track-status ${L?"available":"missing"}`,children:L?"✓":"✗"})},size:100},{accessorKey:"qualityProfileName",header:"Quality Profile",cell:A=>A.getValue()||"—",size:150},{accessorKey:"reason",header:"Reason",cell:A=>{const L=A.getValue();return L?e.jsx("span",{className:"table-badge table-badge-reason",children:L}):e.jsx("span",{className:"table-badge table-badge-reason",children:"Not being searched"})},size:120}],[b]);return e.jsxs("div",{className:"stack animate-fade-in",children:[e.jsxs("div",{className:"row",style:{justifyContent:"space-between"},children:[e.jsxs("div",{className:"hint",children:["Aggregated movies across all instances"," ",m?`(updated ${m})`:"",e.jsx("br",{}),e.jsx("strong",{children:"Available:"})," ",M.available.toLocaleString(void 0,{maximumFractionDigits:0})," •"," ",e.jsx("strong",{children:"Monitored:"})," ",M.monitored.toLocaleString(void 0,{maximumFractionDigits:0})," •"," ",e.jsx("strong",{children:"Missing:"})," ",M.missing.toLocaleString(void 0,{maximumFractionDigits:0})," •"," ",e.jsx("strong",{children:"Total:"})," ",M.total.toLocaleString(void 0,{maximumFractionDigits:0}),B&&h<M.total&&e.jsxs(e.Fragment,{children:[" ","• ",e.jsx("strong",{children:"Filtered:"})," ",h.toLocaleString(void 0,{maximumFractionDigits:0})," of"," ",M.total.toLocaleString(void 0,{maximumFractionDigits:0})]})]}),e.jsxs("button",{className:"btn ghost",onClick:N,disabled:t,children:[e.jsx(qe,{src:Ue}),"Refresh"]})]}),t?e.jsxs("div",{className:"loading",children:[e.jsx("span",{className:"spinner"})," Loading Radarr library…"]}):h?e.jsx(Rs,{data:u,columns:K,getRowKey:A=>`${A.__instance}-${A.title}-${A.year}`}):e.jsx("div",{className:"hint",children:"No movies found."}),h>0&&e.jsxs("div",{className:"pagination",children:[e.jsxs("div",{children:["Page ",y+1," of ",v," (",h.toLocaleString()," items · page size"," ",Be,")"]}),e.jsxs("div",{className:"inline",children:[e.jsx("button",{className:"btn",onClick:()=>F(Math.max(0,y-1)),disabled:y===0||t,children:"Prev"}),e.jsx("button",{className:"btn",onClick:()=>F(Math.min(v-1,y+1)),disabled:y>=v-1||t,children:"Next"})]})]})]})}),Ps=a.memo(function({loading:t,data:u,page:h,totalPages:y,pageSize:v,allMovies:F,onlyMissing:N,reasonFilter:m,onPageChange:T,onRefresh:n,onRestart:M,lastUpdated:b}){const B=a.useMemo(()=>{let g=F;return N&&(g=g.filter(j=>!j.hasFile)),g},[F,N]),K=a.useMemo(()=>m==="all"?B:m==="Not being searched"?B.filter(g=>g.reason==="Not being searched"||!g.reason):B.filter(g=>g.reason===m),[B,m]),A=a.useMemo(()=>F.length,[F]),L=m!=="all"||N,ge=K.length,J=a.useMemo(()=>[{accessorKey:"title",header:"Title",cell:g=>g.getValue()},{accessorKey:"year",header:"Year",size:80},{accessorKey:"monitored",header:"Monitored",cell:g=>{const j=g.getValue();return e.jsx("span",{className:`track-status ${j?"available":"missing"}`,children:j?"✓":"✗"})},size:100},{accessorKey:"hasFile",header:"Has File",cell:g=>{const j=g.getValue();return e.jsx("span",{className:`track-status ${j?"available":"missing"}`,children:j?"✓":"✗"})},size:100},{accessorKey:"qualityProfileName",header:"Quality Profile",cell:g=>g.getValue()||"—",size:150},{accessorKey:"reason",header:"Reason",cell:g=>{const j=g.getValue();return j?e.jsx("span",{className:"table-badge table-badge-reason",children:j}):e.jsx("span",{className:"table-badge table-badge-reason",children:"Not being searched"})},size:120}],[]),C=ze({data:K.slice(h*v,h*v+v),columns:J,getCoreRowModel:Te(),getSortedRowModel:gs()});return e.jsxs("div",{className:"stack animate-fade-in",children:[e.jsxs("div",{className:"row",style:{justifyContent:"space-between"},children:[e.jsxs("div",{className:"hint",children:[u?.counts?e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"Available:"})," ",(u.counts.available??0).toLocaleString(void 0,{maximumFractionDigits:0})," •"," ",e.jsx("strong",{children:"Monitored:"})," ",(u.counts.monitored??0).toLocaleString(void 0,{maximumFractionDigits:0})," •"," ",e.jsx("strong",{children:"Missing:"})," ",((u.counts.monitored??0)-(u.counts.available??0)).toLocaleString(void 0,{maximumFractionDigits:0})," •"," ",e.jsx("strong",{children:"Total:"})," ",A.toLocaleString(void 0,{maximumFractionDigits:0}),L&&ge<A&&e.jsxs(e.Fragment,{children:[" ","• ",e.jsx("strong",{children:"Filtered:"})," ",ge.toLocaleString(void 0,{maximumFractionDigits:0})," of"," ",A.toLocaleString(void 0,{maximumFractionDigits:0})]})]}):"Loading movie information...",b?` (updated ${b})`:""]}),e.jsxs("button",{className:"btn ghost",onClick:M,disabled:t,children:[e.jsx(qe,{src:Ue}),"Restart"]})]}),t?e.jsxs("div",{className:"loading",children:[e.jsx("span",{className:"spinner"})," Loading…"]}):F.length?e.jsx("div",{className:"table-wrapper",children:e.jsxs("table",{className:"responsive-table",children:[e.jsx("thead",{children:C.getHeaderGroups().map(g=>e.jsx("tr",{children:g.headers.map(j=>e.jsx("th",{children:j.isPlaceholder?null:Pe(j.column.columnDef.header,j.getContext())},j.id))},g.id))}),e.jsx("tbody",{children:C.getRowModel().rows.map(g=>{const j=g.original,q=`${j.title}-${j.year}`;return e.jsx("tr",{children:g.getVisibleCells().map(G=>e.jsx("td",{"data-label":String(G.column.columnDef.header),children:Pe(G.column.columnDef.cell,G.getContext())},G.id))},q)})})]})}):e.jsx("div",{className:"hint",children:"No movies found."}),K.length>v&&e.jsxs("div",{className:"pagination",children:[e.jsxs("div",{children:["Page ",h+1," of ",y," (",K.length.toLocaleString()," items · page size"," ",v,")"]}),e.jsxs("div",{className:"inline",children:[e.jsx("button",{className:"btn",onClick:()=>T(Math.max(0,h-1)),disabled:h===0||t,children:"Prev"}),e.jsx("button",{className:"btn",onClick:()=>T(Math.min(y-1,h+1)),disabled:h>=y-1||t,children:"Next"})]})]})]})});function As({active:r}){const{push:t}=is(),{value:u,setValue:h,register:y,clearHandler:v}=rs(),{liveArr:F,setLiveArr:N}=os(),[m,T]=a.useState([]),[n,M]=a.useState(""),[b,B]=a.useState(null),[K,A]=a.useState(0),[L,ge]=a.useState(""),[J,C]=a.useState(!1),[g,j]=a.useState(null),[q,G]=a.useState({}),[Q,le]=a.useState(as),[te,W]=a.useState(1),Z=a.useRef(""),l=a.useRef({}),S=a.useRef(u),D=a.useRef(!1),P=_e({getKey:s=>`${s.title}-${s.year}`,hashFields:["title","year","hasFile","monitored","reason"]}),[X,ie]=a.useState([]),[ee,f]=a.useState(!1),[i,x]=a.useState(0),[R,I]=a.useState(""),[$,U]=a.useState(null),he=_e({getKey:s=>`${s.__instance}-${s.title}-${s.year}`,hashFields:["__instance","title","year","hasFile","monitored","reason"]}),[re,we]=a.useState({key:"__instance",direction:"asc"}),[ye,Re]=a.useState(!1),[me,Y]=a.useState("all"),[fe,Ae]=a.useState({available:0,monitored:0,missing:0,total:0}),be=a.useCallback(async()=>{try{const s=await cs();s.ready===!1&&!D.current?(D.current=!0,t("Radarr backend is still initialising. Check the logs if this persists.","info")):s.ready&&(D.current=!0);const o=(s.arr||[]).filter(c=>c.type==="radarr");if(T(o),!o.length){M("aggregate"),B(null),ie([]),Ae({available:0,monitored:0,missing:0,total:0});return}n===""?M(o.length===1?o[0].category:"aggregate"):n!=="aggregate"&&!o.some(c=>c.category===n)&&M(o[0].category)}catch(s){t(s instanceof Error?s.message:"Unable to load Radarr instances","error")}},[t,n]),De=a.useCallback(async(s,o,c,E,_)=>{if(E.length)try{const O=[];for(const k of E){const z=await Je(s,k,c,o),H=z.page??k;if(O.push({page:H,movies:z.movies??[]}),Z.current!==_)return}if(Z.current!==_)return;G(k=>{const z={...k};let H=!1;for(const{page:oe,movies:w}of O){const se=P.syncData(w);se.hasChanges&&(z[oe]=se.data,H=!0)}return l.current=z,H?z:k})}catch(O){t(O instanceof Error?O.message:`Failed to load additional pages for ${s}`,"error")}},[t]),pe=a.useCallback(async(s,o,c,E={})=>{const _=E.preloadAll!==!1;(E.showLoading??!0)&&C(!0);try{const k=`${s}::${c}`,z=Z.current!==k;z&&(Z.current=k,G(()=>(l.current={},{})));const H=await Je(s,o,as,c);B(H);const oe=H.page??o;A(oe),ge(c);const w=H.page_size??as,se=H.total??(H.movies??[]).length,ue=Math.max(1,Math.ceil((se||0)/w));le(w),W(ue);const xe=H.movies??[],ae=z?{}:l.current,V=P.syncData(xe),de=V.hasChanges;if(z&&P.reset(),(z||de)&&(G(je=>{const Ee={...z?{}:je,[oe]:V.data};return l.current=Ee,Ee}),j(new Date().toLocaleTimeString())),_){const je=[];for(let ce=0;ce<ue;ce+=1)ce!==oe&&(ae[ce]||je.push(ce));De(s,c,w,je,k)}}catch(k){t(k instanceof Error?k.message:`Failed to load ${s} movies`,"error")}finally{C(!1)}},[t,De]),Se=a.useCallback(async s=>{if(!m.length){ie([]),Ae({available:0,monitored:0,missing:0,total:0});return}(s?.showLoading??!0)&&f(!0);try{const c=[];let E=0,_=0;for(const oe of m){let w=0,se=!1;const ue=oe.name||oe.category;for(;w<100;){const xe=await Je(oe.category,w,fs,"");if(!se){const V=xe.counts;V&&(E+=V.available??0,_+=V.monitored??0),se=!0}const ae=xe.movies??[];if(ae.forEach(V=>{c.push({...V,__instance:ue})}),!ae.length||ae.length<fs)break;w+=1}}const O=he.syncData(c),k=O.hasChanges;k&&ie(O.data);const z={available:E,monitored:_,missing:c.length-E,total:c.length},H=fe.available!==z.available||fe.monitored!==z.monitored||fe.missing!==z.missing||fe.total!==z.total;H&&Ae(z),R!==u&&(x(0),I(u)),(k||H)&&U(new Date().toLocaleTimeString())}catch(c){ie([]),Ae({available:0,monitored:0,missing:0,total:0}),t(c instanceof Error?c.message:"Failed to load aggregated Radarr data","error")}finally{f(!1)}},[m,u,t,R]);a.useEffect(()=>{r&&be()},[r,be]),a.useEffect(()=>{if(!r||!n||n==="aggregate")return;l.current={},G({}),W(1),A(0);const s=S.current;pe(n,0,s,{preloadAll:!0,showLoading:!0})},[r,n,pe]),a.useEffect(()=>{r&&n==="aggregate"&&Se()},[r,n,Se]),Ke(()=>{n==="aggregate"&&F&&Se({showLoading:!1})},n==="aggregate"&&F?1e3:null),a.useEffect(()=>{if(!r)return;const s=o=>{n==="aggregate"?(I(o),x(0)):n&&(A(0),pe(n,0,o,{preloadAll:!0,showLoading:!0}))};return y(s),()=>{v(s)}},[r,n,y,v,pe]),Ke(()=>{if(n&&n!=="aggregate"){if(S.current?.trim?.()||"")return;pe(n,K,L,{preloadAll:!1,showLoading:!1})}},r&&n&&n!=="aggregate"&&F?1e3:null),a.useEffect(()=>{S.current=u},[u]),a.useEffect(()=>{n==="aggregate"&&I(u)},[n,u]);const Ce=a.useMemo(()=>{let s=X;if(R){const o=R.toLowerCase();s=s.filter(c=>{const E=(c.title??"").toString().toLowerCase(),_=(c.__instance??"").toLowerCase();return E.includes(o)||_.includes(o)})}return ye&&(s=s.filter(o=>!o.hasFile)),me!=="all"&&(me==="Not being searched"?s=s.filter(o=>o.reason==="Not being searched"||!o.reason):s=s.filter(o=>o.reason===me)),s},[X,R,ye,me]),Ne=!!R||me!=="all",Fe=a.useMemo(()=>{const s=[...Ce],o=(c,E)=>{switch(E){case"__instance":return(c.__instance||"").toLowerCase();case"title":return(c.title||"").toLowerCase();case"year":return c.year??0;case"monitored":return c.monitored?1:0;case"hasFile":return c.hasFile?1:0;default:return""}};return s.sort((c,E)=>{const _=o(c,re.key),O=o(E,re.key);let k=0;return typeof _=="number"&&typeof O=="number"?k=_-O:typeof _=="string"&&typeof O=="string"?k=_.localeCompare(O):k=String(_).localeCompare(String(O)),re.direction==="asc"?k:-k}),s},[Ce,re]),Oe=Math.max(1,Math.ceil(Fe.length/Be)),He=a.useMemo(()=>Fe.slice(i*Be,i*Be+Be),[Fe,i]),$e=a.useMemo(()=>{const s=Object.keys(q).map(Number).sort((c,E)=>c-E),o=[];return s.forEach(c=>{q[c]&&o.push(...q[c])}),o},[q]),Ve=a.useCallback(async()=>{if(!(!n||n==="aggregate"))try{await ds(n),t(`Restarted ${n}`,"success")}catch(s){t(s instanceof Error?s.message:`Failed to restart ${n}`,"error")}},[n,t]),Qe=a.useCallback(()=>{Se({showLoading:!0})},[Se]),We=a.useCallback(s=>{we(o=>o.key===s?{key:s,direction:o.direction==="asc"?"desc":"asc"}:{key:s,direction:"asc"})},[]),Ie=a.useCallback(()=>{n&&n!=="aggregate"&&pe(n,K,L,{preloadAll:!1,showLoading:!0})},[n,K,L,pe]),d=a.useCallback(s=>{const o=s.target.value||"aggregate";M(o),o!=="aggregate"&&h("")},[M,h]),p=n==="aggregate";return e.jsxs("section",{className:"card",children:[e.jsx("div",{className:"card-header",children:"Radarr"}),e.jsx("div",{className:"card-body",children:e.jsxs("div",{className:"split",children:[e.jsxs("aside",{className:"pane sidebar",children:[m.length>1&&e.jsx("button",{className:`btn ${p?"active":""}`,onClick:()=>M("aggregate"),children:"All Radarr"}),m.map(s=>e.jsx("button",{className:`btn ghost ${n===s.category?"active":""}`,onClick:()=>{M(s.category),h("")},children:s.name||s.category},s.category))]}),e.jsxs("div",{className:"pane",children:[e.jsxs("div",{className:"field mobile-instance-select",children:[e.jsx("label",{children:"Instance"}),e.jsxs("select",{value:n||"aggregate",onChange:d,disabled:!m.length,children:[m.length>1&&e.jsx("option",{value:"aggregate",children:"All Radarr"}),m.map(s=>e.jsx("option",{value:s.category,children:s.name||s.category},s.category))]})]}),e.jsxs("div",{className:"row",style:{alignItems:"flex-end",gap:"12px",flexWrap:"wrap"},children:[e.jsxs("div",{className:"col field",style:{flex:"1 1 200px"},children:[e.jsx("label",{children:"Search"}),e.jsx("input",{placeholder:"Filter movies",value:u,onChange:s=>h(s.target.value)})]}),e.jsxs("div",{className:"field",style:{flex:"0 0 auto",minWidth:"140px"},children:[e.jsx("label",{children:"Status"}),e.jsxs("select",{onChange:s=>{const o=s.target.value;Re(o==="missing")},value:ye?"missing":"all",children:[e.jsx("option",{value:"all",children:"All Movies"}),e.jsx("option",{value:"missing",children:"Missing Only"})]})]}),e.jsxs("div",{className:"field",style:{flex:"0 0 auto",minWidth:"140px"},children:[e.jsx("label",{children:"Search Reason"}),e.jsxs("select",{onChange:s=>Y(s.target.value),value:me,children:[e.jsx("option",{value:"all",children:"All Reasons"}),e.jsx("option",{value:"Not being searched",children:"Not Being Searched"}),e.jsx("option",{value:"Missing",children:"Missing"}),e.jsx("option",{value:"Quality",children:"Quality"}),e.jsx("option",{value:"CustomFormat",children:"Custom Format"}),e.jsx("option",{value:"Upgrade",children:"Upgrade"})]})]})]}),p?e.jsx(Ms,{loading:ee,rows:He,total:Fe.length,page:i,totalPages:Oe,onPageChange:x,onRefresh:Qe,lastUpdated:$,sort:re,onSort:We,summary:fe,instanceCount:m.length,isAggFiltered:Ne}):e.jsx(Ps,{loading:J,data:b,page:K,totalPages:te,pageSize:Q,allMovies:$e,onlyMissing:ye,reasonFilter:me,onPageChange:s=>{A(s),pe(n,s,L,{preloadAll:!0})},onRefresh:Ie,onRestart:()=>void Ve(),lastUpdated:g})]})]})})]})}const ts=25,Ge=50,bs=200;function Ds(r,t){if(!t)return r;const u=[];for(const h of r){const y=h.seasons??{},v={};for(const[F,N]of Object.entries(y)){const m=(N.episodes??[]).filter(T=>!T.hasFile);m.length&&(v[F]={...N,episodes:m})}Object.keys(v).length!==0&&u.push({...h,seasons:v})}return u}function Ye(r,t){return JSON.stringify(Ds(r,t))}function $s({active:r}){const{push:t}=is(),{value:u,setValue:h,register:y,clearHandler:v}=rs(),{liveArr:F,setLiveArr:N,groupSonarr:m,setGroupSonarr:T}=os(),[n,M]=a.useState([]),[b,B]=a.useState(""),[K,A]=a.useState(null),[L,ge]=a.useState(0),[J,C]=a.useState(""),[g,j]=a.useState(!1),[q,G]=a.useState(null),[Q,le]=a.useState({}),te=a.useRef({}),W=a.useRef(null),Z=a.useRef(""),[l,S]=a.useState(ts),[D,P]=a.useState(1),[X,ie]=a.useState(0),ee=a.useRef(u),f=a.useRef(!1),i=a.useRef(b),[x,R]=a.useState([]),[I,$]=a.useState(!1),[U,he]=a.useState(0),[re,we]=a.useState(""),[ye,Re]=a.useState(null),me=_e({getKey:s=>`${s.__instance}-${s.series}-${s.season}-${s.episode}`,hashFields:["__instance","series","season","episode","title","hasFile","monitored","airDate","reason","qualityProfileId","qualityProfileName"]}),[Y,fe]=a.useState(!1),Ae=a.useRef(Y),[be,De]=a.useState("all"),[pe,Se]=a.useState({available:0,monitored:0,missing:0,total:0}),Ce=a.useCallback(async()=>{try{const s=await cs();s.ready===!1&&!f.current?(f.current=!0,t("Sonarr backend is still initialising. Check the logs if this persists.","info")):s.ready&&(f.current=!0);const o=(s.arr||[]).filter(c=>c.type==="sonarr");if(M(o),!o.length){B("aggregate"),A(null),R([]),Se({available:0,monitored:0,missing:0,total:0});return}b===""?B(o.length===1?o[0].category:"aggregate"):b!=="aggregate"&&!o.some(c=>c.category===b)&&B(o[0].category)}catch(s){t(s instanceof Error?s.message:"Unable to load Sonarr instances","error")}},[t,b]),Ne=a.useCallback(async(s,o,c,E={})=>{const{preloadAll:_=!0,showLoading:O=!0,missingOnly:k}=E,z=k??Y;O&&j(!0);try{const H=`${s}::${c}::${z?"missing":"all"}`,oe=Z.current!==H;oe&&(Z.current=H,le(()=>(te.current={},{})),ie(0),P(1));const w=await Xe(s,o,ts,c,{missingOnly:z});console.log(`[Sonarr Instance] Response for ${s} page ${o}:`,{total:w.total,page:w.page,page_size:w.page_size,series_count:w.series?.length??0,counts:w.counts,missingOnly:z,firstSeries:w.series?.[0]?{title:w.series[0].series?.title,seasonsCount:Object.keys(w.series[0].seasons??{}).length,firstSeasonEpisodes:Object.values(w.series[0].seasons??{})[0]?.episodes?.length??0}:null});const se=w.page??o,ue=w.page_size??ts,xe=w.total??(w.series??[]).length,ae=Math.max(1,Math.ceil((xe||0)/ue)),V=w.series??[],de=oe?{}:te.current,je={...de,[se]:V},ce=Ye(de[se]??[],z),Ee=Ye(V,z),ke=oe||ce!==Ee;if(te.current=je,ke&&le(je),A(ne=>{const ve=ne?.counts??null,Le=w.counts??null;return!ne||ne.total!==w.total||ne.page!==w.page||ne.page_size!==w.page_size||(ve?.available??null)!==(Le?.available??null)||(ve?.monitored??null)!==(Le?.monitored??null)||(ve?.missing??null)!==(Le?.missing??null)||ke?(W.current=w,w):ne}),ge(ne=>ne===se?ne:se),C(ne=>ne===c?ne:c),S(ne=>ne===ue?ne:ue),P(ne=>ne===ae?ne:ae),ie(ne=>ne===xe?ne:xe),ke&&G(new Date().toLocaleTimeString()),_){const ne=[];for(let ve=0;ve<ae;ve+=1)ve!==se&&(je[ve]||ne.push(ve));for(const ve of ne)try{const Le=await Xe(s,ve,ue,c,{missingOnly:z});if(Z.current!==H)break;const Me=Le.page??ve,Ze=Le.series??[],us=te.current,js=Ye(us[Me]??[],z),ps=Ye(Ze,z);if(js===ps){te.current={...us,[Me]:Ze};continue}le(Ns=>{const hs={...Ns,[Me]:Ze};return te.current=hs,hs})}catch{break}}}catch(H){t(H instanceof Error?H.message:`Failed to load ${s} series`,"error")}finally{O&&j(!1)}},[t,Y]),Fe=a.useCallback(async s=>{if(!n.length){R([]),Se({available:0,monitored:0,missing:0,total:0});return}console.log(`[Sonarr Aggregate] Starting aggregation for ${n.length} instances`),(s?.showLoading??!0)&&$(!0);try{const c=[];let E=0,_=0,O=0;for(const se of n){let ue=0,xe=!1;const ae=se.name||se.category;for(console.log(`[Sonarr Aggregate] Processing instance: ${ae}`);ue<200;){const V=await Xe(se.category,ue,bs,"",{missingOnly:Y});if(console.log(`[Sonarr Aggregate] Response for ${ae} page ${ue}:`,{total:V.total,page:V.page,page_size:V.page_size,series_count:V.series?.length??0,counts:V.counts,missingOnly:Y,firstSeries:V.series?.[0]?{title:V.series[0].series?.title,seasonsCount:Object.keys(V.series[0].seasons??{}).length,firstSeasonEpisodes:Object.values(V.series[0].seasons??{})[0]?.episodes?.length??0,firstEpisode:Object.values(V.series[0].seasons??{})[0]?.episodes?.[0]}:null}),!xe){const ce=V.counts;ce&&(E+=ce.available??0,_+=ce.monitored??0,O+=ce.missing??0),xe=!0}const de=V.series??[];let je=0;if(de.forEach(ce=>{const Ee=Object.keys(ce.seasons??{}).length;let ke=0;Object.values(ce.seasons??{}).forEach(ne=>{ke+=(ne.episodes??[]).length}),je+=ke}),console.log(`[Sonarr Aggregate] Instance: ${ae}, Page: ${ue}, Series count: ${de.length}, Total episodes so far: ${c.length}, Episodes in this response: ${je}`),de.forEach(ce=>{const Ee=ce.series?.title||"",ke=ce.series?.qualityProfileId??null,ne=ce.series?.qualityProfileName??null;Object.entries(ce.seasons??{}).forEach(([ve,Le])=>{(Le.episodes??[]).forEach(Me=>{const Ze=Me.reason??null;c.push({__instance:ae,series:Ee,season:ve,episode:Me.episodeNumber??"",title:Me.title??"",monitored:!!Me.monitored,hasFile:!!Me.hasFile,airDate:Me.airDateUtc??"",reason:Ze,qualityProfileId:ke,qualityProfileName:ne})})})}),!de.length||de.length<bs){console.log(`[Sonarr Aggregate] Breaking pagination for ${ae} - series.length=${de.length}`);break}ue+=1}}const k=me.syncData(c),z=k.hasChanges,H=new Map;c.forEach(se=>{const ue=se.reason||"null/empty";H.set(ue,(H.get(ue)||0)+1)}),console.log("[Sonarr Aggregate] Reason distribution:",Object.fromEntries(H)),z?(console.log(`[Sonarr Aggregate] Data changed, updating from ${x.length} to ${c.length} episodes`),R(k.data)):console.log("[Sonarr Aggregate] Data unchanged, skipping update");const oe={available:E,monitored:_,missing:O,total:c.length},w=pe.available!==oe.available||pe.monitored!==oe.monitored||pe.missing!==oe.missing||pe.total!==oe.total;w&&Se(oe),re!==u&&(he(0),we(u)),(z||w)&&Re(new Date().toLocaleTimeString())}catch(c){R([]),Se({available:0,monitored:0,missing:0,total:0}),t(c instanceof Error?c.message:"Failed to load aggregated Sonarr data","error")}finally{$(!1)}},[n,u,t,Y,re]);a.useEffect(()=>{r&&Ce()},[r,Ce]),a.useEffect(()=>{if(!r||!b||b==="aggregate")return;const s=i.current!==b,o=Ae.current!==Y;s&&(ge(0),i.current=b),o&&(Ae.current=Y);const c=ee.current;Ne(b,s?0:L,c,{preloadAll:!0,showLoading:!0,missingOnly:Y})},[r,b,Y,Ne,L]),a.useEffect(()=>{r&&b==="aggregate"&&Fe()},[r,b,Fe]),Ke(()=>{b==="aggregate"&&F&&Fe({showLoading:!1})},b==="aggregate"&&F?1e3:null),a.useEffect(()=>{if(!r)return;const s=o=>{b==="aggregate"?(we(o),he(0)):b&&(ge(0),Ne(b,0,o,{preloadAll:!0,showLoading:!0,missingOnly:Y}))};return y(s),()=>v(s)},[r,b,y,v,Ne,Y]),Ke(()=>{if(b&&b!=="aggregate"){if(ee.current?.trim?.()||"")return;Ne(b,L,J,{preloadAll:!1,showLoading:!1,missingOnly:Y})}},r&&b&&b!=="aggregate"&&F?1e3:null),a.useEffect(()=>{ee.current=u},[u]),a.useEffect(()=>{b==="aggregate"&&we(u)},[b,u]);const Oe=a.useMemo(()=>{let s=x;if(re){const o=re.toLowerCase();s=s.filter(c=>c.series.toLowerCase().includes(o)||c.title.toLowerCase().includes(o)||c.__instance.toLowerCase().includes(o))}if(Y&&(s=s.filter(o=>!o.hasFile)),be!=="all"){console.log(`[Sonarr Filter] Applying reason filter: "${be}"`);const o=s.length;be==="Not being searched"?s=s.filter(c=>c.reason==="Not being searched"||!c.reason):s=s.filter(c=>c.reason===be),console.log(`[Sonarr Filter] Filtered from ${o} to ${s.length} episodes for reason "${be}"`),s.length<10&&console.log("[Sonarr Filter] Sample filtered rows:",s.slice(0,5).map(c=>({series:c.series,episode:c.episode,reason:c.reason})))}return s},[x,re,Y,be]),He=!!re||Y||be!=="all",$e=Oe,Ve=Math.max(1,Math.ceil($e.length/Ge));a.useMemo(()=>$e.slice(U*Ge,U*Ge+Ge),[$e,U]);const Qe=Q[L]??[],We=a.useMemo(()=>{const s=Object.keys(Q).map(Number).sort((c,E)=>c-E),o=[];return s.forEach(c=>{Q[c]&&o.push(...Q[c])}),o},[Q]),Ie=a.useCallback(async()=>{if(!(!b||b==="aggregate"))try{await ds(b),t(`Restarted ${b}`,"success")}catch(s){t(s instanceof Error?s.message:`Failed to restart ${b}`,"error")}},[b,t]),d=a.useCallback(s=>{const o=s.target.value||"aggregate";B(o),o!=="aggregate"&&h("")},[B,h]),p=b==="aggregate";return e.jsxs("section",{className:"card",children:[e.jsx("div",{className:"card-header",children:"Sonarr"}),e.jsx("div",{className:"card-body",children:e.jsxs("div",{className:"split",children:[e.jsxs("aside",{className:"pane sidebar",children:[n.length>1&&e.jsx("button",{className:`btn ${p?"active":""}`,onClick:()=>B("aggregate"),children:"All Sonarr"}),n.map(s=>e.jsx("button",{className:`btn ghost ${b===s.category?"active":""}`,onClick:()=>{B(s.category),h("")},children:s.name||s.category},s.category))]}),e.jsxs("div",{className:"pane",children:[e.jsxs("div",{className:"field mobile-instance-select",children:[e.jsx("label",{children:"Instance"}),e.jsxs("select",{value:b||"aggregate",onChange:d,disabled:!n.length,children:[n.length>1&&e.jsx("option",{value:"aggregate",children:"All Sonarr"}),n.map(s=>e.jsx("option",{value:s.category,children:s.name||s.category},s.category))]})]}),e.jsxs("div",{className:"row",style:{alignItems:"flex-end",gap:"12px",flexWrap:"wrap"},children:[e.jsxs("div",{className:"col field",style:{flex:"1 1 200px"},children:[e.jsx("label",{children:"Search"}),e.jsx("input",{placeholder:"Filter series or episodes",value:u,onChange:s=>h(s.target.value)})]}),e.jsxs("div",{className:"field",style:{flex:"0 0 auto",minWidth:"140px"},children:[e.jsx("label",{children:"Status"}),e.jsxs("select",{onChange:s=>{const c=s.target.value==="missing";fe(c),b&&b!=="aggregate"&&Ne(b,0,ee.current||"",{preloadAll:!0,showLoading:!0,missingOnly:c})},value:Y?"missing":"all",children:[e.jsx("option",{value:"all",children:"All Episodes"}),e.jsx("option",{value:"missing",children:"Missing Only"})]})]}),e.jsxs("div",{className:"field",style:{flex:"0 0 auto",minWidth:"140px"},children:[e.jsx("label",{children:"Search Reason"}),e.jsxs("select",{onChange:s=>De(s.target.value),value:be,children:[e.jsx("option",{value:"all",children:"All Reasons"}),e.jsx("option",{value:"Not being searched",children:"Not Being Searched"}),e.jsx("option",{value:"Missing",children:"Missing"}),e.jsx("option",{value:"Quality",children:"Quality"}),e.jsx("option",{value:"CustomFormat",children:"Custom Format"}),e.jsx("option",{value:"Upgrade",children:"Upgrade"})]})]})]}),p?e.jsx(ks,{loading:I,rows:$e,total:$e.length,page:U,totalPages:Ve,onPageChange:he,onRefresh:()=>void Fe({showLoading:!0}),lastUpdated:ye,groupSonarr:m,summary:pe,instanceCount:n.length,isAggFiltered:He}):e.jsx(Ls,{loading:g,counts:K?.counts??null,series:m?Qe:We,page:L,pageSize:l,totalPages:D,totalItems:X,onlyMissing:Y,reasonFilter:be,onPageChange:s=>{ge(s),Ne(b,s,J,{preloadAll:!1,showLoading:!0,missingOnly:Y})},onRestart:()=>void Ie(),lastUpdated:q,groupSonarr:m,instances:n,selection:b})]})]})})]})}function ks({loading:r,rows:t,total:u,page:h,totalPages:y,onPageChange:v,onRefresh:F,lastUpdated:N,groupSonarr:m,summary:T,instanceCount:n,isAggFiltered:M=!1}){const b=a.useRef([]),B=a.useRef([]),K=a.useRef(new Map),A=a.useMemo(()=>{if(t===b.current)return B.current;const l=new Map;t.forEach(P=>{const X=P.__instance,ie=P.series,ee=String(P.season);l.has(X)||l.set(X,new Map);const f=l.get(X);f.has(ie)||f.set(ie,new Map);const i=f.get(ie);i.has(ee)||i.set(ee,[]),i.get(ee).push(P)});const S=[],D=new Map;return l.forEach((P,X)=>{P.forEach((ie,ee)=>{const f=`${X}-${ee}`,i=new Set;ie.forEach(($,U)=>{$.forEach(he=>{const re=`${U}-${he.episode}`;i.add(re)})});const x=K.current.get(f);if(x&&x.episodeKeys.size===i.size){let $=!0;for(const U of i)if(!x.episodeKeys.has(U)){$=!1;break}if($){S.push(x),D.set(f,x);return}}const R=Array.from(ie.values())[0]?.[0];console.log(`[Sonarr Grouped] Series: ${ee}, QualityProfile: ${R?.qualityProfileName}, FirstEpisode:`,R);const I={instance:X,series:ee,qualityProfileId:R?.qualityProfileId,qualityProfileName:R?.qualityProfileName,subRows:Array.from(ie.entries()).map(([$,U])=>({seasonNumber:$,isSeason:!0,subRows:U.map(he=>({...he,isEpisode:!0}))})),episodeKeys:i};S.push(I),D.set(f,I)})}),b.current=t,B.current=S,K.current=D,S},[t]),L=a.useMemo(()=>A.slice(h*50,(h+1)*50),[A,h]),ge=a.useMemo(()=>t.slice(h*50,(h+1)*50),[t,h]),J=m?L:ge,C=a.useMemo(()=>[{accessorKey:"title",header:"Title",cell:({row:l})=>{if(l.original.isEpisode)return l.original.title;if(l.original.isSeason)return`Season ${l.original.seasonNumber}`;const S=[l.original.series];return l.original.instance&&S.push(`(${l.original.instance})`),l.original.qualityProfileName&&S.push(`• ${l.original.qualityProfileName}`),S.join(" ")}},{accessorKey:"monitored",header:"Monitored",cell:({row:l})=>{const S=(l.original.isEpisode,l.original.monitored);return e.jsx("span",{className:`track-status ${S?"available":"missing"}`,children:S?"✓":"✗"})}},{accessorKey:"hasFile",header:"Has File",cell:({row:l})=>{if(l.original.isEpisode){const S=l.original.hasFile;return e.jsx("span",{className:`track-status ${S?"available":"missing"}`,children:S?"✓":"✗"})}return null}},{accessorKey:"airDate",header:"Air Date",cell:({row:l})=>l.original.isEpisode?l.original.airDate||"—":null}],[]),g=a.useMemo(()=>[...n>1?[{accessorKey:"__instance",header:"Instance"}]:[],{accessorKey:"series",header:"Series"},{accessorKey:"season",header:"Season"},{accessorKey:"episode",header:"Episode"},{accessorKey:"title",header:"Title"},{accessorKey:"monitored",header:"Monitored",cell:({getValue:l})=>{const S=l();return e.jsx("span",{className:`track-status ${S?"available":"missing"}`,children:S?"✓":"✗"})}},{accessorKey:"hasFile",header:"Has File",cell:({getValue:l})=>{const S=l();return e.jsx("span",{className:`track-status ${S?"available":"missing"}`,children:S?"✓":"✗"})}},{accessorKey:"airDate",header:"Air Date",cell:({getValue:l})=>l()||"—"},{accessorKey:"qualityProfileName",header:"Quality Profile",cell:({getValue:l})=>l()||"—"},{accessorKey:"reason",header:"Reason",cell:({getValue:l})=>{const S=l();return S?e.jsx("span",{className:"table-badge table-badge-reason",children:S}):e.jsx("span",{className:"table-badge table-badge-reason",children:"Not being searched"})}}],[n]),j=m?C:g,q=ze({data:J,columns:j,getCoreRowModel:Te(),getExpandedRowModel:vs()}),G=ze({data:J,columns:j,getCoreRowModel:Te(),getSortedRowModel:gs(),getPaginationRowModel:ys(),state:{pagination:{pageIndex:h,pageSize:50}},manualPagination:!0,pageCount:y}),Q=m?q:G,le=50,te=Math.ceil(m?A.length/le:t.length/le),W=Math.min(h,Math.max(0,te-1)),Z=m?`${A.length} series`:t.length.toLocaleString();return e.jsxs("div",{className:"stack animate-fade-in",children:[e.jsxs("div",{className:"row",style:{justifyContent:"space-between"},children:[e.jsxs("div",{className:"hint",children:["Aggregated episodes across all instances"," ",N?`(updated ${N})`:"",e.jsx("br",{}),e.jsx("strong",{children:"Available:"})," ",T.available.toLocaleString(void 0,{maximumFractionDigits:0})," •"," ",e.jsx("strong",{children:"Monitored:"})," ",T.monitored.toLocaleString(void 0,{maximumFractionDigits:0})," •"," ",e.jsx("strong",{children:"Missing:"})," ",T.missing.toLocaleString(void 0,{maximumFractionDigits:0})," •"," ",e.jsx("strong",{children:"Total Episodes:"})," ",T.total.toLocaleString(void 0,{maximumFractionDigits:0}),M&&t.length<T.total&&e.jsxs(e.Fragment,{children:[" ","• ",e.jsx("strong",{children:"Filtered:"})," ",t.length.toLocaleString(void 0,{maximumFractionDigits:0})," of"," ",T.total.toLocaleString(void 0,{maximumFractionDigits:0})]})]}),e.jsxs("button",{className:"btn ghost",onClick:F,disabled:r,children:[e.jsx(qe,{src:Ue}),"Refresh"]})]}),r?e.jsxs("div",{className:"loading",children:[e.jsx("span",{className:"spinner"})," Loading Sonarr library…"]}):m?e.jsx("div",{className:"sonarr-hierarchical-view",children:L.map(l=>{console.log(`[Sonarr Render] Series: ${l.series}, QualityProfile: ${l.qualityProfileName}`);let S=0;return l.subRows.forEach(D=>{S+=D.subRows.length}),e.jsxs("details",{className:"series-details",children:[e.jsxs("summary",{className:"series-summary",children:[e.jsx("span",{className:"series-title",children:l.series}),e.jsxs("span",{className:"series-instance",children:["(",l.instance,")"]}),e.jsxs("span",{className:"series-count",children:["(",S," episodes)"]}),l.qualityProfileName?e.jsxs("span",{className:"series-quality",children:["• ",l.qualityProfileName]}):null]}),e.jsx("div",{className:"series-content",children:l.subRows.map(D=>e.jsxs("details",{className:"season-details",children:[e.jsxs("summary",{className:"season-summary",children:[e.jsxs("span",{className:"season-title",children:["Season ",D.seasonNumber]}),e.jsxs("span",{className:"season-count",children:["(",D.subRows.length," episodes)"]})]}),e.jsx("div",{className:"season-content",children:e.jsx("div",{className:"episodes-table-wrapper",children:e.jsxs("table",{className:"episodes-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Episode"}),e.jsx("th",{children:"Title"}),e.jsx("th",{children:"Monitored"}),e.jsx("th",{children:"Has File"}),e.jsx("th",{children:"Air Date"}),e.jsx("th",{children:"Reason"})]})}),e.jsx("tbody",{children:D.subRows.map(P=>e.jsxs("tr",{children:[e.jsx("td",{"data-label":"Episode",children:P.episode}),e.jsx("td",{"data-label":"Title",children:P.title}),e.jsx("td",{"data-label":"Monitored",children:e.jsx("span",{className:`track-status ${P.monitored?"available":"missing"}`,children:P.monitored?"✓":"✗"})}),e.jsx("td",{"data-label":"Has File",children:e.jsx("span",{className:`track-status ${P.hasFile?"available":"missing"}`,children:P.hasFile?"✓":"✗"})}),e.jsx("td",{"data-label":"Air Date",children:P.airDate||"—"}),e.jsx("td",{"data-label":"Reason",children:P.reason?e.jsx("span",{className:"table-badge table-badge-reason",children:P.reason}):e.jsx("span",{className:"table-badge table-badge-reason",children:"Not being searched"})})]},`${P.__instance}-${P.series}-${P.season}-${P.episode}`))})]})})})]},`${l.instance}-${l.series}-${D.seasonNumber}`))})]},`${l.instance}-${l.series}`)})}):!r&&T.total===0&&n>0?e.jsxs("div",{className:"hint",children:[e.jsx("p",{children:"No episodes found in the database."}),e.jsx("p",{children:"The backend may still be initializing and syncing data from your Sonarr instances. Please check the logs or wait a few moments and refresh."})]}):J.length?e.jsx("div",{className:"table-wrapper",children:e.jsxs("table",{className:"responsive-table",children:[e.jsx("thead",{children:e.jsx("tr",{children:Q.getFlatHeaders().map(l=>e.jsxs("th",{className:l.column.getCanSort()?"sortable":"",onClick:l.column.getToggleSortingHandler(),children:[l.isPlaceholder?null:Pe(l.column.columnDef.header,l.getContext()),l.column.getCanSort()&&e.jsx("span",{className:"sort-arrow",children:{asc:"▲",desc:"▼"}[l.column.getIsSorted()]??null})]},l.id))})}),e.jsx("tbody",{children:Q.getRowModel().rows.map(l=>{const S=l.original,D=`${S.__instance}-${S.series}-${S.season}-${S.episode}`;return e.jsx("tr",{children:l.getVisibleCells().map(P=>e.jsx("td",{"data-label":P.column.columnDef.header,children:Pe(P.column.columnDef.cell,P.getContext())},P.id))},D)})})]})}):e.jsx("div",{className:"hint",children:"No series found."}),J.length>0&&e.jsxs("div",{className:"pagination",children:[e.jsxs("div",{children:["Page ",W+1," of ",te," (",Z," items · page size ",le,")"]}),e.jsxs("div",{className:"inline",children:[e.jsx("button",{className:"btn",onClick:()=>v(Math.max(0,W-1)),disabled:W===0||r,children:"Prev"}),e.jsx("button",{className:"btn",onClick:()=>v(Math.min(te-1,W+1)),disabled:W>=te-1||r,children:"Next"})]})]})]})}function Ls({loading:r,counts:t,series:u,page:h,pageSize:y,totalPages:v,totalItems:F,onlyMissing:N,reasonFilter:m,onPageChange:T,onRestart:n,lastUpdated:M,groupSonarr:b,instances:B,selection:K}){const[A,L]=a.useState(0),ge=50,J=a.useRef([]),C=a.useRef([]),g=a.useMemo(()=>{if(u===J.current)return C.current;const i=[];for(const x of u){const R=x.series?.title||"",I=x.series?.qualityProfileId??null,$=x.series?.qualityProfileName??null;Object.entries(x.seasons??{}).forEach(([U,he])=>{(he.episodes??[]).forEach(re=>{i.push({__instance:"Instance",series:R,season:U,episode:re.episodeNumber??"",title:re.title??"",monitored:!!re.monitored,hasFile:!!re.hasFile,airDate:re.airDateUtc??"",reason:re.reason??null,qualityProfileId:I,qualityProfileName:$})})})}return J.current=u,C.current=i,i},[u]),j=a.useMemo(()=>{let i=g;if(N&&(i=i.filter(x=>!x.hasFile)),m!=="all"){console.log(`[Sonarr Instance Filter] Applying reason filter: "${m}"`);const x=i.length;m==="Not being searched"?i=i.filter(R=>R.reason==="Not being searched"||!R.reason):i=i.filter(R=>R.reason===m),console.log(`[Sonarr Instance Filter] Filtered from ${x} to ${i.length} episodes for reason "${m}"`),i.length<10&&console.log("[Sonarr Instance Filter] Sample filtered rows:",i.slice(0,5).map(R=>({series:R.series,episode:R.episode,reason:R.reason})))}return i},[g,N,m]);a.useEffect(()=>{L(0)},[N,m]);const q=a.useRef([]),G=a.useRef([]),Q=a.useMemo(()=>{if(j===q.current)return G.current;const i=new Map;j.forEach(R=>{const I=R.series;i.has(I)||i.set(I,new Map);const $=i.get(I),U=String(R.season);$.has(U)||$.set(U,[]),$.get(U).push(R)});const x=Array.from(i.entries()).map(([R,I])=>{const $=Array.from(I.values())[0]?.[0];return{series:R,qualityProfileId:$?.qualityProfileId,qualityProfileName:$?.qualityProfileName,subRows:Array.from(I.entries()).map(([U,he])=>({seasonNumber:U,isSeason:!0,subRows:he.map(re=>({...re,isEpisode:!0}))}))}});return q.current=j,G.current=x,x},[j]),le=a.useMemo(()=>g.length,[g]),te=m!=="all"||N,W=j.length,Z=Math.max(1,Math.ceil(j.length/ge)),l=Math.min(A,Math.max(0,Z-1)),S=a.useMemo(()=>j.slice(l*ge,(l+1)*ge),[j,l]),D=50,[P,X]=a.useState(0),ie=Math.max(1,Math.ceil(Q.length/D)),ee=Math.min(P,Math.max(0,ie-1)),f=a.useMemo(()=>Q.slice(ee*D,(ee+1)*D),[Q,ee]);return a.useEffect(()=>{X(0)},[N,m]),e.jsxs("div",{className:"stack animate-fade-in",children:[e.jsxs("div",{className:"row",style:{justifyContent:"space-between"},children:[e.jsxs("div",{className:"hint",children:[t?e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"Available:"})," ",t.available.toLocaleString(void 0,{maximumFractionDigits:0})," •"," ",e.jsx("strong",{children:"Monitored:"})," ",t.monitored.toLocaleString(void 0,{maximumFractionDigits:0})," •"," ",e.jsx("strong",{children:"Missing:"})," ",(t.missing??0).toLocaleString(void 0,{maximumFractionDigits:0})," •"," ",e.jsx("strong",{children:"Total Episodes:"})," ",le.toLocaleString(void 0,{maximumFractionDigits:0}),te&&W<le&&e.jsxs(e.Fragment,{children:[" ","• ",e.jsx("strong",{children:"Filtered:"})," ",W.toLocaleString(void 0,{maximumFractionDigits:0})," of"," ",le.toLocaleString(void 0,{maximumFractionDigits:0})]})]}):"Loading series information...",M?` (updated ${M})`:""]}),e.jsxs("button",{className:"btn ghost",onClick:n,disabled:r,children:[e.jsx(qe,{src:Ue}),"Restart"]})]}),r?e.jsxs("div",{className:"loading",children:[e.jsx("span",{className:"spinner"})," Loading series…"]}):b?e.jsx("div",{className:"sonarr-hierarchical-view",children:f.map(i=>{let x=0;i.subRows.forEach(I=>{x+=I.subRows.length});const R=B.find(I=>I.category===K)?.name||K;return e.jsxs("details",{className:"series-details",children:[e.jsxs("summary",{className:"series-summary",children:[e.jsx("span",{className:"series-title",children:i.series}),e.jsxs("span",{className:"series-instance",children:["(",R,")"]}),e.jsxs("span",{className:"series-count",children:["(",x," episodes)"]}),i.qualityProfileName?e.jsxs("span",{className:"series-quality",children:["• ",i.qualityProfileName]}):null]}),e.jsx("div",{className:"series-content",children:i.subRows.map(I=>e.jsxs("details",{className:"season-details",children:[e.jsxs("summary",{className:"season-summary",children:[e.jsxs("span",{className:"season-title",children:["Season ",I.seasonNumber]}),e.jsxs("span",{className:"season-count",children:["(",I.subRows.length," episodes)"]})]}),e.jsx("div",{className:"season-content",children:e.jsx("div",{className:"episodes-table-wrapper",children:e.jsxs("table",{className:"episodes-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Episode"}),e.jsx("th",{children:"Title"}),e.jsx("th",{children:"Monitored"}),e.jsx("th",{children:"Has File"}),e.jsx("th",{children:"Air Date"}),e.jsx("th",{children:"Reason"})]})}),e.jsx("tbody",{children:I.subRows.map($=>e.jsxs("tr",{children:[e.jsx("td",{"data-label":"Episode",children:$.episode}),e.jsx("td",{"data-label":"Title",children:$.title}),e.jsx("td",{"data-label":"Monitored",children:e.jsx("span",{className:`track-status ${$.monitored?"available":"missing"}`,children:$.monitored?"✓":"✗"})}),e.jsx("td",{"data-label":"Has File",children:e.jsx("span",{className:`track-status ${$.hasFile?"available":"missing"}`,children:$.hasFile?"✓":"✗"})}),e.jsx("td",{"data-label":"Air Date",children:$.airDate||"—"}),e.jsx("td",{"data-label":"Reason",children:$.reason?e.jsx("span",{className:"table-badge table-badge-reason",children:$.reason}):e.jsx("span",{className:"table-badge table-badge-reason",children:"Not being searched"})})]},`${$.series}-${$.season}-${$.episode}`))})]})})})]},`${i.series}-${I.seasonNumber}`))})]},`${i.series}`)})}):!r&&u.length>0&&j.length===0&&g.length===0?e.jsxs("div",{className:"hint",children:[e.jsx("p",{children:"No episodes found for these series."}),e.jsx("p",{children:"The backend may still be syncing episode data from Sonarr. Please check the logs or wait a few moments and refresh."})]}):!r&&u.length>0&&j.length===0&&g.length>0?e.jsx("div",{className:"hint",children:"No episodes match the current filter."}):!b&&j.length>0?e.jsxs("div",{className:"table-wrapper",children:[e.jsxs("table",{className:"responsive-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Series"}),e.jsx("th",{children:"Season"}),e.jsx("th",{children:"Episode"}),e.jsx("th",{children:"Title"}),e.jsx("th",{children:"Monitored"}),e.jsx("th",{children:"Has File"}),e.jsx("th",{children:"Air Date"}),e.jsx("th",{children:"Quality Profile"}),e.jsx("th",{children:"Reason"})]})}),e.jsx("tbody",{children:S.map((i,x)=>e.jsxs("tr",{children:[e.jsx("td",{"data-label":"Series",children:i.series}),e.jsx("td",{"data-label":"Season",children:i.season}),e.jsx("td",{"data-label":"Episode",children:i.episode}),e.jsx("td",{"data-label":"Title",children:i.title}),e.jsx("td",{"data-label":"Monitored",children:e.jsx("span",{className:`track-status ${i.monitored?"available":"missing"}`,children:i.monitored?"✓":"✗"})}),e.jsx("td",{"data-label":"Has File",children:e.jsx("span",{className:`track-status ${i.hasFile?"available":"missing"}`,children:i.hasFile?"✓":"✗"})}),e.jsx("td",{"data-label":"Air Date",children:i.airDate||"—"}),e.jsx("td",{"data-label":"Quality Profile",children:i.qualityProfileName||"—"}),e.jsx("td",{"data-label":"Reason",children:i.reason?e.jsx("span",{className:"table-badge table-badge-reason",children:i.reason}):e.jsx("span",{className:"table-badge table-badge-reason",children:"Not being searched"})})]},`${i.series}-${i.season}-${i.episode}-${x}`))})]}),Z>1&&e.jsxs("div",{className:"pagination",children:[e.jsxs("div",{children:["Page ",l+1," of ",Z," (",j.length.toLocaleString()," episodes · page size ",ge,")"]}),e.jsxs("div",{className:"inline",children:[e.jsx("button",{className:"btn",onClick:()=>L(Math.max(0,l-1)),disabled:l===0||r,children:"Prev"}),e.jsx("button",{className:"btn",onClick:()=>L(Math.min(Z-1,l+1)),disabled:l>=Z-1||r,children:"Next"})]})]})]}):e.jsx("div",{className:"hint",children:"No series found."}),b&&Q.length>0&&e.jsxs("div",{className:"pagination",children:[e.jsxs("div",{children:["Page ",ee+1," of ",ie," (",Q.length.toLocaleString()," series · page size ",D,")"]}),e.jsxs("div",{className:"inline",children:[e.jsx("button",{className:"btn",onClick:()=>X(Math.max(0,ee-1)),disabled:ee===0||r,children:"Prev"}),e.jsx("button",{className:"btn",onClick:()=>X(Math.min(ie-1,ee+1)),disabled:ee>=ie-1||r,children:"Next"})]})]})]})}const ns=50,xs=500;function Es({loading:r,rows:t,trackRows:u,page:h,onPageChange:y,onRefresh:v,lastUpdated:F,summary:N,instanceCount:m,groupLidarr:T,isAggFiltered:n=!1}){const M=a.useRef([]),b=a.useRef([]),B=a.useRef(new Map),K=a.useMemo(()=>{if(t===M.current)return b.current;const C=new Map;t.forEach(q=>{const G=q.__instance,Q=q.album?.artistName||"Unknown Artist";C.has(G)||C.set(G,new Map);const le=C.get(G);le.has(Q)||le.set(Q,[]),le.get(Q).push(q)});const g=[],j=new Map;return C.forEach((q,G)=>{q.forEach((Q,le)=>{const te=`${G}-${le}`,W=new Set;Q.forEach(P=>{const ie=`${P.album?.title}`;W.add(ie)});const Z=B.current.get(te);if(Z&&Z.albumKeys.size===W.size){let P=!0;for(const X of W)if(!Z.albumKeys.has(X)){P=!1;break}if(P){g.push(Z),j.set(te,Z);return}}const S=Q[0]?.album,D={instance:G,artist:le,qualityProfileId:S?.qualityProfileId??null,qualityProfileName:S?.qualityProfileName??null,albums:Q,albumKeys:W};g.push(D),j.set(te,D)})}),M.current=t,b.current=g,B.current=j,g},[t]),A=a.useMemo(()=>K.slice(h*50,(h+1)*50),[K,h]),L=a.useMemo(()=>{const g=h*50,j=g+50;return u.slice(g,j)},[u,h]),ge=a.useMemo(()=>[...m>1?[{accessorKey:"__instance",header:"Instance",size:120}]:[],{accessorKey:"artistName",header:"Artist",size:150},{accessorKey:"albumTitle",header:"Album",size:150},{accessorKey:"trackNumber",header:"#",size:50},{accessorKey:"title",header:"Track"},{accessorKey:"duration",header:"Duration",cell:C=>{const g=C.getValue();return g?`${Math.floor(g/60)}:${String(g%60).padStart(2,"0")}`:e.jsx("span",{className:"hint",children:"—"})},size:80},{accessorKey:"monitored",header:"Monitored",cell:C=>{const g=C.getValue();return e.jsx("span",{className:`track-status ${g?"available":"missing"}`,children:g?"✓":"✗"})},size:100},{accessorKey:"hasFile",header:"Has File",cell:C=>{const g=C.getValue();return e.jsx("span",{className:`track-status ${g?"available":"missing"}`,children:g?"✓":"✗"})},size:100},{accessorKey:"qualityProfileName",header:"Quality Profile",cell:C=>C.getValue()||"—",size:150},{accessorKey:"reason",header:"Reason",cell:C=>{const g=C.getValue();return g?e.jsx("span",{className:"table-badge table-badge-reason",children:g}):e.jsx("span",{className:"table-badge table-badge-reason",children:"Not being searched"})},size:120}],[m]),J=ze({data:L,columns:ge,getCoreRowModel:Te()});return e.jsxs("div",{className:"stack animate-fade-in",children:[e.jsxs("div",{className:"row",style:{justifyContent:"space-between"},children:[e.jsxs("div",{className:"hint",children:["Aggregated albums across all instances"," ",F?`(updated ${F})`:"",e.jsx("br",{}),e.jsx("strong",{children:"Available:"})," ",N.available.toLocaleString(void 0,{maximumFractionDigits:0})," •"," ",e.jsx("strong",{children:"Monitored:"})," ",N.monitored.toLocaleString(void 0,{maximumFractionDigits:0})," •"," ",e.jsx("strong",{children:"Missing:"})," ",N.missing.toLocaleString(void 0,{maximumFractionDigits:0})," •"," ",e.jsx("strong",{children:"Total:"})," ",N.total.toLocaleString(void 0,{maximumFractionDigits:0}),n&&(T?t.length:u.length)<N.total&&e.jsxs(e.Fragment,{children:[" ","• ",e.jsx("strong",{children:"Filtered:"})," ",(T?t.length:u.length).toLocaleString(void 0,{maximumFractionDigits:0})," of"," ",N.total.toLocaleString(void 0,{maximumFractionDigits:0})]})]}),e.jsxs("button",{className:"btn ghost",onClick:v,disabled:r,children:[e.jsx(qe,{src:Ue}),"Refresh"]})]}),r?e.jsxs("div",{className:"loading",children:[e.jsx("span",{className:"spinner"})," Loading Lidarr library…"]}):T?e.jsx("div",{className:"lidarr-hierarchical-view",children:A.map(C=>e.jsxs("details",{className:"artist-details",children:[e.jsxs("summary",{className:"artist-summary",children:[e.jsx("span",{className:"artist-title",children:C.artist}),e.jsxs("span",{className:"artist-instance",children:["(",C.instance,")"]}),e.jsxs("span",{className:"artist-count",children:["(",C.albums.length," albums)"]}),C.qualityProfileName?e.jsxs("span",{className:"artist-quality",children:["• ",C.qualityProfileName]}):null]}),e.jsx("div",{className:"artist-content",children:C.albums.map(g=>{const j=g.album,q=j?.title||"Unknown Album",G=j?.id||0,Q=j?.artistName||"",le=j?.releaseDate,te=j?.monitored,W=j?.hasFile,Z=j?.reason,l=g.tracks||[],S=g.totals;return e.jsxs("details",{className:"album-details",children:[e.jsxs("summary",{className:"album-summary",children:[e.jsx("span",{className:"album-title",children:q}),le&&e.jsx("span",{className:"album-date",children:new Date(le).toLocaleDateString()}),l&&l.length>0&&e.jsxs("span",{className:"album-track-count",children:["(",S.available||0,"/",S.monitored||l.length," tracks)"]}),e.jsx("span",{className:`album-status ${W?"has-file":"missing"}`,children:W?"✓":"✗"})]}),e.jsx("div",{className:"album-content",children:l&&l.length>0?e.jsx("div",{className:"tracks-table-wrapper",children:e.jsxs("table",{className:"tracks-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"#"}),e.jsx("th",{children:"Title"}),e.jsx("th",{children:"Duration"}),e.jsx("th",{children:"Has File"}),e.jsx("th",{children:"Reason"})]})}),e.jsx("tbody",{children:l.map(D=>e.jsxs("tr",{className:D.hasFile?"track-available":"track-missing",children:[e.jsx("td",{"data-label":"#",children:D.trackNumber}),e.jsx("td",{"data-label":"Title",children:D.title}),e.jsx("td",{"data-label":"Duration",children:D.duration?`${Math.floor(D.duration/60)}:${String(D.duration%60).padStart(2,"0")}`:"—"}),e.jsx("td",{"data-label":"Has File",children:e.jsx("span",{className:`track-status ${D.hasFile?"available":"missing"}`,children:D.hasFile?"✓":"✗"})}),e.jsx("td",{"data-label":"Reason",children:Z?e.jsx("span",{className:"table-badge table-badge-reason",children:Z}):e.jsx("span",{className:"table-badge table-badge-reason",children:"Not being searched"})})]},`${G}-${D.id}`))})]})}):e.jsxs("div",{className:"album-info",children:[e.jsxs("p",{children:[e.jsx("strong",{children:"Monitored:"})," ",te?"Yes":"No"," | ",e.jsx("strong",{children:"Has File:"})," ",W?"Yes":"No"]}),e.jsxs("p",{children:[e.jsx("strong",{children:"Reason:"})," ",Z?e.jsx("span",{className:"table-badge table-badge-reason",children:Z}):e.jsx("span",{className:"table-badge table-badge-reason",children:"Not being searched"})]})]})})]},`${g.__instance}-${Q}-${q}`)})})]},`${C.instance}-${C.artist}`))}):u.length?e.jsx("div",{className:"table-wrapper",children:e.jsxs("table",{className:"responsive-table",children:[e.jsx("thead",{children:J.getHeaderGroups().map(C=>e.jsx("tr",{children:C.headers.map(g=>e.jsx("th",{children:g.isPlaceholder?null:Pe(g.column.columnDef.header,g.getContext())},g.id))},C.id))}),e.jsx("tbody",{children:J.getRowModel().rows.map(C=>{const g=C.original,j=`${g.__instance}-${g.artistName}-${g.albumTitle}-${g.trackNumber}`;return e.jsx("tr",{children:C.getVisibleCells().map(q=>e.jsx("td",{"data-label":String(q.column.columnDef.header),children:Pe(q.column.columnDef.cell,q.getContext())},q.id))},j)})})]})}):e.jsx("div",{className:"hint",children:"No tracks found."}),(T?A.length>0:L.length>0)&&e.jsxs("div",{className:"pagination",children:[e.jsx("div",{children:T?e.jsxs(e.Fragment,{children:["Page ",h+1," of ",Math.ceil(K.length/50)," (",K.length," artists · page size 50)"]}):e.jsxs(e.Fragment,{children:["Page ",h+1," of ",Math.ceil(u.length/50)," (",u.length.toLocaleString()," tracks · page size 50)"]})}),e.jsxs("div",{className:"inline",children:[e.jsx("button",{className:"btn",onClick:()=>y(Math.max(0,h-1)),disabled:h===0||r,children:"Prev"}),e.jsx("button",{className:"btn",onClick:()=>y(Math.min(Math.ceil(T?K.length/50:u.length/50)-1,h+1)),disabled:h>=Math.ceil(T?K.length/50:u.length/50)-1||r,children:"Next"})]})]})]})}function Is({loading:r,data:t,page:u,totalPages:h,pageSize:y,allAlbums:v,onlyMissing:F,reasonFilter:N,onPageChange:m,onRestart:T,lastUpdated:n,groupLidarr:M,instances:b,selection:B}){const[K,A]=a.useState(0),L=50,ge=a.useMemo(()=>{let f=v;return F&&(f=f.filter(i=>!i.album?.hasFile)),f},[v,F]),J=a.useMemo(()=>N==="all"?ge:N==="Not being searched"?ge.filter(f=>{const i=f.album;return i?.reason==="Not being searched"||!i?.reason}):ge.filter(f=>f.album?.reason===N),[ge,N]),C=a.useMemo(()=>v.length,[v]),g=N!=="all"||F,j=J.length;a.useMemo(()=>{let f=0;return v.forEach(i=>{const x=i.tracks||[];f+=x.length}),f},[v]),a.useMemo(()=>{let f=0;return J.forEach(i=>{const x=i.tracks||[];f+=x.length}),f},[J]),a.useEffect(()=>{A(0)},[F,N]);const q=a.useRef([]),G=a.useRef([]),Q=a.useMemo(()=>{if(J===q.current)return G.current;const f=new Map;J.forEach(x=>{const I=x.album?.artistName||"Unknown Artist";f.has(I)||f.set(I,[]),f.get(I).push(x)});const i=Array.from(f.entries()).map(([x,R])=>{const $=R[0]?.album?.qualityProfileName??null;return{artist:x,albums:R,qualityProfileName:$}});return q.current=J,G.current=i,i},[J]),le=a.useMemo(()=>[{id:"title",header:"Album",cell:f=>f.row.original.album?.title||"Unknown Album"},{id:"artistName",header:"Artist",cell:f=>f.row.original.album?.artistName||"Unknown Artist",size:150},{id:"releaseDate",header:"Release Date",cell:f=>{const x=f.row.original.album?.releaseDate;return x?new Date(x).toLocaleDateString():e.jsx("span",{className:"hint",children:"—"})},size:120},{id:"monitored",header:"Monitored",cell:f=>{const x=f.row.original.album?.monitored;return e.jsx("span",{className:`track-status ${x?"available":"missing"}`,children:x?"✓":"✗"})},size:100},{id:"hasFile",header:"Has File",cell:f=>{const x=f.row.original.album?.hasFile;return e.jsx("span",{className:`track-status ${x?"available":"missing"}`,children:x?"✓":"✗"})},size:100},{id:"qualityProfileName",header:"Quality Profile",cell:f=>f.row.original.album?.qualityProfileName||"—",size:150},{id:"reason",header:"Reason",cell:f=>{const x=f.row.original.album?.reason;return x?e.jsx("span",{className:"table-badge table-badge-reason",children:x}):e.jsx("span",{className:"table-badge table-badge-reason",children:"Not being searched"})},size:120}],[]),te=Math.max(1,Math.ceil(J.length/L)),W=Math.min(K,Math.max(0,te-1)),Z=a.useMemo(()=>J.slice(W*L,(W+1)*L),[J,W]),l=50,[S,D]=a.useState(0),P=Math.max(1,Math.ceil(Q.length/l)),X=Math.min(S,Math.max(0,P-1)),ie=a.useMemo(()=>Q.slice(X*l,(X+1)*l),[Q,X]);a.useEffect(()=>{D(0)},[F,N]);const ee=ze({data:Z,columns:le,getCoreRowModel:Te(),getSortedRowModel:gs()});return e.jsxs("div",{className:"stack animate-fade-in",children:[e.jsxs("div",{className:"row",style:{justifyContent:"space-between"},children:[e.jsxs("div",{className:"hint",children:[t?.counts?e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"Available:"})," ",(t.counts.available??0).toLocaleString(void 0,{maximumFractionDigits:0})," •"," ",e.jsx("strong",{children:"Monitored:"})," ",(t.counts.monitored??0).toLocaleString(void 0,{maximumFractionDigits:0})," •"," ",e.jsx("strong",{children:"Missing:"})," ",((t.counts.monitored??0)-(t.counts.available??0)).toLocaleString(void 0,{maximumFractionDigits:0})," •"," ",e.jsx("strong",{children:"Total:"})," ",C.toLocaleString(void 0,{maximumFractionDigits:0}),g&&j<C&&e.jsxs(e.Fragment,{children:[" ","• ",e.jsx("strong",{children:"Filtered:"})," ",j.toLocaleString(void 0,{maximumFractionDigits:0})," of"," ",C.toLocaleString(void 0,{maximumFractionDigits:0})]})]}):"Loading album information...",n?` (updated ${n})`:""]}),e.jsxs("button",{className:"btn ghost",onClick:T,disabled:r,children:[e.jsx(qe,{src:Ue}),"Restart"]})]}),r?e.jsxs("div",{className:"loading",children:[e.jsx("span",{className:"spinner"})," Loading…"]}):M?e.jsx("div",{className:"lidarr-hierarchical-view",children:ie.map(f=>{const i=b.find(x=>x.category===B)?.name||B;return e.jsxs("details",{className:"artist-details",children:[e.jsxs("summary",{className:"artist-summary",children:[e.jsx("span",{className:"artist-title",children:f.artist}),e.jsxs("span",{className:"artist-instance",children:["(",i,")"]}),e.jsxs("span",{className:"artist-count",children:["(",f.albums.length," albums)"]}),f.qualityProfileName?e.jsxs("span",{className:"artist-quality",children:["• ",f.qualityProfileName]}):null]}),e.jsx("div",{className:"artist-content",children:f.albums.map(x=>{const R=x.album,I=R?.title||"Unknown Album",$=R?.id||0,U=R?.artistName||"",he=R?.releaseDate,re=R?.monitored,we=R?.hasFile,ye=R?.reason,Re=x.tracks||[],me=x.totals;return e.jsxs("details",{className:"album-details",children:[e.jsxs("summary",{className:"album-summary",children:[e.jsx("span",{className:"album-title",children:I}),he&&e.jsx("span",{className:"album-date",children:new Date(he).toLocaleDateString()}),Re&&Re.length>0&&e.jsxs("span",{className:"album-track-count",children:["(",me.available||0,"/",me.monitored||Re.length," tracks)"]}),e.jsx("span",{className:`album-status ${we?"has-file":"missing"}`,children:we?"✓":"✗"})]}),e.jsx("div",{className:"album-content",children:Re&&Re.length>0?e.jsx("div",{className:"tracks-table-wrapper",children:e.jsxs("table",{className:"tracks-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"#"}),e.jsx("th",{children:"Title"}),e.jsx("th",{children:"Duration"}),e.jsx("th",{children:"Has File"}),e.jsx("th",{children:"Reason"})]})}),e.jsx("tbody",{children:Re.map(Y=>e.jsxs("tr",{className:Y.hasFile?"track-available":"track-missing",children:[e.jsx("td",{"data-label":"#",children:Y.trackNumber}),e.jsx("td",{"data-label":"Title",children:Y.title}),e.jsx("td",{"data-label":"Duration",children:Y.duration?`${Math.floor(Y.duration/60)}:${String(Y.duration%60).padStart(2,"0")}`:"—"}),e.jsx("td",{"data-label":"Has File",children:e.jsx("span",{className:`track-status ${Y.hasFile?"available":"missing"}`,children:Y.hasFile?"✓":"✗"})}),e.jsx("td",{"data-label":"Reason",children:ye?e.jsx("span",{className:"table-badge table-badge-reason",children:ye}):e.jsx("span",{className:"table-badge table-badge-reason",children:"Not being searched"})})]},`${$}-${Y.id}`))})]})}):e.jsxs("div",{className:"album-info",children:[e.jsxs("p",{children:[e.jsx("strong",{children:"Monitored:"})," ",re?"Yes":"No"," | ",e.jsx("strong",{children:"Has File:"})," ",we?"Yes":"No"]}),e.jsxs("p",{children:[e.jsx("strong",{children:"Reason:"})," ",ye?e.jsx("span",{className:"table-badge table-badge-reason",children:ye}):e.jsx("span",{className:"table-badge table-badge-reason",children:"Not being searched"})]})]})})]},`${U}-${I}`)})})]},f.artist)})}):!M&&v.length?e.jsxs("div",{className:"table-wrapper",children:[e.jsxs("table",{className:"responsive-table",children:[e.jsx("thead",{children:ee.getHeaderGroups().map(f=>e.jsx("tr",{children:f.headers.map(i=>e.jsx("th",{children:i.isPlaceholder?null:Pe(i.column.columnDef.header,i.getContext())},i.id))},f.id))}),e.jsx("tbody",{children:ee.getRowModel().rows.map(f=>{const x=f.original.album,R=x?.title||"Unknown",I=x?.artistName||"Unknown",$=`${R}-${I}`;return e.jsx("tr",{children:f.getVisibleCells().map(U=>e.jsx("td",{"data-label":String(U.column.columnDef.header),children:Pe(U.column.columnDef.cell,U.getContext())},U.id))},$)})})]}),te>1&&e.jsxs("div",{className:"pagination",children:[e.jsxs("div",{children:["Page ",W+1," of ",te," (",J.length.toLocaleString()," albums · page size ",L,")"]}),e.jsxs("div",{className:"inline",children:[e.jsx("button",{className:"btn",onClick:()=>A(Math.max(0,W-1)),disabled:W===0||r,children:"Prev"}),e.jsx("button",{className:"btn",onClick:()=>A(Math.min(te-1,W+1)),disabled:W>=te-1||r,children:"Next"})]})]})]}):e.jsx("div",{className:"hint",children:"No albums found."}),M&&Q.length>0&&e.jsxs("div",{className:"pagination",children:[e.jsxs("div",{children:["Page ",X+1," of ",P," (",Q.length.toLocaleString()," artists · page size ",l,")"]}),e.jsxs("div",{className:"inline",children:[e.jsx("button",{className:"btn",onClick:()=>D(Math.max(0,X-1)),disabled:X===0||r,children:"Prev"}),e.jsx("button",{className:"btn",onClick:()=>D(Math.min(P-1,X+1)),disabled:X>=P-1||r,children:"Next"})]})]})]})}function _s({active:r}){const{push:t}=is(),{value:u,setValue:h,register:y,clearHandler:v}=rs(),{liveArr:F,groupLidarr:N}=os(),[m,T]=a.useState([]),[n,M]=a.useState(""),[b,B]=a.useState(null),[K,A]=a.useState(0),[L,ge]=a.useState(""),[J,C]=a.useState(!1),[g,j]=a.useState(null),[q,G]=a.useState({}),[Q,le]=a.useState(ns),[te,W]=a.useState(1),Z=a.useRef(""),l=a.useRef({}),S=a.useRef(u),D=a.useRef(!1),P=a.useRef(n),X=_e({getKey:d=>{const p=d.album,s=p?.artistName||"",o=p?.title||"";return`${s}-${o}`},hashFields:["album","tracks","totals"]}),[ie,ee]=a.useState([]),[f,i]=a.useState([]),[x,R]=a.useState(!1),[I,$]=a.useState(0),[U,he]=a.useState(""),[re,we]=a.useState(null),ye=_e({getKey:d=>{const p=d.album,s=p?.artistName||"",o=p?.title||"";return`${d.__instance}-${s}-${o}`},hashFields:["__instance","album","tracks","totals"]}),Re=_e({getKey:d=>`${d.__instance}-${d.artistName}-${d.albumTitle}-${d.trackNumber}`,hashFields:["__instance","artistName","albumTitle","trackNumber","title","hasFile","monitored","reason"]}),[me,Y]=a.useState(!1),[fe,Ae]=a.useState("all"),[be,De]=a.useState({available:0,monitored:0,missing:0,total:0}),pe=a.useCallback(async()=>{try{const d=await cs();d.ready===!1&&!D.current?(D.current=!0,t("Lidarr backend is still initialising. Check the logs if this persists.","info")):d.ready&&(D.current=!0);const p=(d.arr||[]).filter(s=>s.type==="lidarr");if(T(p),!p.length){M("aggregate"),B(null),ee([]),De({available:0,monitored:0,missing:0,total:0});return}n===""?M(p.length===1?p[0].category:"aggregate"):n!=="aggregate"&&!p.some(s=>s.category===n)&&M(p[0].category)}catch(d){t(d instanceof Error?d.message:"Unable to load Lidarr instances","error")}},[t,n]),Se=a.useCallback(async(d,p,s,o,c)=>{if(o.length)try{const E=[];for(const _ of o){const O=await es(d,_,s,p),k=O.page??_;if(E.push({page:k,albums:O.albums??[]}),Z.current!==c)return}if(Z.current!==c)return;G(_=>{const O={..._};let k=!1;for(const{page:z,albums:H}of E){const oe=X.syncData(H);oe.hasChanges&&(O[z]=oe.data,k=!0)}return l.current=O,k?O:_})}catch(E){t(E instanceof Error?E.message:`Failed to load additional pages for ${d}`,"error")}},[t]),Ce=a.useCallback(async(d,p,s,o={})=>{const c=o.preloadAll!==!1;(o.showLoading??!0)&&C(!0);try{const _=`${d}::${s}`,O=Z.current!==_;O&&(Z.current=_,G(()=>(l.current={},{})));const k=await es(d,p,ns,s);B(k);const z=k.page??p;A(z),ge(s);const H=k.page_size??ns,oe=k.total??(k.albums??[]).length,w=Math.max(1,Math.ceil((oe||0)/H));le(H),W(w);const se=k.albums??[],ue=O?{}:l.current,xe=X.syncData(se),ae=xe.hasChanges;if(O&&X.reset(),(O||ae)&&(G(V=>{const je={...O?{}:V,[z]:xe.data};return l.current=je,je}),j(new Date().toLocaleTimeString())),c){const V=[];for(let de=0;de<w;de+=1)de!==z&&(ue[de]||V.push(de));Se(d,s,H,V,_)}}catch(_){t(_ instanceof Error?_.message:`Failed to load ${d} albums`,"error")}finally{C(!1)}},[t,Se]),Ne=a.useCallback(async d=>{if(!m.length){ee([]),De({available:0,monitored:0,missing:0,total:0});return}(d?.showLoading??!0)&&R(!0);try{const s=[];let o=0,c=0;for(const w of m){let se=0,ue=!1;const xe=w.name||w.category;for(;se<100;){const ae=await es(w.category,se,xs,"");if(console.log("=== Lidarr API Response ==="),console.log("Instance:",w.category),console.log("Response:",ae),console.log("Albums count:",ae.albums?.length),ae.albums&&ae.albums.length>0&&(console.log("First album entry:",ae.albums[0]),console.log("First album.album:",ae.albums[0].album),console.log("First album.totals:",ae.albums[0].totals),console.log("First album.tracks:",ae.albums[0].tracks)),console.log("========================="),!ue){const de=ae.counts;de&&(o+=de.available??0,c+=de.monitored??0),ue=!0}const V=ae.albums??[];if(V.forEach(de=>{s.push({...de,__instance:xe})}),!V.length||V.length<xs)break;se+=1}}const E=[];s.forEach(w=>{const se=w.album,ue=se?.artistName||"Unknown Artist",xe=se?.title||"Unknown Album",ae=se?.reason,V=se?.qualityProfileId,de=se?.qualityProfileName,je=w.tracks||[];je&&je.length>0&&je.forEach(ce=>{E.push({__instance:w.__instance,artistName:ue,albumTitle:xe,trackNumber:ce.trackNumber||0,title:ce.title||"Unknown Track",duration:ce.duration,hasFile:ce.hasFile||!1,monitored:ce.monitored||!1,reason:ae,qualityProfileId:V,qualityProfileName:de})})});const _=ye.syncData(s),O=_.hasChanges,k=Re.syncData(E),z=k.hasChanges;O&&ee(_.data),z&&i(k.data);const H=N?{available:o,monitored:c,missing:s.length-o,total:s.length}:{available:E.filter(w=>w.hasFile).length,monitored:E.filter(w=>w.monitored).length,missing:E.filter(w=>!w.hasFile).length,total:E.length},oe=be.available!==H.available||be.monitored!==H.monitored||be.missing!==H.missing||be.total!==H.total;oe&&De(H),U!==u&&($(0),he(u)),(O||oe)&&we(new Date().toLocaleTimeString())}catch(s){ee([]),De({available:0,monitored:0,missing:0,total:0}),t(s instanceof Error?s.message:"Failed to load aggregated Lidarr data","error")}finally{R(!1)}},[m,u,t,U,N]);a.useEffect(()=>{r&&pe()},[r,pe]),a.useEffect(()=>{if(!r||!n||n==="aggregate")return;const d=P.current!==n;d&&(l.current={},G({}),W(1),A(0),P.current=n);const p=S.current;Ce(n,d?0:K,p,{preloadAll:!0,showLoading:!0})},[r,n,Ce,K]),a.useEffect(()=>{r&&n==="aggregate"&&Ne()},[r,n,Ne]),Ke(()=>{n==="aggregate"&&F&&Ne({showLoading:!1})},n==="aggregate"&&F?1e3:null),a.useEffect(()=>{if(!r)return;const d=p=>{n==="aggregate"?(he(p),$(0)):n&&(A(0),Ce(n,0,p,{preloadAll:!0,showLoading:!0}))};return y(d),()=>{v(d)}},[r,n,y,v,Ce]),Ke(()=>{if(n&&n!=="aggregate"){if(S.current?.trim?.()||"")return;Ce(n,K,L,{preloadAll:!1,showLoading:!1})}},r&&n&&n!=="aggregate"&&F?1e3:null),a.useEffect(()=>{S.current=u},[u]),a.useEffect(()=>{n==="aggregate"&&he(u)},[n,u]);const Fe=a.useMemo(()=>{let d=ie;if(U){const p=U.toLowerCase();d=d.filter(s=>{const o=s.album,c=(o?.title??"").toString().toLowerCase(),E=(o?.artistName??"").toString().toLowerCase(),_=(s.__instance??"").toLowerCase();return c.includes(p)||E.includes(p)||_.includes(p)})}return me&&(d=d.filter(p=>!p.album?.hasFile)),fe!=="all"&&(fe==="Not being searched"?d=d.filter(p=>{const s=p.album;return s?.reason==="Not being searched"||!s?.reason}):d=d.filter(p=>p.album?.reason===fe)),d},[ie,U,me,fe]),Oe=!!U||fe!=="all",He=a.useMemo(()=>{let d=f;if(U){const p=U.toLowerCase();d=d.filter(s=>s.artistName.toLowerCase().includes(p)||s.albumTitle.toLowerCase().includes(p)||s.title.toLowerCase().includes(p)||s.__instance.toLowerCase().includes(p))}return me&&(d=d.filter(p=>!p.hasFile)),fe!=="all"&&(fe==="Not being searched"?d=d.filter(p=>p.reason==="Not being searched"||!p.reason):d=d.filter(p=>p.reason===fe)),d},[f,U,me,fe]),$e=a.useMemo(()=>{const d=Object.keys(q).map(Number).sort((s,o)=>s-o),p=[];return d.forEach(s=>{q[s]&&p.push(...q[s])}),p},[q]),Ve=a.useMemo(()=>q[K]??[],[q,K]),Qe=a.useCallback(async()=>{if(!(!n||n==="aggregate"))try{await ds(n),t(`Restarted ${n}`,"success")}catch(d){t(d instanceof Error?d.message:`Failed to restart ${n}`,"error")}},[n,t]),We=a.useCallback(d=>{const p=d.target.value||"aggregate";M(p),p!=="aggregate"&&h("")},[M,h]),Ie=n==="aggregate";return e.jsxs("section",{className:"card",children:[e.jsx("div",{className:"card-header",children:"Lidarr"}),e.jsx("div",{className:"card-body",children:e.jsxs("div",{className:"split",children:[e.jsxs("aside",{className:"pane sidebar",children:[m.length>1&&e.jsx("button",{className:`btn ${Ie?"active":""}`,onClick:()=>M("aggregate"),children:"All Lidarr"}),m.map(d=>e.jsx("button",{className:`btn ghost ${n===d.category?"active":""}`,onClick:()=>{M(d.category),h("")},children:d.name||d.category},d.category))]}),e.jsxs("div",{className:"pane",children:[e.jsxs("div",{className:"field mobile-instance-select",children:[e.jsx("label",{children:"Instance"}),e.jsxs("select",{value:n||"aggregate",onChange:We,disabled:!m.length,children:[m.length>1&&e.jsx("option",{value:"aggregate",children:"All Lidarr"}),m.map(d=>e.jsx("option",{value:d.category,children:d.name||d.category},d.category))]})]}),e.jsxs("div",{className:"row",style:{alignItems:"flex-end",gap:"12px",flexWrap:"wrap"},children:[e.jsxs("div",{className:"col field",style:{flex:"1 1 200px"},children:[e.jsx("label",{children:"Search"}),e.jsx("input",{placeholder:"Filter albums",value:u,onChange:d=>h(d.target.value)})]}),e.jsxs("div",{className:"field",style:{flex:"0 0 auto",minWidth:"140px"},children:[e.jsx("label",{children:"Status"}),e.jsxs("select",{onChange:d=>{const p=d.target.value;Y(p==="missing")},value:me?"missing":"all",children:[e.jsx("option",{value:"all",children:"All Albums"}),e.jsx("option",{value:"missing",children:"Missing Only"})]})]}),e.jsxs("div",{className:"field",style:{flex:"0 0 auto",minWidth:"140px"},children:[e.jsx("label",{children:"Search Reason"}),e.jsxs("select",{onChange:d=>Ae(d.target.value),value:fe,children:[e.jsx("option",{value:"all",children:"All Reasons"}),e.jsx("option",{value:"Not being searched",children:"Not Being Searched"}),e.jsx("option",{value:"Missing",children:"Missing"}),e.jsx("option",{value:"Quality",children:"Quality"}),e.jsx("option",{value:"CustomFormat",children:"Custom Format"}),e.jsx("option",{value:"Upgrade",children:"Upgrade"})]})]})]}),Ie?e.jsx(Es,{loading:x,rows:Fe,trackRows:He,page:I,onPageChange:$,onRefresh:()=>void Ne({showLoading:!0}),lastUpdated:re,summary:be,instanceCount:m.length,groupLidarr:N,isAggFiltered:Oe}):e.jsx(Is,{loading:J,data:b,page:K,totalPages:te,pageSize:Q,allAlbums:N?Ve:$e,onlyMissing:me,reasonFilter:fe,onPageChange:d=>{A(d),Ce(n,d,L,{preloadAll:!0})},onRestart:()=>void Qe(),lastUpdated:g,groupLidarr:N,instances:m,selection:n})]})]})})]})}function Us({type:r,active:t}){return r==="radarr"?e.jsx(As,{active:t}):r==="lidarr"?e.jsx(_s,{active:t}):e.jsx($s,{active:t})}export{Us as ArrView};
2
2
  //# sourceMappingURL=ArrView.js.map