qBitrr2 5.4.2__tar.gz → 5.4.3__tar.gz

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.
Files changed (72) hide show
  1. {qbitrr2-5.4.2/qBitrr2.egg-info → qbitrr2-5.4.3}/PKG-INFO +1 -1
  2. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/pyproject.toml +1 -1
  3. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/bundled_data.py +2 -2
  4. qbitrr2-5.4.3/qBitrr/static/assets/app.js +11 -0
  5. qbitrr2-5.4.3/qBitrr/static/assets/app.js.map +1 -0
  6. qbitrr2-5.4.3/qBitrr/static/index.html +47 -0
  7. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/webui.py +7 -3
  8. {qbitrr2-5.4.2 → qbitrr2-5.4.3/qBitrr2.egg-info}/PKG-INFO +1 -1
  9. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/setup.cfg +1 -1
  10. qbitrr2-5.4.2/qBitrr/static/assets/app.js +0 -11
  11. qbitrr2-5.4.2/qBitrr/static/assets/app.js.map +0 -1
  12. qbitrr2-5.4.2/qBitrr/static/index.html +0 -33
  13. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/LICENSE +0 -0
  14. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/MANIFEST.in +0 -0
  15. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/README.md +0 -0
  16. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/config.example.toml +0 -0
  17. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/__init__.py +0 -0
  18. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/arss.py +0 -0
  19. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/auto_update.py +0 -0
  20. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/config.py +0 -0
  21. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/db_lock.py +0 -0
  22. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/env_config.py +0 -0
  23. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/errors.py +0 -0
  24. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/ffprobe.py +0 -0
  25. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/gen_config.py +0 -0
  26. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/home_path.py +0 -0
  27. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/logger.py +0 -0
  28. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/main.py +0 -0
  29. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/search_activity_store.py +0 -0
  30. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/ArrView.js +0 -0
  31. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/ArrView.js.map +0 -0
  32. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/ConfigView.js +0 -0
  33. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/ConfigView.js.map +0 -0
  34. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/LogsView.js +0 -0
  35. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/LogsView.js.map +0 -0
  36. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/ProcessesView.js +0 -0
  37. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/ProcessesView.js.map +0 -0
  38. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/app.css +0 -0
  39. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/build.svg +0 -0
  40. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/check-mark.svg +0 -0
  41. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/close.svg +0 -0
  42. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/download.svg +0 -0
  43. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/gear.svg +0 -0
  44. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/lidarr.svg +0 -0
  45. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/live-streaming.svg +0 -0
  46. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/log.svg +0 -0
  47. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/plus.svg +0 -0
  48. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/process.svg +0 -0
  49. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/react-select.esm.js +0 -0
  50. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/react-select.esm.js.map +0 -0
  51. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/refresh-arrow.svg +0 -0
  52. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/table.js +0 -0
  53. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/table.js.map +0 -0
  54. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/trash.svg +0 -0
  55. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/up-arrow.svg +0 -0
  56. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/useInterval.js +0 -0
  57. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/useInterval.js.map +0 -0
  58. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/vendor.js +0 -0
  59. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/vendor.js.map +0 -0
  60. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/assets/visibility.svg +0 -0
  61. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/manifest.json +0 -0
  62. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/sw.js +0 -0
  63. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/static/vite.svg +0 -0
  64. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/tables.py +0 -0
  65. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/utils.py +0 -0
  66. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr/versioning.py +0 -0
  67. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr2.egg-info/SOURCES.txt +0 -0
  68. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr2.egg-info/dependency_links.txt +0 -0
  69. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr2.egg-info/entry_points.txt +0 -0
  70. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr2.egg-info/requires.txt +0 -0
  71. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/qBitrr2.egg-info/top_level.txt +0 -0
  72. {qbitrr2-5.4.2 → qbitrr2-5.4.3}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qBitrr2
3
- Version: 5.4.2
3
+ Version: 5.4.3
4
4
  Summary: Intelligent automation for qBittorrent and *Arr apps (Radarr/Sonarr/Lidarr) - health monitoring, instant imports, quality upgrades, request integration
5
5
  Home-page: https://github.com/Feramance/qBitrr
6
6
  Author: Feramance
@@ -28,7 +28,7 @@ target-version = ['py312']
28
28
 
29
29
  [tool.poetry]
30
30
  name = "pypi-public"
31
- version = "5.4.2"
31
+ version = "5.4.3"
32
32
  description = "Intelligent automation for qBittorrent and *Arr apps (Radarr/Sonarr/Lidarr) - health monitoring, instant imports, quality upgrades, request integration"
33
33
  authors = ["Drapersniper", "Feramance"]
34
34
  readme = "README.md"
@@ -1,5 +1,5 @@
1
- version = "5.4.2"
2
- git_hash = "c96179b9"
1
+ version = "5.4.3"
2
+ git_hash = "eb7a9ae5"
3
3
  license_text = (
4
4
  "Licence can be found on:\n\nhttps://github.com/Feramance/qBitrr/blob/master/LICENSE"
5
5
  )
@@ -0,0 +1,11 @@
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/ProcessesView.js","assets/table.js","assets/vendor.js","assets/useInterval.js","assets/LogsView.js","assets/react-select.esm.js","assets/ArrView.js","assets/ConfigView.js"])))=>i.map(i=>d[i]);
2
+ import{r as Ee,a as Re}from"./vendor.js";import{r as o}from"./table.js";(function(){const r=document.createElement("link").relList;if(r&&r.supports&&r.supports("modulepreload"))return;for(const s of document.querySelectorAll('link[rel="modulepreload"]'))i(s);new MutationObserver(s=>{for(const a of s)if(a.type==="childList")for(const f of a.addedNodes)f.tagName==="LINK"&&f.rel==="modulepreload"&&i(f)}).observe(document,{childList:!0,subtree:!0});function n(s){const a={};return s.integrity&&(a.integrity=s.integrity),s.referrerPolicy&&(a.referrerPolicy=s.referrerPolicy),s.crossOrigin==="use-credentials"?a.credentials="include":s.crossOrigin==="anonymous"?a.credentials="omit":a.credentials="same-origin",a}function i(s){if(s.ep)return;s.ep=!0;const a=n(s);fetch(s.href,a)}})();var F={exports:{}},P={};/**
3
+ * @license React
4
+ * react-jsx-runtime.production.min.js
5
+ *
6
+ * Copyright (c) Facebook, Inc. and its affiliates.
7
+ *
8
+ * This source code is licensed under the MIT license found in the
9
+ * LICENSE file in the root directory of this source tree.
10
+ */var se;function Le(){if(se)return P;se=1;var e=Ee(),r=Symbol.for("react.element"),n=Symbol.for("react.fragment"),i=Object.prototype.hasOwnProperty,s=e.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,a={key:!0,ref:!0,__self:!0,__source:!0};function f(h,m,c){var p,w={},d=null,g=null;c!==void 0&&(d=""+c),m.key!==void 0&&(d=""+m.key),m.ref!==void 0&&(g=m.ref);for(p in m)i.call(m,p)&&!a.hasOwnProperty(p)&&(w[p]=m[p]);if(h&&h.defaultProps)for(p in m=h.defaultProps,m)w[p]===void 0&&(w[p]=m[p]);return{$$typeof:r,type:h,key:d,ref:g,props:w,_owner:s.current}}return P.Fragment=n,P.jsx=f,P.jsxs=f,P}var ne;function Ne(){return ne||(ne=1,F.exports=Le()),F.exports}var t=Ne(),q={},oe;function Ie(){if(oe)return q;oe=1;var e=Re();return q.createRoot=e.createRoot,q.hydrateRoot=e.hydrateRoot,q}var Te=Ie();const Pe="modulepreload",Ue=function(e){return"/static/"+e},ae={},W=function(r,n,i){let s=Promise.resolve();if(n&&n.length>0){let m=function(c){return Promise.all(c.map(p=>Promise.resolve(p).then(w=>({status:"fulfilled",value:w}),w=>({status:"rejected",reason:w}))))};document.getElementsByTagName("link");const f=document.querySelector("meta[property=csp-nonce]"),h=f?.nonce||f?.getAttribute("nonce");s=m(n.map(c=>{if(c=Ue(c),c in ae)return;ae[c]=!0;const p=c.endsWith(".css"),w=p?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${c}"]${w}`))return;const d=document.createElement("link");if(d.rel=p?"stylesheet":Pe,p||(d.as="script"),d.crossOrigin="",d.href=c,h&&d.setAttribute("nonce",h),document.head.appendChild(d),p)return new Promise((g,v)=>{d.addEventListener("load",g),d.addEventListener("error",()=>v(new Error(`Unable to preload CSS for ${c}`)))})}))}function a(f){const h=new Event("vite:preloadError",{cancelable:!0});if(h.payload=f,window.dispatchEvent(h),!h.defaultPrevented)throw f}return s.then(f=>{for(const h of f||[])h.status==="rejected"&&a(h.reason);return r().catch(a)})},ue=o.createContext(void 0);let $e=0;function Ae({children:e}){const[r,n]=o.useState([]),i=o.useCallback(f=>{n(h=>h.filter(m=>m.id!==f))},[]),s=o.useCallback((f,h="info")=>{const m=++$e;n(c=>[...c,{id:m,message:f,kind:h}]),window.setTimeout(()=>i(m),3500)},[i]),a=o.useMemo(()=>({toasts:r,push:s,dismiss:i}),[r,s,i]);return t.jsx(ue.Provider,{value:a,children:e})}function de(){const e=o.useContext(ue);if(!e)throw new Error("useToast must be used within a ToastProvider");return e}function Oe(){const{toasts:e,dismiss:r}=de();return e.length?t.jsx("div",{className:"toasts",children:e.map(n=>t.jsx("div",{className:`toast ${n.kind!=="info"?n.kind:""}`,role:"status",onClick:()=>r(n.id),children:n.message},n.id))}):null}const fe=o.createContext(void 0);function De({children:e}){const[r,n]=o.useState(""),i=o.useRef(new Set),s=o.useCallback(m=>{n(m),i.current.forEach(c=>{c?.(m)})},[]),a=o.useCallback(m=>{m&&i.current.add(m)},[]),f=o.useCallback(m=>{i.current.delete(m)},[]),h=o.useMemo(()=>({value:r,setValue:s,register:a,clearHandler:f}),[r,s,a,f]);return t.jsx(fe.Provider,{value:h,children:e})}function Ve(){const e=o.useContext(fe);if(!e)throw new Error("useSearch must be used within a SearchProvider");return e}const Me={"Content-Type":"application/json"},Y=["token","webui-token","webui_token"],qe=1,J=new Map;function Be(e,r){const n=e instanceof Request?e.url:String(e),i=r?.method||"GET",s=r?.body?String(r.body):"";return`${i}:${n}:${s}`}function me(){for(const e of Y){const r=localStorage.getItem(e)||sessionStorage.getItem(e);if(r)return e!=="token"&&localStorage.setItem("token",r),r}try{const r=new URLSearchParams(window.location.search).get("token");if(r)return localStorage.setItem("token",r),r}catch{}return null}function We(){for(const e of Y)localStorage.removeItem(e);try{for(const e of Y)sessionStorage.removeItem(e)}catch{}}function he(e,r){const n=new Headers(e?.headers||{});return Object.entries(Me).forEach(([i,s])=>{n.has(i)||n.set(i,s)}),r&&!n.has("Authorization")&&n.set("Authorization",`Bearer ${r}`),{...e,headers:n}}async function B(e,r,n,i=qe){const s=me(),a=await fetch(e,he(r,s));return a.status===401&&i>0&&s?(We(),B(e,r,n,i-1)):n(a)}async function k(e,r){if((r?.method||"GET")==="GET"){const i=Be(e,r),s=J.get(i);if(s)return s;const a=B(e,r,f=>ce(f)).finally(()=>{J.delete(i)});return J.set(i,a),a}return B(e,r,i=>ce(i))}async function Ge(e,r){return B(e,r,n=>He(n))}async function ce(e){if(!e.ok){let r=null;try{r=await e.json()}catch{}let n=`${e.status} ${e.statusText}`;if(r&&typeof r=="object"&&"error"in r&&typeof r.error=="string"){const i=r.error;i.trim()&&(n=i)}throw new Error(n)}return await e.json()}async function He(e){if(!e.ok)throw new Error(`${e.status} ${e.statusText}`);return e.text()}async function ie(e){const r=e?.force?"?force=1":"";return k(`/web/meta${r}`)}async function le(){return k("/web/status")}async function gt(){return k("/web/processes")}async function pt(e,r){const n=`/web/processes/${encodeURIComponent(e)}/${encodeURIComponent(r)}/restart`;return k(n,{method:"POST"})}async function vt(){return k("/web/processes/restart_all",{method:"POST"})}async function wt(){return k("/web/arr/rebuild",{method:"POST"})}async function yt(){return k("/web/logs")}async function bt(e){return Ge(`/web/logs/${encodeURIComponent(e)}`)}function xt(e){return`/web/logs/${encodeURIComponent(e)}/download`}async function _t(){return k("/web/arr")}async function jt(e,r,n,i){const s=new URLSearchParams;return s.set("page",String(r)),s.set("page_size",String(n)),i&&s.set("q",i),k(`/web/radarr/${encodeURIComponent(e)}/movies?${s}`)}async function kt(e,r,n,i,s){const a=new URLSearchParams;return a.set("page",String(r)),a.set("page_size",String(n)),i&&a.set("q",i),s?.missingOnly&&a.set("missing","1"),k(`/web/sonarr/${encodeURIComponent(e)}/series?${a}`)}async function Ct(e,r,n,i){const s=new URLSearchParams;return s.set("page",r.toString()),s.set("page_size",n.toString()),i&&s.set("q",i),s.set("include_tracks","true"),k(`/web/lidarr/${encodeURIComponent(e)}/albums?${s}`)}async function St(e){await k(`/web/arr/${encodeURIComponent(e)}/restart`,{method:"POST"})}async function ze(){return k("/web/config")}async function Fe(e){const r=me(),n=await fetch("/web/config",he({method:"POST",body:JSON.stringify(e)},r));if(!n.ok){let s=null;try{s=await n.json()}catch{}let a=`${n.status} ${n.statusText}`;if(s&&typeof s=="object"&&"error"in s&&typeof s.error=="string"){const f=s.error;f.trim()&&(a=f)}throw new Error(a)}return await n.json()}async function Je(){await k("/web/update",{method:"POST"})}const ge=o.createContext(null);function Ke({children:e}){const[r,n]=o.useState({liveArr:!0,groupSonarr:!0,groupLidarr:!0,viewDensity:"comfortable",theme:"dark"}),[i,s]=o.useState(!0);o.useEffect(()=>{(async()=>{try{const v=(await ze())?.WebUI,x=localStorage.getItem("viewDensity"),S=localStorage.getItem("theme"),I=v?.Theme,E=S||I?.toLowerCase()||"dark";n({liveArr:v?.LiveArr===!0,groupSonarr:v?.GroupSonarr===!0,groupLidarr:v?.GroupLidarr===!0,viewDensity:x||"comfortable",theme:E}),document.documentElement.setAttribute("data-theme",E)}catch(g){console.error("Failed to load WebUI settings:",g)}finally{s(!1)}})()},[]);const a=o.useCallback(async(d,g)=>{try{const v={WebUI:{[d]:g}};await Fe({changes:v})}catch(v){console.error(`Failed to save ${d}:`,v)}},[]),f=o.useCallback(d=>{n(g=>({...g,liveArr:d})),a("LiveArr",d)},[a]),h=o.useCallback(d=>{n(g=>({...g,groupSonarr:d})),a("GroupSonarr",d)},[a]),m=o.useCallback(d=>{n(g=>({...g,groupLidarr:d})),a("GroupLidarr",d)},[a]),c=o.useCallback(d=>{n(g=>({...g,viewDensity:d})),localStorage.setItem("viewDensity",d)},[]),p=o.useCallback(d=>{n(v=>({...v,theme:d})),localStorage.setItem("theme",d),document.documentElement.setAttribute("data-theme",d),a("Theme",d==="light"?"Light":"Dark")},[a]),w={liveArr:r.liveArr,groupSonarr:r.groupSonarr,groupLidarr:r.groupLidarr,viewDensity:r.viewDensity,theme:r.theme,setLiveArr:f,setGroupSonarr:h,setGroupLidarr:m,setViewDensity:c,setTheme:p,loading:i};return t.jsx(ge.Provider,{value:w,children:e})}function Ye(){const e=o.useContext(ge);if(!e)throw new Error("useWebUI must be used within WebUIProvider");return e}function Qe(){const[e,r]=o.useState(navigator.onLine);return o.useEffect(()=>{const n=()=>r(!0),i=()=>r(!1);return window.addEventListener("online",n),window.addEventListener("offline",i),()=>{window.removeEventListener("online",n),window.removeEventListener("offline",i)}},[]),e}function C({src:e,alt:r,className:n,...i}){return t.jsx("img",{src:e,alt:r??"",className:n?`icon ${n}`:"icon","aria-hidden":r?void 0:!0,...i})}const Xe="/static/assets/close.svg",Q="data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20xml:space='preserve'%20viewBox='0%200%20512%20512'%3e%3cpath%20d='M256%206.3C114.6%206.3%200%20120.9%200%20262.3c0%20113.3%2073.3%20209%20175%20242.9%2012.8%202.2%2017.6-5.4%2017.6-12.2%200-6.1-.3-26.2-.3-47.7-64.3%2011.8-81-15.7-86.1-30.1-2.9-7.4-15.4-30.1-26.2-36.2-9-4.8-21.8-16.6-.3-17%2020.2-.3%2034.6%2018.6%2039.4%2026.2%2023%2038.7%2059.8%2027.8%2074.6%2021.1%202.2-16.6%209-27.8%2016.3-34.2-57-6.4-116.5-28.5-116.5-126.4%200-27.8%209.9-50.9%2026.2-68.8-2.6-6.4-11.5-32.6%202.6-67.8%200%200%2021.4-6.7%2070.4%2026.2%2020.5-5.8%2042.2-8.6%2064-8.6s43.5%202.9%2064%208.6c49-33.3%2070.4-26.2%2070.4-26.2%2014.1%2035.2%205.1%2061.4%202.6%2067.8%2016.3%2017.9%2026.2%2040.6%2026.2%2068.8%200%2098.2-59.8%20120-116.8%20126.4%209.3%208%2017.3%2023.4%2017.3%2047.4%200%2034.2-.3%2061.8-.3%2070.4%200%206.7%204.8%2014.7%2017.6%2012.2C438.7%20471.3%20512%20375.3%20512%20262.3c0-141.4-114.6-256-256-256'%20style='fill-rule:evenodd;clip-rule:evenodd;fill:%231b1f23'/%3e%3c/svg%3e",Ze="/static/assets/refresh-arrow.svg",pe="/static/assets/up-arrow.svg",et="/static/assets/process.svg",tt="/static/assets/log.svg",rt="data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20xml:space='preserve'%20id='Layer_1'%20x='0'%20y='0'%20version='1.1'%20viewBox='0%200%20512%20512'%3e%3cstyle%3e.st0{fill:%2324292e}%3c/style%3e%3cg%20id='Group-Copy'%20transform='translate(70%2021)'%3e%3cpath%20id='Shape'%20d='m10.3%2059.8%203.9%20372.4c-31.4%203.9-54.9-11.8-54.9-43.1l-3.9-309.7c0-98%2090.2-121.5%20145.1-82.3l278.3%20160.7c39.2%2027.4%2047%2078.4%2027.4%20113.7-3.9-27.4-15.7-43.1-39.2-58.8L53.4%2036.2C29.9%2020.6%2010.3%2024.5%2010.3%2059.8'%20class='st0'/%3e%3cpath%20id='Shape_00000114049535938561773820000018271523940913105341_'%20d='M-13.2%20451.8c23.5%207.8%2047%203.9%2066.6-7.8l321.5-188.2c19.6%2027.4%2015.7%2054.9-7.8%2070.6L96.5%20483.2c-39.2%2019.6-90.1%200-109.7-31.4'%20class='st0'/%3e%3cpath%20id='Shape_00000165935924413286433040000003668002807793862576_'%20d='M80.9%20342%20273%20232.3%2084.8%20126.4z'%20style='fill:%23ffc230'/%3e%3c/g%3e%3c/svg%3e",st="data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20xml:space='preserve'%20viewBox='0%200%20512%20512'%3e%3cpath%20d='M511.8%20256c0%2070.4-24.9%20130.8-74.6%20181.1-1.7%202-3.5%203.8-5.5%205.4-8.2%208-16.8%2015.3-26%2021.8Q341.05%20512%20256.3%20512c-56.6%200-106.3-15.9-149.2-47.7-11.3-8-22-17.1-31.9-27.3C36.5%20398.7%2012.8%20354%204%20303.2c-1.7-9.9-2.9-20-3.4-30.2-.2-5.7-.4-11.3-.4-17%200-6%20.1-11.7.4-17.1%200-.6.2-1.1.5-1.7%203.7-62.8%2028.4-117%2074.1-162.8C125.5%2024.8%20185.8%200%20256.2%200c70.7%200%20131%2024.8%20180.9%2074.5q74.7%2075.9%2074.7%20181.5'%20style='fill-rule:evenodd;clip-rule:evenodd;fill:%23eee'/%3e%3cpath%20d='m459.7%20100.3-52.9%2052.9c-30.9%2030.9-33.6%2057.8-33.6%20105.3%200%2042.3%206.7%2081.1%2038.2%20112.6%2023%2023%2044.9%2044.7%2044.9%2044.7-5.9%207.2-12.3%2014.3-19.1%2021.2-1.7%202-3.5%203.8-5.5%205.4-6%205.9-12.2%2011.4-18.6%2016.4l-41.4-41.4C334.9%20380.6%20305.6%20377%20257%20377c-46.7%200-78.4%204.3-112.6%2038.5-20.4%2020.4-43.8%2043.9-43.8%2043.9-8.9-6.8-17.3-14.2-25.3-22.4-6.6-6.6-12.8-13.4-18.5-20.3%200%200%2023.1-23.2%2045.2-45.3%2032.7-32.7%2038-70.6%2038-113%200-41.3-6.8-79.8-36.8-109.9C82.2%20127.7%2053.3%2099%2053.3%2099c6.7-8.5%2014-16.7%2021.8-24.5%206.9-6.8%2014-13.1%2021.2-19l48%2048c30.7%2030.7%2070%2038.6%20112.4%2038.6%2043.6%200%2082.8-8.4%20114.7-40.4C391%2082.1%20417%2056.3%20417%2056.3c6.8%205.6%2013.5%2011.6%2020.1%2018.2%208.3%208.3%2015.8%2016.9%2022.6%2025.8'%20style='fill-rule:evenodd;clip-rule:evenodd;fill:%233a3f51'/%3e%3cpath%20d='M186%20269.1c-.5-2.8-.8-5.5-.9-8.4-.1-1.6-.1-3.1-.1-4.7%200-1.7%200-3.2.1-4.7%200-.2%200-.3.1-.5%201-17.4%207.9-32.4%2020.5-45.1%2013.9-13.8%2030.6-20.7%2050.2-20.7s36.3%206.9%2050.2%2020.7c13.8%2014%2020.7%2030.8%2020.7%2050.3s-6.9%2036.2-20.7%2050.2c-.5.5-1%201.1-1.5%201.5q-3.45%203.3-7.2%206-18%2013.2-41.4%2013.2c-23.4%200-29.4-4.4-41.3-13.2-3.1-2.2-6.1-4.7-8.9-7.6-10.8-10.6-17.3-22.9-19.8-37'%20style='fill-rule:evenodd;clip-rule:evenodd;fill:%230cf'/%3e%3cpath%20d='m372.7%20141-35.4%2034.6M72.9%2076.8l96.5%2096.1m199.7%20198.9%2065.6%2067.9m4.4-363.3L372.7%20141M76.6%20438.5l64.6-64.7'%20style='fill:none;stroke:%230cf;stroke-width:2;stroke-miterlimit:1'/%3e%3cpath%20d='m372.7%20141-40%2040.6m-193.3-38.5%2040.6%2040.5M141%20374l39.5-41.1m146.2-3.3%2042.6%2042.4'%20style='fill:none;stroke:%230cf;stroke-width:7;stroke-miterlimit:1'/%3e%3c/svg%3e",nt="/static/assets/lidarr.svg",ot="/static/assets/gear.svg",at=o.lazy(()=>W(()=>import("./ProcessesView.js"),__vite__mapDeps([0,1,2,3])).then(e=>({default:e.ProcessesView}))),ct=o.lazy(()=>W(()=>import("./LogsView.js"),__vite__mapDeps([4,1,2,5,3])).then(e=>({default:e.LogsView}))),K=o.lazy(()=>W(()=>import("./ArrView.js"),__vite__mapDeps([6,1,2,3])).then(e=>({default:e.ArrView}))),it=o.lazy(()=>W(()=>import("./ConfigView.js"),__vite__mapDeps([7,1,2,5])).then(e=>({default:e.ConfigView})));function U(e){if(!e)return"unknown";const r=e.trim();return r?r[0]==="v"||r[0]==="V"?r:`v${r}`:"unknown"}function lt({currentVersion:e,changelog:r,changelogUrl:n,repositoryUrl:i,onClose:s}){return t.jsx("div",{className:"modal-backdrop",role:"presentation",onClick:s,children:t.jsxs("div",{className:"modal",role:"dialog","aria-modal":"true","aria-labelledby":"welcome-title",onClick:a=>a.stopPropagation(),children:[t.jsx("div",{className:"modal-header",children:t.jsxs("h2",{id:"welcome-title",children:["🎉 Welcome to qBitrr ",U(e),"!"]})}),t.jsxs("div",{className:"modal-body changelog-modal__body",children:[t.jsx("div",{className:"changelog-meta",children:t.jsxs("p",{style:{marginBottom:"1rem",color:"var(--text-secondary)"},children:["You've been updated to version ",t.jsx("strong",{children:U(e)}),". Here's what's new in this release:"]})}),t.jsxs("div",{className:"changelog-section",children:[t.jsx("h3",{children:"Release Notes"}),t.jsx("pre",{className:"changelog-body",children:r?.trim()?r.trim():"No changelog available for this version."})]})]}),t.jsxs("div",{className:"modal-footer",children:[t.jsx("div",{className:"changelog-links",children:(n||i)&&t.jsxs("a",{className:"btn ghost small",href:n??i,target:"_blank",rel:"noreferrer",children:[t.jsx(C,{src:Q}),"View Full Release on GitHub"]})}),t.jsx("div",{className:"changelog-buttons",children:t.jsx("button",{className:"btn primary",type:"button",onClick:s,children:"Got it!"})})]})]})})}function ut({currentVersion:e,latestVersion:r,changelog:n,changelogUrl:i,repositoryUrl:s,updateState:a,updating:f,onClose:h,onUpdate:m}){const[c,p]=o.useState(null),w=f||!!a?.in_progress,d=a?.completed_at?new Date(a.completed_at).toLocaleString():null;o.useEffect(()=>{if(a?.last_result==="success"&&a?.completed_at){let x=10;p(x);const S=setInterval(()=>{x-=1,x<=0?(clearInterval(S),window.location.reload()):p(x)},1e3);return()=>clearInterval(S)}},[a?.last_result,a?.completed_at]);let g="",v=null;if(a?.in_progress)g="text-info",v="⏳ Update in progress...";else if(a?.last_result==="success")g="text-success",c!==null?v=`✓ Update completed! Reloading in ${c}s...`:(v="✓ Update completed successfully",d&&(v=`${v} (${d})`));else if(a?.last_result==="error"){g="text-danger";const x=a.last_error?a.last_error.trim():"";v=x?`✗ Update failed: ${x}`:"✗ Update failed"}return t.jsx("div",{className:"modal-backdrop",role:"presentation",onClick:h,children:t.jsxs("div",{className:"modal",role:"dialog","aria-modal":"true","aria-labelledby":"changelog-title",onClick:x=>x.stopPropagation(),children:[t.jsxs("div",{className:"modal-header",children:[t.jsx("h2",{id:"changelog-title",children:a?.in_progress?"⚙️ Updating...":"🚀 Update Available"}),t.jsxs("button",{className:"btn ghost",type:"button",onClick:h,disabled:a?.in_progress,children:[t.jsx(C,{src:Xe}),"Close"]})]}),t.jsxs("div",{className:"modal-body changelog-modal__body",children:[t.jsxs("div",{className:"changelog-meta",children:[t.jsxs("div",{className:"version-comparison",children:[t.jsxs("span",{className:"version-item",children:[t.jsx("strong",{children:"Current:"})," ",t.jsx("span",{className:"version-badge version-current",children:U(e)})]}),t.jsx("span",{className:"version-arrow",children:"→"}),t.jsxs("span",{className:"version-item",children:[t.jsx("strong",{children:"Latest:"})," ",t.jsx("span",{className:"version-badge version-latest",children:r?U(r):"Unknown"})]})]}),v?t.jsx("div",{className:`update-status ${g}`,children:v}):null]}),t.jsxs("div",{className:"changelog-section",children:[t.jsx("h3",{children:"What's New"}),t.jsx("pre",{className:"changelog-body",children:n?.trim()?n.trim():"No changelog provided."})]})]}),t.jsxs("div",{className:"modal-footer",children:[t.jsx("div",{className:"changelog-links",children:(i||s)&&t.jsxs("a",{className:"btn ghost small",href:i??s,target:"_blank",rel:"noreferrer",children:[t.jsx(C,{src:Q}),"View on GitHub"]})}),t.jsx("div",{className:"changelog-buttons",children:t.jsxs("button",{className:"btn primary",type:"button",onClick:m,disabled:w,children:[t.jsx(C,{src:pe}),w?"Updating...":"Update Now"]})})]})]})})}function dt(){const[e,r]=o.useState("processes"),[n,i]=o.useState(!1),{push:s}=de(),{setValue:a}=Ve(),{viewDensity:f,setViewDensity:h}=Ye(),m=Qe(),[c,p]=o.useState(null),[w,d]=o.useState(!1),[g,v]=o.useState(!1),[x,S]=o.useState(!1),[I,E]=o.useState(!1),R=o.useRef(0),G=o.useRef(null),H=o.useRef(!1),$=o.useRef(!1),L=o.useRef(null),[N,X]=o.useState(0),[Z,ee]=o.useState(null),[ve,te]=o.useState(!1);o.useEffect(()=>{(async()=>{if("caches"in window)try{const l=await caches.keys();await Promise.all(l.map(b=>caches.delete(b))),console.log("Cache cleared on page load")}catch(l){console.error("Failed to clear cache:",l)}})()},[]);const _=o.useCallback(async u=>{const l=u?.force??!1,b=u?.silent??!l;b||d(!0);try{const j=await ie({force:l});p(j)}catch(j){if(!b){const y=j instanceof Error?j.message:"Failed to fetch version information";s(y,"error")}}finally{b||d(!1)}},[s]);o.useEffect(()=>{_({force:!0})},[_]),o.useEffect(()=>{if(!c?.current_version)return;const u=localStorage.getItem("lastSeenVersion"),l=c.current_version;u&&u!==l&&(!c.current_version_changelog&&!c.changelog&&_({force:!0,silent:!0}),te(!0)),u||localStorage.setItem("lastSeenVersion",l)},[c?.current_version,c?.changelog,_]),o.useEffect(()=>{m||s("You are offline. Some features may not work.","warning")},[m,s]),o.useEffect(()=>{const u=l=>{if(l.target instanceof HTMLInputElement||l.target instanceof HTMLTextAreaElement||l.target instanceof HTMLSelectElement)return;const b=l.ctrlKey||l.metaKey;if(b&&l.key==="k"){l.preventDefault(),document.querySelector('input[type="text"][placeholder*="Search"]')?.focus();return}if(l.key==="r"||l.key==="R"){l.preventDefault(),X(j=>j+1),s("Refreshed","success");return}if(l.key==="Escape"){a("");return}if(l.key>="1"&&l.key<="6"&&!b){l.preventDefault();const j=parseInt(l.key)-1,y=["processes","logs","radarr","sonarr","lidarr","config"];j<y.length&&r(y[j]);return}};return window.addEventListener("keydown",u),()=>window.removeEventListener("keydown",u)},[a,s]),o.useEffect(()=>{const u=window.setInterval(()=>{_()},3e5);return()=>window.clearInterval(u)},[_]),o.useEffect(()=>{const u=()=>{document.visibilityState==="visible"&&(X(l=>l+1),_({force:!0}),A())};return document.addEventListener("visibilitychange",u),()=>{document.removeEventListener("visibilitychange",u)}},[_]);const A=o.useCallback(async()=>{try{const u=await le();ee(u)}catch{}},[]);o.useEffect(()=>{A();const u=window.setInterval(()=>{A()},5*1e3);return()=>window.clearInterval(u)},[A]),o.useEffect(()=>{if(!c?.update_state?.in_progress&&!I){R.current=0;return}const u=window.setInterval(async()=>{try{const l=await ie({force:!0});p(l),I&&window.location.reload(),R.current=0}catch{if(R.current+=1,R.current>20){E(!1),R.current=0,s("Update completed but backend restart timed out. Please refresh the page manually.","warning");return}c?.update_state?.in_progress&&E(!0)}},3e3);return()=>window.clearInterval(u)},[c?.update_state?.in_progress,I,c,s]),o.useEffect(()=>{const u=c?.update_state;if(!u){G.current=null;return}const l=u.last_result??null;l&&l!==G.current&&(l==="success"?(s("Update completed successfully. Restarting...","success"),E(!0),R.current=0):l==="error"&&s(u.last_error||"Update failed.","error")),G.current=l},[c?.update_state,s]),o.useEffect(()=>{let u=!1,l=0;const b=y=>{L.current!==null&&window.clearTimeout(L.current),L.current=window.setTimeout(()=>{j()},y)},j=async()=>{if(!(u||H.current)){l+=1;try{const y=await le();if(u)return;if(ee(y),y.ready??(Array.isArray(y.arrs)&&y.arrs.length>0)){H.current=!0;return}y.ready===!1&&l>=3&&!$.current&&($.current=!0,s("qBitrr backend is still initialising. Check the logs if this persists.","warning"))}catch(y){if(!$.current&&l>=3){$.current=!0;const M=y instanceof Error?y.message:"Unknown backend error";s(`Unable to confirm qBitrr readiness (${M}). Please inspect the logs.`,"warning")}}finally{if(!u&&!H.current){const y=l<3?3e3:1e4;b(y)}}}};return b(0),()=>{u=!0,L.current!==null&&(window.clearTimeout(L.current),L.current=null)}},[s]);const O=o.useMemo(()=>{const u=[{id:"processes",label:"Processes",icon:et},{id:"logs",label:"Logs",icon:tt}],l=[],b=Z?.arrs??[],j=b.some(T=>T.type==="radarr"),y=b.some(T=>T.type==="sonarr"),M=b.some(T=>T.type==="lidarr");return j&&l.push({id:"radarr",label:"Radarr",icon:rt}),y&&l.push({id:"sonarr",label:"Sonarr",icon:st}),M&&l.push({id:"lidarr",label:"Lidarr",icon:nt}),[...u,...l,{id:"config",label:"Config",icon:ot}]},[Z]),D=c?.repository_url??"https://github.com/Feramance/qBitrr",we=c?.current_version?U(c.current_version):"...",ye=c?.latest_version??null,be=!!c?.update_available,z=c?.update_state,re=c?.changelog_url??D,V=[];c?.last_checked&&V.push(`Last checked ${new Date(c.last_checked).toLocaleString()}`),c?.error&&V.push(`Update check failed: ${c.error}`);const xe=V.length?V.join(" • "):void 0;o.useEffect(()=>{!O.some(l=>l.id===e)&&O.length>0&&r("processes")},[O,e]);const _e=o.useCallback(()=>{_({force:!0})},[_]),je=o.useCallback(()=>{v(!0),c?.changelog||_({force:!0,silent:!0})},[c?.changelog,_]),ke=o.useCallback(()=>{v(!1)},[]),Ce=o.useCallback(()=>{te(!1),c?.current_version&&localStorage.setItem("lastSeenVersion",c.current_version)},[c?.current_version]),Se=o.useCallback(async()=>{S(!0),E(!1),R.current=0;try{await Je(),s("Update started in the background.","info"),await _({force:!0,silent:!0})}catch(u){const l=u instanceof Error?u.message:"Failed to start update";s(l,"error")}finally{S(!1)}},[s,_]);return t.jsxs("div",{"data-density":f,children:[t.jsx("header",{className:"appbar",children:t.jsxs("div",{className:"appbar__inner",children:[t.jsxs("div",{className:"appbar__title",children:[t.jsx("h1",{children:"qBitrr"}),t.jsx("span",{className:"appbar__version",title:xe,children:we}),w?t.jsx("span",{className:"spinner","aria-hidden":"true"}):null,z?.in_progress?t.jsx("span",{className:"appbar__status text-info",children:"Updating..."}):null,be?t.jsxs("button",{type:"button",className:"btn small primary appbar__update",onClick:je,disabled:x||!!z?.in_progress,children:[t.jsx("span",{className:"appbar__update-indicator","aria-hidden":"true"}),t.jsx(C,{src:pe}),"Update available"]}):null]}),t.jsxs("div",{className:"appbar__actions",children:[!m&&t.jsx("span",{className:"badge",style:{background:"rgba(239, 68, 68, 0.15)",borderColor:"rgba(239, 68, 68, 0.3)",color:"var(--danger)"},children:"Offline"}),t.jsxs("div",{className:"view-density-toggle",children:[t.jsx("button",{type:"button",className:f==="comfortable"?"active":"",onClick:()=>h("comfortable"),title:"Comfortable view",children:"Comfortable"}),t.jsx("button",{type:"button",className:f==="compact"?"active":"",onClick:()=>h("compact"),title:"Compact view",children:"Compact"})]}),t.jsxs("button",{type:"button",className:"btn small ghost",onClick:_e,disabled:w,children:[t.jsx(C,{src:Ze}),w?"Checking...":"Check Updates"]}),t.jsxs("a",{href:D,target:"_blank",rel:"noreferrer",className:"btn small ghost",children:[t.jsx(C,{src:Q}),"GitHub"]})]})]})}),t.jsxs("main",{className:"container",children:[t.jsx("nav",{className:"nav",children:O.map(u=>t.jsxs("button",{type:"button",className:e===u.id?"active":"",onClick:()=>{e==="config"&&u.id!=="config"&&n&&!window.confirm("You have unsaved configuration changes. Leave without saving?")||(r(u.id),a(""))},children:[t.jsx(C,{src:u.icon}),t.jsx("span",{children:u.label})]},u.id))}),t.jsxs(o.Suspense,{fallback:t.jsx("div",{className:"loading",children:"Loading..."}),children:[e==="processes"&&t.jsx(at,{active:!0},`processes-${N}`),e==="logs"&&t.jsx(ct,{active:!0},`logs-${N}`),e==="radarr"&&t.jsx(K,{type:"radarr",active:!0},`radarr-${N}`),e==="sonarr"&&t.jsx(K,{type:"sonarr",active:!0},`sonarr-${N}`),e==="lidarr"&&t.jsx(K,{type:"lidarr",active:!0},`lidarr-${N}`),e==="config"&&t.jsx(it,{onDirtyChange:i},`config-${N}`)]})]}),g&&c?t.jsx(ut,{currentVersion:c.current_version,latestVersion:ye,changelog:c.changelog,changelogUrl:re,repositoryUrl:D,updateState:z,updating:x,onClose:ke,onUpdate:Se}):null,ve&&c?t.jsx(lt,{currentVersion:c.current_version,changelog:c.current_version_changelog||c.changelog,changelogUrl:re,repositoryUrl:D,onClose:Ce}):null]})}function ft(){return t.jsx(Ae,{children:t.jsx(De,{children:t.jsxs(Ke,{children:[t.jsx(dt,{}),t.jsx(Oe,{})]})})})}Te.createRoot(document.getElementById("root")).render(t.jsx(o.StrictMode,{children:t.jsx(ft,{})}));export{Xe as C,C as I,Ze as R,le as a,vt as b,wt as c,yt as d,bt as e,xt as f,gt as g,Ve as h,Ye as i,t as j,_t as k,jt as l,St as m,kt as n,Ct as o,ze as p,Fe as q,pt as r,ot as s,de as u};
11
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"mappings":"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","names":["f","require$$0","k","l","m","n","p","q","c","a","g","b","d","e","h","reactJsxRuntime_production_min","jsxRuntimeModule","client","ToastContext","createContext","toastCounter","ToastProvider","children","toasts","setToasts","useState","dismiss","useCallback","id","prev","t","push","message","kind","value","useMemo","jsx","useToast","ctx","useContext","ToastViewport","toast","SearchContext","SearchProvider","setValueState","handlers","useRef","setValue","term","handler","register","clearHandler","valueObj","useSearch","JSON_HEADERS","TOKEN_STORAGE_KEYS","MAX_AUTH_RETRIES","inflightRequests","createRequestKey","input","init","url","method","body","resolveToken","key","fromQuery","clearStoredToken","buildInit","token","headers","fetchWithAuthRetry","retries","response","fetchJson","existingRequest","promise","handleJson","fetchTextResponse","handleText","res","detail","errorText","getMeta","params","query","getStatus","getProcesses","restartProcess","category","restartAllProcesses","rebuildArrs","getLogs","getLogTail","name","getLogDownloadUrl","getArrList","getRadarrMovies","page","pageSize","getSonarrSeries","options","getLidarrAlbums","restartArr","getConfig","updateConfig","payload","triggerUpdate","WebUIContext","WebUIProvider","settings","setSettings","loading","setLoading","useEffect","webui","storedDensity","storedTheme","backendTheme","theme","error","saveSettings","changes","setLiveArr","setGroupSonarr","setGroupLidarr","setViewDensity","setTheme","useWebUI","context","useNetworkStatus","isOnline","setIsOnline","handleOnline","handleOffline","IconImage","src","alt","className","rest","CloseIcon","ExternalIcon","RefreshIcon","UpdateIcon","ProcessesIcon","LogsIcon","RadarrIcon","SonarrIcon","LidarrIcon","ConfigureIcon","ProcessesView","lazy","__vitePreload","module","LogsView","ArrView","ConfigView","formatVersionLabel","trimmed","WelcomeModal","currentVersion","changelog","changelogUrl","repositoryUrl","onClose","jsxs","event","ChangelogModal","latestVersion","updateState","updating","onUpdate","countdown","setCountdown","updateDisabled","completedLabel","timer","statusClass","statusMessage","AppShell","activeTab","setActiveTab","configDirty","setConfigDirty","setSearchValue","viewDensity","meta","setMeta","metaLoading","setMetaLoading","showChangelog","setShowChangelog","updateBusy","setUpdateBusy","backendRestarting","setBackendRestarting","restartPollCount","prevUpdateResult","backendReadyRef","backendWarnedRef","backendTimerRef","reloadKey","setReloadKey","statusData","setStatusData","showWelcomeChangelog","setShowWelcomeChangelog","cacheNames","cacheName","refreshMeta","force","silent","data","lastSeenVersion","handleKeyDown","isMod","tabIndex","tabIds","handleVisibilityChange","refreshStatus","status","state","result","cancelled","attempts","schedule","delay","poll","tabs","baseTabs","arrTabs","arrs","hasRadarr","arr","hasSonarr","hasLidarr","ConfigIcon","displayVersion","updateAvailable","versionTitleParts","versionTitle","tab","handleCheckUpdates","handleOpenChangelog","handleCloseChangelog","handleCloseWelcomeChangelog","handleTriggerUpdate","Suspense","App","createRoot","StrictMode"],"ignoreList":[0,1,2],"sources":["../../../webui/node_modules/react/cjs/react-jsx-runtime.production.min.js","../../../webui/node_modules/react/jsx-runtime.js","../../../webui/node_modules/react-dom/client.js","../../../webui/src/context/ToastContext.tsx","../../../webui/src/context/SearchContext.tsx","../../../webui/src/api/client.ts","../../../webui/src/context/WebUIContext.tsx","../../../webui/src/hooks/useNetworkStatus.ts","../../../webui/src/components/IconImage.tsx","../../../webui/src/icons/close.svg","../../../webui/src/icons/github.svg","../../../webui/src/icons/refresh-arrow.svg","../../../webui/src/icons/up-arrow.svg","../../../webui/src/icons/process.svg","../../../webui/src/icons/log.svg","../../../webui/src/icons/radarr.svg","../../../webui/src/icons/sonarr.svg","../../../webui/src/icons/lidarr.svg","../../../webui/src/icons/gear.svg","../../../webui/src/App.tsx","../../../webui/src/main.tsx"],"sourcesContent":["/**\n * @license React\n * react-jsx-runtime.production.min.js\n *\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n'use strict';var f=require(\"react\"),k=Symbol.for(\"react.element\"),l=Symbol.for(\"react.fragment\"),m=Object.prototype.hasOwnProperty,n=f.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,p={key:!0,ref:!0,__self:!0,__source:!0};\nfunction q(c,a,g){var b,d={},e=null,h=null;void 0!==g&&(e=\"\"+g);void 0!==a.key&&(e=\"\"+a.key);void 0!==a.ref&&(h=a.ref);for(b in a)m.call(a,b)&&!p.hasOwnProperty(b)&&(d[b]=a[b]);if(c&&c.defaultProps)for(b in a=c.defaultProps,a)void 0===d[b]&&(d[b]=a[b]);return{$$typeof:k,type:c,key:e,ref:h,props:d,_owner:n.current}}exports.Fragment=l;exports.jsx=q;exports.jsxs=q;\n","'use strict';\n\nif (process.env.NODE_ENV === 'production') {\n module.exports = require('./cjs/react-jsx-runtime.production.min.js');\n} else {\n module.exports = require('./cjs/react-jsx-runtime.development.js');\n}\n","'use strict';\n\nvar m = require('react-dom');\nif (process.env.NODE_ENV === 'production') {\n exports.createRoot = m.createRoot;\n exports.hydrateRoot = m.hydrateRoot;\n} else {\n var i = m.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;\n exports.createRoot = function(c, o) {\n i.usingClientEntryPoint = true;\n try {\n return m.createRoot(c, o);\n } finally {\n i.usingClientEntryPoint = false;\n }\n };\n exports.hydrateRoot = function(c, h, o) {\n i.usingClientEntryPoint = true;\n try {\n return m.hydrateRoot(c, h, o);\n } finally {\n i.usingClientEntryPoint = false;\n }\n };\n}\n","/* eslint-disable react-refresh/only-export-components */\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useState,\n type PropsWithChildren,\n type JSX,\n} from \"react\";\n\nexport type ToastKind = \"info\" | \"success\" | \"warning\" | \"error\";\n\nexport interface Toast {\n id: number;\n message: string;\n kind: ToastKind;\n}\n\ninterface ToastContextValue {\n toasts: Toast[];\n push: (message: string, kind?: ToastKind) => void;\n dismiss: (id: number) => void;\n}\n\nconst ToastContext = createContext<ToastContextValue | undefined>(undefined);\n\nlet toastCounter = 0;\n\nexport function ToastProvider({ children }: PropsWithChildren): JSX.Element {\n const [toasts, setToasts] = useState<Toast[]>([]);\n\n const dismiss = useCallback((id: number) => {\n setToasts((prev) => prev.filter((t) => t.id !== id));\n }, []);\n\n const push = useCallback(\n (message: string, kind: ToastKind = \"info\") => {\n const id = ++toastCounter;\n setToasts((prev) => [...prev, { id, message, kind }]);\n // Auto dismiss\n window.setTimeout(() => dismiss(id), 3500);\n },\n [dismiss]\n );\n\n const value = useMemo(\n () => ({\n toasts,\n push,\n dismiss,\n }),\n [toasts, push, dismiss]\n );\n\n return (\n <ToastContext.Provider value={value}>{children}</ToastContext.Provider>\n );\n}\n\nexport function useToast(): ToastContextValue {\n const ctx = useContext(ToastContext);\n if (!ctx) {\n throw new Error(\"useToast must be used within a ToastProvider\");\n }\n return ctx;\n}\n\nexport function ToastViewport(): JSX.Element | null {\n const { toasts, dismiss } = useToast();\n if (!toasts.length) return null;\n return (\n <div className=\"toasts\">\n {toasts.map((toast) => (\n <div\n key={toast.id}\n className={`toast ${toast.kind !== \"info\" ? toast.kind : \"\"}`}\n role=\"status\"\n onClick={() => dismiss(toast.id)}\n >\n {toast.message}\n </div>\n ))}\n </div>\n );\n}\n","/* eslint-disable react-refresh/only-export-components */\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useRef,\n useState,\n type PropsWithChildren,\n type JSX,\n} from \"react\";\n\ntype SearchHandler = ((term: string) => void) | null;\n\ninterface SearchContextValue {\n value: string;\n setValue: (term: string) => void;\n register: (handler: SearchHandler) => void;\n clearHandler: (handler: SearchHandler) => void;\n}\n\nconst SearchContext = createContext<SearchContextValue | undefined>(undefined);\n\nexport function SearchProvider({ children }: PropsWithChildren): JSX.Element {\n const [value, setValueState] = useState(\"\");\n const handlers = useRef<Set<SearchHandler>>(new Set());\n\n const setValue = useCallback((term: string) => {\n setValueState(term);\n handlers.current.forEach((handler) => {\n handler?.(term);\n });\n }, []);\n\n const register = useCallback((handler: SearchHandler) => {\n if (!handler) return;\n handlers.current.add(handler);\n }, []);\n\n const clearHandler = useCallback((handler: SearchHandler) => {\n handlers.current.delete(handler);\n }, []);\n\n const valueObj = useMemo(\n () => ({\n value,\n setValue,\n register,\n clearHandler,\n }),\n [value, setValue, register, clearHandler]\n );\n\n return (\n <SearchContext.Provider value={valueObj}>\n {children}\n </SearchContext.Provider>\n );\n}\n\nexport function useSearch(): SearchContextValue {\n const ctx = useContext(SearchContext);\n if (!ctx) {\n throw new Error(\"useSearch must be used within a SearchProvider\");\n }\n return ctx;\n}\n","import type {\n ArrListResponse,\n ConfigDocument,\n ConfigUpdatePayload,\n ConfigUpdateResponse,\n MetaResponse,\n LogsListResponse,\n ProcessesResponse,\n RadarrMoviesResponse,\n RestartResponse,\n SonarrSeriesResponse,\n LidarrAlbumsResponse,\n LidarrAlbum,\n StatusResponse,\n} from \"./types\";\n\nconst JSON_HEADERS = { \"Content-Type\": \"application/json\" } as const;\nconst TOKEN_STORAGE_KEYS = [\"token\", \"webui-token\", \"webui_token\"] as const;\nconst MAX_AUTH_RETRIES = 1;\n\n// Request deduplication cache\nconst inflightRequests = new Map<string, Promise<unknown>>();\n\nfunction createRequestKey(input: RequestInfo | URL, init?: RequestInit): string {\n const url = input instanceof Request ? input.url : String(input);\n const method = init?.method || \"GET\";\n const body = init?.body ? String(init.body) : \"\";\n return `${method}:${url}:${body}`;\n}\n\nfunction resolveToken(): string | null {\n for (const key of TOKEN_STORAGE_KEYS) {\n const value = localStorage.getItem(key) || sessionStorage.getItem(key);\n if (value) {\n if (key !== \"token\") {\n localStorage.setItem(\"token\", value);\n }\n return value;\n }\n }\n try {\n const params = new URLSearchParams(window.location.search);\n const fromQuery = params.get(\"token\");\n if (fromQuery) {\n localStorage.setItem(\"token\", fromQuery);\n return fromQuery;\n }\n } catch {\n // ignore\n }\n return null;\n}\n\nfunction clearStoredToken(): void {\n for (const key of TOKEN_STORAGE_KEYS) {\n localStorage.removeItem(key);\n }\n try {\n for (const key of TOKEN_STORAGE_KEYS) {\n sessionStorage.removeItem(key);\n }\n } catch {\n // ignore session storage errors\n }\n}\n\nfunction buildInit(init: RequestInit | undefined, token: string | null): RequestInit {\n const headers = new Headers(init?.headers || {});\n Object.entries(JSON_HEADERS).forEach(([key, value]) => {\n if (!headers.has(key)) headers.set(key, value);\n });\n if (token && !headers.has(\"Authorization\")) {\n headers.set(\"Authorization\", `Bearer ${token}`);\n }\n return {\n ...init,\n headers,\n };\n}\n\nasync function fetchWithAuthRetry<T>(\n input: RequestInfo | URL,\n init: RequestInit | undefined,\n handler: (response: Response) => Promise<T>,\n retries = MAX_AUTH_RETRIES\n): Promise<T> {\n const token = resolveToken();\n const response = await fetch(input, buildInit(init, token));\n if (response.status === 401 && retries > 0 && token) {\n clearStoredToken();\n return fetchWithAuthRetry(input, init, handler, retries - 1);\n }\n return handler(response);\n}\n\nasync function fetchJson<T>(input: RequestInfo | URL, init?: RequestInit): Promise<T> {\n // Only deduplicate GET requests (safe to share)\n const method = init?.method || \"GET\";\n if (method === \"GET\") {\n const key = createRequestKey(input, init);\n const existingRequest = inflightRequests.get(key) as Promise<T> | undefined;\n\n if (existingRequest) {\n return existingRequest;\n }\n\n const promise = fetchWithAuthRetry<T>(input, init, (response) => handleJson<T>(response))\n .finally(() => {\n inflightRequests.delete(key);\n });\n\n inflightRequests.set(key, promise);\n return promise;\n }\n\n return fetchWithAuthRetry<T>(input, init, (response) => handleJson<T>(response));\n}\n\nasync function fetchTextResponse(input: RequestInfo | URL, init?: RequestInit): Promise<string> {\n return fetchWithAuthRetry<string>(input, init, (response) => handleText(response));\n}\n\nasync function handleJson<T>(res: Response): Promise<T> {\n if (!res.ok) {\n let detail: unknown = null;\n try {\n detail = await res.json();\n } catch {\n // ignore\n }\n let message = `${res.status} ${res.statusText}`;\n if (\n detail &&\n typeof detail === \"object\" &&\n \"error\" in detail &&\n typeof (detail as Record<string, unknown>).error === \"string\"\n ) {\n const errorText = (detail as Record<string, unknown>).error as string;\n if (errorText.trim()) {\n message = errorText;\n }\n }\n throw new Error(message);\n }\n return (await res.json()) as T;\n}\n\nasync function handleText(res: Response): Promise<string> {\n if (!res.ok) {\n throw new Error(`${res.status} ${res.statusText}`);\n }\n return res.text();\n}\n\nexport async function getMeta(params?: { force?: boolean }): Promise<MetaResponse> {\n const query = params?.force ? \"?force=1\" : \"\";\n return fetchJson<MetaResponse>(`/web/meta${query}`);\n}\n\nexport async function getStatus(): Promise<StatusResponse> {\n return fetchJson<StatusResponse>(\"/web/status\");\n}\n\nexport async function getProcesses(): Promise<ProcessesResponse> {\n return fetchJson<ProcessesResponse>(\"/web/processes\");\n}\n\nexport async function restartProcess(\n category: string,\n kind: string\n): Promise<RestartResponse> {\n const url = `/web/processes/${encodeURIComponent(\n category\n )}/${encodeURIComponent(kind)}/restart`;\n return fetchJson<RestartResponse>(url, { method: \"POST\" });\n}\n\nexport async function restartAllProcesses(): Promise<RestartResponse> {\n return fetchJson<RestartResponse>(\"/web/processes/restart_all\", {\n method: \"POST\",\n });\n}\n\nexport async function rebuildArrs(): Promise<RestartResponse> {\n return fetchJson<RestartResponse>(\"/web/arr/rebuild\", { method: \"POST\" });\n}\n\nexport async function setLogLevel(level: string): Promise<void> {\n await fetchJson<void>(\"/web/loglevel\", {\n method: \"POST\",\n body: JSON.stringify({ level }),\n });\n}\n\nexport async function getLogs(): Promise<LogsListResponse> {\n return fetchJson<LogsListResponse>(\"/web/logs\");\n}\n\nexport async function getLogTail(name: string): Promise<string> {\n return fetchTextResponse(`/web/logs/${encodeURIComponent(name)}`);\n}\n\nexport function getLogDownloadUrl(name: string): string {\n return `/web/logs/${encodeURIComponent(name)}/download`;\n}\n\nexport async function getArrList(): Promise<ArrListResponse> {\n return fetchJson<ArrListResponse>(\"/web/arr\");\n}\n\nexport async function getRadarrMovies(\n category: string,\n page: number,\n pageSize: number,\n q: string\n): Promise<RadarrMoviesResponse> {\n const params = new URLSearchParams();\n params.set(\"page\", String(page));\n params.set(\"page_size\", String(pageSize));\n if (q) params.set(\"q\", q);\n return fetchJson<RadarrMoviesResponse>(\n `/web/radarr/${encodeURIComponent(category)}/movies?${params}`\n );\n}\n\nexport async function getSonarrSeries(\n category: string,\n page: number,\n pageSize: number,\n q: string,\n options?: { missingOnly?: boolean }\n): Promise<SonarrSeriesResponse> {\n const params = new URLSearchParams();\n params.set(\"page\", String(page));\n params.set(\"page_size\", String(pageSize));\n if (q) params.set(\"q\", q);\n if (options?.missingOnly) {\n params.set(\"missing\", \"1\");\n }\n return fetchJson<SonarrSeriesResponse>(\n `/web/sonarr/${encodeURIComponent(category)}/series?${params}`\n );\n}\n\nexport async function getLidarrAlbums(\n category: string,\n page: number,\n pageSize: number,\n query?: string\n): Promise<LidarrAlbumsResponse> {\n const params = new URLSearchParams();\n params.set(\"page\", page.toString());\n params.set(\"page_size\", pageSize.toString());\n if (query) {\n params.set(\"q\", query);\n }\n // Always include tracks\n params.set(\"include_tracks\", \"true\");\n return fetchJson<LidarrAlbumsResponse>(\n `/web/lidarr/${encodeURIComponent(category)}/albums?${params}`\n );\n}\n\nexport async function restartArr(category: string): Promise<void> {\n await fetchJson<void>(\n `/web/arr/${encodeURIComponent(category)}/restart`,\n { method: \"POST\" }\n );\n}\n\nexport async function getConfig(): Promise<ConfigDocument> {\n return fetchJson<ConfigDocument>(\"/web/config\");\n}\n\nexport async function updateConfig(\n payload: ConfigUpdatePayload\n): Promise<ConfigUpdateResponse> {\n const token = resolveToken();\n const response = await fetch(\"/web/config\", buildInit({\n method: \"POST\",\n body: JSON.stringify(payload),\n }, token));\n\n if (!response.ok) {\n let detail: unknown = null;\n try {\n detail = await response.json();\n } catch {\n // ignore\n }\n let message = `${response.status} ${response.statusText}`;\n if (\n detail &&\n typeof detail === \"object\" &&\n \"error\" in detail &&\n typeof (detail as Record<string, unknown>).error === \"string\"\n ) {\n const errorText = (detail as Record<string, unknown>).error as string;\n if (errorText.trim()) {\n message = errorText;\n }\n }\n throw new Error(message);\n }\n\n // Parse response body with full type information\n const data = await response.json() as ConfigUpdateResponse;\n return data;\n}\n\nexport async function triggerUpdate(): Promise<void> {\n await fetchJson<void>(\"/web/update\", { method: \"POST\" });\n}\n","import { createContext, useCallback, useContext, useEffect, useState, type JSX, type ReactNode } from \"react\";\nimport { getConfig, updateConfig } from \"../api/client\";\n\ntype ViewDensity = \"comfortable\" | \"compact\";\ntype Theme = \"light\" | \"dark\";\n\ninterface WebUISettings {\n liveArr: boolean;\n groupSonarr: boolean;\n groupLidarr: boolean;\n viewDensity: ViewDensity;\n theme: Theme;\n}\n\ninterface WebUIContextValue {\n liveArr: boolean;\n groupSonarr: boolean;\n groupLidarr: boolean;\n viewDensity: ViewDensity;\n theme: Theme;\n setLiveArr: (value: boolean) => void;\n setGroupSonarr: (value: boolean) => void;\n setGroupLidarr: (value: boolean) => void;\n setViewDensity: (value: ViewDensity) => void;\n setTheme: (value: Theme) => void;\n loading: boolean;\n}\n\nconst WebUIContext = createContext<WebUIContextValue | null>(null);\n\nexport function WebUIProvider({ children }: { children: ReactNode }): JSX.Element {\n const [settings, setSettings] = useState<WebUISettings>({\n liveArr: true,\n groupSonarr: true,\n groupLidarr: true,\n viewDensity: \"comfortable\",\n theme: \"dark\",\n });\n const [loading, setLoading] = useState(true);\n\n // Load initial settings\n useEffect(() => {\n const loadSettings = async () => {\n try {\n const config = await getConfig();\n const webui = config?.WebUI as Record<string, unknown> | undefined;\n\n // Load from localStorage as fallback for view density (client-side preference)\n const storedDensity = localStorage.getItem(\"viewDensity\") as ViewDensity | null;\n const storedTheme = localStorage.getItem(\"theme\") as Theme | null;\n\n // Get theme from backend or localStorage\n const backendTheme = webui?.Theme as string | undefined;\n const theme: Theme = storedTheme || (backendTheme?.toLowerCase() as Theme) || \"dark\";\n\n setSettings({\n liveArr: webui?.LiveArr === true,\n groupSonarr: webui?.GroupSonarr === true,\n groupLidarr: webui?.GroupLidarr === true,\n viewDensity: storedDensity || \"comfortable\",\n theme,\n });\n\n // Apply theme immediately\n document.documentElement.setAttribute('data-theme', theme);\n } catch (error) {\n console.error(\"Failed to load WebUI settings:\", error);\n } finally {\n setLoading(false);\n }\n };\n\n void loadSettings();\n }, []);\n\n // Auto-save settings to backend\n const saveSettings = useCallback(async (key: string, value: boolean | string) => {\n try {\n const changes: Record<string, unknown> = {\n WebUI: {\n [key]: value,\n },\n };\n await updateConfig({ changes });\n } catch (error) {\n console.error(`Failed to save ${key}:`, error);\n }\n }, []);\n\n const setLiveArr = useCallback((value: boolean) => {\n setSettings(prev => ({ ...prev, liveArr: value }));\n void saveSettings(\"LiveArr\", value);\n }, [saveSettings]);\n\n const setGroupSonarr = useCallback((value: boolean) => {\n setSettings(prev => ({ ...prev, groupSonarr: value }));\n void saveSettings(\"GroupSonarr\", value);\n }, [saveSettings]);\n\n const setGroupLidarr = useCallback((value: boolean) => {\n setSettings(prev => ({ ...prev, groupLidarr: value }));\n void saveSettings(\"GroupLidarr\", value);\n }, [saveSettings]);\n\n const setViewDensity = useCallback((value: ViewDensity) => {\n setSettings(prev => ({ ...prev, viewDensity: value }));\n // Store in localStorage (client-side preference, not sent to backend)\n localStorage.setItem(\"viewDensity\", value);\n }, []);\n\n const setTheme = useCallback((value: Theme) => {\n setSettings(prev => ({ ...prev, theme: value }));\n // Store in localStorage for instant application\n localStorage.setItem(\"theme\", value);\n // Apply theme immediately to DOM\n document.documentElement.setAttribute('data-theme', value);\n // Save to backend with proper capitalization (Light or Dark)\n const capitalizedTheme = value === \"light\" ? \"Light\" : \"Dark\";\n void saveSettings(\"Theme\", capitalizedTheme);\n }, [saveSettings]);\n\n const value: WebUIContextValue = {\n liveArr: settings.liveArr,\n groupSonarr: settings.groupSonarr,\n groupLidarr: settings.groupLidarr,\n viewDensity: settings.viewDensity,\n theme: settings.theme,\n setLiveArr,\n setGroupSonarr,\n setGroupLidarr,\n setViewDensity,\n setTheme,\n loading,\n };\n\n return <WebUIContext.Provider value={value}>{children}</WebUIContext.Provider>;\n}\n\nexport function useWebUI(): WebUIContextValue {\n const context = useContext(WebUIContext);\n if (!context) {\n throw new Error(\"useWebUI must be used within WebUIProvider\");\n }\n return context;\n}\n","import { useEffect, useState } from \"react\";\n\nexport function useNetworkStatus(): boolean {\n const [isOnline, setIsOnline] = useState(navigator.onLine);\n\n useEffect(() => {\n const handleOnline = () => setIsOnline(true);\n const handleOffline = () => setIsOnline(false);\n\n window.addEventListener('online', handleOnline);\n window.addEventListener('offline', handleOffline);\n\n return () => {\n window.removeEventListener('online', handleOnline);\n window.removeEventListener('offline', handleOffline);\n };\n }, []);\n\n return isOnline;\n}\n","import type { ImgHTMLAttributes, JSX } from \"react\";\n\ninterface IconImageProps extends Omit<ImgHTMLAttributes<HTMLImageElement>, \"src\"> {\n src: string;\n alt?: string;\n}\n\nexport function IconImage({ src, alt, className, ...rest }: IconImageProps): JSX.Element {\n return (\n <img\n src={src}\n alt={alt ?? \"\"}\n className={className ? `icon ${className}` : \"icon\"}\n aria-hidden={alt ? undefined : true}\n {...rest}\n />\n );\n}\n","export default \"__VITE_ASSET__BwSX1QeM__\"","export default \"data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20xml:space='preserve'%20viewBox='0%200%20512%20512'%3e%3cpath%20d='M256%206.3C114.6%206.3%200%20120.9%200%20262.3c0%20113.3%2073.3%20209%20175%20242.9%2012.8%202.2%2017.6-5.4%2017.6-12.2%200-6.1-.3-26.2-.3-47.7-64.3%2011.8-81-15.7-86.1-30.1-2.9-7.4-15.4-30.1-26.2-36.2-9-4.8-21.8-16.6-.3-17%2020.2-.3%2034.6%2018.6%2039.4%2026.2%2023%2038.7%2059.8%2027.8%2074.6%2021.1%202.2-16.6%209-27.8%2016.3-34.2-57-6.4-116.5-28.5-116.5-126.4%200-27.8%209.9-50.9%2026.2-68.8-2.6-6.4-11.5-32.6%202.6-67.8%200%200%2021.4-6.7%2070.4%2026.2%2020.5-5.8%2042.2-8.6%2064-8.6s43.5%202.9%2064%208.6c49-33.3%2070.4-26.2%2070.4-26.2%2014.1%2035.2%205.1%2061.4%202.6%2067.8%2016.3%2017.9%2026.2%2040.6%2026.2%2068.8%200%2098.2-59.8%20120-116.8%20126.4%209.3%208%2017.3%2023.4%2017.3%2047.4%200%2034.2-.3%2061.8-.3%2070.4%200%206.7%204.8%2014.7%2017.6%2012.2C438.7%20471.3%20512%20375.3%20512%20262.3c0-141.4-114.6-256-256-256'%20style='fill-rule:evenodd;clip-rule:evenodd;fill:%231b1f23'/%3e%3c/svg%3e\"","export default \"__VITE_ASSET__B5Abvgg6__\"","export default \"__VITE_ASSET__CFg2sUO1__\"","export default \"__VITE_ASSET__DruObj$B__\"","export default \"__VITE_ASSET__DKTRAwQu__\"","export default \"data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20xml:space='preserve'%20id='Layer_1'%20x='0'%20y='0'%20version='1.1'%20viewBox='0%200%20512%20512'%3e%3cstyle%3e.st0{fill:%2324292e}%3c/style%3e%3cg%20id='Group-Copy'%20transform='translate(70%2021)'%3e%3cpath%20id='Shape'%20d='m10.3%2059.8%203.9%20372.4c-31.4%203.9-54.9-11.8-54.9-43.1l-3.9-309.7c0-98%2090.2-121.5%20145.1-82.3l278.3%20160.7c39.2%2027.4%2047%2078.4%2027.4%20113.7-3.9-27.4-15.7-43.1-39.2-58.8L53.4%2036.2C29.9%2020.6%2010.3%2024.5%2010.3%2059.8'%20class='st0'/%3e%3cpath%20id='Shape_00000114049535938561773820000018271523940913105341_'%20d='M-13.2%20451.8c23.5%207.8%2047%203.9%2066.6-7.8l321.5-188.2c19.6%2027.4%2015.7%2054.9-7.8%2070.6L96.5%20483.2c-39.2%2019.6-90.1%200-109.7-31.4'%20class='st0'/%3e%3cpath%20id='Shape_00000165935924413286433040000003668002807793862576_'%20d='M80.9%20342%20273%20232.3%2084.8%20126.4z'%20style='fill:%23ffc230'/%3e%3c/g%3e%3c/svg%3e\"","export default \"data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20xml:space='preserve'%20viewBox='0%200%20512%20512'%3e%3cpath%20d='M511.8%20256c0%2070.4-24.9%20130.8-74.6%20181.1-1.7%202-3.5%203.8-5.5%205.4-8.2%208-16.8%2015.3-26%2021.8Q341.05%20512%20256.3%20512c-56.6%200-106.3-15.9-149.2-47.7-11.3-8-22-17.1-31.9-27.3C36.5%20398.7%2012.8%20354%204%20303.2c-1.7-9.9-2.9-20-3.4-30.2-.2-5.7-.4-11.3-.4-17%200-6%20.1-11.7.4-17.1%200-.6.2-1.1.5-1.7%203.7-62.8%2028.4-117%2074.1-162.8C125.5%2024.8%20185.8%200%20256.2%200c70.7%200%20131%2024.8%20180.9%2074.5q74.7%2075.9%2074.7%20181.5'%20style='fill-rule:evenodd;clip-rule:evenodd;fill:%23eee'/%3e%3cpath%20d='m459.7%20100.3-52.9%2052.9c-30.9%2030.9-33.6%2057.8-33.6%20105.3%200%2042.3%206.7%2081.1%2038.2%20112.6%2023%2023%2044.9%2044.7%2044.9%2044.7-5.9%207.2-12.3%2014.3-19.1%2021.2-1.7%202-3.5%203.8-5.5%205.4-6%205.9-12.2%2011.4-18.6%2016.4l-41.4-41.4C334.9%20380.6%20305.6%20377%20257%20377c-46.7%200-78.4%204.3-112.6%2038.5-20.4%2020.4-43.8%2043.9-43.8%2043.9-8.9-6.8-17.3-14.2-25.3-22.4-6.6-6.6-12.8-13.4-18.5-20.3%200%200%2023.1-23.2%2045.2-45.3%2032.7-32.7%2038-70.6%2038-113%200-41.3-6.8-79.8-36.8-109.9C82.2%20127.7%2053.3%2099%2053.3%2099c6.7-8.5%2014-16.7%2021.8-24.5%206.9-6.8%2014-13.1%2021.2-19l48%2048c30.7%2030.7%2070%2038.6%20112.4%2038.6%2043.6%200%2082.8-8.4%20114.7-40.4C391%2082.1%20417%2056.3%20417%2056.3c6.8%205.6%2013.5%2011.6%2020.1%2018.2%208.3%208.3%2015.8%2016.9%2022.6%2025.8'%20style='fill-rule:evenodd;clip-rule:evenodd;fill:%233a3f51'/%3e%3cpath%20d='M186%20269.1c-.5-2.8-.8-5.5-.9-8.4-.1-1.6-.1-3.1-.1-4.7%200-1.7%200-3.2.1-4.7%200-.2%200-.3.1-.5%201-17.4%207.9-32.4%2020.5-45.1%2013.9-13.8%2030.6-20.7%2050.2-20.7s36.3%206.9%2050.2%2020.7c13.8%2014%2020.7%2030.8%2020.7%2050.3s-6.9%2036.2-20.7%2050.2c-.5.5-1%201.1-1.5%201.5q-3.45%203.3-7.2%206-18%2013.2-41.4%2013.2c-23.4%200-29.4-4.4-41.3-13.2-3.1-2.2-6.1-4.7-8.9-7.6-10.8-10.6-17.3-22.9-19.8-37'%20style='fill-rule:evenodd;clip-rule:evenodd;fill:%230cf'/%3e%3cpath%20d='m372.7%20141-35.4%2034.6M72.9%2076.8l96.5%2096.1m199.7%20198.9%2065.6%2067.9m4.4-363.3L372.7%20141M76.6%20438.5l64.6-64.7'%20style='fill:none;stroke:%230cf;stroke-width:2;stroke-miterlimit:1'/%3e%3cpath%20d='m372.7%20141-40%2040.6m-193.3-38.5%2040.6%2040.5M141%20374l39.5-41.1m146.2-3.3%2042.6%2042.4'%20style='fill:none;stroke:%230cf;stroke-width:7;stroke-miterlimit:1'/%3e%3c/svg%3e\"","export default \"__VITE_ASSET__B_sq1wA9__\"","export default \"__VITE_ASSET__CITwrObj__\"","import { useCallback, useEffect, useMemo, useRef, useState, type JSX, lazy, Suspense } from \"react\";\nconst ProcessesView = lazy(() => import(\"./pages/ProcessesView\").then(module => ({ default: module.ProcessesView })));\nconst LogsView = lazy(() => import(\"./pages/LogsView\").then(module => ({ default: module.LogsView })));\nconst ArrView = lazy(() => import(\"./pages/ArrView\").then(module => ({ default: module.ArrView })));\nconst ConfigView = lazy(() => import(\"./pages/ConfigView\").then(module => ({ default: module.ConfigView })));\nimport { ToastProvider, ToastViewport, useToast } from \"./context/ToastContext\";\nimport { SearchProvider, useSearch } from \"./context/SearchContext\";\nimport { WebUIProvider, useWebUI } from \"./context/WebUIContext\";\nimport { useNetworkStatus } from \"./hooks/useNetworkStatus\";\nimport { getMeta, getStatus, triggerUpdate } from \"./api/client\";\nimport type { MetaResponse, StatusResponse } from \"./api/types\";\nimport { IconImage } from \"./components/IconImage\";\nimport CloseIcon from \"./icons/close.svg\";\nimport ExternalIcon from \"./icons/github.svg\";\nimport RefreshIcon from \"./icons/refresh-arrow.svg\";\nimport UpdateIcon from \"./icons/up-arrow.svg\";\nimport ProcessesIcon from \"./icons/process.svg\";\nimport LogsIcon from \"./icons/log.svg\";\nimport RadarrIcon from \"./icons/radarr.svg\";\nimport SonarrIcon from \"./icons/sonarr.svg\";\nimport LidarrIcon from \"./icons/lidarr.svg\";\nimport ConfigIcon from \"./icons/gear.svg\";\n\ntype Tab = \"processes\" | \"logs\" | \"radarr\" | \"sonarr\" | \"lidarr\" | \"config\";\n\ninterface NavTab {\n id: Tab;\n label: string;\n icon: string;\n}\n\nfunction formatVersionLabel(value: string | null | undefined): string {\n if (!value) {\n return \"unknown\";\n }\n const trimmed = value.trim();\n if (!trimmed) {\n return \"unknown\";\n }\n return trimmed[0] === \"v\" || trimmed[0] === \"V\" ? trimmed : `v${trimmed}`;\n}\n\ninterface WelcomeModalProps {\n currentVersion: string;\n changelog: string | null;\n changelogUrl: string | null;\n repositoryUrl: string;\n onClose: () => void;\n}\n\nfunction WelcomeModal({\n currentVersion,\n changelog,\n changelogUrl,\n repositoryUrl,\n onClose,\n}: WelcomeModalProps): JSX.Element {\n return (\n <div className=\"modal-backdrop\" role=\"presentation\" onClick={onClose}>\n <div\n className=\"modal\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"welcome-title\"\n onClick={(event) => event.stopPropagation()}\n >\n <div className=\"modal-header\">\n <h2 id=\"welcome-title\">\n 🎉 Welcome to qBitrr {formatVersionLabel(currentVersion)}!\n </h2>\n </div>\n <div className=\"modal-body changelog-modal__body\">\n <div className=\"changelog-meta\">\n <p style={{ marginBottom: '1rem', color: 'var(--text-secondary)' }}>\n You've been updated to version <strong>{formatVersionLabel(currentVersion)}</strong>.\n Here's what's new in this release:\n </p>\n </div>\n <div className=\"changelog-section\">\n <h3>Release Notes</h3>\n <pre className=\"changelog-body\">\n {changelog?.trim() ? changelog.trim() : \"No changelog available for this version.\"}\n </pre>\n </div>\n </div>\n <div className=\"modal-footer\">\n <div className=\"changelog-links\">\n {(changelogUrl || repositoryUrl) && (\n <a\n className=\"btn ghost small\"\n href={changelogUrl ?? repositoryUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n <IconImage src={ExternalIcon} />\n View Full Release on GitHub\n </a>\n )}\n </div>\n <div className=\"changelog-buttons\">\n <button className=\"btn primary\" type=\"button\" onClick={onClose}>\n Got it!\n </button>\n </div>\n </div>\n </div>\n </div>\n );\n}\n\ninterface ChangelogModalProps {\n currentVersion: string;\n latestVersion: string | null;\n changelog: string | null;\n changelogUrl: string | null;\n repositoryUrl: string;\n updateState: MetaResponse[\"update_state\"] | null | undefined;\n updating: boolean;\n onClose: () => void;\n onUpdate: () => void;\n}\n\nfunction ChangelogModal({\n currentVersion,\n latestVersion,\n changelog,\n changelogUrl,\n repositoryUrl,\n updateState,\n updating,\n onClose,\n onUpdate,\n}: ChangelogModalProps): JSX.Element {\n const [countdown, setCountdown] = useState<number | null>(null);\n const updateDisabled = updating || Boolean(updateState?.in_progress);\n const completedLabel = updateState?.completed_at\n ? new Date(updateState.completed_at).toLocaleString()\n : null;\n\n // Start countdown when update completes successfully\n useEffect(() => {\n if (updateState?.last_result === \"success\" && updateState?.completed_at) {\n let countdown = 10;\n setCountdown(countdown);\n const timer = setInterval(() => {\n countdown -= 1;\n if (countdown <= 0) {\n clearInterval(timer);\n window.location.reload();\n } else {\n setCountdown(countdown);\n }\n }, 1000);\n return () => clearInterval(timer);\n }\n }, [updateState?.last_result, updateState?.completed_at]);\n\n let statusClass = \"\";\n let statusMessage: string | null = null;\n if (updateState?.in_progress) {\n statusClass = \"text-info\";\n statusMessage = \"⏳ Update in progress...\";\n } else if (updateState?.last_result === \"success\") {\n statusClass = \"text-success\";\n if (countdown !== null) {\n statusMessage = `✓ Update completed! Reloading in ${countdown}s...`;\n } else {\n statusMessage = \"✓ Update completed successfully\";\n if (completedLabel) {\n statusMessage = `${statusMessage} (${completedLabel})`;\n }\n }\n } else if (updateState?.last_result === \"error\") {\n statusClass = \"text-danger\";\n const detail = updateState.last_error ? updateState.last_error.trim() : \"\";\n statusMessage = detail ? `✗ Update failed: ${detail}` : \"✗ Update failed\";\n }\n\n return (\n <div className=\"modal-backdrop\" role=\"presentation\" onClick={onClose}>\n <div\n className=\"modal\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"changelog-title\"\n onClick={(event) => event.stopPropagation()}\n >\n <div className=\"modal-header\">\n <h2 id=\"changelog-title\">\n {updateState?.in_progress ? \"⚙️ Updating...\" : \"🚀 Update Available\"}\n </h2>\n <button className=\"btn ghost\" type=\"button\" onClick={onClose} disabled={updateState?.in_progress}>\n <IconImage src={CloseIcon} />\n Close\n </button>\n </div>\n <div className=\"modal-body changelog-modal__body\">\n <div className=\"changelog-meta\">\n <div className=\"version-comparison\">\n <span className=\"version-item\">\n <strong>Current:</strong>{\" \"}\n <span className=\"version-badge version-current\">{formatVersionLabel(currentVersion)}</span>\n </span>\n <span className=\"version-arrow\">→</span>\n <span className=\"version-item\">\n <strong>Latest:</strong>{\" \"}\n <span className=\"version-badge version-latest\">\n {latestVersion ? formatVersionLabel(latestVersion) : \"Unknown\"}\n </span>\n </span>\n </div>\n {statusMessage ? (\n <div className={`update-status ${statusClass}`}>\n {statusMessage}\n </div>\n ) : null}\n </div>\n <div className=\"changelog-section\">\n <h3>What's New</h3>\n <pre className=\"changelog-body\">\n {changelog?.trim() ? changelog.trim() : \"No changelog provided.\"}\n </pre>\n </div>\n </div>\n <div className=\"modal-footer\">\n <div className=\"changelog-links\">\n {(changelogUrl || repositoryUrl) && (\n <a\n className=\"btn ghost small\"\n href={changelogUrl ?? repositoryUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n <IconImage src={ExternalIcon} />\n View on GitHub\n </a>\n )}\n </div>\n <div className=\"changelog-buttons\">\n <button\n className=\"btn primary\"\n type=\"button\"\n onClick={onUpdate}\n disabled={updateDisabled}\n >\n <IconImage src={UpdateIcon} />\n {updateDisabled ? \"Updating...\" : \"Update Now\"}\n </button>\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nfunction AppShell(): JSX.Element {\n const [activeTab, setActiveTab] = useState<Tab>(\"processes\");\n const [configDirty, setConfigDirty] = useState(false);\n const { push } = useToast();\n const { setValue: setSearchValue } = useSearch();\n const { viewDensity, setViewDensity } = useWebUI();\n const isOnline = useNetworkStatus();\n const [meta, setMeta] = useState<MetaResponse | null>(null);\n const [metaLoading, setMetaLoading] = useState(false);\n const [showChangelog, setShowChangelog] = useState(false);\n const [updateBusy, setUpdateBusy] = useState(false);\n const [backendRestarting, setBackendRestarting] = useState(false);\n const restartPollCount = useRef(0);\n const prevUpdateResult = useRef<string | null>(null);\n const backendReadyRef = useRef(false);\n const backendWarnedRef = useRef(false);\n const backendTimerRef = useRef<number | null>(null);\n const [reloadKey, setReloadKey] = useState(0);\n const [statusData, setStatusData] = useState<StatusResponse | null>(null);\n const [showWelcomeChangelog, setShowWelcomeChangelog] = useState(false);\n\n // Theme is now managed by WebUIContext and applied automatically\n\n // Clear cache on every page load to ensure fresh content\n useEffect(() => {\n const clearCache = async () => {\n if ('caches' in window) {\n try {\n const cacheNames = await caches.keys();\n await Promise.all(\n cacheNames.map(cacheName => caches.delete(cacheName))\n );\n console.log('Cache cleared on page load');\n } catch (error) {\n console.error('Failed to clear cache:', error);\n }\n }\n };\n clearCache();\n }, []);\n\n const refreshMeta = useCallback(\n async (options?: { force?: boolean; silent?: boolean }) => {\n const force = options?.force ?? false;\n const silent = options?.silent ?? !force;\n if (!silent) {\n setMetaLoading(true);\n }\n try {\n const data = await getMeta({ force });\n setMeta(data);\n } catch (error) {\n if (!silent) {\n const message =\n error instanceof Error ? error.message : \"Failed to fetch version information\";\n push(message, \"error\");\n }\n } finally {\n if (!silent) {\n setMetaLoading(false);\n }\n }\n },\n [push]\n );\n\n useEffect(() => {\n void refreshMeta({ force: true });\n }, [refreshMeta]);\n\n // Check for new version on first launch - show welcome popup with changelog\n useEffect(() => {\n if (!meta?.current_version) {\n return;\n }\n\n const lastSeenVersion = localStorage.getItem(\"lastSeenVersion\");\n const currentVersion = meta.current_version;\n\n // Show welcome popup if this is a new version (but not on very first install)\n if (lastSeenVersion && lastSeenVersion !== currentVersion) {\n // Ensure we have changelog data before showing popup\n if (!meta.current_version_changelog && !meta.changelog) {\n void refreshMeta({ force: true, silent: true });\n }\n setShowWelcomeChangelog(true);\n }\n\n // Store current version as last seen when user opens the app (first install)\n if (!lastSeenVersion) {\n localStorage.setItem(\"lastSeenVersion\", currentVersion);\n }\n }, [meta?.current_version, meta?.changelog, refreshMeta]);\n\n // Network status notifications\n useEffect(() => {\n if (!isOnline) {\n push(\"You are offline. Some features may not work.\", \"warning\");\n }\n }, [isOnline, push]);\n\n // Keyboard shortcuts\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n // Don't trigger shortcuts when typing in inputs\n if (event.target instanceof HTMLInputElement ||\n event.target instanceof HTMLTextAreaElement ||\n event.target instanceof HTMLSelectElement) {\n return;\n }\n\n const isMod = event.ctrlKey || event.metaKey;\n\n // Ctrl/Cmd + K - Focus search\n if (isMod && event.key === 'k') {\n event.preventDefault();\n const searchInput = document.querySelector('input[type=\"text\"][placeholder*=\"Search\"]') as HTMLInputElement;\n searchInput?.focus();\n return;\n }\n\n // R - Refresh current view\n if (event.key === 'r' || event.key === 'R') {\n event.preventDefault();\n setReloadKey(prev => prev + 1);\n push('Refreshed', 'success');\n return;\n }\n\n // ESC - Clear search\n if (event.key === 'Escape') {\n setSearchValue('');\n return;\n }\n\n // Number keys 1-6 for tab switching\n if (event.key >= '1' && event.key <= '6' && !isMod) {\n event.preventDefault();\n const tabIndex = parseInt(event.key) - 1;\n const tabIds: Tab[] = ['processes', 'logs', 'radarr', 'sonarr', 'lidarr', 'config'];\n if (tabIndex < tabIds.length) {\n setActiveTab(tabIds[tabIndex]);\n }\n return;\n }\n };\n\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, [setSearchValue, push]);\n\n useEffect(() => {\n const id = window.setInterval(() => {\n void refreshMeta();\n }, 5 * 60 * 1000);\n return () => window.clearInterval(id);\n }, [refreshMeta]);\n\n useEffect(() => {\n const handleVisibilityChange = () => {\n if (document.visibilityState === \"visible\") {\n // Force reload all data by incrementing the reload key\n setReloadKey((prev) => prev + 1);\n void refreshMeta({ force: true });\n void refreshStatus();\n }\n };\n\n document.addEventListener(\"visibilitychange\", handleVisibilityChange);\n return () => {\n document.removeEventListener(\"visibilitychange\", handleVisibilityChange);\n };\n }, [refreshMeta]);\n\n const refreshStatus = useCallback(async () => {\n try {\n const status = await getStatus();\n setStatusData(status);\n } catch {\n // Silently fail - status is not critical\n }\n }, []);\n\n useEffect(() => {\n void refreshStatus();\n const id = window.setInterval(() => {\n void refreshStatus();\n }, 5 * 1000); // Refresh every 5 seconds for more dynamic tab loading\n return () => window.clearInterval(id);\n }, [refreshStatus]);\n\n useEffect(() => {\n if (!meta?.update_state?.in_progress && !backendRestarting) {\n restartPollCount.current = 0;\n return;\n }\n const id = window.setInterval(async () => {\n try {\n const data = await getMeta({ force: true });\n setMeta(data);\n if (backendRestarting) {\n // Backend came back after restart\n window.location.reload();\n }\n restartPollCount.current = 0;\n } catch {\n restartPollCount.current += 1;\n if (restartPollCount.current > 20) { // 60 seconds\n setBackendRestarting(false);\n restartPollCount.current = 0;\n push(\"Update completed but backend restart timed out. Please refresh the page manually.\", \"warning\");\n return;\n }\n if (meta?.update_state?.in_progress) {\n // Failed while update in progress, likely restarting\n setBackendRestarting(true);\n }\n }\n }, 3000);\n return () => window.clearInterval(id);\n }, [meta?.update_state?.in_progress, backendRestarting, meta, push]);\n\n useEffect(() => {\n const state = meta?.update_state;\n if (!state) {\n prevUpdateResult.current = null;\n return;\n }\n const result = state.last_result ?? null;\n if (result && result !== prevUpdateResult.current) {\n if (result === \"success\") {\n push(\"Update completed successfully. Restarting...\", \"success\");\n setBackendRestarting(true);\n restartPollCount.current = 0;\n } else if (result === \"error\") {\n push(state.last_error || \"Update failed.\", \"error\");\n }\n }\n prevUpdateResult.current = result;\n }, [meta?.update_state, push]);\n\n useEffect(() => {\n let cancelled = false;\n let attempts = 0;\n\n const schedule = (delay: number) => {\n if (backendTimerRef.current !== null) {\n window.clearTimeout(backendTimerRef.current);\n }\n backendTimerRef.current = window.setTimeout(() => {\n void poll();\n }, delay);\n };\n\n const poll = async () => {\n if (cancelled || backendReadyRef.current) {\n return;\n }\n attempts += 1;\n try {\n const status = await getStatus();\n if (cancelled) {\n return;\n }\n setStatusData(status);\n const readyHint =\n status.ready ?? (Array.isArray(status.arrs) && status.arrs.length > 0);\n if (readyHint) {\n backendReadyRef.current = true;\n return;\n }\n if (status.ready === false && attempts >= 3 && !backendWarnedRef.current) {\n backendWarnedRef.current = true;\n push(\n \"qBitrr backend is still initialising. Check the logs if this persists.\",\n \"warning\"\n );\n }\n } catch (error) {\n if (!backendWarnedRef.current && attempts >= 3) {\n backendWarnedRef.current = true;\n const detail = error instanceof Error ? error.message : \"Unknown backend error\";\n push(\n `Unable to confirm qBitrr readiness (${detail}). Please inspect the logs.`,\n \"warning\"\n );\n }\n } finally {\n if (!cancelled && !backendReadyRef.current) {\n const delay = attempts < 3 ? 3000 : 10000;\n schedule(delay);\n }\n }\n };\n\n schedule(0);\n\n return () => {\n cancelled = true;\n if (backendTimerRef.current !== null) {\n window.clearTimeout(backendTimerRef.current);\n backendTimerRef.current = null;\n }\n };\n }, [push]);\n\n const tabs = useMemo<NavTab[]>(() => {\n const baseTabs: NavTab[] = [\n { id: \"processes\", label: \"Processes\", icon: ProcessesIcon },\n { id: \"logs\", label: \"Logs\", icon: LogsIcon },\n ];\n\n const arrTabs: NavTab[] = [];\n const arrs = statusData?.arrs ?? [];\n\n const hasRadarr = arrs.some((arr) => arr.type === \"radarr\");\n const hasSonarr = arrs.some((arr) => arr.type === \"sonarr\");\n const hasLidarr = arrs.some((arr) => arr.type === \"lidarr\");\n\n if (hasRadarr) {\n arrTabs.push({ id: \"radarr\", label: \"Radarr\", icon: RadarrIcon });\n }\n if (hasSonarr) {\n arrTabs.push({ id: \"sonarr\", label: \"Sonarr\", icon: SonarrIcon });\n }\n if (hasLidarr) {\n arrTabs.push({ id: \"lidarr\", label: \"Lidarr\", icon: LidarrIcon });\n }\n\n return [\n ...baseTabs,\n ...arrTabs,\n { id: \"config\", label: \"Config\", icon: ConfigIcon },\n ];\n }, [statusData]);\n\n const repositoryUrl = meta?.repository_url ?? \"https://github.com/Feramance/qBitrr\";\n const displayVersion = meta?.current_version\n ? formatVersionLabel(meta.current_version)\n : \"...\";\n const latestVersion = meta?.latest_version ?? null;\n const updateAvailable = Boolean(meta?.update_available);\n const updateState = meta?.update_state;\n const changelogUrl = meta?.changelog_url ?? repositoryUrl;\n\n const versionTitleParts: string[] = [];\n if (meta?.last_checked) {\n versionTitleParts.push(`Last checked ${new Date(meta.last_checked).toLocaleString()}`);\n }\n if (meta?.error) {\n versionTitleParts.push(`Update check failed: ${meta.error}`);\n }\n const versionTitle = versionTitleParts.length ? versionTitleParts.join(\" • \") : undefined;\n\n // Redirect to processes if active tab is no longer available\n useEffect(() => {\n const tabExists = tabs.some((tab) => tab.id === activeTab);\n if (!tabExists && tabs.length > 0) {\n setActiveTab(\"processes\");\n }\n }, [tabs, activeTab]);\n\n const handleCheckUpdates = useCallback(() => {\n void refreshMeta({ force: true });\n }, [refreshMeta]);\n\n const handleOpenChangelog = useCallback(() => {\n setShowChangelog(true);\n if (!meta?.changelog) {\n void refreshMeta({ force: true, silent: true });\n }\n }, [meta?.changelog, refreshMeta]);\n\n const handleCloseChangelog = useCallback(() => {\n setShowChangelog(false);\n }, []);\n\n const handleCloseWelcomeChangelog = useCallback(() => {\n setShowWelcomeChangelog(false);\n // Mark this version as seen\n if (meta?.current_version) {\n localStorage.setItem(\"lastSeenVersion\", meta.current_version);\n }\n }, [meta?.current_version]);\n\n const handleTriggerUpdate = useCallback(async () => {\n setUpdateBusy(true);\n setBackendRestarting(false);\n restartPollCount.current = 0;\n try {\n await triggerUpdate();\n push(\"Update started in the background.\", \"info\");\n await refreshMeta({ force: true, silent: true });\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Failed to start update\";\n push(message, \"error\");\n } finally {\n setUpdateBusy(false);\n }\n }, [push, refreshMeta]);\n\n return (\n <div data-density={viewDensity}>\n <header className=\"appbar\">\n <div className=\"appbar__inner\">\n <div className=\"appbar__title\">\n <h1>qBitrr</h1>\n <span className=\"appbar__version\" title={versionTitle}>\n {displayVersion}\n </span>\n {metaLoading ? <span className=\"spinner\" aria-hidden=\"true\" /> : null}\n {updateState?.in_progress ? (\n <span className=\"appbar__status text-info\">Updating...</span>\n ) : null}\n {updateAvailable ? (\n <button\n type=\"button\"\n className=\"btn small primary appbar__update\"\n onClick={handleOpenChangelog}\n disabled={updateBusy || Boolean(updateState?.in_progress)}\n >\n <span className=\"appbar__update-indicator\" aria-hidden=\"true\" />\n <IconImage src={UpdateIcon} />\n Update available\n </button>\n ) : null}\n </div>\n <div className=\"appbar__actions\">\n {!isOnline && (\n <span className=\"badge\" style={{ background: 'rgba(239, 68, 68, 0.15)', borderColor: 'rgba(239, 68, 68, 0.3)', color: 'var(--danger)' }}>\n Offline\n </span>\n )}\n <div className=\"view-density-toggle\">\n <button\n type=\"button\"\n className={viewDensity === \"comfortable\" ? \"active\" : \"\"}\n onClick={() => setViewDensity(\"comfortable\")}\n title=\"Comfortable view\"\n >\n Comfortable\n </button>\n <button\n type=\"button\"\n className={viewDensity === \"compact\" ? \"active\" : \"\"}\n onClick={() => setViewDensity(\"compact\")}\n title=\"Compact view\"\n >\n Compact\n </button>\n </div>\n <button\n type=\"button\"\n className=\"btn small ghost\"\n onClick={handleCheckUpdates}\n disabled={metaLoading}\n >\n <IconImage src={RefreshIcon} />\n {metaLoading ? \"Checking...\" : \"Check Updates\"}\n </button>\n <a\n href={repositoryUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"btn small ghost\"\n >\n <IconImage src={ExternalIcon} />\n GitHub\n </a>\n </div>\n </div>\n </header>\n <main className=\"container\">\n <nav className=\"nav\">\n {tabs.map((tab) => (\n <button\n type=\"button\"\n key={tab.id}\n className={activeTab === tab.id ? \"active\" : \"\"}\n onClick={() => {\n if (activeTab === \"config\" && tab.id !== \"config\" && configDirty) {\n const shouldLeave = window.confirm(\n \"You have unsaved configuration changes. Leave without saving?\"\n );\n if (!shouldLeave) {\n return;\n }\n }\n setActiveTab(tab.id);\n setSearchValue(\"\");\n }}\n >\n <IconImage src={tab.icon} />\n <span>{tab.label}</span>\n </button>\n ))}\n </nav>\n <Suspense fallback={<div className=\"loading\">Loading...</div>}>\n {activeTab === \"processes\" && <ProcessesView key={`processes-${reloadKey}`} active />}\n {activeTab === \"logs\" && <LogsView key={`logs-${reloadKey}`} active />}\n {activeTab === \"radarr\" && <ArrView key={`radarr-${reloadKey}`} type=\"radarr\" active />}\n {activeTab === \"sonarr\" && <ArrView key={`sonarr-${reloadKey}`} type=\"sonarr\" active />}\n {activeTab === \"lidarr\" && <ArrView key={`lidarr-${reloadKey}`} type=\"lidarr\" active />}\n {activeTab === \"config\" && <ConfigView key={`config-${reloadKey}`} onDirtyChange={setConfigDirty} />}\n </Suspense>\n </main>\n {showChangelog && meta ? (\n <ChangelogModal\n currentVersion={meta.current_version}\n latestVersion={latestVersion}\n changelog={meta.changelog}\n changelogUrl={changelogUrl}\n repositoryUrl={repositoryUrl}\n updateState={updateState}\n updating={updateBusy}\n onClose={handleCloseChangelog}\n onUpdate={handleTriggerUpdate}\n />\n ) : null}\n {showWelcomeChangelog && meta ? (\n <WelcomeModal\n currentVersion={meta.current_version}\n changelog={meta.current_version_changelog || meta.changelog}\n changelogUrl={changelogUrl}\n repositoryUrl={repositoryUrl}\n onClose={handleCloseWelcomeChangelog}\n />\n ) : null}\n </div>\n );\n}\n\nexport default function App(): JSX.Element {\n return (\n <ToastProvider>\n <SearchProvider>\n <WebUIProvider>\n <AppShell />\n <ToastViewport />\n </WebUIProvider>\n </SearchProvider>\n </ToastProvider>\n );\n}\n","import { StrictMode } from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport \"./styles.css\";\nimport App from \"./App\";\n\ncreateRoot(document.getElementById(\"root\")!).render(\n <StrictMode>\n <App />\n </StrictMode>\n);\n"],"file":"app.js"}
@@ -0,0 +1,47 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/static/vite.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <meta name="description" content="A Radarr and Sonarr companion app for managing torrents" />
8
+ <meta name="theme-color" content="#7aa2f7" />
9
+ <link rel="manifest" href="/static/manifest.json" />
10
+ <title>qBitrr</title>
11
+ <script type="module" crossorigin src="/static/assets/app.js"></script>
12
+ <link rel="modulepreload" crossorigin href="/static/assets/vendor.js">
13
+ <link rel="modulepreload" crossorigin href="/static/assets/table.js">
14
+ <link rel="stylesheet" crossorigin href="/static/assets/app.css">
15
+ </head>
16
+ <body>
17
+ <div id="root"></div>
18
+ <script>
19
+ // Register service worker for PWA support
20
+ // Note: Service workers require HTTPS or localhost. The /sw.js endpoint can be
21
+ // whitelisted in auth proxies (e.g., Authentik) to enable PWA features.
22
+ if ('serviceWorker' in navigator) {
23
+ window.addEventListener('load', async () => {
24
+ try {
25
+ // Check if service worker file is accessible (not behind auth redirect)
26
+ const swResponse = await fetch('/sw.js', { method: 'HEAD', credentials: 'same-origin' });
27
+ if (!swResponse.ok || swResponse.status === 401 || swResponse.status === 403) {
28
+ console.debug('ServiceWorker not available: requires whitelisting /sw.js in auth proxy');
29
+ return;
30
+ }
31
+
32
+ // Attempt registration
33
+ const registration = await navigator.serviceWorker.register('/sw.js');
34
+ console.log('ServiceWorker registered successfully');
35
+ } catch (error) {
36
+ // Silently fail on insecure contexts or other errors
37
+ if (error.name === 'SecurityError' || error.name === 'TypeError') {
38
+ console.debug('ServiceWorker not available (requires HTTPS or localhost)');
39
+ } else {
40
+ console.debug('ServiceWorker registration failed:', error.message);
41
+ }
42
+ }
43
+ });
44
+ }
45
+ </script>
46
+ </body>
47
+ </html>
@@ -1192,10 +1192,14 @@ class WebUI:
1192
1192
 
1193
1193
  @app.get("/sw.js")
1194
1194
  def service_worker():
1195
- # Service worker must be served from root path for PWA support
1196
- from flask import make_response
1195
+ # Service worker must be served directly (not redirected) for PWA support
1196
+ # This allows the endpoint to be whitelisted in auth proxies (e.g., Authentik)
1197
+ import os
1198
+
1199
+ from flask import send_from_directory
1197
1200
 
1198
- response = make_response(redirect("/static/sw.js"))
1201
+ static_dir = os.path.join(os.path.dirname(__file__), "static")
1202
+ response = send_from_directory(static_dir, "sw.js")
1199
1203
  # Prevent caching of the service worker to ensure updates are picked up
1200
1204
  response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
1201
1205
  response.headers["Pragma"] = "no-cache"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qBitrr2
3
- Version: 5.4.2
3
+ Version: 5.4.3
4
4
  Summary: Intelligent automation for qBittorrent and *Arr apps (Radarr/Sonarr/Lidarr) - health monitoring, instant imports, quality upgrades, request integration
5
5
  Home-page: https://github.com/Feramance/qBitrr
6
6
  Author: Feramance
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = qBitrr2
3
- version = 5.4.2
3
+ version = 5.4.3
4
4
  description = Intelligent automation for qBittorrent and *Arr apps (Radarr/Sonarr/Lidarr) - health monitoring, instant imports, quality upgrades, request integration
5
5
  long_description = file: README.md
6
6
  long_description_content_type = text/markdown
@@ -1,11 +0,0 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/ProcessesView.js","assets/table.js","assets/vendor.js","assets/useInterval.js","assets/LogsView.js","assets/react-select.esm.js","assets/ArrView.js","assets/ConfigView.js"])))=>i.map(i=>d[i]);
2
- import{r as Re,a as Le}from"./vendor.js";import{r as o}from"./table.js";(function(){const s=document.createElement("link").relList;if(s&&s.supports&&s.supports("modulepreload"))return;for(const r of document.querySelectorAll('link[rel="modulepreload"]'))i(r);new MutationObserver(r=>{for(const a of r)if(a.type==="childList")for(const f of a.addedNodes)f.tagName==="LINK"&&f.rel==="modulepreload"&&i(f)}).observe(document,{childList:!0,subtree:!0});function n(r){const a={};return r.integrity&&(a.integrity=r.integrity),r.referrerPolicy&&(a.referrerPolicy=r.referrerPolicy),r.crossOrigin==="use-credentials"?a.credentials="include":r.crossOrigin==="anonymous"?a.credentials="omit":a.credentials="same-origin",a}function i(r){if(r.ep)return;r.ep=!0;const a=n(r);fetch(r.href,a)}})();var F={exports:{}},P={};/**
3
- * @license React
4
- * react-jsx-runtime.production.min.js
5
- *
6
- * Copyright (c) Facebook, Inc. and its affiliates.
7
- *
8
- * This source code is licensed under the MIT license found in the
9
- * LICENSE file in the root directory of this source tree.
10
- */var re;function Ne(){if(re)return P;re=1;var e=Re(),s=Symbol.for("react.element"),n=Symbol.for("react.fragment"),i=Object.prototype.hasOwnProperty,r=e.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,a={key:!0,ref:!0,__self:!0,__source:!0};function f(h,m,c){var p,y={},d=null,g=null;c!==void 0&&(d=""+c),m.key!==void 0&&(d=""+m.key),m.ref!==void 0&&(g=m.ref);for(p in m)i.call(m,p)&&!a.hasOwnProperty(p)&&(y[p]=m[p]);if(h&&h.defaultProps)for(p in m=h.defaultProps,m)y[p]===void 0&&(y[p]=m[p]);return{$$typeof:s,type:h,key:d,ref:g,props:y,_owner:r.current}}return P.Fragment=n,P.jsx=f,P.jsxs=f,P}var ne;function Ie(){return ne||(ne=1,F.exports=Ne()),F.exports}var t=Ie(),q={},oe;function Te(){if(oe)return q;oe=1;var e=Le();return q.createRoot=e.createRoot,q.hydrateRoot=e.hydrateRoot,q}var Pe=Te();const Ue="modulepreload",$e=function(e){return"/static/"+e},ae={},W=function(s,n,i){let r=Promise.resolve();if(n&&n.length>0){let m=function(c){return Promise.all(c.map(p=>Promise.resolve(p).then(y=>({status:"fulfilled",value:y}),y=>({status:"rejected",reason:y}))))};document.getElementsByTagName("link");const f=document.querySelector("meta[property=csp-nonce]"),h=f?.nonce||f?.getAttribute("nonce");r=m(n.map(c=>{if(c=$e(c),c in ae)return;ae[c]=!0;const p=c.endsWith(".css"),y=p?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${c}"]${y}`))return;const d=document.createElement("link");if(d.rel=p?"stylesheet":Ue,p||(d.as="script"),d.crossOrigin="",d.href=c,h&&d.setAttribute("nonce",h),document.head.appendChild(d),p)return new Promise((g,v)=>{d.addEventListener("load",g),d.addEventListener("error",()=>v(new Error(`Unable to preload CSS for ${c}`)))})}))}function a(f){const h=new Event("vite:preloadError",{cancelable:!0});if(h.payload=f,window.dispatchEvent(h),!h.defaultPrevented)throw f}return r.then(f=>{for(const h of f||[])h.status==="rejected"&&a(h.reason);return s().catch(a)})},ue=o.createContext(void 0);let Ae=0;function Oe({children:e}){const[s,n]=o.useState([]),i=o.useCallback(f=>{n(h=>h.filter(m=>m.id!==f))},[]),r=o.useCallback((f,h="info")=>{const m=++Ae;n(c=>[...c,{id:m,message:f,kind:h}]),window.setTimeout(()=>i(m),3500)},[i]),a=o.useMemo(()=>({toasts:s,push:r,dismiss:i}),[s,r,i]);return t.jsx(ue.Provider,{value:a,children:e})}function de(){const e=o.useContext(ue);if(!e)throw new Error("useToast must be used within a ToastProvider");return e}function De(){const{toasts:e,dismiss:s}=de();return e.length?t.jsx("div",{className:"toasts",children:e.map(n=>t.jsx("div",{className:`toast ${n.kind!=="info"?n.kind:""}`,role:"status",onClick:()=>s(n.id),children:n.message},n.id))}):null}const fe=o.createContext(void 0);function Ve({children:e}){const[s,n]=o.useState(""),i=o.useRef(new Set),r=o.useCallback(m=>{n(m),i.current.forEach(c=>{c?.(m)})},[]),a=o.useCallback(m=>{m&&i.current.add(m)},[]),f=o.useCallback(m=>{i.current.delete(m)},[]),h=o.useMemo(()=>({value:s,setValue:r,register:a,clearHandler:f}),[s,r,a,f]);return t.jsx(fe.Provider,{value:h,children:e})}function Me(){const e=o.useContext(fe);if(!e)throw new Error("useSearch must be used within a SearchProvider");return e}const qe={"Content-Type":"application/json"},Y=["token","webui-token","webui_token"],Be=1,J=new Map;function We(e,s){const n=e instanceof Request?e.url:String(e),i=s?.method||"GET",r=s?.body?String(s.body):"";return`${i}:${n}:${r}`}function me(){for(const e of Y){const s=localStorage.getItem(e)||sessionStorage.getItem(e);if(s)return e!=="token"&&localStorage.setItem("token",s),s}try{const s=new URLSearchParams(window.location.search).get("token");if(s)return localStorage.setItem("token",s),s}catch{}return null}function Ge(){for(const e of Y)localStorage.removeItem(e);try{for(const e of Y)sessionStorage.removeItem(e)}catch{}}function he(e,s){const n=new Headers(e?.headers||{});return Object.entries(qe).forEach(([i,r])=>{n.has(i)||n.set(i,r)}),s&&!n.has("Authorization")&&n.set("Authorization",`Bearer ${s}`),{...e,headers:n}}async function B(e,s,n,i=Be){const r=me(),a=await fetch(e,he(s,r));return a.status===401&&i>0&&r?(Ge(),B(e,s,n,i-1)):n(a)}async function k(e,s){if((s?.method||"GET")==="GET"){const i=We(e,s),r=J.get(i);if(r)return r;const a=B(e,s,f=>ce(f)).finally(()=>{J.delete(i)});return J.set(i,a),a}return B(e,s,i=>ce(i))}async function He(e,s){return B(e,s,n=>ze(n))}async function ce(e){if(!e.ok){let s=null;try{s=await e.json()}catch{}let n=`${e.status} ${e.statusText}`;if(s&&typeof s=="object"&&"error"in s&&typeof s.error=="string"){const i=s.error;i.trim()&&(n=i)}throw new Error(n)}return await e.json()}async function ze(e){if(!e.ok)throw new Error(`${e.status} ${e.statusText}`);return e.text()}async function ie(e){const s=e?.force?"?force=1":"";return k(`/web/meta${s}`)}async function le(){return k("/web/status")}async function gt(){return k("/web/processes")}async function pt(e,s){const n=`/web/processes/${encodeURIComponent(e)}/${encodeURIComponent(s)}/restart`;return k(n,{method:"POST"})}async function vt(){return k("/web/processes/restart_all",{method:"POST"})}async function yt(){return k("/web/arr/rebuild",{method:"POST"})}async function wt(){return k("/web/logs")}async function bt(e){return He(`/web/logs/${encodeURIComponent(e)}`)}function xt(e){return`/web/logs/${encodeURIComponent(e)}/download`}async function _t(){return k("/web/arr")}async function jt(e,s,n,i){const r=new URLSearchParams;return r.set("page",String(s)),r.set("page_size",String(n)),i&&r.set("q",i),k(`/web/radarr/${encodeURIComponent(e)}/movies?${r}`)}async function kt(e,s,n,i,r){const a=new URLSearchParams;return a.set("page",String(s)),a.set("page_size",String(n)),i&&a.set("q",i),r?.missingOnly&&a.set("missing","1"),k(`/web/sonarr/${encodeURIComponent(e)}/series?${a}`)}async function Ct(e,s,n,i){const r=new URLSearchParams;return r.set("page",s.toString()),r.set("page_size",n.toString()),i&&r.set("q",i),r.set("include_tracks","true"),k(`/web/lidarr/${encodeURIComponent(e)}/albums?${r}`)}async function St(e){await k(`/web/arr/${encodeURIComponent(e)}/restart`,{method:"POST"})}async function Fe(){return k("/web/config")}async function Je(e){const s=me(),n=await fetch("/web/config",he({method:"POST",body:JSON.stringify(e)},s));if(!n.ok){let r=null;try{r=await n.json()}catch{}let a=`${n.status} ${n.statusText}`;if(r&&typeof r=="object"&&"error"in r&&typeof r.error=="string"){const f=r.error;f.trim()&&(a=f)}throw new Error(a)}return await n.json()}async function Ke(){await k("/web/update",{method:"POST"})}const ge=o.createContext(null);function Ye({children:e}){const[s,n]=o.useState({liveArr:!0,groupSonarr:!0,groupLidarr:!0,viewDensity:"comfortable",theme:"dark"}),[i,r]=o.useState(!0);o.useEffect(()=>{(async()=>{try{const v=(await Fe())?.WebUI,x=localStorage.getItem("viewDensity"),S=localStorage.getItem("theme"),I=v?.Theme,E=S||I?.toLowerCase()||"dark";n({liveArr:v?.LiveArr===!0,groupSonarr:v?.GroupSonarr===!0,groupLidarr:v?.GroupLidarr===!0,viewDensity:x||"comfortable",theme:E}),document.documentElement.setAttribute("data-theme",E)}catch(g){console.error("Failed to load WebUI settings:",g)}finally{r(!1)}})()},[]);const a=o.useCallback(async(d,g)=>{try{const v={WebUI:{[d]:g}};await Je({changes:v})}catch(v){console.error(`Failed to save ${d}:`,v)}},[]),f=o.useCallback(d=>{n(g=>({...g,liveArr:d})),a("LiveArr",d)},[a]),h=o.useCallback(d=>{n(g=>({...g,groupSonarr:d})),a("GroupSonarr",d)},[a]),m=o.useCallback(d=>{n(g=>({...g,groupLidarr:d})),a("GroupLidarr",d)},[a]),c=o.useCallback(d=>{n(g=>({...g,viewDensity:d})),localStorage.setItem("viewDensity",d)},[]),p=o.useCallback(d=>{n(v=>({...v,theme:d})),localStorage.setItem("theme",d),document.documentElement.setAttribute("data-theme",d),a("Theme",d==="light"?"Light":"Dark")},[a]),y={liveArr:s.liveArr,groupSonarr:s.groupSonarr,groupLidarr:s.groupLidarr,viewDensity:s.viewDensity,theme:s.theme,setLiveArr:f,setGroupSonarr:h,setGroupLidarr:m,setViewDensity:c,setTheme:p,loading:i};return t.jsx(ge.Provider,{value:y,children:e})}function Qe(){const e=o.useContext(ge);if(!e)throw new Error("useWebUI must be used within WebUIProvider");return e}function Xe(){const[e,s]=o.useState(navigator.onLine);return o.useEffect(()=>{const n=()=>s(!0),i=()=>s(!1);return window.addEventListener("online",n),window.addEventListener("offline",i),()=>{window.removeEventListener("online",n),window.removeEventListener("offline",i)}},[]),e}function C({src:e,alt:s,className:n,...i}){return t.jsx("img",{src:e,alt:s??"",className:n?`icon ${n}`:"icon","aria-hidden":s?void 0:!0,...i})}const pe="/static/assets/close.svg",Q="data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20xml:space='preserve'%20viewBox='0%200%20512%20512'%3e%3cpath%20d='M256%206.3C114.6%206.3%200%20120.9%200%20262.3c0%20113.3%2073.3%20209%20175%20242.9%2012.8%202.2%2017.6-5.4%2017.6-12.2%200-6.1-.3-26.2-.3-47.7-64.3%2011.8-81-15.7-86.1-30.1-2.9-7.4-15.4-30.1-26.2-36.2-9-4.8-21.8-16.6-.3-17%2020.2-.3%2034.6%2018.6%2039.4%2026.2%2023%2038.7%2059.8%2027.8%2074.6%2021.1%202.2-16.6%209-27.8%2016.3-34.2-57-6.4-116.5-28.5-116.5-126.4%200-27.8%209.9-50.9%2026.2-68.8-2.6-6.4-11.5-32.6%202.6-67.8%200%200%2021.4-6.7%2070.4%2026.2%2020.5-5.8%2042.2-8.6%2064-8.6s43.5%202.9%2064%208.6c49-33.3%2070.4-26.2%2070.4-26.2%2014.1%2035.2%205.1%2061.4%202.6%2067.8%2016.3%2017.9%2026.2%2040.6%2026.2%2068.8%200%2098.2-59.8%20120-116.8%20126.4%209.3%208%2017.3%2023.4%2017.3%2047.4%200%2034.2-.3%2061.8-.3%2070.4%200%206.7%204.8%2014.7%2017.6%2012.2C438.7%20471.3%20512%20375.3%20512%20262.3c0-141.4-114.6-256-256-256'%20style='fill-rule:evenodd;clip-rule:evenodd;fill:%231b1f23'/%3e%3c/svg%3e",Ze="/static/assets/refresh-arrow.svg",ve="/static/assets/up-arrow.svg",et="/static/assets/process.svg",tt="/static/assets/log.svg",st="data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20xml:space='preserve'%20id='Layer_1'%20x='0'%20y='0'%20version='1.1'%20viewBox='0%200%20512%20512'%3e%3cstyle%3e.st0{fill:%2324292e}%3c/style%3e%3cg%20id='Group-Copy'%20transform='translate(70%2021)'%3e%3cpath%20id='Shape'%20d='m10.3%2059.8%203.9%20372.4c-31.4%203.9-54.9-11.8-54.9-43.1l-3.9-309.7c0-98%2090.2-121.5%20145.1-82.3l278.3%20160.7c39.2%2027.4%2047%2078.4%2027.4%20113.7-3.9-27.4-15.7-43.1-39.2-58.8L53.4%2036.2C29.9%2020.6%2010.3%2024.5%2010.3%2059.8'%20class='st0'/%3e%3cpath%20id='Shape_00000114049535938561773820000018271523940913105341_'%20d='M-13.2%20451.8c23.5%207.8%2047%203.9%2066.6-7.8l321.5-188.2c19.6%2027.4%2015.7%2054.9-7.8%2070.6L96.5%20483.2c-39.2%2019.6-90.1%200-109.7-31.4'%20class='st0'/%3e%3cpath%20id='Shape_00000165935924413286433040000003668002807793862576_'%20d='M80.9%20342%20273%20232.3%2084.8%20126.4z'%20style='fill:%23ffc230'/%3e%3c/g%3e%3c/svg%3e",rt="data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20xml:space='preserve'%20viewBox='0%200%20512%20512'%3e%3cpath%20d='M511.8%20256c0%2070.4-24.9%20130.8-74.6%20181.1-1.7%202-3.5%203.8-5.5%205.4-8.2%208-16.8%2015.3-26%2021.8Q341.05%20512%20256.3%20512c-56.6%200-106.3-15.9-149.2-47.7-11.3-8-22-17.1-31.9-27.3C36.5%20398.7%2012.8%20354%204%20303.2c-1.7-9.9-2.9-20-3.4-30.2-.2-5.7-.4-11.3-.4-17%200-6%20.1-11.7.4-17.1%200-.6.2-1.1.5-1.7%203.7-62.8%2028.4-117%2074.1-162.8C125.5%2024.8%20185.8%200%20256.2%200c70.7%200%20131%2024.8%20180.9%2074.5q74.7%2075.9%2074.7%20181.5'%20style='fill-rule:evenodd;clip-rule:evenodd;fill:%23eee'/%3e%3cpath%20d='m459.7%20100.3-52.9%2052.9c-30.9%2030.9-33.6%2057.8-33.6%20105.3%200%2042.3%206.7%2081.1%2038.2%20112.6%2023%2023%2044.9%2044.7%2044.9%2044.7-5.9%207.2-12.3%2014.3-19.1%2021.2-1.7%202-3.5%203.8-5.5%205.4-6%205.9-12.2%2011.4-18.6%2016.4l-41.4-41.4C334.9%20380.6%20305.6%20377%20257%20377c-46.7%200-78.4%204.3-112.6%2038.5-20.4%2020.4-43.8%2043.9-43.8%2043.9-8.9-6.8-17.3-14.2-25.3-22.4-6.6-6.6-12.8-13.4-18.5-20.3%200%200%2023.1-23.2%2045.2-45.3%2032.7-32.7%2038-70.6%2038-113%200-41.3-6.8-79.8-36.8-109.9C82.2%20127.7%2053.3%2099%2053.3%2099c6.7-8.5%2014-16.7%2021.8-24.5%206.9-6.8%2014-13.1%2021.2-19l48%2048c30.7%2030.7%2070%2038.6%20112.4%2038.6%2043.6%200%2082.8-8.4%20114.7-40.4C391%2082.1%20417%2056.3%20417%2056.3c6.8%205.6%2013.5%2011.6%2020.1%2018.2%208.3%208.3%2015.8%2016.9%2022.6%2025.8'%20style='fill-rule:evenodd;clip-rule:evenodd;fill:%233a3f51'/%3e%3cpath%20d='M186%20269.1c-.5-2.8-.8-5.5-.9-8.4-.1-1.6-.1-3.1-.1-4.7%200-1.7%200-3.2.1-4.7%200-.2%200-.3.1-.5%201-17.4%207.9-32.4%2020.5-45.1%2013.9-13.8%2030.6-20.7%2050.2-20.7s36.3%206.9%2050.2%2020.7c13.8%2014%2020.7%2030.8%2020.7%2050.3s-6.9%2036.2-20.7%2050.2c-.5.5-1%201.1-1.5%201.5q-3.45%203.3-7.2%206-18%2013.2-41.4%2013.2c-23.4%200-29.4-4.4-41.3-13.2-3.1-2.2-6.1-4.7-8.9-7.6-10.8-10.6-17.3-22.9-19.8-37'%20style='fill-rule:evenodd;clip-rule:evenodd;fill:%230cf'/%3e%3cpath%20d='m372.7%20141-35.4%2034.6M72.9%2076.8l96.5%2096.1m199.7%20198.9%2065.6%2067.9m4.4-363.3L372.7%20141M76.6%20438.5l64.6-64.7'%20style='fill:none;stroke:%230cf;stroke-width:2;stroke-miterlimit:1'/%3e%3cpath%20d='m372.7%20141-40%2040.6m-193.3-38.5%2040.6%2040.5M141%20374l39.5-41.1m146.2-3.3%2042.6%2042.4'%20style='fill:none;stroke:%230cf;stroke-width:7;stroke-miterlimit:1'/%3e%3c/svg%3e",nt="/static/assets/lidarr.svg",ot="/static/assets/gear.svg",at=o.lazy(()=>W(()=>import("./ProcessesView.js"),__vite__mapDeps([0,1,2,3])).then(e=>({default:e.ProcessesView}))),ct=o.lazy(()=>W(()=>import("./LogsView.js"),__vite__mapDeps([4,1,2,5,3])).then(e=>({default:e.LogsView}))),K=o.lazy(()=>W(()=>import("./ArrView.js"),__vite__mapDeps([6,1,2,3])).then(e=>({default:e.ArrView}))),it=o.lazy(()=>W(()=>import("./ConfigView.js"),__vite__mapDeps([7,1,2,5])).then(e=>({default:e.ConfigView})));function U(e){if(!e)return"unknown";const s=e.trim();return s?s[0]==="v"||s[0]==="V"?s:`v${s}`:"unknown"}function lt({currentVersion:e,changelog:s,changelogUrl:n,repositoryUrl:i,onClose:r}){return t.jsx("div",{className:"modal-backdrop",role:"presentation",onClick:r,children:t.jsxs("div",{className:"modal",role:"dialog","aria-modal":"true","aria-labelledby":"welcome-title",onClick:a=>a.stopPropagation(),children:[t.jsxs("div",{className:"modal-header",children:[t.jsxs("h2",{id:"welcome-title",children:["🎉 Welcome to qBitrr ",U(e),"!"]}),t.jsxs("button",{className:"btn ghost",type:"button",onClick:r,children:[t.jsx(C,{src:pe}),"Close"]})]}),t.jsxs("div",{className:"modal-body changelog-modal__body",children:[t.jsx("div",{className:"changelog-meta",children:t.jsxs("p",{style:{marginBottom:"1rem",color:"var(--text-secondary)"},children:["You've been updated to version ",t.jsx("strong",{children:U(e)}),". Here's what's new in this release:"]})}),t.jsxs("div",{className:"changelog-section",children:[t.jsx("h3",{children:"Release Notes"}),t.jsx("pre",{className:"changelog-body",children:s?.trim()?s.trim():"No changelog available for this version."})]})]}),t.jsxs("div",{className:"modal-footer",children:[t.jsx("div",{className:"changelog-links",children:(n||i)&&t.jsxs("a",{className:"btn ghost small",href:n??i,target:"_blank",rel:"noreferrer",children:[t.jsx(C,{src:Q}),"View Full Release on GitHub"]})}),t.jsx("div",{className:"changelog-buttons",children:t.jsx("button",{className:"btn primary",type:"button",onClick:r,children:"Got it!"})})]})]})})}function ut({currentVersion:e,latestVersion:s,changelog:n,changelogUrl:i,repositoryUrl:r,updateState:a,updating:f,onClose:h,onUpdate:m}){const[c,p]=o.useState(null),y=f||!!a?.in_progress,d=a?.completed_at?new Date(a.completed_at).toLocaleString():null;o.useEffect(()=>{if(a?.last_result==="success"&&a?.completed_at){let x=10;p(x);const S=setInterval(()=>{x-=1,x<=0?(clearInterval(S),window.location.reload()):p(x)},1e3);return()=>clearInterval(S)}},[a?.last_result,a?.completed_at]);let g="",v=null;if(a?.in_progress)g="text-info",v="⏳ Update in progress...";else if(a?.last_result==="success")g="text-success",c!==null?v=`✓ Update completed! Reloading in ${c}s...`:(v="✓ Update completed successfully",d&&(v=`${v} (${d})`));else if(a?.last_result==="error"){g="text-danger";const x=a.last_error?a.last_error.trim():"";v=x?`✗ Update failed: ${x}`:"✗ Update failed"}return t.jsx("div",{className:"modal-backdrop",role:"presentation",onClick:h,children:t.jsxs("div",{className:"modal",role:"dialog","aria-modal":"true","aria-labelledby":"changelog-title",onClick:x=>x.stopPropagation(),children:[t.jsxs("div",{className:"modal-header",children:[t.jsx("h2",{id:"changelog-title",children:a?.in_progress?"⚙️ Updating...":"🚀 Update Available"}),t.jsxs("button",{className:"btn ghost",type:"button",onClick:h,disabled:a?.in_progress,children:[t.jsx(C,{src:pe}),"Close"]})]}),t.jsxs("div",{className:"modal-body changelog-modal__body",children:[t.jsxs("div",{className:"changelog-meta",children:[t.jsxs("div",{className:"version-comparison",children:[t.jsxs("span",{className:"version-item",children:[t.jsx("strong",{children:"Current:"})," ",t.jsx("span",{className:"version-badge version-current",children:U(e)})]}),t.jsx("span",{className:"version-arrow",children:"→"}),t.jsxs("span",{className:"version-item",children:[t.jsx("strong",{children:"Latest:"})," ",t.jsx("span",{className:"version-badge version-latest",children:s?U(s):"Unknown"})]})]}),v?t.jsx("div",{className:`update-status ${g}`,children:v}):null]}),t.jsxs("div",{className:"changelog-section",children:[t.jsx("h3",{children:"What's New"}),t.jsx("pre",{className:"changelog-body",children:n?.trim()?n.trim():"No changelog provided."})]})]}),t.jsxs("div",{className:"modal-footer",children:[t.jsx("div",{className:"changelog-links",children:(i||r)&&t.jsxs("a",{className:"btn ghost small",href:i??r,target:"_blank",rel:"noreferrer",children:[t.jsx(C,{src:Q}),"View on GitHub"]})}),t.jsx("div",{className:"changelog-buttons",children:t.jsxs("button",{className:"btn primary",type:"button",onClick:m,disabled:y,children:[t.jsx(C,{src:ve}),y?"Updating...":"Update Now"]})})]})]})})}function dt(){const[e,s]=o.useState("processes"),[n,i]=o.useState(!1),{push:r}=de(),{setValue:a}=Me(),{viewDensity:f,setViewDensity:h}=Qe(),m=Xe(),[c,p]=o.useState(null),[y,d]=o.useState(!1),[g,v]=o.useState(!1),[x,S]=o.useState(!1),[I,E]=o.useState(!1),R=o.useRef(0),G=o.useRef(null),H=o.useRef(!1),$=o.useRef(!1),L=o.useRef(null),[N,X]=o.useState(0),[Z,ee]=o.useState(null),[ye,te]=o.useState(!1);o.useEffect(()=>{(async()=>{if("caches"in window)try{const l=await caches.keys();await Promise.all(l.map(b=>caches.delete(b))),console.log("Cache cleared on page load")}catch(l){console.error("Failed to clear cache:",l)}})()},[]);const _=o.useCallback(async u=>{const l=u?.force??!1,b=u?.silent??!l;b||d(!0);try{const j=await ie({force:l});p(j)}catch(j){if(!b){const w=j instanceof Error?j.message:"Failed to fetch version information";r(w,"error")}}finally{b||d(!1)}},[r]);o.useEffect(()=>{_({force:!0})},[_]),o.useEffect(()=>{if(!c?.current_version)return;const u=localStorage.getItem("lastSeenVersion"),l=c.current_version;u&&u!==l&&(!c.current_version_changelog&&!c.changelog&&_({force:!0,silent:!0}),te(!0)),u||localStorage.setItem("lastSeenVersion",l)},[c?.current_version,c?.changelog,_]),o.useEffect(()=>{m||r("You are offline. Some features may not work.","warning")},[m,r]),o.useEffect(()=>{const u=l=>{if(l.target instanceof HTMLInputElement||l.target instanceof HTMLTextAreaElement||l.target instanceof HTMLSelectElement)return;const b=l.ctrlKey||l.metaKey;if(b&&l.key==="k"){l.preventDefault(),document.querySelector('input[type="text"][placeholder*="Search"]')?.focus();return}if(l.key==="r"||l.key==="R"){l.preventDefault(),X(j=>j+1),r("Refreshed","success");return}if(l.key==="Escape"){a("");return}if(l.key>="1"&&l.key<="6"&&!b){l.preventDefault();const j=parseInt(l.key)-1,w=["processes","logs","radarr","sonarr","lidarr","config"];j<w.length&&s(w[j]);return}};return window.addEventListener("keydown",u),()=>window.removeEventListener("keydown",u)},[a,r]),o.useEffect(()=>{const u=window.setInterval(()=>{_()},3e5);return()=>window.clearInterval(u)},[_]),o.useEffect(()=>{const u=()=>{document.visibilityState==="visible"&&(X(l=>l+1),_({force:!0}),A())};return document.addEventListener("visibilitychange",u),()=>{document.removeEventListener("visibilitychange",u)}},[_]);const A=o.useCallback(async()=>{try{const u=await le();ee(u)}catch{}},[]);o.useEffect(()=>{A();const u=window.setInterval(()=>{A()},5*1e3);return()=>window.clearInterval(u)},[A]),o.useEffect(()=>{if(!c?.update_state?.in_progress&&!I){R.current=0;return}const u=window.setInterval(async()=>{try{const l=await ie({force:!0});p(l),I&&window.location.reload(),R.current=0}catch{if(R.current+=1,R.current>20){E(!1),R.current=0,r("Update completed but backend restart timed out. Please refresh the page manually.","warning");return}c?.update_state?.in_progress&&E(!0)}},3e3);return()=>window.clearInterval(u)},[c?.update_state?.in_progress,I,c,r]),o.useEffect(()=>{const u=c?.update_state;if(!u){G.current=null;return}const l=u.last_result??null;l&&l!==G.current&&(l==="success"?(r("Update completed successfully. Restarting...","success"),E(!0),R.current=0):l==="error"&&r(u.last_error||"Update failed.","error")),G.current=l},[c?.update_state,r]),o.useEffect(()=>{let u=!1,l=0;const b=w=>{L.current!==null&&window.clearTimeout(L.current),L.current=window.setTimeout(()=>{j()},w)},j=async()=>{if(!(u||H.current)){l+=1;try{const w=await le();if(u)return;if(ee(w),w.ready??(Array.isArray(w.arrs)&&w.arrs.length>0)){H.current=!0;return}w.ready===!1&&l>=3&&!$.current&&($.current=!0,r("qBitrr backend is still initialising. Check the logs if this persists.","warning"))}catch(w){if(!$.current&&l>=3){$.current=!0;const M=w instanceof Error?w.message:"Unknown backend error";r(`Unable to confirm qBitrr readiness (${M}). Please inspect the logs.`,"warning")}}finally{if(!u&&!H.current){const w=l<3?3e3:1e4;b(w)}}}};return b(0),()=>{u=!0,L.current!==null&&(window.clearTimeout(L.current),L.current=null)}},[r]);const O=o.useMemo(()=>{const u=[{id:"processes",label:"Processes",icon:et},{id:"logs",label:"Logs",icon:tt}],l=[],b=Z?.arrs??[],j=b.some(T=>T.type==="radarr"),w=b.some(T=>T.type==="sonarr"),M=b.some(T=>T.type==="lidarr");return j&&l.push({id:"radarr",label:"Radarr",icon:st}),w&&l.push({id:"sonarr",label:"Sonarr",icon:rt}),M&&l.push({id:"lidarr",label:"Lidarr",icon:nt}),[...u,...l,{id:"config",label:"Config",icon:ot}]},[Z]),D=c?.repository_url??"https://github.com/Feramance/qBitrr",we=c?.current_version?U(c.current_version):"...",be=c?.latest_version??null,xe=!!c?.update_available,z=c?.update_state,se=c?.changelog_url??D,V=[];c?.last_checked&&V.push(`Last checked ${new Date(c.last_checked).toLocaleString()}`),c?.error&&V.push(`Update check failed: ${c.error}`);const _e=V.length?V.join(" • "):void 0;o.useEffect(()=>{!O.some(l=>l.id===e)&&O.length>0&&s("processes")},[O,e]);const je=o.useCallback(()=>{_({force:!0})},[_]),ke=o.useCallback(()=>{v(!0),c?.changelog||_({force:!0,silent:!0})},[c?.changelog,_]),Ce=o.useCallback(()=>{v(!1)},[]),Se=o.useCallback(()=>{te(!1),c?.current_version&&localStorage.setItem("lastSeenVersion",c.current_version)},[c?.current_version]),Ee=o.useCallback(async()=>{S(!0),E(!1),R.current=0;try{await Ke(),r("Update started in the background.","info"),await _({force:!0,silent:!0})}catch(u){const l=u instanceof Error?u.message:"Failed to start update";r(l,"error")}finally{S(!1)}},[r,_]);return t.jsxs("div",{"data-density":f,children:[t.jsx("header",{className:"appbar",children:t.jsxs("div",{className:"appbar__inner",children:[t.jsxs("div",{className:"appbar__title",children:[t.jsx("h1",{children:"qBitrr"}),t.jsx("span",{className:"appbar__version",title:_e,children:we}),y?t.jsx("span",{className:"spinner","aria-hidden":"true"}):null,z?.in_progress?t.jsx("span",{className:"appbar__status text-info",children:"Updating..."}):null,xe?t.jsxs("button",{type:"button",className:"btn small primary appbar__update",onClick:ke,disabled:x||!!z?.in_progress,children:[t.jsx("span",{className:"appbar__update-indicator","aria-hidden":"true"}),t.jsx(C,{src:ve}),"Update available"]}):null]}),t.jsxs("div",{className:"appbar__actions",children:[!m&&t.jsx("span",{className:"badge",style:{background:"rgba(239, 68, 68, 0.15)",borderColor:"rgba(239, 68, 68, 0.3)",color:"var(--danger)"},children:"Offline"}),t.jsxs("div",{className:"view-density-toggle",children:[t.jsx("button",{type:"button",className:f==="comfortable"?"active":"",onClick:()=>h("comfortable"),title:"Comfortable view",children:"Comfortable"}),t.jsx("button",{type:"button",className:f==="compact"?"active":"",onClick:()=>h("compact"),title:"Compact view",children:"Compact"})]}),t.jsxs("button",{type:"button",className:"btn small ghost",onClick:je,disabled:y,children:[t.jsx(C,{src:Ze}),y?"Checking...":"Check Updates"]}),t.jsxs("a",{href:D,target:"_blank",rel:"noreferrer",className:"btn small ghost",children:[t.jsx(C,{src:Q}),"GitHub"]})]})]})}),t.jsxs("main",{className:"container",children:[t.jsx("nav",{className:"nav",children:O.map(u=>t.jsxs("button",{type:"button",className:e===u.id?"active":"",onClick:()=>{e==="config"&&u.id!=="config"&&n&&!window.confirm("You have unsaved configuration changes. Leave without saving?")||(s(u.id),a(""))},children:[t.jsx(C,{src:u.icon}),t.jsx("span",{children:u.label})]},u.id))}),t.jsxs(o.Suspense,{fallback:t.jsx("div",{className:"loading",children:"Loading..."}),children:[e==="processes"&&t.jsx(at,{active:!0},`processes-${N}`),e==="logs"&&t.jsx(ct,{active:!0},`logs-${N}`),e==="radarr"&&t.jsx(K,{type:"radarr",active:!0},`radarr-${N}`),e==="sonarr"&&t.jsx(K,{type:"sonarr",active:!0},`sonarr-${N}`),e==="lidarr"&&t.jsx(K,{type:"lidarr",active:!0},`lidarr-${N}`),e==="config"&&t.jsx(it,{onDirtyChange:i},`config-${N}`)]})]}),g&&c?t.jsx(ut,{currentVersion:c.current_version,latestVersion:be,changelog:c.changelog,changelogUrl:se,repositoryUrl:D,updateState:z,updating:x,onClose:Ce,onUpdate:Ee}):null,ye&&c?t.jsx(lt,{currentVersion:c.current_version,changelog:c.current_version_changelog||c.changelog,changelogUrl:se,repositoryUrl:D,onClose:Se}):null]})}function ft(){return t.jsx(Oe,{children:t.jsx(Ve,{children:t.jsxs(Ye,{children:[t.jsx(dt,{}),t.jsx(De,{})]})})})}Pe.createRoot(document.getElementById("root")).render(t.jsx(o.StrictMode,{children:t.jsx(ft,{})}));export{pe as C,C as I,Ze as R,le as a,vt as b,yt as c,wt as d,bt as e,xt as f,gt as g,Me as h,Qe as i,t as j,_t as k,jt as l,St as m,kt as n,Ct as o,Fe as p,Je as q,pt as r,ot as s,de as u};
11
- //# sourceMappingURL=app.js.map
@@ -1 +0,0 @@
1
- {"version":3,"mappings":";;;;;;;;;4CASa,IAAIA,EAAEC,GAAA,EAAiBC,EAAE,OAAO,IAAI,eAAe,EAAEC,EAAE,OAAO,IAAI,gBAAgB,EAAEC,EAAE,OAAO,UAAU,eAAeC,EAAEL,EAAE,mDAAmD,kBAAkBM,EAAE,CAAC,IAAI,GAAG,IAAI,GAAG,OAAO,GAAG,SAAS,EAAE,EAClP,SAASC,EAAEC,EAAEC,EAAEC,EAAE,CAAC,IAAIC,EAAEC,EAAE,GAAGC,EAAE,KAAKC,EAAE,KAAcJ,IAAT,SAAaG,EAAE,GAAGH,GAAYD,EAAE,MAAX,SAAiBI,EAAE,GAAGJ,EAAE,KAAcA,EAAE,MAAX,SAAiBK,EAAEL,EAAE,KAAK,IAAIE,KAAKF,EAAEL,EAAE,KAAKK,EAAEE,CAAC,GAAG,CAACL,EAAE,eAAeK,CAAC,IAAIC,EAAED,CAAC,EAAEF,EAAEE,CAAC,GAAG,GAAGH,GAAGA,EAAE,aAAa,IAAIG,KAAKF,EAAED,EAAE,aAAaC,EAAWG,EAAED,CAAC,IAAZ,SAAgBC,EAAED,CAAC,EAAEF,EAAEE,CAAC,GAAG,MAAM,CAAC,SAAST,EAAE,KAAKM,EAAE,IAAIK,EAAE,IAAIC,EAAE,MAAMF,EAAE,OAAOP,EAAE,OAAO,CAAC,CAAC,OAAAU,WAAiBZ,EAAEY,EAAA,IAAYR,EAAEQ,EAAA,KAAaR,0CCPxWS,EAAA,QAAiBf,GAAA,kECDnB,IAAIG,EAAIH,GAAA,EAEN,OAAAgB,EAAA,WAAqBb,EAAE,WACvBa,EAAA,YAAsBb,EAAE,8mCCoBpBc,GAAeC,gBAA6C,MAAS,EAE3E,IAAIC,GAAe,EAEZ,SAASC,GAAc,CAAE,SAAAC,GAA4C,CAC1E,KAAM,CAACC,EAAQC,CAAS,EAAIC,WAAkB,EAAE,EAE1CC,EAAUC,cAAaC,GAAe,CAC1CJ,EAAWK,GAASA,EAAK,OAAQC,GAAMA,EAAE,KAAOF,CAAE,CAAC,CACrD,EAAG,EAAE,EAECG,EAAOJ,cACX,CAACK,EAAiBC,EAAkB,SAAW,CAC7C,MAAML,EAAK,EAAER,GACbI,EAAWK,GAAS,CAAC,GAAGA,EAAM,CAAE,GAAAD,EAAI,QAAAI,EAAS,KAAAC,CAAA,CAAM,CAAC,EAEpD,OAAO,WAAW,IAAMP,EAAQE,CAAE,EAAG,IAAI,CAC3C,EACA,CAACF,CAAO,GAGJQ,EAAQC,UACZ,KAAO,CACL,OAAAZ,EACA,KAAAQ,EACA,QAAAL,CAAA,GAEF,CAACH,EAAQQ,EAAML,CAAO,GAGxB,OACEU,MAAClB,GAAa,SAAb,CAAsB,MAAAgB,EAAe,SAAAZ,CAAA,CAAS,CAEnD,CAEO,SAASe,IAA8B,CAC5C,MAAMC,EAAMC,aAAWrB,EAAY,EACnC,GAAI,CAACoB,EACH,MAAM,IAAI,MAAM,8CAA8C,EAEhE,OAAOA,CACT,CAEO,SAASE,IAAoC,CAClD,KAAM,CAAE,OAAAjB,EAAQ,QAAAG,CAAA,EAAYW,GAAA,EAC5B,OAAKd,EAAO,aAET,OAAI,UAAU,SACZ,SAAAA,EAAO,IAAKkB,GACXL,MAAC,OAEC,UAAW,SAASK,EAAM,OAAS,OAASA,EAAM,KAAO,EAAE,GAC3D,KAAK,SACL,QAAS,IAAMf,EAAQe,EAAM,EAAE,EAE9B,SAAAA,EAAM,SALFA,EAAM,GAOd,EACH,EAbyB,IAe7B,CChEA,MAAMC,GAAgBvB,gBAA8C,MAAS,EAEtE,SAASwB,GAAe,CAAE,SAAArB,GAA4C,CAC3E,KAAM,CAACY,EAAOU,CAAa,EAAInB,WAAS,EAAE,EACpCoB,EAAWC,SAA2B,IAAI,GAAK,EAE/CC,EAAWpB,cAAaqB,GAAiB,CAC7CJ,EAAcI,CAAI,EAClBH,EAAS,QAAQ,QAASI,GAAY,CACpCA,IAAUD,CAAI,CAChB,CAAC,CACH,EAAG,EAAE,EAECE,EAAWvB,cAAasB,GAA2B,CAClDA,GACLJ,EAAS,QAAQ,IAAII,CAAO,CAC9B,EAAG,EAAE,EAECE,EAAexB,cAAasB,GAA2B,CAC3DJ,EAAS,QAAQ,OAAOI,CAAO,CACjC,EAAG,EAAE,EAECG,EAAWjB,UACf,KAAO,CACL,MAAAD,EACA,SAAAa,EACA,SAAAG,EACA,aAAAC,CAAA,GAEF,CAACjB,EAAOa,EAAUG,EAAUC,CAAY,GAG1C,aACGT,GAAc,SAAd,CAAuB,MAAOU,EAC5B,SAAA9B,EACH,CAEJ,CAEO,SAAS+B,IAAgC,CAC9C,MAAMf,EAAMC,aAAWG,EAAa,EACpC,GAAI,CAACJ,EACH,MAAM,IAAI,MAAM,gDAAgD,EAElE,OAAOA,CACT,CClDA,MAAMgB,GAAe,CAAE,eAAgB,oBACjCC,EAAqB,CAAC,QAAS,cAAe,aAAa,EAC3DC,GAAmB,EAGnBC,MAAuB,IAE7B,SAASC,GAAiBC,EAA0BC,EAA4B,CAC9E,MAAMC,EAAMF,aAAiB,QAAUA,EAAM,IAAM,OAAOA,CAAK,EACzDG,EAASF,GAAM,QAAU,MACzBG,EAAOH,GAAM,KAAO,OAAOA,EAAK,IAAI,EAAI,GAC9C,MAAO,GAAGE,CAAM,IAAID,CAAG,IAAIE,CAAI,EACjC,CAEA,SAASC,IAA8B,CACrC,UAAWC,KAAOV,EAAoB,CACpC,MAAMrB,EAAQ,aAAa,QAAQ+B,CAAG,GAAK,eAAe,QAAQA,CAAG,EACrE,GAAI/B,EACF,OAAI+B,IAAQ,SACV,aAAa,QAAQ,QAAS/B,CAAK,EAE9BA,CAEX,CACA,GAAI,CAEF,MAAMgC,EADS,IAAI,gBAAgB,OAAO,SAAS,MAAM,EAChC,IAAI,OAAO,EACpC,GAAIA,EACF,oBAAa,QAAQ,QAASA,CAAS,EAChCA,CAEX,MAAQ,CAER,CACA,OAAO,IACT,CAEA,SAASC,IAAyB,CAChC,UAAWF,KAAOV,EAChB,aAAa,WAAWU,CAAG,EAE7B,GAAI,CACF,UAAWA,KAAOV,EAChB,eAAe,WAAWU,CAAG,CAEjC,MAAQ,CAER,CACF,CAEA,SAASG,GAAUR,EAA+BS,EAAmC,CACnF,MAAMC,EAAU,IAAI,QAAQV,GAAM,SAAW,EAAE,EAC/C,cAAO,QAAQN,EAAY,EAAE,QAAQ,CAAC,CAACW,EAAK/B,CAAK,IAAM,CAChDoC,EAAQ,IAAIL,CAAG,GAAGK,EAAQ,IAAIL,EAAK/B,CAAK,CAC/C,CAAC,EACGmC,GAAS,CAACC,EAAQ,IAAI,eAAe,GACvCA,EAAQ,IAAI,gBAAiB,UAAUD,CAAK,EAAE,EAEzC,CACL,GAAGT,EACH,QAAAU,CAAA,CAEJ,CAEA,eAAeC,EACbZ,EACAC,EACAX,EACAuB,EAAUhB,GACE,CACZ,MAAMa,EAAQL,GAAA,EACRS,EAAW,MAAM,MAAMd,EAAOS,GAAUR,EAAMS,CAAK,CAAC,EAC1D,OAAII,EAAS,SAAW,KAAOD,EAAU,GAAKH,GAC5CF,GAAA,EACOI,EAAmBZ,EAAOC,EAAMX,EAASuB,EAAU,CAAC,GAEtDvB,EAAQwB,CAAQ,CACzB,CAEA,eAAeC,EAAaf,EAA0BC,EAAgC,CAGpF,IADeA,GAAM,QAAU,SAChB,MAAO,CACpB,MAAMK,EAAMP,GAAiBC,EAAOC,CAAI,EAClCe,EAAkBlB,EAAiB,IAAIQ,CAAG,EAEhD,GAAIU,EACF,OAAOA,EAGT,MAAMC,EAAUL,EAAsBZ,EAAOC,EAAOa,GAAaI,GAAcJ,CAAQ,CAAC,EACrF,QAAQ,IAAM,CACbhB,EAAiB,OAAOQ,CAAG,CAC7B,CAAC,EAEH,OAAAR,EAAiB,IAAIQ,EAAKW,CAAO,EAC1BA,CACT,CAEA,OAAOL,EAAsBZ,EAAOC,EAAOa,GAAaI,GAAcJ,CAAQ,CAAC,CACjF,CAEA,eAAeK,GAAkBnB,EAA0BC,EAAqC,CAC9F,OAAOW,EAA2BZ,EAAOC,EAAOa,GAAaM,GAAWN,CAAQ,CAAC,CACnF,CAEA,eAAeI,GAAcG,EAA2B,CACtD,GAAI,CAACA,EAAI,GAAI,CACX,IAAIC,EAAkB,KACtB,GAAI,CACFA,EAAS,MAAMD,EAAI,MACrB,MAAQ,CAER,CACA,IAAIhD,EAAU,GAAGgD,EAAI,MAAM,IAAIA,EAAI,UAAU,GAC7C,GACEC,GACA,OAAOA,GAAW,UAClB,UAAWA,GACX,OAAQA,EAAmC,OAAU,SACrD,CACA,MAAMC,EAAaD,EAAmC,MAClDC,EAAU,SACZlD,EAAUkD,EAEd,CACA,MAAM,IAAI,MAAMlD,CAAO,CACzB,CACA,OAAQ,MAAMgD,EAAI,MACpB,CAEA,eAAeD,GAAWC,EAAgC,CACxD,GAAI,CAACA,EAAI,GACP,MAAM,IAAI,MAAM,GAAGA,EAAI,MAAM,IAAIA,EAAI,UAAU,EAAE,EAEnD,OAAOA,EAAI,MACb,CAEA,eAAsBG,GAAQC,EAAqD,CACjF,MAAMC,EAAQD,GAAQ,MAAQ,WAAa,GAC3C,OAAOV,EAAwB,YAAYW,CAAK,EAAE,CACpD,CAEA,eAAsBC,IAAqC,CACzD,OAAOZ,EAA0B,aAAa,CAChD,CAEA,eAAsBa,IAA2C,CAC/D,OAAOb,EAA6B,gBAAgB,CACtD,CAEA,eAAsBc,GACpBC,EACAxD,EAC0B,CAC1B,MAAM4B,EAAM,kBAAkB,mBAC5B4B,CAAA,CACD,IAAI,mBAAmBxD,CAAI,CAAC,WAC7B,OAAOyC,EAA2Bb,EAAK,CAAE,OAAQ,OAAQ,CAC3D,CAEA,eAAsB6B,IAAgD,CACpE,OAAOhB,EAA2B,6BAA8B,CAC9D,OAAQ,OACT,CACH,CAEA,eAAsBiB,IAAwC,CAC5D,OAAOjB,EAA2B,mBAAoB,CAAE,OAAQ,OAAQ,CAC1E,CASA,eAAsBkB,IAAqC,CACzD,OAAOlB,EAA4B,WAAW,CAChD,CAEA,eAAsBmB,GAAWC,EAA+B,CAC9D,OAAOhB,GAAkB,aAAa,mBAAmBgB,CAAI,CAAC,EAAE,CAClE,CAEO,SAASC,GAAkBD,EAAsB,CACtD,MAAO,aAAa,mBAAmBA,CAAI,CAAC,WAC9C,CAEA,eAAsBE,IAAuC,CAC3D,OAAOtB,EAA2B,UAAU,CAC9C,CAEA,eAAsBuB,GACpBR,EACAS,EACAC,EACA5F,EAC+B,CAC/B,MAAM6E,EAAS,IAAI,gBACnB,OAAAA,EAAO,IAAI,OAAQ,OAAOc,CAAI,CAAC,EAC/Bd,EAAO,IAAI,YAAa,OAAOe,CAAQ,CAAC,EACpC5F,GAAG6E,EAAO,IAAI,IAAK7E,CAAC,EACjBmE,EACL,eAAe,mBAAmBe,CAAQ,CAAC,WAAWL,CAAM,GAEhE,CAEA,eAAsBgB,GACpBX,EACAS,EACAC,EACA5F,EACA8F,EAC+B,CAC/B,MAAMjB,EAAS,IAAI,gBACnB,OAAAA,EAAO,IAAI,OAAQ,OAAOc,CAAI,CAAC,EAC/Bd,EAAO,IAAI,YAAa,OAAOe,CAAQ,CAAC,EACpC5F,GAAG6E,EAAO,IAAI,IAAK7E,CAAC,EACpB8F,GAAS,aACXjB,EAAO,IAAI,UAAW,GAAG,EAEpBV,EACL,eAAe,mBAAmBe,CAAQ,CAAC,WAAWL,CAAM,GAEhE,CAEA,eAAsBkB,GACpBb,EACAS,EACAC,EACAd,EAC+B,CAC/B,MAAMD,EAAS,IAAI,gBACnB,OAAAA,EAAO,IAAI,OAAQc,EAAK,UAAU,EAClCd,EAAO,IAAI,YAAae,EAAS,UAAU,EACvCd,GACFD,EAAO,IAAI,IAAKC,CAAK,EAGvBD,EAAO,IAAI,iBAAkB,MAAM,EAC5BV,EACL,eAAe,mBAAmBe,CAAQ,CAAC,WAAWL,CAAM,GAEhE,CAEA,eAAsBmB,GAAWd,EAAiC,CAChE,MAAMf,EACJ,YAAY,mBAAmBe,CAAQ,CAAC,WACxC,CAAE,OAAQ,OAAO,CAErB,CAEA,eAAsBe,IAAqC,CACzD,OAAO9B,EAA0B,aAAa,CAChD,CAEA,eAAsB+B,GACpBC,EAC+B,CAC/B,MAAMrC,EAAQL,GAAA,EACRS,EAAW,MAAM,MAAM,cAAeL,GAAU,CACpD,OAAQ,OACR,KAAM,KAAK,UAAUsC,CAAO,GAC3BrC,CAAK,CAAC,EAET,GAAI,CAACI,EAAS,GAAI,CAChB,IAAIQ,EAAkB,KACtB,GAAI,CACFA,EAAS,MAAMR,EAAS,MAC1B,MAAQ,CAER,CACA,IAAIzC,EAAU,GAAGyC,EAAS,MAAM,IAAIA,EAAS,UAAU,GACvD,GACEQ,GACA,OAAOA,GAAW,UAClB,UAAWA,GACX,OAAQA,EAAmC,OAAU,SACrD,CACA,MAAMC,EAAaD,EAAmC,MAClDC,EAAU,SACZlD,EAAUkD,EAEd,CACA,MAAM,IAAI,MAAMlD,CAAO,CACzB,CAIA,OADa,MAAMyC,EAAS,MAE9B,CAEA,eAAsBkC,IAA+B,CACnD,MAAMjC,EAAgB,cAAe,CAAE,OAAQ,OAAQ,CACzD,CC5RA,MAAMkC,GAAezF,gBAAwC,IAAI,EAE1D,SAAS0F,GAAc,CAAE,SAAAvF,GAAkD,CAChF,KAAM,CAACwF,EAAUC,CAAW,EAAItF,WAAwB,CACtD,QAAS,GACT,YAAa,GACb,YAAa,GACb,YAAa,cACb,MAAO,OACR,EACK,CAACuF,EAASC,CAAU,EAAIxF,WAAS,EAAI,EAG3CyF,YAAU,IAAM,EACO,SAAY,CAC/B,GAAI,CAEF,MAAMC,GADS,MAAMX,GAAA,IACC,MAGhBY,EAAgB,aAAa,QAAQ,aAAa,EAClDC,EAAc,aAAa,QAAQ,OAAO,EAG1CC,EAAeH,GAAO,MACtBI,EAAeF,GAAgBC,GAAc,eAA2B,OAE9EP,EAAY,CACV,QAASI,GAAO,UAAY,GAC5B,YAAaA,GAAO,cAAgB,GACpC,YAAaA,GAAO,cAAgB,GACpC,YAAaC,GAAiB,cAC9B,MAAAG,CAAA,CACD,EAGD,SAAS,gBAAgB,aAAa,aAAcA,CAAK,CAC3D,OAASC,EAAO,CACd,QAAQ,MAAM,iCAAkCA,CAAK,CACvD,SACEP,EAAW,EAAK,CAClB,CACF,GAEK,CACP,EAAG,EAAE,EAGL,MAAMQ,EAAe9F,cAAY,MAAOsC,EAAa/B,IAA4B,CAC/E,GAAI,CACF,MAAMwF,EAAmC,CACvC,MAAO,CACL,CAACzD,CAAG,EAAG/B,CAAA,CACT,EAEF,MAAMuE,GAAa,CAAE,QAAAiB,EAAS,CAChC,OAASF,EAAO,CACd,QAAQ,MAAM,kBAAkBvD,CAAG,IAAKuD,CAAK,CAC/C,CACF,EAAG,EAAE,EAECG,EAAahG,cAAaO,GAAmB,CACjD6E,MAAqB,CAAE,GAAGlF,EAAM,QAASK,GAAQ,EAC5CuF,EAAa,UAAWvF,CAAK,CACpC,EAAG,CAACuF,CAAY,CAAC,EAEXG,EAAiBjG,cAAaO,GAAmB,CACrD6E,MAAqB,CAAE,GAAGlF,EAAM,YAAaK,GAAQ,EAChDuF,EAAa,cAAevF,CAAK,CACxC,EAAG,CAACuF,CAAY,CAAC,EAEXI,EAAiBlG,cAAaO,GAAmB,CACrD6E,MAAqB,CAAE,GAAGlF,EAAM,YAAaK,GAAQ,EAChDuF,EAAa,cAAevF,CAAK,CACxC,EAAG,CAACuF,CAAY,CAAC,EAEXK,EAAiBnG,cAAaO,GAAuB,CACzD6E,MAAqB,CAAE,GAAGlF,EAAM,YAAaK,GAAQ,EAErD,aAAa,QAAQ,cAAeA,CAAK,CAC3C,EAAG,EAAE,EAEC6F,EAAWpG,cAAaO,GAAiB,CAC7C6E,MAAqB,CAAE,GAAGlF,EAAM,MAAOK,GAAQ,EAE/C,aAAa,QAAQ,QAASA,CAAK,EAEnC,SAAS,gBAAgB,aAAa,aAAcA,CAAK,EAGpDuF,EAAa,QADOvF,IAAU,QAAU,QAAU,MACZ,CAC7C,EAAG,CAACuF,CAAY,CAAC,EAEXvF,EAA2B,CAC/B,QAAS4E,EAAS,QAClB,YAAaA,EAAS,YACtB,YAAaA,EAAS,YACtB,YAAaA,EAAS,YACtB,MAAOA,EAAS,MAChB,WAAAa,EACA,eAAAC,EACA,eAAAC,EACA,eAAAC,EACA,SAAAC,EACA,QAAAf,CAAA,EAGF,OAAO5E,MAACwE,GAAa,SAAb,CAAsB,MAAA1E,EAAe,SAAAZ,CAAA,CAAS,CACxD,CAEO,SAAS0G,IAA8B,CAC5C,MAAMC,EAAU1F,aAAWqE,EAAY,EACvC,GAAI,CAACqB,EACH,MAAM,IAAI,MAAM,4CAA4C,EAE9D,OAAOA,CACT,CC9IO,SAASC,IAA4B,CAC1C,KAAM,CAACC,EAAUC,CAAW,EAAI3G,WAAS,UAAU,MAAM,EAEzDyF,mBAAU,IAAM,CACd,MAAMmB,EAAe,IAAMD,EAAY,EAAI,EACrCE,EAAgB,IAAMF,EAAY,EAAK,EAE7C,cAAO,iBAAiB,SAAUC,CAAY,EAC9C,OAAO,iBAAiB,UAAWC,CAAa,EAEzC,IAAM,CACX,OAAO,oBAAoB,SAAUD,CAAY,EACjD,OAAO,oBAAoB,UAAWC,CAAa,CACrD,CACF,EAAG,EAAE,EAEEH,CACT,CCZO,SAASI,EAAU,CAAE,IAAAC,EAAK,IAAAC,EAAK,UAAAC,EAAW,GAAGC,GAAqC,CACvF,OACEvG,MAAC,OACC,IAAAoG,EACA,IAAKC,GAAO,GACZ,UAAWC,EAAY,QAAQA,CAAS,GAAK,OAC7C,cAAaD,EAAM,OAAY,GAC9B,GAAGE,CAAA,EAGV,CCjBA,MAAAC,GAAe,2BCAfC,EAAe,ohCCAfC,GAAe,mCCAfC,GAAe,8BCAfC,GAAe,6BCAfC,GAAe,yBCAfC,GAAe,07BCAfC,GAAe,41ECAfC,GAAe,4BCAfC,GAAe,0BCCTC,GAAgBC,OAAK,IAAAC,EAAA,IAAM,OAAO,oBAAuB,8BAAE,KAAKC,IAAW,CAAE,QAASA,EAAO,eAAgB,CAAC,EAC9GC,GAAWH,OAAK,IAAAC,EAAA,IAAM,OAAO,eAAkB,gCAAE,KAAKC,IAAW,CAAE,QAASA,EAAO,UAAW,CAAC,EAC/FE,EAAUJ,OAAK,IAAAC,EAAA,IAAM,OAAO,cAAiB,8BAAE,KAAKC,IAAW,CAAE,QAASA,EAAO,SAAU,CAAC,EAC5FG,GAAaL,OAAK,IAAAC,EAAA,IAAM,OAAO,iBAAoB,8BAAE,KAAKC,IAAW,CAAE,QAASA,EAAO,YAAa,CAAC,EA2B3G,SAASI,EAAmB3H,EAA0C,CACpE,GAAI,CAACA,EACH,MAAO,UAET,MAAM4H,EAAU5H,EAAM,OACtB,OAAK4H,EAGEA,EAAQ,CAAC,IAAM,KAAOA,EAAQ,CAAC,IAAM,IAAMA,EAAU,IAAIA,CAAO,GAF9D,SAGX,CAUA,SAASC,GAAa,CACpB,eAAAC,EACA,UAAAC,EACA,aAAAC,EACA,cAAAC,EACA,QAAAC,CACF,EAAmC,CACjC,aACG,OAAI,UAAU,iBAAiB,KAAK,eAAe,QAASA,EAC3D,SAAAC,OAAC,OACC,UAAU,QACV,KAAK,SACL,aAAW,OACX,kBAAgB,gBAChB,QAAUC,GAAUA,EAAM,kBAE1B,UAAAD,OAAC,OAAI,UAAU,eACb,UAAAA,OAAC,MAAG,GAAG,gBAAgB,kCACCR,EAAmBG,CAAc,EAAE,KAC3D,SACC,UAAO,UAAU,YAAY,KAAK,SAAS,QAASI,EACnD,UAAAhI,MAACmG,EAAA,CAAU,IAAKK,EAAA,CAAW,EAAE,SAE/B,GACF,EACAyB,OAAC,OAAI,UAAU,mCACb,UAAAjI,MAAC,OAAI,UAAU,iBACb,SAAAiI,OAAC,KAAE,MAAO,CAAE,aAAc,OAAQ,MAAO,yBAA2B,4CACnCjI,MAAC,UAAQ,SAAAyH,EAAmBG,CAAc,EAAE,EAAS,wCAEtF,EACF,EACAK,OAAC,OAAI,UAAU,oBACb,UAAAjI,MAAC,MAAG,yBAAa,EACjBA,MAAC,OAAI,UAAU,iBACZ,SAAA6H,GAAW,OAASA,EAAU,OAAS,2CAC1C,GACF,GACF,EACAI,OAAC,OAAI,UAAU,eACb,UAAAjI,MAAC,OAAI,UAAU,kBACX,UAAA8H,GAAgBC,IAChBE,OAAC,KACC,UAAU,kBACV,KAAMH,GAAgBC,EACtB,OAAO,SACP,IAAI,aAEJ,UAAA/H,MAACmG,EAAA,CAAU,IAAKM,CAAA,CAAc,EAAE,iCAItC,EACAzG,MAAC,OAAI,UAAU,oBACb,SAAAA,MAAC,UAAO,UAAU,cAAc,KAAK,SAAS,QAASgI,EAAS,mBAEhE,EACF,GACF,KAEJ,CAEJ,CAcA,SAASG,GAAe,CACtB,eAAAP,EACA,cAAAQ,EACA,UAAAP,EACA,aAAAC,EACA,cAAAC,EACA,YAAAM,EACA,SAAAC,EACA,QAAAN,EACA,SAAAO,CACF,EAAqC,CACnC,KAAM,CAACC,EAAWC,CAAY,EAAIpJ,WAAwB,IAAI,EACxDqJ,EAAiBJ,GAAY,EAAQD,GAAa,YAClDM,EAAiBN,GAAa,aAChC,IAAI,KAAKA,EAAY,YAAY,EAAE,iBACnC,KAGJvD,YAAU,IAAM,CACd,GAAIuD,GAAa,cAAgB,WAAaA,GAAa,aAAc,CACvE,IAAIG,EAAY,GAChBC,EAAaD,CAAS,EACtB,MAAMI,EAAQ,YAAY,IAAM,CAC9BJ,GAAa,EACTA,GAAa,GACf,cAAcI,CAAK,EACnB,OAAO,SAAS,UAEhBH,EAAaD,CAAS,CAE1B,EAAG,GAAI,EACP,MAAO,IAAM,cAAcI,CAAK,CAClC,CACF,EAAG,CAACP,GAAa,YAAaA,GAAa,YAAY,CAAC,EAExD,IAAIQ,EAAc,GACdC,EAA+B,KACnC,GAAIT,GAAa,YACfQ,EAAc,YACdC,EAAgB,kCACPT,GAAa,cAAgB,UACtCQ,EAAc,eACVL,IAAc,KAChBM,EAAgB,oCAAoCN,CAAS,QAE7DM,EAAgB,kCACZH,IACFG,EAAgB,GAAGA,CAAa,KAAKH,CAAc,cAG9CN,GAAa,cAAgB,QAAS,CAC/CQ,EAAc,cACd,MAAMhG,EAASwF,EAAY,WAAaA,EAAY,WAAW,OAAS,GACxES,EAAgBjG,EAAS,oBAAoBA,CAAM,GAAK,iBAC1D,CAEA,aACG,OAAI,UAAU,iBAAiB,KAAK,eAAe,QAASmF,EAC3D,SAAAC,OAAC,OACC,UAAU,QACV,KAAK,SACL,aAAW,OACX,kBAAgB,kBAChB,QAAUC,GAAUA,EAAM,kBAE1B,UAAAD,OAAC,OAAI,UAAU,eACb,UAAAjI,MAAC,MAAG,GAAG,kBACJ,SAAAqI,GAAa,YAAc,iBAAmB,sBACjD,EACAJ,OAAC,UAAO,UAAU,YAAY,KAAK,SAAS,QAASD,EAAS,SAAUK,GAAa,YACnF,UAAArI,MAACmG,EAAA,CAAU,IAAKK,EAAA,CAAW,EAAE,SAE/B,GACF,EACAyB,OAAC,OAAI,UAAU,mCACb,UAAAA,OAAC,OAAI,UAAU,iBACb,UAAAA,OAAC,OAAI,UAAU,qBACb,UAAAA,OAAC,QAAK,UAAU,eACd,UAAAjI,MAAC,UAAO,oBAAQ,EAAU,UACzB,QAAK,UAAU,gCAAiC,SAAAyH,EAAmBG,CAAc,EAAE,GACtF,EACA5H,MAAC,QAAK,UAAU,gBAAgB,aAAC,EACjCiI,OAAC,QAAK,UAAU,eACd,UAAAjI,MAAC,UAAO,mBAAO,EAAU,IACzBA,MAAC,QAAK,UAAU,+BACb,WAAgByH,EAAmBW,CAAa,EAAI,UACvD,GACF,GACF,EACCU,QACE,OAAI,UAAW,iBAAiBD,CAAW,GACzC,WACH,EACE,MACN,EACAZ,OAAC,OAAI,UAAU,oBACb,UAAAjI,MAAC,MAAG,sBAAU,EACdA,MAAC,OAAI,UAAU,iBACZ,SAAA6H,GAAW,OAASA,EAAU,OAAS,yBAC1C,GACF,GACF,EACAI,OAAC,OAAI,UAAU,eACb,UAAAjI,MAAC,OAAI,UAAU,kBACX,UAAA8H,GAAgBC,IAChBE,OAAC,KACC,UAAU,kBACV,KAAMH,GAAgBC,EACtB,OAAO,SACP,IAAI,aAEJ,UAAA/H,MAACmG,EAAA,CAAU,IAAKM,CAAA,CAAc,EAAE,oBAItC,EACAzG,MAAC,OAAI,UAAU,oBACb,SAAAiI,OAAC,UACC,UAAU,cACV,KAAK,SACL,QAASM,EACT,SAAUG,EAEV,UAAA1I,MAACmG,EAAA,CAAU,IAAKQ,EAAA,CAAY,EAC3B+B,EAAiB,cAAgB,eACpC,CACF,GACF,KAEJ,CAEJ,CAEA,SAASK,IAAwB,CAC/B,KAAM,CAACC,EAAWC,CAAY,EAAI5J,WAAc,WAAW,EACrD,CAAC6J,EAAaC,CAAc,EAAI9J,WAAS,EAAK,EAC9C,CAAE,KAAAM,CAAA,EAASM,GAAA,EACX,CAAE,SAAUmJ,CAAA,EAAmBnI,GAAA,EAC/B,CAAE,YAAAoI,EAAa,eAAA3D,CAAA,EAAmBE,GAAA,EAClCG,EAAWD,GAAA,EACX,CAACwD,EAAMC,CAAO,EAAIlK,WAA8B,IAAI,EACpD,CAACmK,EAAaC,CAAc,EAAIpK,WAAS,EAAK,EAC9C,CAACqK,EAAeC,CAAgB,EAAItK,WAAS,EAAK,EAClD,CAACuK,EAAYC,CAAa,EAAIxK,WAAS,EAAK,EAC5C,CAACyK,EAAmBC,CAAoB,EAAI1K,WAAS,EAAK,EAC1D2K,EAAmBtJ,SAAO,CAAC,EAC3BuJ,EAAmBvJ,SAAsB,IAAI,EAC7CwJ,EAAkBxJ,SAAO,EAAK,EAC9ByJ,EAAmBzJ,SAAO,EAAK,EAC/B0J,EAAkB1J,SAAsB,IAAI,EAC5C,CAAC2J,EAAWC,CAAY,EAAIjL,WAAS,CAAC,EACtC,CAACkL,EAAYC,EAAa,EAAInL,WAAgC,IAAI,EAClE,CAACoL,GAAsBC,EAAuB,EAAIrL,WAAS,EAAK,EAKtEyF,YAAU,IAAM,EACK,SAAY,CAC7B,GAAI,WAAY,OACd,GAAI,CACF,MAAM6F,EAAa,MAAM,OAAO,OAChC,MAAM,QAAQ,IACZA,EAAW,IAAIC,GAAa,OAAO,OAAOA,CAAS,CAAC,GAEtD,QAAQ,IAAI,4BAA4B,CAC1C,OAASxF,EAAO,CACd,QAAQ,MAAM,yBAA0BA,CAAK,CAC/C,CAEJ,GACA,CACF,EAAG,EAAE,EAEL,MAAMyF,EAActL,cAClB,MAAO0E,GAAoD,CACzD,MAAM6G,EAAQ7G,GAAS,OAAS,GAC1B8G,EAAS9G,GAAS,QAAU,CAAC6G,EAC9BC,GACHtB,EAAe,EAAI,EAErB,GAAI,CACF,MAAMuB,EAAO,MAAMjI,GAAQ,CAAE,MAAA+H,EAAO,EACpCvB,EAAQyB,CAAI,CACd,OAAS5F,EAAO,CACd,GAAI,CAAC2F,EAAQ,CACX,MAAMnL,EACJwF,aAAiB,MAAQA,EAAM,QAAU,sCAC3CzF,EAAKC,EAAS,OAAO,CACvB,CACF,SACOmL,GACHtB,EAAe,EAAK,CAExB,CACF,EACA,CAAC9J,CAAI,GAGPmF,YAAU,IAAM,CACT+F,EAAY,CAAE,MAAO,GAAM,CAClC,EAAG,CAACA,CAAW,CAAC,EAGhB/F,YAAU,IAAM,CACd,GAAI,CAACwE,GAAM,gBACT,OAGF,MAAM2B,EAAkB,aAAa,QAAQ,iBAAiB,EACxDrD,EAAiB0B,EAAK,gBAGxB2B,GAAmBA,IAAoBrD,IAErC,CAAC0B,EAAK,2BAA6B,CAACA,EAAK,WACtCuB,EAAY,CAAE,MAAO,GAAM,OAAQ,GAAM,EAEhDH,GAAwB,EAAI,GAIzBO,GACH,aAAa,QAAQ,kBAAmBrD,CAAc,CAE1D,EAAG,CAAC0B,GAAM,gBAAiBA,GAAM,UAAWuB,CAAW,CAAC,EAGxD/F,YAAU,IAAM,CACTiB,GACHpG,EAAK,+CAAgD,SAAS,CAElE,EAAG,CAACoG,EAAUpG,CAAI,CAAC,EAGnBmF,YAAU,IAAM,CACd,MAAMoG,EAAiBhD,GAAyB,CAE9C,GAAIA,EAAM,kBAAkB,kBACxBA,EAAM,kBAAkB,qBACxBA,EAAM,kBAAkB,kBAC1B,OAGF,MAAMiD,EAAQjD,EAAM,SAAWA,EAAM,QAGrC,GAAIiD,GAASjD,EAAM,MAAQ,IAAK,CAC9BA,EAAM,iBACc,SAAS,cAAc,2CAA2C,GACzE,QACb,MACF,CAGA,GAAIA,EAAM,MAAQ,KAAOA,EAAM,MAAQ,IAAK,CAC1CA,EAAM,iBACNoC,EAAa7K,GAAQA,EAAO,CAAC,EAC7BE,EAAK,YAAa,SAAS,EAC3B,MACF,CAGA,GAAIuI,EAAM,MAAQ,SAAU,CAC1BkB,EAAe,EAAE,EACjB,MACF,CAGA,GAAIlB,EAAM,KAAO,KAAOA,EAAM,KAAO,KAAO,CAACiD,EAAO,CAClDjD,EAAM,iBACN,MAAMkD,EAAW,SAASlD,EAAM,GAAG,EAAI,EACjCmD,EAAgB,CAAC,YAAa,OAAQ,SAAU,SAAU,SAAU,QAAQ,EAC9ED,EAAWC,EAAO,QACpBpC,EAAaoC,EAAOD,CAAQ,CAAC,EAE/B,MACF,CACF,EAEA,cAAO,iBAAiB,UAAWF,CAAa,EACzC,IAAM,OAAO,oBAAoB,UAAWA,CAAa,CAClE,EAAG,CAAC9B,EAAgBzJ,CAAI,CAAC,EAEzBmF,YAAU,IAAM,CACd,MAAMtF,EAAK,OAAO,YAAY,IAAM,CAC7BqL,EAAA,CACP,EAAG,GAAa,EAChB,MAAO,IAAM,OAAO,cAAcrL,CAAE,CACtC,EAAG,CAACqL,CAAW,CAAC,EAEhB/F,YAAU,IAAM,CACd,MAAMwG,EAAyB,IAAM,CAC/B,SAAS,kBAAoB,YAE/BhB,EAAc7K,GAASA,EAAO,CAAC,EAC1BoL,EAAY,CAAE,MAAO,GAAM,EAC3BU,EAAA,EAET,EAEA,gBAAS,iBAAiB,mBAAoBD,CAAsB,EAC7D,IAAM,CACX,SAAS,oBAAoB,mBAAoBA,CAAsB,CACzE,CACF,EAAG,CAACT,CAAW,CAAC,EAEhB,MAAMU,EAAgBhM,cAAY,SAAY,CAC5C,GAAI,CACF,MAAMiM,EAAS,MAAMtI,GAAA,EACrBsH,GAAcgB,CAAM,CACtB,MAAQ,CAER,CACF,EAAG,EAAE,EAEL1G,YAAU,IAAM,CACTyG,EAAA,EACL,MAAM/L,EAAK,OAAO,YAAY,IAAM,CAC7B+L,EAAA,CACP,EAAG,EAAI,GAAI,EACX,MAAO,IAAM,OAAO,cAAc/L,CAAE,CACtC,EAAG,CAAC+L,CAAa,CAAC,EAElBzG,YAAU,IAAM,CACd,GAAI,CAACwE,GAAM,cAAc,aAAe,CAACQ,EAAmB,CAC1DE,EAAiB,QAAU,EAC3B,MACF,CACA,MAAMxK,EAAK,OAAO,YAAY,SAAY,CACxC,GAAI,CACF,MAAMwL,EAAO,MAAMjI,GAAQ,CAAE,MAAO,GAAM,EAC1CwG,EAAQyB,CAAI,EACRlB,GAEF,OAAO,SAAS,SAElBE,EAAiB,QAAU,CAC7B,MAAQ,CAEN,GADAA,EAAiB,SAAW,EACxBA,EAAiB,QAAU,GAAI,CACjCD,EAAqB,EAAK,EAC1BC,EAAiB,QAAU,EAC3BrK,EAAK,oFAAqF,SAAS,EACnG,MACF,CACI2J,GAAM,cAAc,aAEtBS,EAAqB,EAAI,CAE7B,CACF,EAAG,GAAI,EACP,MAAO,IAAM,OAAO,cAAcvK,CAAE,CACtC,EAAG,CAAC8J,GAAM,cAAc,YAAaQ,EAAmBR,EAAM3J,CAAI,CAAC,EAEnEmF,YAAU,IAAM,CACd,MAAM2G,EAAQnC,GAAM,aACpB,GAAI,CAACmC,EAAO,CACVxB,EAAiB,QAAU,KAC3B,MACF,CACA,MAAMyB,EAASD,EAAM,aAAe,KAChCC,GAAUA,IAAWzB,EAAiB,UACpCyB,IAAW,WACb/L,EAAK,+CAAgD,SAAS,EAC9DoK,EAAqB,EAAI,EACzBC,EAAiB,QAAU,GAClB0B,IAAW,SACpB/L,EAAK8L,EAAM,YAAc,iBAAkB,OAAO,GAGtDxB,EAAiB,QAAUyB,CAC7B,EAAG,CAACpC,GAAM,aAAc3J,CAAI,CAAC,EAE7BmF,YAAU,IAAM,CACd,IAAI6G,EAAY,GACZC,EAAW,EAEf,MAAMC,EAAYC,GAAkB,CAC9B1B,EAAgB,UAAY,MAC9B,OAAO,aAAaA,EAAgB,OAAO,EAE7CA,EAAgB,QAAU,OAAO,WAAW,IAAM,CAC3C2B,EAAA,CACP,EAAGD,CAAK,CACV,EAEMC,EAAO,SAAY,CACvB,GAAI,EAAAJ,GAAazB,EAAgB,SAGjC,CAAA0B,GAAY,EACZ,GAAI,CACF,MAAMJ,EAAS,MAAMtI,GAAA,EACrB,GAAIyI,EACF,OAKF,GAHAnB,GAAcgB,CAAM,EAElBA,EAAO,QAAU,MAAM,QAAQA,EAAO,IAAI,GAAKA,EAAO,KAAK,OAAS,GACvD,CACbtB,EAAgB,QAAU,GAC1B,MACF,CACIsB,EAAO,QAAU,IAASI,GAAY,GAAK,CAACzB,EAAiB,UAC/DA,EAAiB,QAAU,GAC3BxK,EACE,yEACA,WAGN,OAASyF,EAAO,CACd,GAAI,CAAC+E,EAAiB,SAAWyB,GAAY,EAAG,CAC9CzB,EAAiB,QAAU,GAC3B,MAAMtH,EAASuC,aAAiB,MAAQA,EAAM,QAAU,wBACxDzF,EACE,uCAAuCkD,CAAM,8BAC7C,UAEJ,CACF,SACE,GAAI,CAAC8I,GAAa,CAACzB,EAAgB,QAAS,CAC1C,MAAM4B,EAAQF,EAAW,EAAI,IAAO,IACpCC,EAASC,CAAK,CAChB,CACF,EACF,EAEA,OAAAD,EAAS,CAAC,EAEH,IAAM,CACXF,EAAY,GACRvB,EAAgB,UAAY,OAC9B,OAAO,aAAaA,EAAgB,OAAO,EAC3CA,EAAgB,QAAU,KAE9B,CACF,EAAG,CAACzK,CAAI,CAAC,EAET,MAAMqM,EAAOjM,UAAkB,IAAM,CACnC,MAAMkM,EAAqB,CACzB,CAAE,GAAI,YAAa,MAAO,YAAa,KAAMrF,EAAA,EAC7C,CAAE,GAAI,OAAQ,MAAO,OAAQ,KAAMC,EAAA,CAAS,EAGxCqF,EAAoB,GACpBC,EAAO5B,GAAY,MAAQ,GAE3B6B,EAAYD,EAAK,KAAME,GAAQA,EAAI,OAAS,QAAQ,EACpDC,EAAYH,EAAK,KAAME,GAAQA,EAAI,OAAS,QAAQ,EACpDE,EAAYJ,EAAK,KAAME,GAAQA,EAAI,OAAS,QAAQ,EAE1D,OAAID,GACFF,EAAQ,KAAK,CAAE,GAAI,SAAU,MAAO,SAAU,KAAMpF,GAAY,EAE9DwF,GACFJ,EAAQ,KAAK,CAAE,GAAI,SAAU,MAAO,SAAU,KAAMnF,GAAY,EAE9DwF,GACFL,EAAQ,KAAK,CAAE,GAAI,SAAU,MAAO,SAAU,KAAMlF,GAAY,EAG3D,CACL,GAAGiF,EACH,GAAGC,EACH,CAAE,GAAI,SAAU,MAAO,SAAU,KAAMM,EAAA,CAAW,CAEtD,EAAG,CAACjC,CAAU,CAAC,EAETxC,EAAgBuB,GAAM,gBAAkB,sCACxCmD,GAAiBnD,GAAM,gBACzB7B,EAAmB6B,EAAK,eAAe,EACvC,MACElB,GAAgBkB,GAAM,gBAAkB,KACxCoD,GAAkB,EAAQpD,GAAM,iBAChCjB,EAAciB,GAAM,aACpBxB,GAAewB,GAAM,eAAiBvB,EAEtC4E,EAA8B,GAChCrD,GAAM,cACRqD,EAAkB,KAAK,gBAAgB,IAAI,KAAKrD,EAAK,YAAY,EAAE,gBAAgB,EAAE,EAEnFA,GAAM,OACRqD,EAAkB,KAAK,wBAAwBrD,EAAK,KAAK,EAAE,EAE7D,MAAMsD,GAAeD,EAAkB,OAASA,EAAkB,KAAK,KAAK,EAAI,OAGhF7H,YAAU,IAAM,CAEV,CADckH,EAAK,KAAMa,GAAQA,EAAI,KAAO7D,CAAS,GACvCgD,EAAK,OAAS,GAC9B/C,EAAa,WAAW,CAE5B,EAAG,CAAC+C,EAAMhD,CAAS,CAAC,EAEpB,MAAM8D,GAAqBvN,cAAY,IAAM,CACtCsL,EAAY,CAAE,MAAO,GAAM,CAClC,EAAG,CAACA,CAAW,CAAC,EAEVkC,GAAsBxN,cAAY,IAAM,CAC5CoK,EAAiB,EAAI,EAChBL,GAAM,WACJuB,EAAY,CAAE,MAAO,GAAM,OAAQ,GAAM,CAElD,EAAG,CAACvB,GAAM,UAAWuB,CAAW,CAAC,EAE3BmC,GAAuBzN,cAAY,IAAM,CAC7CoK,EAAiB,EAAK,CACxB,EAAG,EAAE,EAECsD,GAA8B1N,cAAY,IAAM,CACpDmL,GAAwB,EAAK,EAEzBpB,GAAM,iBACR,aAAa,QAAQ,kBAAmBA,EAAK,eAAe,CAEhE,EAAG,CAACA,GAAM,eAAe,CAAC,EAEpB4D,GAAsB3N,cAAY,SAAY,CAClDsK,EAAc,EAAI,EAClBE,EAAqB,EAAK,EAC1BC,EAAiB,QAAU,EAC3B,GAAI,CACF,MAAMzF,GAAA,EACN5E,EAAK,oCAAqC,MAAM,EAChD,MAAMkL,EAAY,CAAE,MAAO,GAAM,OAAQ,GAAM,CACjD,OAASzF,EAAO,CACd,MAAMxF,EAAUwF,aAAiB,MAAQA,EAAM,QAAU,yBACzDzF,EAAKC,EAAS,OAAO,CACvB,SACEiK,EAAc,EAAK,CACrB,CACF,EAAG,CAAClK,EAAMkL,CAAW,CAAC,EAEtB,OACE5C,OAAC,OAAI,eAAcoB,EACjB,UAAArJ,MAAC,UAAO,UAAU,SAChB,SAAAiI,OAAC,OAAI,UAAU,gBACb,UAAAA,OAAC,OAAI,UAAU,gBACb,UAAAjI,MAAC,MAAG,kBAAM,QACT,QAAK,UAAU,kBAAkB,MAAO4M,GACtC,SAAAH,GACH,EACCjD,EAAcxJ,MAAC,QAAK,UAAU,UAAU,cAAY,OAAO,EAAK,KAChEqI,GAAa,YACZrI,MAAC,QAAK,UAAU,2BAA2B,uBAAW,EACpD,KACH0M,GACCzE,OAAC,UACC,KAAK,SACL,UAAU,mCACV,QAAS8E,GACT,SAAUnD,GAAc,EAAQvB,GAAa,YAE7C,UAAArI,MAAC,QAAK,UAAU,2BAA2B,cAAY,OAAO,EAC9DA,MAACmG,EAAA,CAAU,IAAKQ,EAAA,CAAY,EAAE,sBAG9B,MACN,EACAsB,OAAC,OAAI,UAAU,kBACZ,WAAClC,GACA/F,MAAC,QAAK,UAAU,QAAQ,MAAO,CAAE,WAAY,0BAA2B,YAAa,yBAA0B,MAAO,iBAAmB,mBAEzI,EAEFiI,OAAC,OAAI,UAAU,sBACb,UAAAjI,MAAC,UACC,KAAK,SACL,UAAWqJ,IAAgB,cAAgB,SAAW,GACtD,QAAS,IAAM3D,EAAe,aAAa,EAC3C,MAAM,mBACP,yBAGD1F,MAAC,UACC,KAAK,SACL,UAAWqJ,IAAgB,UAAY,SAAW,GAClD,QAAS,IAAM3D,EAAe,SAAS,EACvC,MAAM,eACP,oBAED,EACF,EACAuC,OAAC,UACC,KAAK,SACL,UAAU,kBACV,QAAS6E,GACT,SAAUtD,EAEV,UAAAxJ,MAACmG,EAAA,CAAU,IAAKO,EAAA,CAAa,EAC5B8C,EAAc,cAAgB,mBAEjCvB,OAAC,KACC,KAAMF,EACN,OAAO,SACP,IAAI,aACJ,UAAU,kBAEV,UAAA/H,MAACmG,EAAA,CAAU,IAAKM,CAAA,CAAc,EAAE,WAElC,EACF,GACF,EACF,EACAwB,OAAC,QAAK,UAAU,YACd,UAAAjI,MAAC,OAAI,UAAU,MACZ,SAAAgM,EAAK,IAAKa,GACT5E,OAAC,UACC,KAAK,SAEL,UAAWe,IAAc6D,EAAI,GAAK,SAAW,GAC7C,QAAS,IAAM,CACT7D,IAAc,UAAY6D,EAAI,KAAO,UAAY3D,GAI/C,CAHgB,OAAO,QACzB,mEAMJD,EAAa4D,EAAI,EAAE,EACnBzD,EAAe,EAAE,EACnB,EAEA,UAAApJ,MAACmG,EAAA,CAAU,IAAK0G,EAAI,KAAM,EAC1B7M,MAAC,QAAM,SAAA6M,EAAI,MAAM,IAhBZA,EAAI,GAkBZ,EACH,EACA5E,OAACkF,YAAS,SAAUnN,MAAC,OAAI,UAAU,UAAU,sBAAU,EACpD,UAAAgJ,IAAc,aAAehJ,MAACkH,GAAA,CAA6C,OAAM,IAAhC,aAAamD,CAAS,EAAW,EAClFrB,IAAc,QAAUhJ,MAACsH,GAAA,CAAmC,OAAM,IAA3B,QAAQ+C,CAAS,EAAW,EACnErB,IAAc,UAAYhJ,MAACuH,EAAA,CAAoC,KAAK,SAAS,OAAM,IAA3C,UAAU8C,CAAS,EAAyB,EACpFrB,IAAc,UAAYhJ,MAACuH,EAAA,CAAoC,KAAK,SAAS,OAAM,IAA3C,UAAU8C,CAAS,EAAyB,EACpFrB,IAAc,UAAYhJ,MAACuH,EAAA,CAAoC,KAAK,SAAS,OAAM,IAA3C,UAAU8C,CAAS,EAAyB,EACpFrB,IAAc,UAAYhJ,MAACwH,GAAA,CAAuC,cAAe2B,GAAtC,UAAUkB,CAAS,EAAmC,GACpG,GACF,EACCX,GAAiBJ,EAChBtJ,MAACmI,GAAA,CACC,eAAgBmB,EAAK,gBACrB,cAAAlB,GACA,UAAWkB,EAAK,UAChB,aAAAxB,GACA,cAAAC,EACA,YAAAM,EACA,SAAUuB,EACV,QAASoD,GACT,SAAUE,EAAA,GAEV,KACHzC,IAAwBnB,EACvBtJ,MAAC2H,GAAA,CACC,eAAgB2B,EAAK,gBACrB,UAAWA,EAAK,2BAA6BA,EAAK,UAClD,aAAAxB,GACA,cAAAC,EACA,QAASkF,EAAA,GAET,MACN,CAEJ,CAEA,SAAwBG,IAAmB,CACzC,OACEpN,MAACf,GAAA,CACC,SAAAe,MAACO,GAAA,CACC,gBAACkE,GAAA,CACC,UAAAzE,MAAC+I,GAAA,EAAS,QACT3I,GAAA,EAAc,GACjB,EACF,EACF,CAEJ,CC7xBAiN,cAAW,SAAS,eAAe,MAAM,CAAE,EAAE,OAC3CrN,MAACsN,aAAA,CACC,SAAAtN,MAACoN,GAAA,EAAI,EACP,CACF","names":["f","require$$0","k","l","m","n","p","q","c","a","g","b","d","e","h","reactJsxRuntime_production_min","jsxRuntimeModule","client","ToastContext","createContext","toastCounter","ToastProvider","children","toasts","setToasts","useState","dismiss","useCallback","id","prev","t","push","message","kind","value","useMemo","jsx","useToast","ctx","useContext","ToastViewport","toast","SearchContext","SearchProvider","setValueState","handlers","useRef","setValue","term","handler","register","clearHandler","valueObj","useSearch","JSON_HEADERS","TOKEN_STORAGE_KEYS","MAX_AUTH_RETRIES","inflightRequests","createRequestKey","input","init","url","method","body","resolveToken","key","fromQuery","clearStoredToken","buildInit","token","headers","fetchWithAuthRetry","retries","response","fetchJson","existingRequest","promise","handleJson","fetchTextResponse","handleText","res","detail","errorText","getMeta","params","query","getStatus","getProcesses","restartProcess","category","restartAllProcesses","rebuildArrs","getLogs","getLogTail","name","getLogDownloadUrl","getArrList","getRadarrMovies","page","pageSize","getSonarrSeries","options","getLidarrAlbums","restartArr","getConfig","updateConfig","payload","triggerUpdate","WebUIContext","WebUIProvider","settings","setSettings","loading","setLoading","useEffect","webui","storedDensity","storedTheme","backendTheme","theme","error","saveSettings","changes","setLiveArr","setGroupSonarr","setGroupLidarr","setViewDensity","setTheme","useWebUI","context","useNetworkStatus","isOnline","setIsOnline","handleOnline","handleOffline","IconImage","src","alt","className","rest","CloseIcon","ExternalIcon","RefreshIcon","UpdateIcon","ProcessesIcon","LogsIcon","RadarrIcon","SonarrIcon","LidarrIcon","ConfigureIcon","ProcessesView","lazy","__vitePreload","module","LogsView","ArrView","ConfigView","formatVersionLabel","trimmed","WelcomeModal","currentVersion","changelog","changelogUrl","repositoryUrl","onClose","jsxs","event","ChangelogModal","latestVersion","updateState","updating","onUpdate","countdown","setCountdown","updateDisabled","completedLabel","timer","statusClass","statusMessage","AppShell","activeTab","setActiveTab","configDirty","setConfigDirty","setSearchValue","viewDensity","meta","setMeta","metaLoading","setMetaLoading","showChangelog","setShowChangelog","updateBusy","setUpdateBusy","backendRestarting","setBackendRestarting","restartPollCount","prevUpdateResult","backendReadyRef","backendWarnedRef","backendTimerRef","reloadKey","setReloadKey","statusData","setStatusData","showWelcomeChangelog","setShowWelcomeChangelog","cacheNames","cacheName","refreshMeta","force","silent","data","lastSeenVersion","handleKeyDown","isMod","tabIndex","tabIds","handleVisibilityChange","refreshStatus","status","state","result","cancelled","attempts","schedule","delay","poll","tabs","baseTabs","arrTabs","arrs","hasRadarr","arr","hasSonarr","hasLidarr","ConfigIcon","displayVersion","updateAvailable","versionTitleParts","versionTitle","tab","handleCheckUpdates","handleOpenChangelog","handleCloseChangelog","handleCloseWelcomeChangelog","handleTriggerUpdate","Suspense","App","createRoot","StrictMode"],"ignoreList":[0,1,2],"sources":["../../../webui/node_modules/react/cjs/react-jsx-runtime.production.min.js","../../../webui/node_modules/react/jsx-runtime.js","../../../webui/node_modules/react-dom/client.js","../../../webui/src/context/ToastContext.tsx","../../../webui/src/context/SearchContext.tsx","../../../webui/src/api/client.ts","../../../webui/src/context/WebUIContext.tsx","../../../webui/src/hooks/useNetworkStatus.ts","../../../webui/src/components/IconImage.tsx","../../../webui/src/icons/close.svg","../../../webui/src/icons/github.svg","../../../webui/src/icons/refresh-arrow.svg","../../../webui/src/icons/up-arrow.svg","../../../webui/src/icons/process.svg","../../../webui/src/icons/log.svg","../../../webui/src/icons/radarr.svg","../../../webui/src/icons/sonarr.svg","../../../webui/src/icons/lidarr.svg","../../../webui/src/icons/gear.svg","../../../webui/src/App.tsx","../../../webui/src/main.tsx"],"sourcesContent":["/**\n * @license React\n * react-jsx-runtime.production.min.js\n *\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n'use strict';var f=require(\"react\"),k=Symbol.for(\"react.element\"),l=Symbol.for(\"react.fragment\"),m=Object.prototype.hasOwnProperty,n=f.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,p={key:!0,ref:!0,__self:!0,__source:!0};\nfunction q(c,a,g){var b,d={},e=null,h=null;void 0!==g&&(e=\"\"+g);void 0!==a.key&&(e=\"\"+a.key);void 0!==a.ref&&(h=a.ref);for(b in a)m.call(a,b)&&!p.hasOwnProperty(b)&&(d[b]=a[b]);if(c&&c.defaultProps)for(b in a=c.defaultProps,a)void 0===d[b]&&(d[b]=a[b]);return{$$typeof:k,type:c,key:e,ref:h,props:d,_owner:n.current}}exports.Fragment=l;exports.jsx=q;exports.jsxs=q;\n","'use strict';\n\nif (process.env.NODE_ENV === 'production') {\n module.exports = require('./cjs/react-jsx-runtime.production.min.js');\n} else {\n module.exports = require('./cjs/react-jsx-runtime.development.js');\n}\n","'use strict';\n\nvar m = require('react-dom');\nif (process.env.NODE_ENV === 'production') {\n exports.createRoot = m.createRoot;\n exports.hydrateRoot = m.hydrateRoot;\n} else {\n var i = m.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;\n exports.createRoot = function(c, o) {\n i.usingClientEntryPoint = true;\n try {\n return m.createRoot(c, o);\n } finally {\n i.usingClientEntryPoint = false;\n }\n };\n exports.hydrateRoot = function(c, h, o) {\n i.usingClientEntryPoint = true;\n try {\n return m.hydrateRoot(c, h, o);\n } finally {\n i.usingClientEntryPoint = false;\n }\n };\n}\n","/* eslint-disable react-refresh/only-export-components */\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useState,\n type PropsWithChildren,\n type JSX,\n} from \"react\";\n\nexport type ToastKind = \"info\" | \"success\" | \"warning\" | \"error\";\n\nexport interface Toast {\n id: number;\n message: string;\n kind: ToastKind;\n}\n\ninterface ToastContextValue {\n toasts: Toast[];\n push: (message: string, kind?: ToastKind) => void;\n dismiss: (id: number) => void;\n}\n\nconst ToastContext = createContext<ToastContextValue | undefined>(undefined);\n\nlet toastCounter = 0;\n\nexport function ToastProvider({ children }: PropsWithChildren): JSX.Element {\n const [toasts, setToasts] = useState<Toast[]>([]);\n\n const dismiss = useCallback((id: number) => {\n setToasts((prev) => prev.filter((t) => t.id !== id));\n }, []);\n\n const push = useCallback(\n (message: string, kind: ToastKind = \"info\") => {\n const id = ++toastCounter;\n setToasts((prev) => [...prev, { id, message, kind }]);\n // Auto dismiss\n window.setTimeout(() => dismiss(id), 3500);\n },\n [dismiss]\n );\n\n const value = useMemo(\n () => ({\n toasts,\n push,\n dismiss,\n }),\n [toasts, push, dismiss]\n );\n\n return (\n <ToastContext.Provider value={value}>{children}</ToastContext.Provider>\n );\n}\n\nexport function useToast(): ToastContextValue {\n const ctx = useContext(ToastContext);\n if (!ctx) {\n throw new Error(\"useToast must be used within a ToastProvider\");\n }\n return ctx;\n}\n\nexport function ToastViewport(): JSX.Element | null {\n const { toasts, dismiss } = useToast();\n if (!toasts.length) return null;\n return (\n <div className=\"toasts\">\n {toasts.map((toast) => (\n <div\n key={toast.id}\n className={`toast ${toast.kind !== \"info\" ? toast.kind : \"\"}`}\n role=\"status\"\n onClick={() => dismiss(toast.id)}\n >\n {toast.message}\n </div>\n ))}\n </div>\n );\n}\n","/* eslint-disable react-refresh/only-export-components */\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useRef,\n useState,\n type PropsWithChildren,\n type JSX,\n} from \"react\";\n\ntype SearchHandler = ((term: string) => void) | null;\n\ninterface SearchContextValue {\n value: string;\n setValue: (term: string) => void;\n register: (handler: SearchHandler) => void;\n clearHandler: (handler: SearchHandler) => void;\n}\n\nconst SearchContext = createContext<SearchContextValue | undefined>(undefined);\n\nexport function SearchProvider({ children }: PropsWithChildren): JSX.Element {\n const [value, setValueState] = useState(\"\");\n const handlers = useRef<Set<SearchHandler>>(new Set());\n\n const setValue = useCallback((term: string) => {\n setValueState(term);\n handlers.current.forEach((handler) => {\n handler?.(term);\n });\n }, []);\n\n const register = useCallback((handler: SearchHandler) => {\n if (!handler) return;\n handlers.current.add(handler);\n }, []);\n\n const clearHandler = useCallback((handler: SearchHandler) => {\n handlers.current.delete(handler);\n }, []);\n\n const valueObj = useMemo(\n () => ({\n value,\n setValue,\n register,\n clearHandler,\n }),\n [value, setValue, register, clearHandler]\n );\n\n return (\n <SearchContext.Provider value={valueObj}>\n {children}\n </SearchContext.Provider>\n );\n}\n\nexport function useSearch(): SearchContextValue {\n const ctx = useContext(SearchContext);\n if (!ctx) {\n throw new Error(\"useSearch must be used within a SearchProvider\");\n }\n return ctx;\n}\n","import type {\n ArrListResponse,\n ConfigDocument,\n ConfigUpdatePayload,\n ConfigUpdateResponse,\n MetaResponse,\n LogsListResponse,\n ProcessesResponse,\n RadarrMoviesResponse,\n RestartResponse,\n SonarrSeriesResponse,\n LidarrAlbumsResponse,\n LidarrAlbum,\n StatusResponse,\n} from \"./types\";\n\nconst JSON_HEADERS = { \"Content-Type\": \"application/json\" } as const;\nconst TOKEN_STORAGE_KEYS = [\"token\", \"webui-token\", \"webui_token\"] as const;\nconst MAX_AUTH_RETRIES = 1;\n\n// Request deduplication cache\nconst inflightRequests = new Map<string, Promise<unknown>>();\n\nfunction createRequestKey(input: RequestInfo | URL, init?: RequestInit): string {\n const url = input instanceof Request ? input.url : String(input);\n const method = init?.method || \"GET\";\n const body = init?.body ? String(init.body) : \"\";\n return `${method}:${url}:${body}`;\n}\n\nfunction resolveToken(): string | null {\n for (const key of TOKEN_STORAGE_KEYS) {\n const value = localStorage.getItem(key) || sessionStorage.getItem(key);\n if (value) {\n if (key !== \"token\") {\n localStorage.setItem(\"token\", value);\n }\n return value;\n }\n }\n try {\n const params = new URLSearchParams(window.location.search);\n const fromQuery = params.get(\"token\");\n if (fromQuery) {\n localStorage.setItem(\"token\", fromQuery);\n return fromQuery;\n }\n } catch {\n // ignore\n }\n return null;\n}\n\nfunction clearStoredToken(): void {\n for (const key of TOKEN_STORAGE_KEYS) {\n localStorage.removeItem(key);\n }\n try {\n for (const key of TOKEN_STORAGE_KEYS) {\n sessionStorage.removeItem(key);\n }\n } catch {\n // ignore session storage errors\n }\n}\n\nfunction buildInit(init: RequestInit | undefined, token: string | null): RequestInit {\n const headers = new Headers(init?.headers || {});\n Object.entries(JSON_HEADERS).forEach(([key, value]) => {\n if (!headers.has(key)) headers.set(key, value);\n });\n if (token && !headers.has(\"Authorization\")) {\n headers.set(\"Authorization\", `Bearer ${token}`);\n }\n return {\n ...init,\n headers,\n };\n}\n\nasync function fetchWithAuthRetry<T>(\n input: RequestInfo | URL,\n init: RequestInit | undefined,\n handler: (response: Response) => Promise<T>,\n retries = MAX_AUTH_RETRIES\n): Promise<T> {\n const token = resolveToken();\n const response = await fetch(input, buildInit(init, token));\n if (response.status === 401 && retries > 0 && token) {\n clearStoredToken();\n return fetchWithAuthRetry(input, init, handler, retries - 1);\n }\n return handler(response);\n}\n\nasync function fetchJson<T>(input: RequestInfo | URL, init?: RequestInit): Promise<T> {\n // Only deduplicate GET requests (safe to share)\n const method = init?.method || \"GET\";\n if (method === \"GET\") {\n const key = createRequestKey(input, init);\n const existingRequest = inflightRequests.get(key) as Promise<T> | undefined;\n\n if (existingRequest) {\n return existingRequest;\n }\n\n const promise = fetchWithAuthRetry<T>(input, init, (response) => handleJson<T>(response))\n .finally(() => {\n inflightRequests.delete(key);\n });\n\n inflightRequests.set(key, promise);\n return promise;\n }\n\n return fetchWithAuthRetry<T>(input, init, (response) => handleJson<T>(response));\n}\n\nasync function fetchTextResponse(input: RequestInfo | URL, init?: RequestInit): Promise<string> {\n return fetchWithAuthRetry<string>(input, init, (response) => handleText(response));\n}\n\nasync function handleJson<T>(res: Response): Promise<T> {\n if (!res.ok) {\n let detail: unknown = null;\n try {\n detail = await res.json();\n } catch {\n // ignore\n }\n let message = `${res.status} ${res.statusText}`;\n if (\n detail &&\n typeof detail === \"object\" &&\n \"error\" in detail &&\n typeof (detail as Record<string, unknown>).error === \"string\"\n ) {\n const errorText = (detail as Record<string, unknown>).error as string;\n if (errorText.trim()) {\n message = errorText;\n }\n }\n throw new Error(message);\n }\n return (await res.json()) as T;\n}\n\nasync function handleText(res: Response): Promise<string> {\n if (!res.ok) {\n throw new Error(`${res.status} ${res.statusText}`);\n }\n return res.text();\n}\n\nexport async function getMeta(params?: { force?: boolean }): Promise<MetaResponse> {\n const query = params?.force ? \"?force=1\" : \"\";\n return fetchJson<MetaResponse>(`/web/meta${query}`);\n}\n\nexport async function getStatus(): Promise<StatusResponse> {\n return fetchJson<StatusResponse>(\"/web/status\");\n}\n\nexport async function getProcesses(): Promise<ProcessesResponse> {\n return fetchJson<ProcessesResponse>(\"/web/processes\");\n}\n\nexport async function restartProcess(\n category: string,\n kind: string\n): Promise<RestartResponse> {\n const url = `/web/processes/${encodeURIComponent(\n category\n )}/${encodeURIComponent(kind)}/restart`;\n return fetchJson<RestartResponse>(url, { method: \"POST\" });\n}\n\nexport async function restartAllProcesses(): Promise<RestartResponse> {\n return fetchJson<RestartResponse>(\"/web/processes/restart_all\", {\n method: \"POST\",\n });\n}\n\nexport async function rebuildArrs(): Promise<RestartResponse> {\n return fetchJson<RestartResponse>(\"/web/arr/rebuild\", { method: \"POST\" });\n}\n\nexport async function setLogLevel(level: string): Promise<void> {\n await fetchJson<void>(\"/web/loglevel\", {\n method: \"POST\",\n body: JSON.stringify({ level }),\n });\n}\n\nexport async function getLogs(): Promise<LogsListResponse> {\n return fetchJson<LogsListResponse>(\"/web/logs\");\n}\n\nexport async function getLogTail(name: string): Promise<string> {\n return fetchTextResponse(`/web/logs/${encodeURIComponent(name)}`);\n}\n\nexport function getLogDownloadUrl(name: string): string {\n return `/web/logs/${encodeURIComponent(name)}/download`;\n}\n\nexport async function getArrList(): Promise<ArrListResponse> {\n return fetchJson<ArrListResponse>(\"/web/arr\");\n}\n\nexport async function getRadarrMovies(\n category: string,\n page: number,\n pageSize: number,\n q: string\n): Promise<RadarrMoviesResponse> {\n const params = new URLSearchParams();\n params.set(\"page\", String(page));\n params.set(\"page_size\", String(pageSize));\n if (q) params.set(\"q\", q);\n return fetchJson<RadarrMoviesResponse>(\n `/web/radarr/${encodeURIComponent(category)}/movies?${params}`\n );\n}\n\nexport async function getSonarrSeries(\n category: string,\n page: number,\n pageSize: number,\n q: string,\n options?: { missingOnly?: boolean }\n): Promise<SonarrSeriesResponse> {\n const params = new URLSearchParams();\n params.set(\"page\", String(page));\n params.set(\"page_size\", String(pageSize));\n if (q) params.set(\"q\", q);\n if (options?.missingOnly) {\n params.set(\"missing\", \"1\");\n }\n return fetchJson<SonarrSeriesResponse>(\n `/web/sonarr/${encodeURIComponent(category)}/series?${params}`\n );\n}\n\nexport async function getLidarrAlbums(\n category: string,\n page: number,\n pageSize: number,\n query?: string\n): Promise<LidarrAlbumsResponse> {\n const params = new URLSearchParams();\n params.set(\"page\", page.toString());\n params.set(\"page_size\", pageSize.toString());\n if (query) {\n params.set(\"q\", query);\n }\n // Always include tracks\n params.set(\"include_tracks\", \"true\");\n return fetchJson<LidarrAlbumsResponse>(\n `/web/lidarr/${encodeURIComponent(category)}/albums?${params}`\n );\n}\n\nexport async function restartArr(category: string): Promise<void> {\n await fetchJson<void>(\n `/web/arr/${encodeURIComponent(category)}/restart`,\n { method: \"POST\" }\n );\n}\n\nexport async function getConfig(): Promise<ConfigDocument> {\n return fetchJson<ConfigDocument>(\"/web/config\");\n}\n\nexport async function updateConfig(\n payload: ConfigUpdatePayload\n): Promise<ConfigUpdateResponse> {\n const token = resolveToken();\n const response = await fetch(\"/web/config\", buildInit({\n method: \"POST\",\n body: JSON.stringify(payload),\n }, token));\n\n if (!response.ok) {\n let detail: unknown = null;\n try {\n detail = await response.json();\n } catch {\n // ignore\n }\n let message = `${response.status} ${response.statusText}`;\n if (\n detail &&\n typeof detail === \"object\" &&\n \"error\" in detail &&\n typeof (detail as Record<string, unknown>).error === \"string\"\n ) {\n const errorText = (detail as Record<string, unknown>).error as string;\n if (errorText.trim()) {\n message = errorText;\n }\n }\n throw new Error(message);\n }\n\n // Parse response body with full type information\n const data = await response.json() as ConfigUpdateResponse;\n return data;\n}\n\nexport async function triggerUpdate(): Promise<void> {\n await fetchJson<void>(\"/web/update\", { method: \"POST\" });\n}\n","import { createContext, useCallback, useContext, useEffect, useState, type JSX, type ReactNode } from \"react\";\nimport { getConfig, updateConfig } from \"../api/client\";\n\ntype ViewDensity = \"comfortable\" | \"compact\";\ntype Theme = \"light\" | \"dark\";\n\ninterface WebUISettings {\n liveArr: boolean;\n groupSonarr: boolean;\n groupLidarr: boolean;\n viewDensity: ViewDensity;\n theme: Theme;\n}\n\ninterface WebUIContextValue {\n liveArr: boolean;\n groupSonarr: boolean;\n groupLidarr: boolean;\n viewDensity: ViewDensity;\n theme: Theme;\n setLiveArr: (value: boolean) => void;\n setGroupSonarr: (value: boolean) => void;\n setGroupLidarr: (value: boolean) => void;\n setViewDensity: (value: ViewDensity) => void;\n setTheme: (value: Theme) => void;\n loading: boolean;\n}\n\nconst WebUIContext = createContext<WebUIContextValue | null>(null);\n\nexport function WebUIProvider({ children }: { children: ReactNode }): JSX.Element {\n const [settings, setSettings] = useState<WebUISettings>({\n liveArr: true,\n groupSonarr: true,\n groupLidarr: true,\n viewDensity: \"comfortable\",\n theme: \"dark\",\n });\n const [loading, setLoading] = useState(true);\n\n // Load initial settings\n useEffect(() => {\n const loadSettings = async () => {\n try {\n const config = await getConfig();\n const webui = config?.WebUI as Record<string, unknown> | undefined;\n\n // Load from localStorage as fallback for view density (client-side preference)\n const storedDensity = localStorage.getItem(\"viewDensity\") as ViewDensity | null;\n const storedTheme = localStorage.getItem(\"theme\") as Theme | null;\n\n // Get theme from backend or localStorage\n const backendTheme = webui?.Theme as string | undefined;\n const theme: Theme = storedTheme || (backendTheme?.toLowerCase() as Theme) || \"dark\";\n\n setSettings({\n liveArr: webui?.LiveArr === true,\n groupSonarr: webui?.GroupSonarr === true,\n groupLidarr: webui?.GroupLidarr === true,\n viewDensity: storedDensity || \"comfortable\",\n theme,\n });\n\n // Apply theme immediately\n document.documentElement.setAttribute('data-theme', theme);\n } catch (error) {\n console.error(\"Failed to load WebUI settings:\", error);\n } finally {\n setLoading(false);\n }\n };\n\n void loadSettings();\n }, []);\n\n // Auto-save settings to backend\n const saveSettings = useCallback(async (key: string, value: boolean | string) => {\n try {\n const changes: Record<string, unknown> = {\n WebUI: {\n [key]: value,\n },\n };\n await updateConfig({ changes });\n } catch (error) {\n console.error(`Failed to save ${key}:`, error);\n }\n }, []);\n\n const setLiveArr = useCallback((value: boolean) => {\n setSettings(prev => ({ ...prev, liveArr: value }));\n void saveSettings(\"LiveArr\", value);\n }, [saveSettings]);\n\n const setGroupSonarr = useCallback((value: boolean) => {\n setSettings(prev => ({ ...prev, groupSonarr: value }));\n void saveSettings(\"GroupSonarr\", value);\n }, [saveSettings]);\n\n const setGroupLidarr = useCallback((value: boolean) => {\n setSettings(prev => ({ ...prev, groupLidarr: value }));\n void saveSettings(\"GroupLidarr\", value);\n }, [saveSettings]);\n\n const setViewDensity = useCallback((value: ViewDensity) => {\n setSettings(prev => ({ ...prev, viewDensity: value }));\n // Store in localStorage (client-side preference, not sent to backend)\n localStorage.setItem(\"viewDensity\", value);\n }, []);\n\n const setTheme = useCallback((value: Theme) => {\n setSettings(prev => ({ ...prev, theme: value }));\n // Store in localStorage for instant application\n localStorage.setItem(\"theme\", value);\n // Apply theme immediately to DOM\n document.documentElement.setAttribute('data-theme', value);\n // Save to backend with proper capitalization (Light or Dark)\n const capitalizedTheme = value === \"light\" ? \"Light\" : \"Dark\";\n void saveSettings(\"Theme\", capitalizedTheme);\n }, [saveSettings]);\n\n const value: WebUIContextValue = {\n liveArr: settings.liveArr,\n groupSonarr: settings.groupSonarr,\n groupLidarr: settings.groupLidarr,\n viewDensity: settings.viewDensity,\n theme: settings.theme,\n setLiveArr,\n setGroupSonarr,\n setGroupLidarr,\n setViewDensity,\n setTheme,\n loading,\n };\n\n return <WebUIContext.Provider value={value}>{children}</WebUIContext.Provider>;\n}\n\nexport function useWebUI(): WebUIContextValue {\n const context = useContext(WebUIContext);\n if (!context) {\n throw new Error(\"useWebUI must be used within WebUIProvider\");\n }\n return context;\n}\n","import { useEffect, useState } from \"react\";\n\nexport function useNetworkStatus(): boolean {\n const [isOnline, setIsOnline] = useState(navigator.onLine);\n\n useEffect(() => {\n const handleOnline = () => setIsOnline(true);\n const handleOffline = () => setIsOnline(false);\n\n window.addEventListener('online', handleOnline);\n window.addEventListener('offline', handleOffline);\n\n return () => {\n window.removeEventListener('online', handleOnline);\n window.removeEventListener('offline', handleOffline);\n };\n }, []);\n\n return isOnline;\n}\n","import type { ImgHTMLAttributes, JSX } from \"react\";\n\ninterface IconImageProps extends Omit<ImgHTMLAttributes<HTMLImageElement>, \"src\"> {\n src: string;\n alt?: string;\n}\n\nexport function IconImage({ src, alt, className, ...rest }: IconImageProps): JSX.Element {\n return (\n <img\n src={src}\n alt={alt ?? \"\"}\n className={className ? `icon ${className}` : \"icon\"}\n aria-hidden={alt ? undefined : true}\n {...rest}\n />\n );\n}\n","export default \"__VITE_ASSET__BwSX1QeM__\"","export default \"data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20xml:space='preserve'%20viewBox='0%200%20512%20512'%3e%3cpath%20d='M256%206.3C114.6%206.3%200%20120.9%200%20262.3c0%20113.3%2073.3%20209%20175%20242.9%2012.8%202.2%2017.6-5.4%2017.6-12.2%200-6.1-.3-26.2-.3-47.7-64.3%2011.8-81-15.7-86.1-30.1-2.9-7.4-15.4-30.1-26.2-36.2-9-4.8-21.8-16.6-.3-17%2020.2-.3%2034.6%2018.6%2039.4%2026.2%2023%2038.7%2059.8%2027.8%2074.6%2021.1%202.2-16.6%209-27.8%2016.3-34.2-57-6.4-116.5-28.5-116.5-126.4%200-27.8%209.9-50.9%2026.2-68.8-2.6-6.4-11.5-32.6%202.6-67.8%200%200%2021.4-6.7%2070.4%2026.2%2020.5-5.8%2042.2-8.6%2064-8.6s43.5%202.9%2064%208.6c49-33.3%2070.4-26.2%2070.4-26.2%2014.1%2035.2%205.1%2061.4%202.6%2067.8%2016.3%2017.9%2026.2%2040.6%2026.2%2068.8%200%2098.2-59.8%20120-116.8%20126.4%209.3%208%2017.3%2023.4%2017.3%2047.4%200%2034.2-.3%2061.8-.3%2070.4%200%206.7%204.8%2014.7%2017.6%2012.2C438.7%20471.3%20512%20375.3%20512%20262.3c0-141.4-114.6-256-256-256'%20style='fill-rule:evenodd;clip-rule:evenodd;fill:%231b1f23'/%3e%3c/svg%3e\"","export default \"__VITE_ASSET__B5Abvgg6__\"","export default \"__VITE_ASSET__CFg2sUO1__\"","export default \"__VITE_ASSET__DruObj$B__\"","export default \"__VITE_ASSET__DKTRAwQu__\"","export default \"data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20xml:space='preserve'%20id='Layer_1'%20x='0'%20y='0'%20version='1.1'%20viewBox='0%200%20512%20512'%3e%3cstyle%3e.st0{fill:%2324292e}%3c/style%3e%3cg%20id='Group-Copy'%20transform='translate(70%2021)'%3e%3cpath%20id='Shape'%20d='m10.3%2059.8%203.9%20372.4c-31.4%203.9-54.9-11.8-54.9-43.1l-3.9-309.7c0-98%2090.2-121.5%20145.1-82.3l278.3%20160.7c39.2%2027.4%2047%2078.4%2027.4%20113.7-3.9-27.4-15.7-43.1-39.2-58.8L53.4%2036.2C29.9%2020.6%2010.3%2024.5%2010.3%2059.8'%20class='st0'/%3e%3cpath%20id='Shape_00000114049535938561773820000018271523940913105341_'%20d='M-13.2%20451.8c23.5%207.8%2047%203.9%2066.6-7.8l321.5-188.2c19.6%2027.4%2015.7%2054.9-7.8%2070.6L96.5%20483.2c-39.2%2019.6-90.1%200-109.7-31.4'%20class='st0'/%3e%3cpath%20id='Shape_00000165935924413286433040000003668002807793862576_'%20d='M80.9%20342%20273%20232.3%2084.8%20126.4z'%20style='fill:%23ffc230'/%3e%3c/g%3e%3c/svg%3e\"","export default \"data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20xml:space='preserve'%20viewBox='0%200%20512%20512'%3e%3cpath%20d='M511.8%20256c0%2070.4-24.9%20130.8-74.6%20181.1-1.7%202-3.5%203.8-5.5%205.4-8.2%208-16.8%2015.3-26%2021.8Q341.05%20512%20256.3%20512c-56.6%200-106.3-15.9-149.2-47.7-11.3-8-22-17.1-31.9-27.3C36.5%20398.7%2012.8%20354%204%20303.2c-1.7-9.9-2.9-20-3.4-30.2-.2-5.7-.4-11.3-.4-17%200-6%20.1-11.7.4-17.1%200-.6.2-1.1.5-1.7%203.7-62.8%2028.4-117%2074.1-162.8C125.5%2024.8%20185.8%200%20256.2%200c70.7%200%20131%2024.8%20180.9%2074.5q74.7%2075.9%2074.7%20181.5'%20style='fill-rule:evenodd;clip-rule:evenodd;fill:%23eee'/%3e%3cpath%20d='m459.7%20100.3-52.9%2052.9c-30.9%2030.9-33.6%2057.8-33.6%20105.3%200%2042.3%206.7%2081.1%2038.2%20112.6%2023%2023%2044.9%2044.7%2044.9%2044.7-5.9%207.2-12.3%2014.3-19.1%2021.2-1.7%202-3.5%203.8-5.5%205.4-6%205.9-12.2%2011.4-18.6%2016.4l-41.4-41.4C334.9%20380.6%20305.6%20377%20257%20377c-46.7%200-78.4%204.3-112.6%2038.5-20.4%2020.4-43.8%2043.9-43.8%2043.9-8.9-6.8-17.3-14.2-25.3-22.4-6.6-6.6-12.8-13.4-18.5-20.3%200%200%2023.1-23.2%2045.2-45.3%2032.7-32.7%2038-70.6%2038-113%200-41.3-6.8-79.8-36.8-109.9C82.2%20127.7%2053.3%2099%2053.3%2099c6.7-8.5%2014-16.7%2021.8-24.5%206.9-6.8%2014-13.1%2021.2-19l48%2048c30.7%2030.7%2070%2038.6%20112.4%2038.6%2043.6%200%2082.8-8.4%20114.7-40.4C391%2082.1%20417%2056.3%20417%2056.3c6.8%205.6%2013.5%2011.6%2020.1%2018.2%208.3%208.3%2015.8%2016.9%2022.6%2025.8'%20style='fill-rule:evenodd;clip-rule:evenodd;fill:%233a3f51'/%3e%3cpath%20d='M186%20269.1c-.5-2.8-.8-5.5-.9-8.4-.1-1.6-.1-3.1-.1-4.7%200-1.7%200-3.2.1-4.7%200-.2%200-.3.1-.5%201-17.4%207.9-32.4%2020.5-45.1%2013.9-13.8%2030.6-20.7%2050.2-20.7s36.3%206.9%2050.2%2020.7c13.8%2014%2020.7%2030.8%2020.7%2050.3s-6.9%2036.2-20.7%2050.2c-.5.5-1%201.1-1.5%201.5q-3.45%203.3-7.2%206-18%2013.2-41.4%2013.2c-23.4%200-29.4-4.4-41.3-13.2-3.1-2.2-6.1-4.7-8.9-7.6-10.8-10.6-17.3-22.9-19.8-37'%20style='fill-rule:evenodd;clip-rule:evenodd;fill:%230cf'/%3e%3cpath%20d='m372.7%20141-35.4%2034.6M72.9%2076.8l96.5%2096.1m199.7%20198.9%2065.6%2067.9m4.4-363.3L372.7%20141M76.6%20438.5l64.6-64.7'%20style='fill:none;stroke:%230cf;stroke-width:2;stroke-miterlimit:1'/%3e%3cpath%20d='m372.7%20141-40%2040.6m-193.3-38.5%2040.6%2040.5M141%20374l39.5-41.1m146.2-3.3%2042.6%2042.4'%20style='fill:none;stroke:%230cf;stroke-width:7;stroke-miterlimit:1'/%3e%3c/svg%3e\"","export default \"__VITE_ASSET__B_sq1wA9__\"","export default \"__VITE_ASSET__CITwrObj__\"","import { useCallback, useEffect, useMemo, useRef, useState, type JSX, lazy, Suspense } from \"react\";\nconst ProcessesView = lazy(() => import(\"./pages/ProcessesView\").then(module => ({ default: module.ProcessesView })));\nconst LogsView = lazy(() => import(\"./pages/LogsView\").then(module => ({ default: module.LogsView })));\nconst ArrView = lazy(() => import(\"./pages/ArrView\").then(module => ({ default: module.ArrView })));\nconst ConfigView = lazy(() => import(\"./pages/ConfigView\").then(module => ({ default: module.ConfigView })));\nimport { ToastProvider, ToastViewport, useToast } from \"./context/ToastContext\";\nimport { SearchProvider, useSearch } from \"./context/SearchContext\";\nimport { WebUIProvider, useWebUI } from \"./context/WebUIContext\";\nimport { useNetworkStatus } from \"./hooks/useNetworkStatus\";\nimport { getMeta, getStatus, triggerUpdate } from \"./api/client\";\nimport type { MetaResponse, StatusResponse } from \"./api/types\";\nimport { IconImage } from \"./components/IconImage\";\nimport CloseIcon from \"./icons/close.svg\";\nimport ExternalIcon from \"./icons/github.svg\";\nimport RefreshIcon from \"./icons/refresh-arrow.svg\";\nimport UpdateIcon from \"./icons/up-arrow.svg\";\nimport ProcessesIcon from \"./icons/process.svg\";\nimport LogsIcon from \"./icons/log.svg\";\nimport RadarrIcon from \"./icons/radarr.svg\";\nimport SonarrIcon from \"./icons/sonarr.svg\";\nimport LidarrIcon from \"./icons/lidarr.svg\";\nimport ConfigIcon from \"./icons/gear.svg\";\n\ntype Tab = \"processes\" | \"logs\" | \"radarr\" | \"sonarr\" | \"lidarr\" | \"config\";\n\ninterface NavTab {\n id: Tab;\n label: string;\n icon: string;\n}\n\nfunction formatVersionLabel(value: string | null | undefined): string {\n if (!value) {\n return \"unknown\";\n }\n const trimmed = value.trim();\n if (!trimmed) {\n return \"unknown\";\n }\n return trimmed[0] === \"v\" || trimmed[0] === \"V\" ? trimmed : `v${trimmed}`;\n}\n\ninterface WelcomeModalProps {\n currentVersion: string;\n changelog: string | null;\n changelogUrl: string | null;\n repositoryUrl: string;\n onClose: () => void;\n}\n\nfunction WelcomeModal({\n currentVersion,\n changelog,\n changelogUrl,\n repositoryUrl,\n onClose,\n}: WelcomeModalProps): JSX.Element {\n return (\n <div className=\"modal-backdrop\" role=\"presentation\" onClick={onClose}>\n <div\n className=\"modal\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"welcome-title\"\n onClick={(event) => event.stopPropagation()}\n >\n <div className=\"modal-header\">\n <h2 id=\"welcome-title\">\n 🎉 Welcome to qBitrr {formatVersionLabel(currentVersion)}!\n </h2>\n <button className=\"btn ghost\" type=\"button\" onClick={onClose}>\n <IconImage src={CloseIcon} />\n Close\n </button>\n </div>\n <div className=\"modal-body changelog-modal__body\">\n <div className=\"changelog-meta\">\n <p style={{ marginBottom: '1rem', color: 'var(--text-secondary)' }}>\n You've been updated to version <strong>{formatVersionLabel(currentVersion)}</strong>.\n Here's what's new in this release:\n </p>\n </div>\n <div className=\"changelog-section\">\n <h3>Release Notes</h3>\n <pre className=\"changelog-body\">\n {changelog?.trim() ? changelog.trim() : \"No changelog available for this version.\"}\n </pre>\n </div>\n </div>\n <div className=\"modal-footer\">\n <div className=\"changelog-links\">\n {(changelogUrl || repositoryUrl) && (\n <a\n className=\"btn ghost small\"\n href={changelogUrl ?? repositoryUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n <IconImage src={ExternalIcon} />\n View Full Release on GitHub\n </a>\n )}\n </div>\n <div className=\"changelog-buttons\">\n <button className=\"btn primary\" type=\"button\" onClick={onClose}>\n Got it!\n </button>\n </div>\n </div>\n </div>\n </div>\n );\n}\n\ninterface ChangelogModalProps {\n currentVersion: string;\n latestVersion: string | null;\n changelog: string | null;\n changelogUrl: string | null;\n repositoryUrl: string;\n updateState: MetaResponse[\"update_state\"] | null | undefined;\n updating: boolean;\n onClose: () => void;\n onUpdate: () => void;\n}\n\nfunction ChangelogModal({\n currentVersion,\n latestVersion,\n changelog,\n changelogUrl,\n repositoryUrl,\n updateState,\n updating,\n onClose,\n onUpdate,\n}: ChangelogModalProps): JSX.Element {\n const [countdown, setCountdown] = useState<number | null>(null);\n const updateDisabled = updating || Boolean(updateState?.in_progress);\n const completedLabel = updateState?.completed_at\n ? new Date(updateState.completed_at).toLocaleString()\n : null;\n\n // Start countdown when update completes successfully\n useEffect(() => {\n if (updateState?.last_result === \"success\" && updateState?.completed_at) {\n let countdown = 10;\n setCountdown(countdown);\n const timer = setInterval(() => {\n countdown -= 1;\n if (countdown <= 0) {\n clearInterval(timer);\n window.location.reload();\n } else {\n setCountdown(countdown);\n }\n }, 1000);\n return () => clearInterval(timer);\n }\n }, [updateState?.last_result, updateState?.completed_at]);\n\n let statusClass = \"\";\n let statusMessage: string | null = null;\n if (updateState?.in_progress) {\n statusClass = \"text-info\";\n statusMessage = \"⏳ Update in progress...\";\n } else if (updateState?.last_result === \"success\") {\n statusClass = \"text-success\";\n if (countdown !== null) {\n statusMessage = `✓ Update completed! Reloading in ${countdown}s...`;\n } else {\n statusMessage = \"✓ Update completed successfully\";\n if (completedLabel) {\n statusMessage = `${statusMessage} (${completedLabel})`;\n }\n }\n } else if (updateState?.last_result === \"error\") {\n statusClass = \"text-danger\";\n const detail = updateState.last_error ? updateState.last_error.trim() : \"\";\n statusMessage = detail ? `✗ Update failed: ${detail}` : \"✗ Update failed\";\n }\n\n return (\n <div className=\"modal-backdrop\" role=\"presentation\" onClick={onClose}>\n <div\n className=\"modal\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"changelog-title\"\n onClick={(event) => event.stopPropagation()}\n >\n <div className=\"modal-header\">\n <h2 id=\"changelog-title\">\n {updateState?.in_progress ? \"⚙️ Updating...\" : \"🚀 Update Available\"}\n </h2>\n <button className=\"btn ghost\" type=\"button\" onClick={onClose} disabled={updateState?.in_progress}>\n <IconImage src={CloseIcon} />\n Close\n </button>\n </div>\n <div className=\"modal-body changelog-modal__body\">\n <div className=\"changelog-meta\">\n <div className=\"version-comparison\">\n <span className=\"version-item\">\n <strong>Current:</strong>{\" \"}\n <span className=\"version-badge version-current\">{formatVersionLabel(currentVersion)}</span>\n </span>\n <span className=\"version-arrow\">→</span>\n <span className=\"version-item\">\n <strong>Latest:</strong>{\" \"}\n <span className=\"version-badge version-latest\">\n {latestVersion ? formatVersionLabel(latestVersion) : \"Unknown\"}\n </span>\n </span>\n </div>\n {statusMessage ? (\n <div className={`update-status ${statusClass}`}>\n {statusMessage}\n </div>\n ) : null}\n </div>\n <div className=\"changelog-section\">\n <h3>What's New</h3>\n <pre className=\"changelog-body\">\n {changelog?.trim() ? changelog.trim() : \"No changelog provided.\"}\n </pre>\n </div>\n </div>\n <div className=\"modal-footer\">\n <div className=\"changelog-links\">\n {(changelogUrl || repositoryUrl) && (\n <a\n className=\"btn ghost small\"\n href={changelogUrl ?? repositoryUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n <IconImage src={ExternalIcon} />\n View on GitHub\n </a>\n )}\n </div>\n <div className=\"changelog-buttons\">\n <button\n className=\"btn primary\"\n type=\"button\"\n onClick={onUpdate}\n disabled={updateDisabled}\n >\n <IconImage src={UpdateIcon} />\n {updateDisabled ? \"Updating...\" : \"Update Now\"}\n </button>\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nfunction AppShell(): JSX.Element {\n const [activeTab, setActiveTab] = useState<Tab>(\"processes\");\n const [configDirty, setConfigDirty] = useState(false);\n const { push } = useToast();\n const { setValue: setSearchValue } = useSearch();\n const { viewDensity, setViewDensity } = useWebUI();\n const isOnline = useNetworkStatus();\n const [meta, setMeta] = useState<MetaResponse | null>(null);\n const [metaLoading, setMetaLoading] = useState(false);\n const [showChangelog, setShowChangelog] = useState(false);\n const [updateBusy, setUpdateBusy] = useState(false);\n const [backendRestarting, setBackendRestarting] = useState(false);\n const restartPollCount = useRef(0);\n const prevUpdateResult = useRef<string | null>(null);\n const backendReadyRef = useRef(false);\n const backendWarnedRef = useRef(false);\n const backendTimerRef = useRef<number | null>(null);\n const [reloadKey, setReloadKey] = useState(0);\n const [statusData, setStatusData] = useState<StatusResponse | null>(null);\n const [showWelcomeChangelog, setShowWelcomeChangelog] = useState(false);\n\n // Theme is now managed by WebUIContext and applied automatically\n\n // Clear cache on every page load to ensure fresh content\n useEffect(() => {\n const clearCache = async () => {\n if ('caches' in window) {\n try {\n const cacheNames = await caches.keys();\n await Promise.all(\n cacheNames.map(cacheName => caches.delete(cacheName))\n );\n console.log('Cache cleared on page load');\n } catch (error) {\n console.error('Failed to clear cache:', error);\n }\n }\n };\n clearCache();\n }, []);\n\n const refreshMeta = useCallback(\n async (options?: { force?: boolean; silent?: boolean }) => {\n const force = options?.force ?? false;\n const silent = options?.silent ?? !force;\n if (!silent) {\n setMetaLoading(true);\n }\n try {\n const data = await getMeta({ force });\n setMeta(data);\n } catch (error) {\n if (!silent) {\n const message =\n error instanceof Error ? error.message : \"Failed to fetch version information\";\n push(message, \"error\");\n }\n } finally {\n if (!silent) {\n setMetaLoading(false);\n }\n }\n },\n [push]\n );\n\n useEffect(() => {\n void refreshMeta({ force: true });\n }, [refreshMeta]);\n\n // Check for new version on first launch - show welcome popup with changelog\n useEffect(() => {\n if (!meta?.current_version) {\n return;\n }\n\n const lastSeenVersion = localStorage.getItem(\"lastSeenVersion\");\n const currentVersion = meta.current_version;\n\n // Show welcome popup if this is a new version (but not on very first install)\n if (lastSeenVersion && lastSeenVersion !== currentVersion) {\n // Ensure we have changelog data before showing popup\n if (!meta.current_version_changelog && !meta.changelog) {\n void refreshMeta({ force: true, silent: true });\n }\n setShowWelcomeChangelog(true);\n }\n\n // Store current version as last seen when user opens the app (first install)\n if (!lastSeenVersion) {\n localStorage.setItem(\"lastSeenVersion\", currentVersion);\n }\n }, [meta?.current_version, meta?.changelog, refreshMeta]);\n\n // Network status notifications\n useEffect(() => {\n if (!isOnline) {\n push(\"You are offline. Some features may not work.\", \"warning\");\n }\n }, [isOnline, push]);\n\n // Keyboard shortcuts\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n // Don't trigger shortcuts when typing in inputs\n if (event.target instanceof HTMLInputElement ||\n event.target instanceof HTMLTextAreaElement ||\n event.target instanceof HTMLSelectElement) {\n return;\n }\n\n const isMod = event.ctrlKey || event.metaKey;\n\n // Ctrl/Cmd + K - Focus search\n if (isMod && event.key === 'k') {\n event.preventDefault();\n const searchInput = document.querySelector('input[type=\"text\"][placeholder*=\"Search\"]') as HTMLInputElement;\n searchInput?.focus();\n return;\n }\n\n // R - Refresh current view\n if (event.key === 'r' || event.key === 'R') {\n event.preventDefault();\n setReloadKey(prev => prev + 1);\n push('Refreshed', 'success');\n return;\n }\n\n // ESC - Clear search\n if (event.key === 'Escape') {\n setSearchValue('');\n return;\n }\n\n // Number keys 1-6 for tab switching\n if (event.key >= '1' && event.key <= '6' && !isMod) {\n event.preventDefault();\n const tabIndex = parseInt(event.key) - 1;\n const tabIds: Tab[] = ['processes', 'logs', 'radarr', 'sonarr', 'lidarr', 'config'];\n if (tabIndex < tabIds.length) {\n setActiveTab(tabIds[tabIndex]);\n }\n return;\n }\n };\n\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, [setSearchValue, push]);\n\n useEffect(() => {\n const id = window.setInterval(() => {\n void refreshMeta();\n }, 5 * 60 * 1000);\n return () => window.clearInterval(id);\n }, [refreshMeta]);\n\n useEffect(() => {\n const handleVisibilityChange = () => {\n if (document.visibilityState === \"visible\") {\n // Force reload all data by incrementing the reload key\n setReloadKey((prev) => prev + 1);\n void refreshMeta({ force: true });\n void refreshStatus();\n }\n };\n\n document.addEventListener(\"visibilitychange\", handleVisibilityChange);\n return () => {\n document.removeEventListener(\"visibilitychange\", handleVisibilityChange);\n };\n }, [refreshMeta]);\n\n const refreshStatus = useCallback(async () => {\n try {\n const status = await getStatus();\n setStatusData(status);\n } catch {\n // Silently fail - status is not critical\n }\n }, []);\n\n useEffect(() => {\n void refreshStatus();\n const id = window.setInterval(() => {\n void refreshStatus();\n }, 5 * 1000); // Refresh every 5 seconds for more dynamic tab loading\n return () => window.clearInterval(id);\n }, [refreshStatus]);\n\n useEffect(() => {\n if (!meta?.update_state?.in_progress && !backendRestarting) {\n restartPollCount.current = 0;\n return;\n }\n const id = window.setInterval(async () => {\n try {\n const data = await getMeta({ force: true });\n setMeta(data);\n if (backendRestarting) {\n // Backend came back after restart\n window.location.reload();\n }\n restartPollCount.current = 0;\n } catch {\n restartPollCount.current += 1;\n if (restartPollCount.current > 20) { // 60 seconds\n setBackendRestarting(false);\n restartPollCount.current = 0;\n push(\"Update completed but backend restart timed out. Please refresh the page manually.\", \"warning\");\n return;\n }\n if (meta?.update_state?.in_progress) {\n // Failed while update in progress, likely restarting\n setBackendRestarting(true);\n }\n }\n }, 3000);\n return () => window.clearInterval(id);\n }, [meta?.update_state?.in_progress, backendRestarting, meta, push]);\n\n useEffect(() => {\n const state = meta?.update_state;\n if (!state) {\n prevUpdateResult.current = null;\n return;\n }\n const result = state.last_result ?? null;\n if (result && result !== prevUpdateResult.current) {\n if (result === \"success\") {\n push(\"Update completed successfully. Restarting...\", \"success\");\n setBackendRestarting(true);\n restartPollCount.current = 0;\n } else if (result === \"error\") {\n push(state.last_error || \"Update failed.\", \"error\");\n }\n }\n prevUpdateResult.current = result;\n }, [meta?.update_state, push]);\n\n useEffect(() => {\n let cancelled = false;\n let attempts = 0;\n\n const schedule = (delay: number) => {\n if (backendTimerRef.current !== null) {\n window.clearTimeout(backendTimerRef.current);\n }\n backendTimerRef.current = window.setTimeout(() => {\n void poll();\n }, delay);\n };\n\n const poll = async () => {\n if (cancelled || backendReadyRef.current) {\n return;\n }\n attempts += 1;\n try {\n const status = await getStatus();\n if (cancelled) {\n return;\n }\n setStatusData(status);\n const readyHint =\n status.ready ?? (Array.isArray(status.arrs) && status.arrs.length > 0);\n if (readyHint) {\n backendReadyRef.current = true;\n return;\n }\n if (status.ready === false && attempts >= 3 && !backendWarnedRef.current) {\n backendWarnedRef.current = true;\n push(\n \"qBitrr backend is still initialising. Check the logs if this persists.\",\n \"warning\"\n );\n }\n } catch (error) {\n if (!backendWarnedRef.current && attempts >= 3) {\n backendWarnedRef.current = true;\n const detail = error instanceof Error ? error.message : \"Unknown backend error\";\n push(\n `Unable to confirm qBitrr readiness (${detail}). Please inspect the logs.`,\n \"warning\"\n );\n }\n } finally {\n if (!cancelled && !backendReadyRef.current) {\n const delay = attempts < 3 ? 3000 : 10000;\n schedule(delay);\n }\n }\n };\n\n schedule(0);\n\n return () => {\n cancelled = true;\n if (backendTimerRef.current !== null) {\n window.clearTimeout(backendTimerRef.current);\n backendTimerRef.current = null;\n }\n };\n }, [push]);\n\n const tabs = useMemo<NavTab[]>(() => {\n const baseTabs: NavTab[] = [\n { id: \"processes\", label: \"Processes\", icon: ProcessesIcon },\n { id: \"logs\", label: \"Logs\", icon: LogsIcon },\n ];\n\n const arrTabs: NavTab[] = [];\n const arrs = statusData?.arrs ?? [];\n\n const hasRadarr = arrs.some((arr) => arr.type === \"radarr\");\n const hasSonarr = arrs.some((arr) => arr.type === \"sonarr\");\n const hasLidarr = arrs.some((arr) => arr.type === \"lidarr\");\n\n if (hasRadarr) {\n arrTabs.push({ id: \"radarr\", label: \"Radarr\", icon: RadarrIcon });\n }\n if (hasSonarr) {\n arrTabs.push({ id: \"sonarr\", label: \"Sonarr\", icon: SonarrIcon });\n }\n if (hasLidarr) {\n arrTabs.push({ id: \"lidarr\", label: \"Lidarr\", icon: LidarrIcon });\n }\n\n return [\n ...baseTabs,\n ...arrTabs,\n { id: \"config\", label: \"Config\", icon: ConfigIcon },\n ];\n }, [statusData]);\n\n const repositoryUrl = meta?.repository_url ?? \"https://github.com/Feramance/qBitrr\";\n const displayVersion = meta?.current_version\n ? formatVersionLabel(meta.current_version)\n : \"...\";\n const latestVersion = meta?.latest_version ?? null;\n const updateAvailable = Boolean(meta?.update_available);\n const updateState = meta?.update_state;\n const changelogUrl = meta?.changelog_url ?? repositoryUrl;\n\n const versionTitleParts: string[] = [];\n if (meta?.last_checked) {\n versionTitleParts.push(`Last checked ${new Date(meta.last_checked).toLocaleString()}`);\n }\n if (meta?.error) {\n versionTitleParts.push(`Update check failed: ${meta.error}`);\n }\n const versionTitle = versionTitleParts.length ? versionTitleParts.join(\" • \") : undefined;\n\n // Redirect to processes if active tab is no longer available\n useEffect(() => {\n const tabExists = tabs.some((tab) => tab.id === activeTab);\n if (!tabExists && tabs.length > 0) {\n setActiveTab(\"processes\");\n }\n }, [tabs, activeTab]);\n\n const handleCheckUpdates = useCallback(() => {\n void refreshMeta({ force: true });\n }, [refreshMeta]);\n\n const handleOpenChangelog = useCallback(() => {\n setShowChangelog(true);\n if (!meta?.changelog) {\n void refreshMeta({ force: true, silent: true });\n }\n }, [meta?.changelog, refreshMeta]);\n\n const handleCloseChangelog = useCallback(() => {\n setShowChangelog(false);\n }, []);\n\n const handleCloseWelcomeChangelog = useCallback(() => {\n setShowWelcomeChangelog(false);\n // Mark this version as seen\n if (meta?.current_version) {\n localStorage.setItem(\"lastSeenVersion\", meta.current_version);\n }\n }, [meta?.current_version]);\n\n const handleTriggerUpdate = useCallback(async () => {\n setUpdateBusy(true);\n setBackendRestarting(false);\n restartPollCount.current = 0;\n try {\n await triggerUpdate();\n push(\"Update started in the background.\", \"info\");\n await refreshMeta({ force: true, silent: true });\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Failed to start update\";\n push(message, \"error\");\n } finally {\n setUpdateBusy(false);\n }\n }, [push, refreshMeta]);\n\n return (\n <div data-density={viewDensity}>\n <header className=\"appbar\">\n <div className=\"appbar__inner\">\n <div className=\"appbar__title\">\n <h1>qBitrr</h1>\n <span className=\"appbar__version\" title={versionTitle}>\n {displayVersion}\n </span>\n {metaLoading ? <span className=\"spinner\" aria-hidden=\"true\" /> : null}\n {updateState?.in_progress ? (\n <span className=\"appbar__status text-info\">Updating...</span>\n ) : null}\n {updateAvailable ? (\n <button\n type=\"button\"\n className=\"btn small primary appbar__update\"\n onClick={handleOpenChangelog}\n disabled={updateBusy || Boolean(updateState?.in_progress)}\n >\n <span className=\"appbar__update-indicator\" aria-hidden=\"true\" />\n <IconImage src={UpdateIcon} />\n Update available\n </button>\n ) : null}\n </div>\n <div className=\"appbar__actions\">\n {!isOnline && (\n <span className=\"badge\" style={{ background: 'rgba(239, 68, 68, 0.15)', borderColor: 'rgba(239, 68, 68, 0.3)', color: 'var(--danger)' }}>\n Offline\n </span>\n )}\n <div className=\"view-density-toggle\">\n <button\n type=\"button\"\n className={viewDensity === \"comfortable\" ? \"active\" : \"\"}\n onClick={() => setViewDensity(\"comfortable\")}\n title=\"Comfortable view\"\n >\n Comfortable\n </button>\n <button\n type=\"button\"\n className={viewDensity === \"compact\" ? \"active\" : \"\"}\n onClick={() => setViewDensity(\"compact\")}\n title=\"Compact view\"\n >\n Compact\n </button>\n </div>\n <button\n type=\"button\"\n className=\"btn small ghost\"\n onClick={handleCheckUpdates}\n disabled={metaLoading}\n >\n <IconImage src={RefreshIcon} />\n {metaLoading ? \"Checking...\" : \"Check Updates\"}\n </button>\n <a\n href={repositoryUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"btn small ghost\"\n >\n <IconImage src={ExternalIcon} />\n GitHub\n </a>\n </div>\n </div>\n </header>\n <main className=\"container\">\n <nav className=\"nav\">\n {tabs.map((tab) => (\n <button\n type=\"button\"\n key={tab.id}\n className={activeTab === tab.id ? \"active\" : \"\"}\n onClick={() => {\n if (activeTab === \"config\" && tab.id !== \"config\" && configDirty) {\n const shouldLeave = window.confirm(\n \"You have unsaved configuration changes. Leave without saving?\"\n );\n if (!shouldLeave) {\n return;\n }\n }\n setActiveTab(tab.id);\n setSearchValue(\"\");\n }}\n >\n <IconImage src={tab.icon} />\n <span>{tab.label}</span>\n </button>\n ))}\n </nav>\n <Suspense fallback={<div className=\"loading\">Loading...</div>}>\n {activeTab === \"processes\" && <ProcessesView key={`processes-${reloadKey}`} active />}\n {activeTab === \"logs\" && <LogsView key={`logs-${reloadKey}`} active />}\n {activeTab === \"radarr\" && <ArrView key={`radarr-${reloadKey}`} type=\"radarr\" active />}\n {activeTab === \"sonarr\" && <ArrView key={`sonarr-${reloadKey}`} type=\"sonarr\" active />}\n {activeTab === \"lidarr\" && <ArrView key={`lidarr-${reloadKey}`} type=\"lidarr\" active />}\n {activeTab === \"config\" && <ConfigView key={`config-${reloadKey}`} onDirtyChange={setConfigDirty} />}\n </Suspense>\n </main>\n {showChangelog && meta ? (\n <ChangelogModal\n currentVersion={meta.current_version}\n latestVersion={latestVersion}\n changelog={meta.changelog}\n changelogUrl={changelogUrl}\n repositoryUrl={repositoryUrl}\n updateState={updateState}\n updating={updateBusy}\n onClose={handleCloseChangelog}\n onUpdate={handleTriggerUpdate}\n />\n ) : null}\n {showWelcomeChangelog && meta ? (\n <WelcomeModal\n currentVersion={meta.current_version}\n changelog={meta.current_version_changelog || meta.changelog}\n changelogUrl={changelogUrl}\n repositoryUrl={repositoryUrl}\n onClose={handleCloseWelcomeChangelog}\n />\n ) : null}\n </div>\n );\n}\n\nexport default function App(): JSX.Element {\n return (\n <ToastProvider>\n <SearchProvider>\n <WebUIProvider>\n <AppShell />\n <ToastViewport />\n </WebUIProvider>\n </SearchProvider>\n </ToastProvider>\n );\n}\n","import { StrictMode } from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport \"./styles.css\";\nimport App from \"./App\";\n\ncreateRoot(document.getElementById(\"root\")!).render(\n <StrictMode>\n <App />\n </StrictMode>\n);\n"],"file":"app.js"}
@@ -1,33 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <link rel="icon" type="image/svg+xml" href="/static/vite.svg" />
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <meta name="description" content="A Radarr and Sonarr companion app for managing torrents" />
8
- <meta name="theme-color" content="#7aa2f7" />
9
- <link rel="manifest" href="/static/manifest.json" />
10
- <title>qBitrr</title>
11
- <script type="module" crossorigin src="/static/assets/app.js"></script>
12
- <link rel="modulepreload" crossorigin href="/static/assets/vendor.js">
13
- <link rel="modulepreload" crossorigin href="/static/assets/table.js">
14
- <link rel="stylesheet" crossorigin href="/static/assets/app.css">
15
- </head>
16
- <body>
17
- <div id="root"></div>
18
- <script>
19
- // Register service worker for PWA support
20
- if ('serviceWorker' in navigator) {
21
- window.addEventListener('load', () => {
22
- navigator.serviceWorker.register('/sw.js')
23
- .then((registration) => {
24
- console.log('ServiceWorker registered:', registration);
25
- })
26
- .catch((error) => {
27
- console.log('ServiceWorker registration failed:', error);
28
- });
29
- });
30
- }
31
- </script>
32
- </body>
33
- </html>
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes