diff --git a/client/src/App.css b/client/src/App.css index 1831a5c..084372a 100644 --- a/client/src/App.css +++ b/client/src/App.css @@ -459,3 +459,41 @@ body { .trigger-value.inactive { color: #999; } + +.webhook-stats { + margin-top: 15px; + padding-top: 15px; + border-top: 1px solid #e0e0e0; +} + +.webhook-stats-title { + color: #999; + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.6px; + margin-bottom: 10px; +} + +.webhook-stats-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); + gap: 10px; +} + +.webhook-stat { + display: flex; + flex-direction: column; + gap: 3px; +} + +.webhook-stat-label { + color: #999; + font-size: 0.8rem; +} + +.webhook-stat-value { + color: #333; + font-size: 0.95rem; + font-weight: 500; +} diff --git a/client/src/App.jsx b/client/src/App.jsx index aeef72d..6b27a6d 100644 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -11,8 +11,9 @@ function App() { const [error, setError] = useState(null); const [sessions, setSessions] = useState([]); const [webhookSectionExpanded, setWebhookSectionExpanded] = useState(false); - const [sonarrWebhook, setSonarrWebhook] = useState({ enabled: false, triggers: { onGrab: false, onDownload: false, onImport: false, onUpgrade: false } }); - const [radarrWebhook, setRadarrWebhook] = useState({ enabled: false, triggers: { onGrab: false, onDownload: false, onImport: false, onUpgrade: false } }); + const [sonarrWebhook, setSonarrWebhook] = useState({ enabled: false, triggers: { onGrab: false, onDownload: false, onImport: false, onUpgrade: false }, stats: null }); + const [radarrWebhook, setRadarrWebhook] = useState({ enabled: false, triggers: { onGrab: false, onDownload: false, onImport: false, onUpgrade: false }, stats: null }); + const [webhookMetrics, setWebhookMetrics] = useState(null); const [webhookLoading, setWebhookLoading] = useState(false); useEffect(() => { @@ -72,43 +73,82 @@ function App() { return new Date(dateString).toLocaleString(); }; + const formatTimeAgo = (timestamp) => { + if (!timestamp) return 'Never'; + const seconds = Math.floor((Date.now() - timestamp) / 1000); + if (seconds < 60) return `${seconds}s ago`; + const minutes = Math.floor(seconds / 60); + if (minutes < 60) return `${minutes}m ago`; + const hours = Math.floor(minutes / 60); + if (hours < 24) return `${hours}h ago`; + return `${Math.floor(hours / 24)}d ago`; + }; + + const fetchWebhookMetrics = async () => { + try { + const response = await axios.get('/api/dashboard/webhook-metrics'); + setWebhookMetrics(response.data); + return response.data; + } catch (err) { + // Not fatal — stats just won't display + return null; + } + }; + const fetchWebhookStatus = async () => { try { + // Fetch metrics in parallel with notification status + const metricsPromise = fetchWebhookMetrics(); + // Fetch Sonarr notifications + let sonarrEnabled = false; + let sonarrTriggers = { onGrab: false, onDownload: false, onImport: false, onUpgrade: false }; try { const sonarrResponse = await axios.get('/api/sonarr/notifications'); const sonarrSofarr = sonarrResponse.data.find(n => n.name === 'Sofarr'); - setSonarrWebhook({ - enabled: !!sonarrSofarr, - triggers: sonarrSofarr ? { + sonarrEnabled = !!sonarrSofarr; + if (sonarrSofarr) { + sonarrTriggers = { onGrab: sonarrSofarr.onGrab, onDownload: sonarrSofarr.onDownload, onImport: sonarrSofarr.onImport, onUpgrade: sonarrSofarr.onUpgrade - } : { onGrab: false, onDownload: false, onImport: false, onUpgrade: false } - }); + }; + } } catch (err) { // Sonarr not configured or not accessible - setSonarrWebhook({ enabled: false, triggers: { onGrab: false, onDownload: false, onImport: false, onUpgrade: false } }); } // Fetch Radarr notifications + let radarrEnabled = false; + let radarrTriggers = { onGrab: false, onDownload: false, onImport: false, onUpgrade: false }; try { const radarrResponse = await axios.get('/api/radarr/notifications'); const radarrSofarr = radarrResponse.data.find(n => n.name === 'Sofarr'); - setRadarrWebhook({ - enabled: !!radarrSofarr, - triggers: radarrSofarr ? { + radarrEnabled = !!radarrSofarr; + if (radarrSofarr) { + radarrTriggers = { onGrab: radarrSofarr.onGrab, onDownload: radarrSofarr.onDownload, onImport: radarrSofarr.onImport, onUpgrade: radarrSofarr.onUpgrade - } : { onGrab: false, onDownload: false, onImport: false, onUpgrade: false } - }); + }; + } } catch (err) { // Radarr not configured or not accessible - setRadarrWebhook({ enabled: false, triggers: { onGrab: false, onDownload: false, onImport: false, onUpgrade: false } }); } + + const metrics = await metricsPromise; + + // Attach per-instance stats from global metrics. + // The instances object is keyed by instance URL; we pick the first + // sonarr/radarr entry by matching env-configured URLs. + const instanceEntries = metrics ? Object.entries(metrics.instances || {}) : []; + const sonarrStats = instanceEntries.find(([url]) => url.includes('sonarr'))?.[1] || null; + const radarrStats = instanceEntries.find(([url]) => url.includes('radarr'))?.[1] || null; + + setSonarrWebhook({ enabled: sonarrEnabled, triggers: sonarrTriggers, stats: sonarrStats }); + setRadarrWebhook({ enabled: radarrEnabled, triggers: radarrTriggers, stats: radarrStats }); } catch (err) { console.error('Failed to fetch webhook status:', err); } @@ -147,6 +187,7 @@ function App() { const sonarrSofarr = sonarrResponse.data.find(n => n.name === 'Sofarr'); if (sonarrSofarr) { await axios.post('/api/sonarr/notifications/test', { id: sonarrSofarr.id }); + await fetchWebhookStatus(); alert('Sonarr webhook test sent successfully!'); } else { alert('Sofarr webhook not configured for Sonarr.'); @@ -166,6 +207,7 @@ function App() { const radarrSofarr = radarrResponse.data.find(n => n.name === 'Sofarr'); if (radarrSofarr) { await axios.post('/api/radarr/notifications/test', { id: radarrSofarr.id }); + await fetchWebhookStatus(); alert('Radarr webhook test sent successfully!'); } else { alert('Sofarr webhook not configured for Radarr.'); @@ -342,6 +384,25 @@ function App() { )} + {sonarrWebhook.stats && ( +
Failed to load status.
'; - } - } -} - -function renderStatusPanel(data, panel) { - const s = data.server; - const hrs = Math.floor(s.uptimeSeconds / 3600); - const mins = Math.floor((s.uptimeSeconds % 3600) / 60); - const secs = s.uptimeSeconds % 60; - const uptime = `${hrs}h ${mins}m ${secs}s`; - - const totalKB = (data.cache.totalSizeBytes / 1024).toFixed(1); - - let html = ` -| Key | Items | Size | TTL |
|---|---|---|---|
${escapeHtml(e.key)} | ${items} | ${sizeStr} | ${ttlStr} |
o(se,x))Ceo(de,se)?(g[I]=de,g[Ce]=x,I=Ce):(g[I]=se,g[te]=x,I=te);else if(Ce o(de,x))g[I]=de,g[Ce]=x,I=Ce;else break e}}return C}function o(g,C){var x=g.sortIndex-C.sortIndex;return x!==0?x:g.id-C.id}if(typeof performance=="object"&&typeof performance.now=="function"){var l=performance;e.unstable_now=function(){return l.now()}}else{var i=Date,s=i.now();e.unstable_now=function(){return i.now()-s}}var u=[],a=[],d=1,m=null,y=3,E=!1,S=!1,v=!1,k=typeof setTimeout=="function"?setTimeout:null,c=typeof clearTimeout=="function"?clearTimeout:null,f=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function p(g){for(var C=n(a);C!==null;){if(C.callback===null)r(a);else if(C.startTime<=g)r(a),C.sortIndex=C.expirationTime,t(u,C);else break;C=n(a)}}function w(g){if(v=!1,p(g),!S)if(n(u)!==null)S=!0,Ge(_);else{var C=n(a);C!==null&&$t(w,C.startTime-g)}}function _(g,C){S=!1,v&&(v=!1,c(L),L=-1),E=!0;var x=y;try{for(p(C),m=n(u);m!==null&&(!(m.expirationTime>C)||g&&!J());){var I=m.callback;if(typeof I=="function"){m.callback=null,y=m.priorityLevel;var W=I(m.expirationTime<=C);C=e.unstable_now(),typeof W=="function"?m.callback=W:m===n(u)&&r(u),p(C)}else r(u);m=n(u)}if(m!==null)var Q=!0;else{var te=n(a);te!==null&&$t(w,te.startTime-C),Q=!1}return Q}finally{m=null,y=x,E=!1}}var O=!1,P=null,L=-1,B=5,z=-1;function J(){return!(e.unstable_now()-zg||125 I?(g.sortIndex=x,t(a,g),n(u)===null&&g===n(a)&&(v?(c(L),L=-1):v=!0,$t(w,x-I))):(g.sortIndex=W,t(u,g),S||E||(S=!0,Ge(_))),g},e.unstable_shouldYield=J,e.unstable_wrapCallback=function(g){var C=y;return function(){var x=y;y=C;try{return g.apply(this,arguments)}finally{y=x}}}})(Na);ka.exports=Na;var pd=ka.exports;/** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var hd=we,Ie=pd;function N(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n "u"||typeof window.document>"u"||typeof window.document.createElement>"u"),jl=Object.prototype.hasOwnProperty,md=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,Vs={},Ws={};function yd(e){return jl.call(Ws,e)?!0:jl.call(Vs,e)?!1:md.test(e)?Ws[e]=!0:(Vs[e]=!0,!1)}function gd(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function vd(e,t,n,r){if(t===null||typeof t>"u"||gd(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function Ne(e,t,n,r,o,l,i){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=o,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=l,this.removeEmptyString=i}var ce={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){ce[e]=new Ne(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];ce[t]=new Ne(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){ce[e]=new Ne(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){ce[e]=new Ne(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){ce[e]=new Ne(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){ce[e]=new Ne(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){ce[e]=new Ne(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){ce[e]=new Ne(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){ce[e]=new Ne(e,5,!1,e.toLowerCase(),null,!1,!1)});var Bi=/[\-:]([a-z])/g;function $i(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(Bi,$i);ce[t]=new Ne(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(Bi,$i);ce[t]=new Ne(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(Bi,$i);ce[t]=new Ne(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){ce[e]=new Ne(e,1,!1,e.toLowerCase(),null,!1,!1)});ce.xlinkHref=new Ne("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){ce[e]=new Ne(e,1,!1,e.toLowerCase(),null,!0,!0)});function Hi(e,t,n,r){var o=ce.hasOwnProperty(t)?ce[t]:null;(o!==null?o.type!==0:r||!(2 s||o[i]!==l[s]){var u=` +`+o[i].replace(" at new "," at ");return e.displayName&&u.includes(" ")&&(u=u.replace(" ",e.displayName)),u}while(1<=i&&0<=s);break}}}finally{cl=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?qn(e):""}function wd(e){switch(e.tag){case 5:return qn(e.type);case 16:return qn("Lazy");case 13:return qn("Suspense");case 19:return qn("SuspenseList");case 0:case 2:case 15:return e=fl(e.type,!1),e;case 11:return e=fl(e.type.render,!1),e;case 1:return e=fl(e.type,!0),e;default:return""}}function Vl(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case un:return"Fragment";case sn:return"Portal";case Bl:return"Profiler";case Vi:return"StrictMode";case $l:return"Suspense";case Hl:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case Ra:return(e.displayName||"Context")+".Consumer";case Ca:return(e._context.displayName||"Context")+".Provider";case Wi:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case Qi:return t=e.displayName||null,t!==null?t:Vl(e.type)||"Memo";case Et:t=e._payload,e=e._init;try{return Vl(e(t))}catch{}}return null}function Sd(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return Vl(t);case 8:return t===Vi?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function Ft(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function Oa(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function Ed(e){var t=Oa(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var o=n.get,l=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return o.call(this)},set:function(i){r=""+i,l.call(this,i)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(i){r=""+i},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function zr(e){e._valueTracker||(e._valueTracker=Ed(e))}function Pa(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=Oa(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function po(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function Wl(e,t){var n=t.checked;return X({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function Ks(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=Ft(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function Ta(e,t){t=t.checked,t!=null&&Hi(e,"checked",t,!1)}function Ql(e,t){Ta(e,t);var n=Ft(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?Kl(e,t.type,n):t.hasOwnProperty("defaultValue")&&Kl(e,t.type,Ft(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function qs(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function Kl(e,t,n){(t!=="number"||po(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var Gn=Array.isArray;function wn(e,t,n,r){if(e=e.options,t){t={};for(var o=0;o "+t.valueOf().toString()+"",t=Fr.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function sr(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var Yn={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},kd=["Webkit","ms","Moz","O"];Object.keys(Yn).forEach(function(e){kd.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),Yn[t]=Yn[e]})});function za(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||Yn.hasOwnProperty(e)&&Yn[e]?(""+t).trim():t+"px"}function Fa(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,o=za(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,o):e[n]=o}}var Nd=X({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function Xl(e,t){if(t){if(Nd[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(N(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(N(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(N(61))}if(t.style!=null&&typeof t.style!="object")throw Error(N(62))}}function Jl(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var Yl=null;function Ki(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var Zl=null,Sn=null,En=null;function Js(e){if(e=Rr(e)){if(typeof Zl!="function")throw Error(N(280));var t=e.stateNode;t&&(t=Wo(t),Zl(e.stateNode,e.type,t))}}function Ia(e){Sn?En?En.push(e):En=[e]:Sn=e}function Ua(){if(Sn){var e=Sn,t=En;if(En=Sn=null,Js(e),t)for(e=0;e >>=0,e===0?32:31-(zd(e)/Fd|0)|0}var Ir=64,Ur=4194304;function Xn(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function go(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,o=e.suspendedLanes,l=e.pingedLanes,i=n&268435455;if(i!==0){var s=i&~o;s!==0?r=Xn(s):(l&=i,l!==0&&(r=Xn(l)))}else i=n&~o,i!==0?r=Xn(i):l!==0&&(r=Xn(l));if(r===0)return 0;if(t!==0&&t!==r&&!(t&o)&&(o=r&-r,l=t&-t,o>=l||o===16&&(l&4194240)!==0))return t;if(r&4&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0 n;n++)t.push(e);return t}function _r(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-et(t),e[t]=n}function jd(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0 =bn),lu=String.fromCharCode(32),iu=!1;function rc(e,t){switch(e){case"keyup":return pp.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function oc(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var an=!1;function mp(e,t){switch(e){case"compositionend":return oc(t);case"keypress":return t.which!==32?null:(iu=!0,lu);case"textInput":return e=t.data,e===lu&&iu?null:e;default:return null}}function yp(e,t){if(an)return e==="compositionend"||!es&&rc(e,t)?(e=tc(),br=Yi=Ct=null,an=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1 =t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=cu(n)}}function uc(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?uc(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function ac(){for(var e=window,t=po();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=po(e.document)}return t}function ts(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function Cp(e){var t=ac(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&uc(n.ownerDocument.documentElement,n)){if(r!==null&&ts(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var o=n.textContent.length,l=Math.min(r.start,o);r=r.end===void 0?l:Math.min(r.end,o),!e.extend&&l>r&&(o=r,r=l,l=o),o=fu(n,l);var i=fu(n,r);o&&i&&(e.rangeCount!==1||e.anchorNode!==o.node||e.anchorOffset!==o.offset||e.focusNode!==i.node||e.focusOffset!==i.offset)&&(t=t.createRange(),t.setStart(o.node,o.offset),e.removeAllRanges(),l>r?(e.addRange(t),e.extend(i.node,i.offset)):(t.setEnd(i.node,i.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n =document.documentMode,cn=null,oi=null,tr=null,li=!1;function du(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;li||cn==null||cn!==po(r)||(r=cn,"selectionStart"in r&&ts(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),tr&&pr(tr,r)||(tr=r,r=So(oi,"onSelect"),0 pn||(e.current=fi[pn],fi[pn]=null,pn--)}function $(e,t){pn++,fi[pn]=e.current,e.current=t}var It={},ge=Mt(It),Pe=Mt(!1),Jt=It;function Rn(e,t){var n=e.type.contextTypes;if(!n)return It;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var o={},l;for(l in n)o[l]=t[l];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=o),o}function Te(e){return e=e.childContextTypes,e!=null}function ko(){V(Pe),V(ge)}function wu(e,t,n){if(ge.current!==It)throw Error(N(168));$(ge,t),$(Pe,n)}function vc(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var o in r)if(!(o in t))throw Error(N(108,Sd(e)||"Unknown",o));return X({},n,r)}function No(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||It,Jt=ge.current,$(ge,e),$(Pe,Pe.current),!0}function Su(e,t,n){var r=e.stateNode;if(!r)throw Error(N(169));n?(e=vc(e,t,Jt),r.__reactInternalMemoizedMergedChildContext=e,V(Pe),V(ge),$(ge,e)):V(Pe),$(Pe,n)}var ct=null,Qo=!1,Cl=!1;function wc(e){ct===null?ct=[e]:ct.push(e)}function Up(e){Qo=!0,wc(e)}function jt(){if(!Cl&&ct!==null){Cl=!0;var e=0,t=M;try{var n=ct;for(M=1;e >=i,o-=i,ft=1<<32-et(t)+o|n< L?(B=P,P=null):B=P.sibling;var z=y(c,P,p[L],w);if(z===null){P===null&&(P=B);break}e&&P&&z.alternate===null&&t(c,P),f=l(z,f,L),O===null?_=z:O.sibling=z,O=z,P=B}if(L===p.length)return n(c,P),K&&Ht(c,L),_;if(P===null){for(;L L?(B=P,P=null):B=P.sibling;var J=y(c,P,z.value,w);if(J===null){P===null&&(P=B);break}e&&P&&J.alternate===null&&t(c,P),f=l(J,f,L),O===null?_=J:O.sibling=J,O=J,P=B}if(z.done)return n(c,P),K&&Ht(c,L),_;if(P===null){for(;!z.done;L++,z=p.next())z=m(c,z.value,w),z!==null&&(f=l(z,f,L),O===null?_=z:O.sibling=z,O=z);return K&&Ht(c,L),_}for(P=r(c,P);!z.done;L++,z=p.next())z=E(P,c,L,z.value,w),z!==null&&(e&&z.alternate!==null&&P.delete(z.key===null?L:z.key),f=l(z,f,L),O===null?_=z:O.sibling=z,O=z);return e&&P.forEach(function(je){return t(c,je)}),K&&Ht(c,L),_}function k(c,f,p,w){if(typeof p=="object"&&p!==null&&p.type===un&&p.key===null&&(p=p.props.children),typeof p=="object"&&p!==null){switch(p.$$typeof){case Ar:e:{for(var _=p.key,O=f;O!==null;){if(O.key===_){if(_=p.type,_===un){if(O.tag===7){n(c,O.sibling),f=o(O,p.props.children),f.return=c,c=f;break e}}else if(O.elementType===_||typeof _=="object"&&_!==null&&_.$$typeof===Et&&Nu(_)===O.type){n(c,O.sibling),f=o(O,p.props),f.ref=Vn(c,O,p),f.return=c,c=f;break e}n(c,O);break}else t(c,O);O=O.sibling}p.type===un?(f=Xt(p.props.children,c.mode,w,p.key),f.return=c,c=f):(w=so(p.type,p.key,p.props,null,c.mode,w),w.ref=Vn(c,f,p),w.return=c,c=w)}return i(c);case sn:e:{for(O=p.key;f!==null;){if(f.key===O)if(f.tag===4&&f.stateNode.containerInfo===p.containerInfo&&f.stateNode.implementation===p.implementation){n(c,f.sibling),f=o(f,p.children||[]),f.return=c,c=f;break e}else{n(c,f);break}else t(c,f);f=f.sibling}f=Al(p,c.mode,w),f.return=c,c=f}return i(c);case Et:return O=p._init,k(c,f,O(p._payload),w)}if(Gn(p))return S(c,f,p,w);if(Mn(p))return v(c,f,p,w);Wr(c,p)}return typeof p=="string"&&p!==""||typeof p=="number"?(p=""+p,f!==null&&f.tag===6?(n(c,f.sibling),f=o(f,p),f.return=c,c=f):(n(c,f),f=Dl(p,c.mode,w),f.return=c,c=f),i(c)):n(c,f)}return k}var On=Nc(!0),_c=Nc(!1),Ro=Mt(null),xo=null,yn=null,ls=null;function is(){ls=yn=xo=null}function ss(e){var t=Ro.current;V(Ro),e._currentValue=t}function hi(e,t,n){for(;e!==null;){var r=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,r!==null&&(r.childLanes|=t)):r!==null&&(r.childLanes&t)!==t&&(r.childLanes|=t),e===n)break;e=e.return}}function Nn(e,t){xo=e,ls=yn=null,e=e.dependencies,e!==null&&e.firstContext!==null&&(e.lanes&t&&(Oe=!0),e.firstContext=null)}function Ke(e){var t=e._currentValue;if(ls!==e)if(e={context:e,memoizedValue:t,next:null},yn===null){if(xo===null)throw Error(N(308));yn=e,xo.dependencies={lanes:0,firstContext:e}}else yn=yn.next=e;return t}var Qt=null;function us(e){Qt===null?Qt=[e]:Qt.push(e)}function Cc(e,t,n,r){var o=t.interleaved;return o===null?(n.next=n,us(t)):(n.next=o.next,o.next=n),t.interleaved=n,yt(e,r)}function yt(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}var kt=!1;function as(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function Rc(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function pt(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function Lt(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,U&2){var o=r.pending;return o===null?t.next=t:(t.next=o.next,o.next=t),r.pending=t,yt(e,n)}return o=r.interleaved,o===null?(t.next=t,us(r)):(t.next=o.next,o.next=t),r.interleaved=t,yt(e,n)}function to(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,(n&4194240)!==0)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,Gi(e,n)}}function _u(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var o=null,l=null;if(n=n.firstBaseUpdate,n!==null){do{var i={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};l===null?o=l=i:l=l.next=i,n=n.next}while(n!==null);l===null?o=l=t:l=l.next=t}else o=l=t;n={baseState:r.baseState,firstBaseUpdate:o,lastBaseUpdate:l,shared:r.shared,effects:r.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function Oo(e,t,n,r){var o=e.updateQueue;kt=!1;var l=o.firstBaseUpdate,i=o.lastBaseUpdate,s=o.shared.pending;if(s!==null){o.shared.pending=null;var u=s,a=u.next;u.next=null,i===null?l=a:i.next=a,i=u;var d=e.alternate;d!==null&&(d=d.updateQueue,s=d.lastBaseUpdate,s!==i&&(s===null?d.firstBaseUpdate=a:s.next=a,d.lastBaseUpdate=u))}if(l!==null){var m=o.baseState;i=0,d=a=u=null,s=l;do{var y=s.lane,E=s.eventTime;if((r&y)===y){d!==null&&(d=d.next={eventTime:E,lane:0,tag:s.tag,payload:s.payload,callback:s.callback,next:null});e:{var S=e,v=s;switch(y=t,E=n,v.tag){case 1:if(S=v.payload,typeof S=="function"){m=S.call(E,m,y);break e}m=S;break e;case 3:S.flags=S.flags&-65537|128;case 0:if(S=v.payload,y=typeof S=="function"?S.call(E,m,y):S,y==null)break e;m=X({},m,y);break e;case 2:kt=!0}}s.callback!==null&&s.lane!==0&&(e.flags|=64,y=o.effects,y===null?o.effects=[s]:y.push(s))}else E={eventTime:E,lane:y,tag:s.tag,payload:s.payload,callback:s.callback,next:null},d===null?(a=d=E,u=m):d=d.next=E,i|=y;if(s=s.next,s===null){if(s=o.shared.pending,s===null)break;y=s,s=y.next,y.next=null,o.lastBaseUpdate=y,o.shared.pending=null}}while(1);if(d===null&&(u=m),o.baseState=u,o.firstBaseUpdate=a,o.lastBaseUpdate=d,t=o.shared.interleaved,t!==null){o=t;do i|=o.lane,o=o.next;while(o!==t)}else l===null&&(o.shared.lanes=0);bt|=i,e.lanes=i,e.memoizedState=m}}function Cu(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;t n?n:4,e(!0);var r=xl.transition;xl.transition={};try{e(!1),t()}finally{M=n,xl.transition=r}}function Vc(){return qe().memoizedState}function $p(e,t,n){var r=At(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},Wc(e))Qc(t,n);else if(n=Cc(e,t,n,r),n!==null){var o=Ee();tt(n,e,r,o),Kc(n,t,r)}}function Hp(e,t,n){var r=At(e),o={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(Wc(e))Qc(t,o);else{var l=e.alternate;if(e.lanes===0&&(l===null||l.lanes===0)&&(l=t.lastRenderedReducer,l!==null))try{var i=t.lastRenderedState,s=l(i,n);if(o.hasEagerState=!0,o.eagerState=s,nt(s,i)){var u=t.interleaved;u===null?(o.next=o,us(t)):(o.next=u.next,u.next=o),t.interleaved=o;return}}catch{}finally{}n=Cc(e,t,o,r),n!==null&&(o=Ee(),tt(n,e,r,o),Kc(n,t,r))}}function Wc(e){var t=e.alternate;return e===G||t!==null&&t===G}function Qc(e,t){nr=To=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Kc(e,t,n){if(n&4194240){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,Gi(e,n)}}var Lo={readContext:Ke,useCallback:pe,useContext:pe,useEffect:pe,useImperativeHandle:pe,useInsertionEffect:pe,useLayoutEffect:pe,useMemo:pe,useReducer:pe,useRef:pe,useState:pe,useDebugValue:pe,useDeferredValue:pe,useTransition:pe,useMutableSource:pe,useSyncExternalStore:pe,useId:pe,unstable_isNewReconciler:!1},Vp={readContext:Ke,useCallback:function(e,t){return lt().memoizedState=[e,t===void 0?null:t],e},useContext:Ke,useEffect:xu,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,ro(4194308,4,Mc.bind(null,t,e),n)},useLayoutEffect:function(e,t){return ro(4194308,4,e,t)},useInsertionEffect:function(e,t){return ro(4,2,e,t)},useMemo:function(e,t){var n=lt();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=lt();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=$p.bind(null,G,e),[r.memoizedState,e]},useRef:function(e){var t=lt();return e={current:e},t.memoizedState=e},useState:Ru,useDebugValue:gs,useDeferredValue:function(e){return lt().memoizedState=e},useTransition:function(){var e=Ru(!1),t=e[0];return e=Bp.bind(null,e[1]),lt().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=G,o=lt();if(K){if(n===void 0)throw Error(N(407));n=n()}else{if(n=t(),ie===null)throw Error(N(349));Zt&30||Tc(r,t,n)}o.memoizedState=n;var l={value:n,getSnapshot:t};return o.queue=l,xu(Dc.bind(null,r,l,e),[e]),r.flags|=2048,Er(9,Lc.bind(null,r,l,n,t),void 0,null),n},useId:function(){var e=lt(),t=ie.identifierPrefix;if(K){var n=dt,r=ft;n=(r&~(1<<32-et(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=wr++,0 <\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=i.createElement(n,{is:r.is}):(e=i.createElement(n),n==="select"&&(i=e,r.multiple?i.multiple=!0:r.size&&(i.size=r.size))):e=i.createElementNS(e,n),e[it]=t,e[yr]=r,nf(e,t,!1,!1),t.stateNode=e;e:{switch(i=Jl(n,r),n){case"dialog":H("cancel",e),H("close",e),o=r;break;case"iframe":case"object":case"embed":H("load",e),o=r;break;case"video":case"audio":for(o=0;o Ln&&(t.flags|=128,r=!0,Wn(l,!1),t.lanes=4194304)}else{if(!r)if(e=Po(i),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),Wn(l,!0),l.tail===null&&l.tailMode==="hidden"&&!i.alternate&&!K)return he(t),null}else 2*Z()-l.renderingStartTime>Ln&&n!==1073741824&&(t.flags|=128,r=!0,Wn(l,!1),t.lanes=4194304);l.isBackwards?(i.sibling=t.child,t.child=i):(n=l.last,n!==null?n.sibling=i:t.child=i,l.last=i)}return l.tail!==null?(t=l.tail,l.rendering=t,l.tail=t.sibling,l.renderingStartTime=Z(),t.sibling=null,n=q.current,$(q,r?n&1|2:n&1),t):(he(t),null);case 22:case 23:return Ns(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&t.mode&1?Ae&1073741824&&(he(t),t.subtreeFlags&6&&(t.flags|=8192)):he(t),null;case 24:return null;case 25:return null}throw Error(N(156,t.tag))}function Yp(e,t){switch(rs(t),t.tag){case 1:return Te(t.type)&&ko(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Pn(),V(Pe),V(ge),ds(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return fs(t),null;case 13:if(V(q),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(N(340));xn()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return V(q),null;case 4:return Pn(),null;case 10:return ss(t.type._context),null;case 22:case 23:return Ns(),null;case 24:return null;default:return null}}var Kr=!1,me=!1,Zp=typeof WeakSet=="function"?WeakSet:Set,T=null;function gn(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){Y(e,t,r)}else n.current=null}function Ni(e,t,n){try{n()}catch(r){Y(e,t,r)}}var Mu=!1;function bp(e,t){if(ii=vo,e=ac(),ts(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var o=r.anchorOffset,l=r.focusNode;r=r.focusOffset;try{n.nodeType,l.nodeType}catch{n=null;break e}var i=0,s=-1,u=-1,a=0,d=0,m=e,y=null;t:for(;;){for(var E;m!==n||o!==0&&m.nodeType!==3||(s=i+o),m!==l||r!==0&&m.nodeType!==3||(u=i+r),m.nodeType===3&&(i+=m.nodeValue.length),(E=m.firstChild)!==null;)y=m,m=E;for(;;){if(m===e)break t;if(y===n&&++a===o&&(s=i),y===l&&++d===r&&(u=i),(E=m.nextSibling)!==null)break;m=y,y=m.parentNode}m=E}n=s===-1||u===-1?null:{start:s,end:u}}else n=null}n=n||{start:0,end:0}}else n=null;for(si={focusedElem:e,selectionRange:n},vo=!1,T=t;T!==null;)if(t=T,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,T=e;else for(;T!==null;){t=T;try{var S=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(S!==null){var v=S.memoizedProps,k=S.memoizedState,c=t.stateNode,f=c.getSnapshotBeforeUpdate(t.elementType===t.type?v:Ye(t.type,v),k);c.__reactInternalSnapshotBeforeUpdate=f}break;case 3:var p=t.stateNode.containerInfo;p.nodeType===1?p.textContent="":p.nodeType===9&&p.documentElement&&p.removeChild(p.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(N(163))}}catch(w){Y(t,t.return,w)}if(e=t.sibling,e!==null){e.return=t.return,T=e;break}T=t.return}return S=Mu,Mu=!1,S}function rr(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var o=r=r.next;do{if((o.tag&e)===e){var l=o.destroy;o.destroy=void 0,l!==void 0&&Ni(t,n,l)}o=o.next}while(o!==r)}}function Go(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function _i(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function lf(e){var t=e.alternate;t!==null&&(e.alternate=null,lf(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[it],delete t[yr],delete t[ci],delete t[Fp],delete t[Ip])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function sf(e){return e.tag===5||e.tag===3||e.tag===4}function ju(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||sf(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Ci(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=Eo));else if(r!==4&&(e=e.child,e!==null))for(Ci(e,t,n),e=e.sibling;e!==null;)Ci(e,t,n),e=e.sibling}function Ri(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(Ri(e,t,n),e=e.sibling;e!==null;)Ri(e,t,n),e=e.sibling}var ue=null,Ze=!1;function St(e,t,n){for(n=n.child;n!==null;)uf(e,t,n),n=n.sibling}function uf(e,t,n){if(st&&typeof st.onCommitFiberUnmount=="function")try{st.onCommitFiberUnmount(Bo,n)}catch{}switch(n.tag){case 5:me||gn(n,t);case 6:var r=ue,o=Ze;ue=null,St(e,t,n),ue=r,Ze=o,ue!==null&&(Ze?(e=ue,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):ue.removeChild(n.stateNode));break;case 18:ue!==null&&(Ze?(e=ue,n=n.stateNode,e.nodeType===8?_l(e.parentNode,n):e.nodeType===1&&_l(e,n),fr(e)):_l(ue,n.stateNode));break;case 4:r=ue,o=Ze,ue=n.stateNode.containerInfo,Ze=!0,St(e,t,n),ue=r,Ze=o;break;case 0:case 11:case 14:case 15:if(!me&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){o=r=r.next;do{var l=o,i=l.destroy;l=l.tag,i!==void 0&&(l&2||l&4)&&Ni(n,t,i),o=o.next}while(o!==r)}St(e,t,n);break;case 1:if(!me&&(gn(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(s){Y(n,t,s)}St(e,t,n);break;case 21:St(e,t,n);break;case 22:n.mode&1?(me=(r=me)||n.memoizedState!==null,St(e,t,n),me=r):St(e,t,n);break;default:St(e,t,n)}}function Bu(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new Zp),t.forEach(function(r){var o=uh.bind(null,e,r);n.has(r)||(n.add(r),r.then(o,o))})}}function Xe(e,t){var n=t.deletions;if(n!==null)for(var r=0;r o&&(o=i),r&=~l}if(r=o,r=Z()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*th(r/1960))-r,10 e?16:e,Rt===null)var r=!1;else{if(e=Rt,Rt=null,zo=0,U&6)throw Error(N(331));var o=U;for(U|=4,T=e.current;T!==null;){var l=T,i=l.child;if(T.flags&16){var s=l.deletions;if(s!==null){for(var u=0;u Z()-Es?Gt(e,0):Ss|=n),Le(e,t)}function yf(e,t){t===0&&(e.mode&1?(t=Ur,Ur<<=1,!(Ur&130023424)&&(Ur=4194304)):t=1);var n=Ee();e=yt(e,t),e!==null&&(_r(e,t,n),Le(e,n))}function sh(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),yf(e,n)}function uh(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,o=e.memoizedState;o!==null&&(n=o.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(N(314))}r!==null&&r.delete(t),yf(e,n)}var gf;gf=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||Pe.current)Oe=!0;else{if(!(e.lanes&n)&&!(t.flags&128))return Oe=!1,Xp(e,t,n);Oe=!!(e.flags&131072)}else Oe=!1,K&&t.flags&1048576&&Sc(t,Co,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;oo(e,t),e=t.pendingProps;var o=Rn(t,ge.current);Nn(t,n),o=hs(null,t,r,e,o,n);var l=ms();return t.flags|=1,typeof o=="object"&&o!==null&&typeof o.render=="function"&&o.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,Te(r)?(l=!0,No(t)):l=!1,t.memoizedState=o.state!==null&&o.state!==void 0?o.state:null,as(t),o.updater=qo,t.stateNode=o,o._reactInternals=t,yi(t,r,e,n),t=wi(null,t,r,!0,l,n)):(t.tag=0,K&&l&&ns(t),Se(null,t,o,n),t=t.child),t;case 16:r=t.elementType;e:{switch(oo(e,t),e=t.pendingProps,o=r._init,r=o(r._payload),t.type=r,o=t.tag=ch(r),e=Ye(r,e),o){case 0:t=vi(null,t,r,e,n);break e;case 1:t=Fu(null,t,r,e,n);break e;case 11:t=Au(null,t,r,e,n);break e;case 14:t=zu(null,t,r,Ye(r.type,e),n);break e}throw Error(N(306,r,""))}return t;case 0:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:Ye(r,o),vi(e,t,r,o,n);case 1:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:Ye(r,o),Fu(e,t,r,o,n);case 3:e:{if(bc(t),e===null)throw Error(N(387));r=t.pendingProps,l=t.memoizedState,o=l.element,Rc(e,t),Oo(t,r,null,n);var i=t.memoizedState;if(r=i.element,l.isDehydrated)if(l={element:r,isDehydrated:!1,cache:i.cache,pendingSuspenseBoundaries:i.pendingSuspenseBoundaries,transitions:i.transitions},t.updateQueue.baseState=l,t.memoizedState=l,t.flags&256){o=Tn(Error(N(423)),t),t=Iu(e,t,r,n,o);break e}else if(r!==o){o=Tn(Error(N(424)),t),t=Iu(e,t,r,n,o);break e}else for(ze=Tt(t.stateNode.containerInfo.firstChild),Fe=t,K=!0,be=null,n=_c(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(xn(),r===o){t=gt(e,t,n);break e}Se(e,t,r,n)}t=t.child}return t;case 5:return xc(t),e===null&&pi(t),r=t.type,o=t.pendingProps,l=e!==null?e.memoizedProps:null,i=o.children,ui(r,o)?i=null:l!==null&&ui(r,l)&&(t.flags|=32),Zc(e,t),Se(e,t,i,n),t.child;case 6:return e===null&&pi(t),null;case 13:return ef(e,t,n);case 4:return cs(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=On(t,null,r,n):Se(e,t,r,n),t.child;case 11:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:Ye(r,o),Au(e,t,r,o,n);case 7:return Se(e,t,t.pendingProps,n),t.child;case 8:return Se(e,t,t.pendingProps.children,n),t.child;case 12:return Se(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,o=t.pendingProps,l=t.memoizedProps,i=o.value,$(Ro,r._currentValue),r._currentValue=i,l!==null)if(nt(l.value,i)){if(l.children===o.children&&!Pe.current){t=gt(e,t,n);break e}}else for(l=t.child,l!==null&&(l.return=t);l!==null;){var s=l.dependencies;if(s!==null){i=l.child;for(var u=s.firstContext;u!==null;){if(u.context===r){if(l.tag===1){u=pt(-1,n&-n),u.tag=2;var a=l.updateQueue;if(a!==null){a=a.shared;var d=a.pending;d===null?u.next=u:(u.next=d.next,d.next=u),a.pending=u}}l.lanes|=n,u=l.alternate,u!==null&&(u.lanes|=n),hi(l.return,n,t),s.lanes|=n;break}u=u.next}}else if(l.tag===10)i=l.type===t.type?null:l.child;else if(l.tag===18){if(i=l.return,i===null)throw Error(N(341));i.lanes|=n,s=i.alternate,s!==null&&(s.lanes|=n),hi(i,n,t),i=l.sibling}else i=l.child;if(i!==null)i.return=l;else for(i=l;i!==null;){if(i===t){i=null;break}if(l=i.sibling,l!==null){l.return=i.return,i=l;break}i=i.return}l=i}Se(e,t,o.children,n),t=t.child}return t;case 9:return o=t.type,r=t.pendingProps.children,Nn(t,n),o=Ke(o),r=r(o),t.flags|=1,Se(e,t,r,n),t.child;case 14:return r=t.type,o=Ye(r,t.pendingProps),o=Ye(r.type,o),zu(e,t,r,o,n);case 15:return Jc(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:Ye(r,o),oo(e,t),t.tag=1,Te(r)?(e=!0,No(t)):e=!1,Nn(t,n),qc(t,r,o),yi(t,r,o,n),wi(null,t,r,!0,e,n);case 19:return tf(e,t,n);case 22:return Yc(e,t,n)}throw Error(N(156,t.tag))};function vf(e,t){return Wa(e,t)}function ah(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Ve(e,t,n,r){return new ah(e,t,n,r)}function Cs(e){return e=e.prototype,!(!e||!e.isReactComponent)}function ch(e){if(typeof e=="function")return Cs(e)?1:0;if(e!=null){if(e=e.$$typeof,e===Wi)return 11;if(e===Qi)return 14}return 2}function zt(e,t){var n=e.alternate;return n===null?(n=Ve(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function so(e,t,n,r,o,l){var i=2;if(r=e,typeof e=="function")Cs(e)&&(i=1);else if(typeof e=="string")i=5;else e:switch(e){case un:return Xt(n.children,o,l,t);case Vi:i=8,o|=8;break;case Bl:return e=Ve(12,n,t,o|2),e.elementType=Bl,e.lanes=l,e;case $l:return e=Ve(13,n,t,o),e.elementType=$l,e.lanes=l,e;case Hl:return e=Ve(19,n,t,o),e.elementType=Hl,e.lanes=l,e;case xa:return Jo(n,o,l,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case Ca:i=10;break e;case Ra:i=9;break e;case Wi:i=11;break e;case Qi:i=14;break e;case Et:i=16,r=null;break e}throw Error(N(130,e==null?e:typeof e,""))}return t=Ve(i,n,t,o),t.elementType=e,t.type=r,t.lanes=l,t}function Xt(e,t,n,r){return e=Ve(7,e,r,t),e.lanes=n,e}function Jo(e,t,n,r){return e=Ve(22,e,r,t),e.elementType=xa,e.lanes=n,e.stateNode={isHidden:!1},e}function Dl(e,t,n){return e=Ve(6,e,null,t),e.lanes=n,e}function Al(e,t,n){return t=Ve(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function fh(e,t,n,r,o){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=pl(0),this.expirationTimes=pl(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=pl(0),this.identifierPrefix=r,this.onRecoverableError=o,this.mutableSourceEagerHydrationData=null}function Rs(e,t,n,r,o,l,i,s,u){return e=new fh(e,t,n,s,u),t===1?(t=1,l===!0&&(t|=8)):t=0,l=Ve(3,null,null,t),e.current=l,l.stateNode=e,l.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},as(l),e}function dh(e,t,n){var r=3 "u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(kf)}catch(e){console.error(e)}}kf(),Ea.exports=Ue;var gh=Ea.exports,Gu=gh;Ml.createRoot=Gu.createRoot,Ml.hydrateRoot=Gu.hydrateRoot;function Nf(e,t){return function(){return e.apply(t,arguments)}}const{toString:vh}=Object.prototype,{getPrototypeOf:tl}=Object,{iterator:nl,toStringTag:_f}=Symbol,rl=(e=>t=>{const n=vh.call(t);return e[n]||(e[n]=n.slice(8,-1).toLowerCase())})(Object.create(null)),rt=e=>(e=e.toLowerCase(),t=>rl(t)===e),ol=e=>t=>typeof t===e,{isArray:In}=Array,Dn=ol("undefined");function Or(e){return e!==null&&!Dn(e)&&e.constructor!==null&&!Dn(e.constructor)&&De(e.constructor.isBuffer)&&e.constructor.isBuffer(e)}const Cf=rt("ArrayBuffer");function wh(e){let t;return typeof ArrayBuffer<"u"&&ArrayBuffer.isView?t=ArrayBuffer.isView(e):t=e&&e.buffer&&Cf(e.buffer),t}const Sh=ol("string"),De=ol("function"),Rf=ol("number"),Pr=e=>e!==null&&typeof e=="object",Eh=e=>e===!0||e===!1,uo=e=>{if(rl(e)!=="object")return!1;const t=tl(e);return(t===null||t===Object.prototype||Object.getPrototypeOf(t)===null)&&!(_f in e)&&!(nl in e)},kh=e=>{if(!Pr(e)||Or(e))return!1;try{return Object.keys(e).length===0&&Object.getPrototypeOf(e)===Object.prototype}catch{return!1}},Nh=rt("Date"),_h=rt("File"),Ch=e=>!!(e&&typeof e.uri<"u"),Rh=e=>e&&typeof e.getParts<"u",xh=rt("Blob"),Oh=rt("FileList"),Ph=e=>Pr(e)&&De(e.pipe);function Th(){return typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{}}const Xu=Th(),Ju=typeof Xu.FormData<"u"?Xu.FormData:void 0,Lh=e=>{if(!e)return!1;if(Ju&&e instanceof Ju)return!0;const t=tl(e);if(!t||t===Object.prototype||!De(e.append))return!1;const n=rl(e);return n==="formdata"||n==="object"&&De(e.toString)&&e.toString()==="[object FormData]"},Dh=rt("URLSearchParams"),[Ah,zh,Fh,Ih]=["ReadableStream","Request","Response","Headers"].map(rt),Uh=e=>e.trim?e.trim():e.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"");function Tr(e,t,{allOwnKeys:n=!1}={}){if(e===null||typeof e>"u")return;let r,o;if(typeof e!="object"&&(e=[e]),In(e))for(r=0,o=e.length;r 0;)if(o=n[r],t===o.toLowerCase())return o;return null}const qt=(()=>typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:global)(),Of=e=>!Dn(e)&&e!==qt;function Li(...e){const{caseless:t,skipUndefined:n}=Of(this)&&this||{},r={},o=(l,i)=>{if(i==="__proto__"||i==="constructor"||i==="prototype")return;const s=t&&xf(r,i)||i,u=Di(r,s)?r[s]:void 0;uo(u)&&uo(l)?r[s]=Li(u,l):uo(l)?r[s]=Li({},l):In(l)?r[s]=l.slice():(!n||!Dn(l))&&(r[s]=l)};for(let l=0,i=e.length;l(Tr(t,(o,l)=>{n&&De(o)?Object.defineProperty(e,l,{__proto__:null,value:Nf(o,n),writable:!0,enumerable:!0,configurable:!0}):Object.defineProperty(e,l,{__proto__:null,value:o,writable:!0,enumerable:!0,configurable:!0})},{allOwnKeys:r}),e),jh=e=>(e.charCodeAt(0)===65279&&(e=e.slice(1)),e),Bh=(e,t,n,r)=>{e.prototype=Object.create(t.prototype,r),Object.defineProperty(e.prototype,"constructor",{__proto__:null,value:e,writable:!0,enumerable:!1,configurable:!0}),Object.defineProperty(e,"super",{__proto__:null,value:t.prototype}),n&&Object.assign(e.prototype,n)},$h=(e,t,n,r)=>{let o,l,i;const s={};if(t=t||{},e==null)return t;do{for(o=Object.getOwnPropertyNames(e),l=o.length;l-- >0;)i=o[l],(!r||r(i,e,t))&&!s[i]&&(t[i]=e[i],s[i]=!0);e=n!==!1&&tl(e)}while(e&&(!n||n(e,t))&&e!==Object.prototype);return t},Hh=(e,t,n)=>{e=String(e),(n===void 0||n>e.length)&&(n=e.length),n-=t.length;const r=e.indexOf(t,n);return r!==-1&&r===n},Vh=e=>{if(!e)return null;if(In(e))return e;let t=e.length;if(!Rf(t))return null;const n=new Array(t);for(;t-- >0;)n[t]=e[t];return n},Wh=(e=>t=>e&&t instanceof e)(typeof Uint8Array<"u"&&tl(Uint8Array)),Qh=(e,t)=>{const r=(e&&e[nl]).call(e);let o;for(;(o=r.next())&&!o.done;){const l=o.value;t.call(e,l[0],l[1])}},Kh=(e,t)=>{let n;const r=[];for(;(n=e.exec(t))!==null;)r.push(n);return r},qh=rt("HTMLFormElement"),Gh=e=>e.toLowerCase().replace(/[-_\s]([a-z\d])(\w*)/g,function(n,r,o){return r.toUpperCase()+o}),Di=(({hasOwnProperty:e})=>(t,n)=>e.call(t,n))(Object.prototype),Xh=rt("RegExp"),Pf=(e,t)=>{const n=Object.getOwnPropertyDescriptors(e),r={};Tr(n,(o,l)=>{let i;(i=t(o,l,e))!==!1&&(r[l]=i||o)}),Object.defineProperties(e,r)},Jh=e=>{Pf(e,(t,n)=>{if(De(e)&&["arguments","caller","callee"].includes(n))return!1;const r=e[n];if(De(r)){if(t.enumerable=!1,"writable"in t){t.writable=!1;return}t.set||(t.set=()=>{throw Error("Can not rewrite read-only method '"+n+"'")})}})},Yh=(e,t)=>{const n={},r=o=>{o.forEach(l=>{n[l]=!0})};return In(e)?r(e):r(String(e).split(t)),n},Zh=()=>{},bh=(e,t)=>e!=null&&Number.isFinite(e=+e)?e:t;function em(e){return!!(e&&De(e.append)&&e[_f]==="FormData"&&e[nl])}const tm=e=>{const t=new WeakSet,n=r=>{if(Pr(r)){if(t.has(r))return;if(Or(r))return r;if(!("toJSON"in r)){t.add(r);const o=In(r)?[]:{};return Tr(r,(l,i)=>{const s=n(l);!Dn(s)&&(o[i]=s)}),t.delete(r),o}}return r};return n(e)},nm=rt("AsyncFunction"),rm=e=>e&&(Pr(e)||De(e))&&De(e.then)&&De(e.catch),Tf=((e,t)=>e?setImmediate:t?((n,r)=>(qt.addEventListener("message",({source:o,data:l})=>{o===qt&&l===n&&r.length&&r.shift()()},!1),o=>{r.push(o),qt.postMessage(n,"*")}))(`axios@${Math.random()}`,[]):n=>setTimeout(n))(typeof setImmediate=="function",De(qt.postMessage)),om=typeof queueMicrotask<"u"?queueMicrotask.bind(qt):typeof process<"u"&&process.nextTick||Tf,lm=e=>e!=null&&De(e[nl]),h={isArray:In,isArrayBuffer:Cf,isBuffer:Or,isFormData:Lh,isArrayBufferView:wh,isString:Sh,isNumber:Rf,isBoolean:Eh,isObject:Pr,isPlainObject:uo,isEmptyObject:kh,isReadableStream:Ah,isRequest:zh,isResponse:Fh,isHeaders:Ih,isUndefined:Dn,isDate:Nh,isFile:_h,isReactNativeBlob:Ch,isReactNative:Rh,isBlob:xh,isRegExp:Xh,isFunction:De,isStream:Ph,isURLSearchParams:Dh,isTypedArray:Wh,isFileList:Oh,forEach:Tr,merge:Li,extend:Mh,trim:Uh,stripBOM:jh,inherits:Bh,toFlatObject:$h,kindOf:rl,kindOfTest:rt,endsWith:Hh,toArray:Vh,forEachEntry:Qh,matchAll:Kh,isHTMLForm:qh,hasOwnProperty:Di,hasOwnProp:Di,reduceDescriptors:Pf,freezeMethods:Jh,toObjectSet:Yh,toCamelCase:Gh,noop:Zh,toFiniteNumber:bh,findKey:xf,global:qt,isContextDefined:Of,isSpecCompliantForm:em,toJSONObject:tm,isAsyncFn:nm,isThenable:rm,setImmediate:Tf,asap:om,isIterable:lm},im=h.toObjectSet(["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"]),sm=e=>{const t={};let n,r,o;return e&&e.split(` +`).forEach(function(i){o=i.indexOf(":"),n=i.substring(0,o).trim().toLowerCase(),r=i.substring(o+1).trim(),!(!n||t[n]&&im[n])&&(n==="set-cookie"?t[n]?t[n].push(r):t[n]=[r]:t[n]=t[n]?t[n]+", "+r:r)}),t};function um(e){let t=0,n=e.length;for(;t t;){const r=e.charCodeAt(n-1);if(r!==9&&r!==32)break;n-=1}return t===0&&n===e.length?e:e.slice(t,n)}const am=new RegExp("[\\u0000-\\u0008\\u000a-\\u001f\\u007f]+","g"),cm=new RegExp("[^\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+","g");function Ts(e,t){return h.isArray(e)?e.map(n=>Ts(n,t)):um(String(e).replace(t,""))}const fm=e=>Ts(e,am),dm=e=>Ts(e,cm);function Lf(e){const t=Object.create(null);return h.forEach(e.toJSON(),(n,r)=>{t[r]=dm(n)}),t}const Yu=Symbol("internals");function Kn(e){return e&&String(e).trim().toLowerCase()}function ao(e){return e===!1||e==null?e:h.isArray(e)?e.map(ao):fm(String(e))}function pm(e){const t=Object.create(null),n=/([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g;let r;for(;r=n.exec(e);)t[r[1]]=r[2];return t}const hm=e=>/^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(e.trim());function zl(e,t,n,r,o){if(h.isFunction(r))return r.call(this,t,n);if(o&&(t=n),!!h.isString(t)){if(h.isString(r))return t.indexOf(r)!==-1;if(h.isRegExp(r))return r.test(t)}}function mm(e){return e.trim().toLowerCase().replace(/([a-z\d])(\w*)/g,(t,n,r)=>n.toUpperCase()+r)}function ym(e,t){const n=h.toCamelCase(" "+t);["get","set","has"].forEach(r=>{Object.defineProperty(e,r+n,{__proto__:null,value:function(o,l,i){return this[r].call(this,t,o,l,i)},configurable:!0})})}class ll{constructor(t){t&&this.set(t)}set(t,n,r){const o=this;function l(s,u,a){const d=Kn(u);if(!d)throw new Error("header name must be a non-empty string");const m=h.findKey(o,d);(!m||o[m]===void 0||a===!0||a===void 0&&o[m]!==!1)&&(o[m||u]=ao(s))}const i=(s,u)=>h.forEach(s,(a,d)=>l(a,d,u));if(h.isPlainObject(t)||t instanceof this.constructor)i(t,n);else if(h.isString(t)&&(t=t.trim())&&!hm(t))i(sm(t),n);else if(h.isObject(t)&&h.isIterable(t)){let s={},u,a;for(const d of t){if(!h.isArray(d))throw TypeError("Object iterator must return a key-value pair");s[a=d[0]]=(u=s[a])?h.isArray(u)?[...u,d[1]]:[u,d[1]]:d[1]}i(s,n)}else t!=null&&l(n,t,r);return this}get(t,n){if(t=Kn(t),t){const r=h.findKey(this,t);if(r){const o=this[r];if(!n)return o;if(n===!0)return pm(o);if(h.isFunction(n))return n.call(this,o,r);if(h.isRegExp(n))return n.exec(o);throw new TypeError("parser must be boolean|regexp|function")}}}has(t,n){if(t=Kn(t),t){const r=h.findKey(this,t);return!!(r&&this[r]!==void 0&&(!n||zl(this,this[r],r,n)))}return!1}delete(t,n){const r=this;let o=!1;function l(i){if(i=Kn(i),i){const s=h.findKey(r,i);s&&(!n||zl(r,r[s],s,n))&&(delete r[s],o=!0)}}return h.isArray(t)?t.forEach(l):l(t),o}clear(t){const n=Object.keys(this);let r=n.length,o=!1;for(;r--;){const l=n[r];(!t||zl(this,this[l],l,t,!0))&&(delete this[l],o=!0)}return o}normalize(t){const n=this,r={};return h.forEach(this,(o,l)=>{const i=h.findKey(r,l);if(i){n[i]=ao(o),delete n[l];return}const s=t?mm(l):String(l).trim();s!==l&&delete n[l],n[s]=ao(o),r[s]=!0}),this}concat(...t){return this.constructor.concat(this,...t)}toJSON(t){const n=Object.create(null);return h.forEach(this,(r,o)=>{r!=null&&r!==!1&&(n[o]=t&&h.isArray(r)?r.join(", "):r)}),n}[Symbol.iterator](){return Object.entries(this.toJSON())[Symbol.iterator]()}toString(){return Object.entries(this.toJSON()).map(([t,n])=>t+": "+n).join(` +`)}getSetCookie(){return this.get("set-cookie")||[]}get[Symbol.toStringTag](){return"AxiosHeaders"}static from(t){return t instanceof this?t:new this(t)}static concat(t,...n){const r=new this(t);return n.forEach(o=>r.set(o)),r}static accessor(t){const r=(this[Yu]=this[Yu]={accessors:{}}).accessors,o=this.prototype;function l(i){const s=Kn(i);r[s]||(ym(o,i),r[s]=!0)}return h.isArray(t)?t.forEach(l):l(t),this}}ll.accessor(["Content-Type","Content-Length","Accept","Accept-Encoding","User-Agent","Authorization"]);h.reduceDescriptors(ll.prototype,({value:e},t)=>{let n=t[0].toUpperCase()+t.slice(1);return{get:()=>e,set(r){this[n]=r}}});h.freezeMethods(ll);const Qe=ll,gm="[REDACTED ****]";function vm(e){if(h.hasOwnProp(e,"toJSON"))return!0;let t=Object.getPrototypeOf(e);for(;t&&t!==Object.prototype;){if(h.hasOwnProp(t,"toJSON"))return!0;t=Object.getPrototypeOf(t)}return!1}function wm(e,t){const n=new Set(t.map(l=>String(l).toLowerCase())),r=[],o=l=>{if(l===null||typeof l!="object"||h.isBuffer(l))return l;if(r.indexOf(l)!==-1)return;l instanceof Qe&&(l=l.toJSON()),r.push(l);let i;if(h.isArray(l))i=[],l.forEach((s,u)=>{const a=o(s);h.isUndefined(a)||(i[u]=a)});else{if(!h.isPlainObject(l)&&vm(l))return r.pop(),l;i=Object.create(null);for(const[s,u]of Object.entries(l)){const a=n.has(s.toLowerCase())?gm:o(u);h.isUndefined(a)||(i[s]=a)}}return r.pop(),i};return o(e)}class fe extends Error{static from(t,n,r,o,l,i){const s=new fe(t.message,n||t.code,r,o,l);return s.cause=t,s.name=t.name,t.status!=null&&s.status==null&&(s.status=t.status),i&&Object.assign(s,i),s}constructor(t,n,r,o,l){super(t),Object.defineProperty(this,"message",{__proto__:null,value:t,enumerable:!0,writable:!0,configurable:!0}),this.name="AxiosError",this.isAxiosError=!0,n&&(this.code=n),r&&(this.config=r),o&&(this.request=o),l&&(this.response=l,this.status=l.status)}toJSON(){const t=this.config,n=t&&h.hasOwnProp(t,"redact")?t.redact:void 0,r=h.isArray(n)&&n.length>0?wm(t,n):h.toJSONObject(t);return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:r,code:this.code,status:this.status}}}fe.ERR_BAD_OPTION_VALUE="ERR_BAD_OPTION_VALUE";fe.ERR_BAD_OPTION="ERR_BAD_OPTION";fe.ECONNABORTED="ECONNABORTED";fe.ETIMEDOUT="ETIMEDOUT";fe.ECONNREFUSED="ECONNREFUSED";fe.ERR_NETWORK="ERR_NETWORK";fe.ERR_FR_TOO_MANY_REDIRECTS="ERR_FR_TOO_MANY_REDIRECTS";fe.ERR_DEPRECATED="ERR_DEPRECATED";fe.ERR_BAD_RESPONSE="ERR_BAD_RESPONSE";fe.ERR_BAD_REQUEST="ERR_BAD_REQUEST";fe.ERR_CANCELED="ERR_CANCELED";fe.ERR_NOT_SUPPORT="ERR_NOT_SUPPORT";fe.ERR_INVALID_URL="ERR_INVALID_URL";fe.ERR_FORM_DATA_DEPTH_EXCEEDED="ERR_FORM_DATA_DEPTH_EXCEEDED";const D=fe,Sm=null;function Ai(e){return h.isPlainObject(e)||h.isArray(e)}function Df(e){return h.endsWith(e,"[]")?e.slice(0,-2):e}function Fl(e,t,n){return e?e.concat(t).map(function(o,l){return o=Df(o),!n&&l?"["+o+"]":o}).join(n?".":""):t}function Em(e){return h.isArray(e)&&!e.some(Ai)}const km=h.toFlatObject(h,{},null,function(t){return/^is[A-Z]/.test(t)});function il(e,t,n){if(!h.isObject(e))throw new TypeError("target must be an object");t=t||new FormData,n=h.toFlatObject(n,{metaTokens:!0,dots:!1,indexes:!1},!1,function(k,c){return!h.isUndefined(c[k])});const r=n.metaTokens,o=n.visitor||m,l=n.dots,i=n.indexes,s=n.Blob||typeof Blob<"u"&&Blob,u=n.maxDepth===void 0?100:n.maxDepth,a=s&&h.isSpecCompliantForm(t);if(!h.isFunction(o))throw new TypeError("visitor must be a function");function d(v){if(v===null)return"";if(h.isDate(v))return v.toISOString();if(h.isBoolean(v))return v.toString();if(!a&&h.isBlob(v))throw new D("Blob is not supported. Use a Buffer instead.");return h.isArrayBuffer(v)||h.isTypedArray(v)?a&&typeof Blob=="function"?new Blob([v]):Buffer.from(v):v}function m(v,k,c){let f=v;if(h.isReactNative(t)&&h.isReactNativeBlob(v))return t.append(Fl(c,k,l),d(v)),!1;if(v&&!c&&typeof v=="object"){if(h.endsWith(k,"{}"))k=r?k:k.slice(0,-2),v=JSON.stringify(v);else if(h.isArray(v)&&Em(v)||(h.isFileList(v)||h.endsWith(k,"[]"))&&(f=h.toArray(v)))return k=Df(k),f.forEach(function(w,_){!(h.isUndefined(w)||w===null)&&t.append(i===!0?Fl([k],_,l):i===null?k:k+"[]",d(w))}),!1}return Ai(v)?!0:(t.append(Fl(c,k,l),d(v)),!1)}const y=[],E=Object.assign(km,{defaultVisitor:m,convertValue:d,isVisitable:Ai});function S(v,k,c=0){if(!h.isUndefined(v)){if(c>u)throw new D("Object is too deeply nested ("+c+" levels). Max depth: "+u,D.ERR_FORM_DATA_DEPTH_EXCEEDED);if(y.indexOf(v)!==-1)throw Error("Circular reference detected in "+k.join("."));y.push(v),h.forEach(v,function(p,w){(!(h.isUndefined(p)||p===null)&&o.call(t,p,h.isString(w)?w.trim():w,k,E))===!0&&S(p,k?k.concat(w):[w],c+1)}),y.pop()}}if(!h.isObject(e))throw new TypeError("data must be an object");return S(e),t}function Zu(e){const t={"!":"%21","'":"%27","(":"%28",")":"%29","~":"%7E","%20":"+"};return encodeURIComponent(e).replace(/[!'()~]|%20/g,function(r){return t[r]})}function Ls(e,t){this._pairs=[],e&&il(e,this,t)}const Af=Ls.prototype;Af.append=function(t,n){this._pairs.push([t,n])};Af.toString=function(t){const n=t?function(r){return t.call(this,r,Zu)}:Zu;return this._pairs.map(function(o){return n(o[0])+"="+n(o[1])},"").join("&")};function Nm(e){return encodeURIComponent(e).replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+")}function zf(e,t,n){if(!t)return e;const r=n&&n.encode||Nm,o=h.isFunction(n)?{serialize:n}:n,l=o&&o.serialize;let i;if(l?i=l(t,o):i=h.isURLSearchParams(t)?t.toString():new Ls(t,o).toString(r),i){const s=e.indexOf("#");s!==-1&&(e=e.slice(0,s)),e+=(e.indexOf("?")===-1?"?":"&")+i}return e}class _m{constructor(){this.handlers=[]}use(t,n,r){return this.handlers.push({fulfilled:t,rejected:n,synchronous:r?r.synchronous:!1,runWhen:r?r.runWhen:null}),this.handlers.length-1}eject(t){this.handlers[t]&&(this.handlers[t]=null)}clear(){this.handlers&&(this.handlers=[])}forEach(t){h.forEach(this.handlers,function(r){r!==null&&t(r)})}}const bu=_m,Ds={silentJSONParsing:!0,forcedJSONParsing:!0,clarifyTimeoutError:!1,legacyInterceptorReqResOrdering:!0},Cm=typeof URLSearchParams<"u"?URLSearchParams:Ls,Rm=typeof FormData<"u"?FormData:null,xm=typeof Blob<"u"?Blob:null,Om={isBrowser:!0,classes:{URLSearchParams:Cm,FormData:Rm,Blob:xm},protocols:["http","https","file","blob","url","data"]},As=typeof window<"u"&&typeof document<"u",zi=typeof navigator=="object"&&navigator||void 0,Pm=As&&(!zi||["ReactNative","NativeScript","NS"].indexOf(zi.product)<0),Tm=(()=>typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope&&typeof self.importScripts=="function")(),Lm=As&&window.location.href||"http://localhost",Dm=Object.freeze(Object.defineProperty({__proto__:null,hasBrowserEnv:As,hasStandardBrowserEnv:Pm,hasStandardBrowserWebWorkerEnv:Tm,navigator:zi,origin:Lm},Symbol.toStringTag,{value:"Module"})),ye={...Dm,...Om};function Am(e,t){return il(e,new ye.classes.URLSearchParams,{visitor:function(n,r,o,l){return ye.isNode&&h.isBuffer(n)?(this.append(r,n.toString("base64")),!1):l.defaultVisitor.apply(this,arguments)},...t})}function zm(e){return h.matchAll(/\w+|\[(\w*)]/g,e).map(t=>t[0]==="[]"?"":t[1]||t[0])}function Fm(e){const t={},n=Object.keys(e);let r;const o=n.length;let l;for(r=0;r =n.length;return i=!i&&h.isArray(o)?o.length:i,u?(h.hasOwnProp(o,i)?o[i]=h.isArray(o[i])?o[i].concat(r):[o[i],r]:o[i]=r,!s):((!h.hasOwnProp(o,i)||!h.isObject(o[i]))&&(o[i]=[]),t(n,r,o[i],l)&&h.isArray(o[i])&&(o[i]=Fm(o[i])),!s)}if(h.isFormData(e)&&h.isFunction(e.entries)){const n={};return h.forEachEntry(e,(r,o)=>{t(zm(r),o,n,0)}),n}return null}const ln=(e,t)=>e!=null&&h.hasOwnProp(e,t)?e[t]:void 0;function Im(e,t,n){if(h.isString(e))try{return(t||JSON.parse)(e),h.trim(e)}catch(r){if(r.name!=="SyntaxError")throw r}return(n||JSON.stringify)(e)}const zs={transitional:Ds,adapter:["xhr","http","fetch"],transformRequest:[function(t,n){const r=n.getContentType()||"",o=r.indexOf("application/json")>-1,l=h.isObject(t);if(l&&h.isHTMLForm(t)&&(t=new FormData(t)),h.isFormData(t))return o?JSON.stringify(Ff(t)):t;if(h.isArrayBuffer(t)||h.isBuffer(t)||h.isStream(t)||h.isFile(t)||h.isBlob(t)||h.isReadableStream(t))return t;if(h.isArrayBufferView(t))return t.buffer;if(h.isURLSearchParams(t))return n.setContentType("application/x-www-form-urlencoded;charset=utf-8",!1),t.toString();let s;if(l){const u=ln(this,"formSerializer");if(r.indexOf("application/x-www-form-urlencoded")>-1)return Am(t,u).toString();if((s=h.isFileList(t))||r.indexOf("multipart/form-data")>-1){const a=ln(this,"env"),d=a&&a.FormData;return il(s?{"files[]":t}:t,d&&new d,u)}}return l||o?(n.setContentType("application/json",!1),Im(t)):t}],transformResponse:[function(t){const n=ln(this,"transitional")||zs.transitional,r=n&&n.forcedJSONParsing,o=ln(this,"responseType"),l=o==="json";if(h.isResponse(t)||h.isReadableStream(t))return t;if(t&&h.isString(t)&&(r&&!o||l)){const s=!(n&&n.silentJSONParsing)&&l;try{return JSON.parse(t,ln(this,"parseReviver"))}catch(u){if(s)throw u.name==="SyntaxError"?D.from(u,D.ERR_BAD_RESPONSE,this,null,ln(this,"response")):u}}return t}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,maxBodyLength:-1,env:{FormData:ye.classes.FormData,Blob:ye.classes.Blob},validateStatus:function(t){return t>=200&&t<300},headers:{common:{Accept:"application/json, text/plain, */*","Content-Type":void 0}}};h.forEach(["delete","get","head","post","put","patch","query"],e=>{zs.headers[e]={}});const Fs=zs;function Il(e,t){const n=this||Fs,r=t||n,o=Qe.from(r.headers);let l=r.data;return h.forEach(e,function(s){l=s.call(n,l,o.normalize(),t?t.status:void 0)}),o.normalize(),l}function If(e){return!!(e&&e.__CANCEL__)}class Um extends D{constructor(t,n,r){super(t??"canceled",D.ERR_CANCELED,n,r),this.name="CanceledError",this.__CANCEL__=!0}}const Lr=Um;function Uf(e,t,n){const r=n.config.validateStatus;!n.status||!r||r(n.status)?e(n):t(new D("Request failed with status code "+n.status,n.status>=400&&n.status<500?D.ERR_BAD_REQUEST:D.ERR_BAD_RESPONSE,n.config,n.request,n))}function Mm(e){const t=/^([-+\w]{1,25}):(?:\/\/)?/.exec(e);return t&&t[1]||""}function jm(e,t){e=e||10;const n=new Array(e),r=new Array(e);let o=0,l=0,i;return t=t!==void 0?t:1e3,function(u){const a=Date.now(),d=r[l];i||(i=a),n[o]=u,r[o]=a;let m=l,y=0;for(;m!==o;)y+=n[m++],m=m%e;if(o=(o+1)%e,o===l&&(l=(l+1)%e),a-i {n=d,o=null,l&&(clearTimeout(l),l=null),e(...a)};return[(...a)=>{const d=Date.now(),m=d-n;m>=r?i(a,d):(o=a,l||(l=setTimeout(()=>{l=null,i(o)},r-m)))},()=>o&&i(o)]}const Uo=(e,t,n=3)=>{let r=0;const o=jm(50,250);return Bm(l=>{if(!l||typeof l.loaded!="number")return;const i=l.loaded,s=l.lengthComputable?l.total:void 0,u=s!=null?Math.min(i,s):i,a=Math.max(0,u-r),d=o(a);r=Math.max(r,u);const m={loaded:u,total:s,progress:s?u/s:void 0,bytes:a,rate:d||void 0,estimated:d&&s?(s-u)/d:void 0,event:l,lengthComputable:s!=null,[t?"download":"upload"]:!0};e(m)},n)},ea=(e,t)=>{const n=e!=null;return[r=>t[0]({lengthComputable:n,total:e,loaded:r}),t[1]]},ta=e=>(...t)=>h.asap(()=>e(...t)),$m=ye.hasStandardBrowserEnv?((e,t)=>n=>(n=new URL(n,ye.origin),e.protocol===n.protocol&&e.host===n.host&&(t||e.port===n.port)))(new URL(ye.origin),ye.navigator&&/(msie|trident)/i.test(ye.navigator.userAgent)):()=>!0,Hm=ye.hasStandardBrowserEnv?{write(e,t,n,r,o,l,i){if(typeof document>"u")return;const s=[`${e}=${encodeURIComponent(t)}`];h.isNumber(n)&&s.push(`expires=${new Date(n).toUTCString()}`),h.isString(r)&&s.push(`path=${r}`),h.isString(o)&&s.push(`domain=${o}`),l===!0&&s.push("secure"),h.isString(i)&&s.push(`SameSite=${i}`),document.cookie=s.join("; ")},read(e){if(typeof document>"u")return null;const t=document.cookie.split(";");for(let n=0;n e instanceof Qe?{...e}:e;function tn(e,t){t=t||{};const n=Object.create(null);Object.defineProperty(n,"hasOwnProperty",{__proto__:null,value:Object.prototype.hasOwnProperty,enumerable:!1,writable:!0,configurable:!0});function r(a,d,m,y){return h.isPlainObject(a)&&h.isPlainObject(d)?h.merge.call({caseless:y},a,d):h.isPlainObject(d)?h.merge({},d):h.isArray(d)?d.slice():d}function o(a,d,m,y){if(h.isUndefined(d)){if(!h.isUndefined(a))return r(void 0,a,m,y)}else return r(a,d,m,y)}function l(a,d){if(!h.isUndefined(d))return r(void 0,d)}function i(a,d){if(h.isUndefined(d)){if(!h.isUndefined(a))return r(void 0,a)}else return r(void 0,d)}function s(a,d,m){if(h.hasOwnProp(t,m))return r(a,d);if(h.hasOwnProp(e,m))return r(void 0,a)}const u={url:l,method:l,data:l,baseURL:i,transformRequest:i,transformResponse:i,paramsSerializer:i,timeout:i,timeoutMessage:i,withCredentials:i,withXSRFToken:i,adapter:i,responseType:i,xsrfCookieName:i,xsrfHeaderName:i,onUploadProgress:i,onDownloadProgress:i,decompress:i,maxContentLength:i,maxBodyLength:i,beforeRedirect:i,transport:i,httpAgent:i,httpsAgent:i,cancelToken:i,socketPath:i,allowedSocketPaths:i,responseEncoding:i,validateStatus:s,headers:(a,d,m)=>o(na(a),na(d),m,!0)};return h.forEach(Object.keys({...e,...t}),function(d){if(d==="__proto__"||d==="constructor"||d==="prototype")return;const m=h.hasOwnProp(u,d)?u[d]:o,y=h.hasOwnProp(e,d)?e[d]:void 0,E=h.hasOwnProp(t,d)?t[d]:void 0,S=m(y,E,d);h.isUndefined(S)&&m!==s||(n[d]=S)}),n}const Qm=["content-type","content-length"];function Km(e,t,n){if(n!=="content-only"){e.set(t);return}Object.entries(t).forEach(([r,o])=>{Qm.includes(r.toLowerCase())&&e.set(r,o)})}const qm=e=>encodeURIComponent(e).replace(/%([0-9A-F]{2})/gi,(t,n)=>String.fromCharCode(parseInt(n,16))),jf=e=>{const t=tn({},e),n=y=>h.hasOwnProp(t,y)?t[y]:void 0,r=n("data");let o=n("withXSRFToken");const l=n("xsrfHeaderName"),i=n("xsrfCookieName");let s=n("headers");const u=n("auth"),a=n("baseURL"),d=n("allowAbsoluteUrls"),m=n("url");if(t.headers=s=Qe.from(s),t.url=zf(Mf(a,m,d),e.params,e.paramsSerializer),u&&s.set("Authorization","Basic "+btoa((u.username||"")+":"+(u.password?qm(u.password):""))),h.isFormData(r)&&(ye.hasStandardBrowserEnv||ye.hasStandardBrowserWebWorkerEnv?s.setContentType(void 0):h.isFunction(r.getHeaders)&&Km(s,r.getHeaders(),n("formDataHeaderPolicy"))),ye.hasStandardBrowserEnv&&(h.isFunction(o)&&(o=o(t)),o===!0||o==null&&$m(t.url))){const E=l&&i&&Hm.read(i);E&&s.set(l,E)}return t},Gm=typeof XMLHttpRequest<"u",Xm=Gm&&function(e){return new Promise(function(n,r){const o=jf(e);let l=o.data;const i=Qe.from(o.headers).normalize();let{responseType:s,onUploadProgress:u,onDownloadProgress:a}=o,d,m,y,E,S;function v(){E&&E(),S&&S(),o.cancelToken&&o.cancelToken.unsubscribe(d),o.signal&&o.signal.removeEventListener("abort",d)}let k=new XMLHttpRequest;k.open(o.method.toUpperCase(),o.url,!0),k.timeout=o.timeout;function c(){if(!k)return;const p=Qe.from("getAllResponseHeaders"in k&&k.getAllResponseHeaders()),_={data:!s||s==="text"||s==="json"?k.responseText:k.response,status:k.status,statusText:k.statusText,headers:p,config:e,request:k};Uf(function(P){n(P),v()},function(P){r(P),v()},_),k=null}"onloadend"in k?k.onloadend=c:k.onreadystatechange=function(){!k||k.readyState!==4||k.status===0&&!(k.responseURL&&k.responseURL.startsWith("file:"))||setTimeout(c)},k.onabort=function(){k&&(r(new D("Request aborted",D.ECONNABORTED,e,k)),v(),k=null)},k.onerror=function(w){const _=w&&w.message?w.message:"Network Error",O=new D(_,D.ERR_NETWORK,e,k);O.event=w||null,r(O),v(),k=null},k.ontimeout=function(){let w=o.timeout?"timeout of "+o.timeout+"ms exceeded":"timeout exceeded";const _=o.transitional||Ds;o.timeoutErrorMessage&&(w=o.timeoutErrorMessage),r(new D(w,_.clarifyTimeoutError?D.ETIMEDOUT:D.ECONNABORTED,e,k)),v(),k=null},l===void 0&&i.setContentType(null),"setRequestHeader"in k&&h.forEach(Lf(i),function(w,_){k.setRequestHeader(_,w)}),h.isUndefined(o.withCredentials)||(k.withCredentials=!!o.withCredentials),s&&s!=="json"&&(k.responseType=o.responseType),a&&([y,S]=Uo(a,!0),k.addEventListener("progress",y)),u&&k.upload&&([m,E]=Uo(u),k.upload.addEventListener("progress",m),k.upload.addEventListener("loadend",E)),(o.cancelToken||o.signal)&&(d=p=>{k&&(r(!p||p.type?new Lr(null,e,k):p),k.abort(),v(),k=null)},o.cancelToken&&o.cancelToken.subscribe(d),o.signal&&(o.signal.aborted?d():o.signal.addEventListener("abort",d)));const f=Mm(o.url);if(f&&!ye.protocols.includes(f)){r(new D("Unsupported protocol "+f+":",D.ERR_BAD_REQUEST,e));return}k.send(l||null)})},Jm=(e,t)=>{if(e=e?e.filter(Boolean):[],!t&&!e.length)return;const n=new AbortController;let r=!1;const o=function(u){if(!r){r=!0,i();const a=u instanceof Error?u:this.reason;n.abort(a instanceof D?a:new Lr(a instanceof Error?a.message:a))}};let l=t&&setTimeout(()=>{l=null,o(new D(`timeout of ${t}ms exceeded`,D.ETIMEDOUT))},t);const i=()=>{e&&(l&&clearTimeout(l),l=null,e.forEach(u=>{u.unsubscribe?u.unsubscribe(o):u.removeEventListener("abort",o)}),e=null)};e.forEach(u=>u.addEventListener("abort",o));const{signal:s}=n;return s.unsubscribe=()=>h.asap(i),s},Ym=Jm,Zm=function*(e,t){let n=e.byteLength;if(!t||n {const o=bm(e,t);let l=0,i,s=u=>{i||(i=!0,r&&r(u))};return new ReadableStream({async pull(u){try{const{done:a,value:d}=await o.next();if(a){s(),u.close();return}let m=d.byteLength;if(n){let y=l+=m;n(y)}u.enqueue(new Uint8Array(d))}catch(a){throw s(a),a}},cancel(u){return s(u),o.return()}},{highWaterMark:2})};function ty(e){if(!e||typeof e!="string"||!e.startsWith("data:"))return 0;const t=e.indexOf(",");if(t<0)return 0;const n=e.slice(5,t),r=e.slice(t+1);if(/;base64/i.test(n)){let i=r.length;const s=r.length;for(let E=0;E =48&&S<=57||S>=65&&S<=70||S>=97&&S<=102)&&(v>=48&&v<=57||v>=65&&v<=70||v>=97&&v<=102)&&(i-=2,E+=2)}let u=0,a=s-1;const d=E=>E>=2&&r.charCodeAt(E-2)===37&&r.charCodeAt(E-1)===51&&(r.charCodeAt(E)===68||r.charCodeAt(E)===100);a>=0&&(r.charCodeAt(a)===61?(u++,a--):d(a)&&(u++,a-=3)),u===1&&a>=0&&(r.charCodeAt(a)===61||d(a))&&u++;const y=Math.floor(i/4)*3-(u||0);return y>0?y:0}if(typeof Buffer<"u"&&typeof Buffer.byteLength=="function")return Buffer.byteLength(r,"utf8");let l=0;for(let i=0,s=r.length;i=55296&&u<=56319&&i+1=56320&&a<=57343?(l+=4,i++):l+=3}else l+=3}return l}const Is="1.16.1",oa=64*1024,{isFunction:Xr}=h,la=(e,...t)=>{try{return!!e(...t)}catch{return!1}},ny=e=>{const t=h.global!==void 0&&h.global!==null?h.global:globalThis,{ReadableStream:n,TextEncoder:r}=t;e=h.merge.call({skipUndefined:!0},{Request:t.Request,Response:t.Response},e);const{fetch:o,Request:l,Response:i}=e,s=o?Xr(o):typeof fetch=="function",u=Xr(l),a=Xr(i);if(!s)return!1;const d=s&&Xr(n),m=s&&(typeof r=="function"?(c=>f=>c.encode(f))(new r):async c=>new Uint8Array(await new l(c).arrayBuffer())),y=u&&d&&la(()=>{let c=!1;const f=new l(ye.origin,{body:new n,method:"POST",get duplex(){return c=!0,"half"}}),p=f.headers.has("Content-Type");return f.body!=null&&f.body.cancel(),c&&!p}),E=a&&d&&la(()=>h.isReadableStream(new i("").body)),S={stream:E&&(c=>c.body)};s&&["text","arrayBuffer","blob","formData","stream"].forEach(c=>{!S[c]&&(S[c]=(f,p)=>{let w=f&&f[c];if(w)return w.call(f);throw new D(`Response type '${c}' is not supported`,D.ERR_NOT_SUPPORT,p)})});const v=async c=>{if(c==null)return 0;if(h.isBlob(c))return c.size;if(h.isSpecCompliantForm(c))return(await new l(ye.origin,{method:"POST",body:c}).arrayBuffer()).byteLength;if(h.isArrayBufferView(c)||h.isArrayBuffer(c))return c.byteLength;if(h.isURLSearchParams(c)&&(c=c+""),h.isString(c))return(await m(c)).byteLength},k=async(c,f)=>{const p=h.toFiniteNumber(c.getContentLength());return p??v(f)};return async c=>{let{url:f,method:p,data:w,signal:_,cancelToken:O,timeout:P,onDownloadProgress:L,onUploadProgress:B,responseType:z,headers:J,withCredentials:je="same-origin",fetchOptions:_e,maxContentLength:ve,maxBodyLength:Bt}=jf(c);const Ge=h.isNumber(ve)&&ve>-1,$t=h.isNumber(Bt)&&Bt>-1;let g=o||fetch;z=z?(z+"").toLowerCase():"text";let C=Ym([_,O&&O.toAbortSignal()],P),x=null;const I=C&&C.unsubscribe&&(()=>{C.unsubscribe()});let W;try{if(Ge&&typeof f=="string"&&f.startsWith("data:")&&ty(f)>ve)throw new D("maxContentLength size of "+ve+" exceeded",D.ERR_BAD_RESPONSE,c,x);if($t&&p!=="get"&&p!=="head"){const j=await k(J,w);if(typeof j=="number"&&isFinite(j)&&j>Bt)throw new D("Request body larger than maxBodyLength limit",D.ERR_BAD_REQUEST,c,x)}if(B&&y&&p!=="get"&&p!=="head"&&(W=await k(J,w))!==0){let j=new l(f,{method:"POST",body:w,duplex:"half"}),Re;if(h.isFormData(w)&&(Re=j.headers.get("content-type"))&&J.setContentType(Re),j.body){const[oe,wt]=ea(W,Uo(ta(B)));w=ra(j.body,oa,oe,wt)}}h.isString(je)||(je=je?"include":"omit");const Q=u&&"credentials"in l.prototype;if(h.isFormData(w)){const j=J.getContentType();j&&/^multipart\/form-data/i.test(j)&&!/boundary=/i.test(j)&&J.delete("content-type")}J.set("User-Agent","axios/"+Is,!1);const te={..._e,signal:C,method:p.toUpperCase(),headers:Lf(J.normalize()),body:w,duplex:"half",credentials:Q?je:void 0};x=u&&new l(f,te);let se=await(u?g(x,_e):g(f,te));if(Ge){const j=h.toFiniteNumber(se.headers.get("content-length"));if(j!=null&&j>ve)throw new D("maxContentLength size of "+ve+" exceeded",D.ERR_BAD_RESPONSE,c,x)}const Ce=E&&(z==="stream"||z==="response");if(E&&se.body&&(L||Ge||Ce&&I)){const j={};["status","statusText","headers"].forEach(Un=>{j[Un]=se[Un]});const Re=h.toFiniteNumber(se.headers.get("content-length")),[oe,wt]=L&&ea(Re,Uo(ta(L),!0))||[];let js=0;const Vf=Un=>{if(Ge&&(js=Un,js>ve))throw new D("maxContentLength size of "+ve+" exceeded",D.ERR_BAD_RESPONSE,c,x);oe&&oe(Un)};se=new i(ra(se.body,oa,Vf,()=>{wt&&wt(),I&&I()}),j)}z=z||"text";let de=await S[h.findKey(S,z)||"text"](se,c);if(Ge&&!E&&!Ce){let j;if(de!=null&&(typeof de.byteLength=="number"?j=de.byteLength:typeof de.size=="number"?j=de.size:typeof de=="string"&&(j=typeof r=="function"?new r().encode(de).byteLength:de.length)),typeof j=="number"&&j>ve)throw new D("maxContentLength size of "+ve+" exceeded",D.ERR_BAD_RESPONSE,c,x)}return!Ce&&I&&I(),await new Promise((j,Re)=>{Uf(j,Re,{data:de,headers:Qe.from(se.headers),status:se.status,statusText:se.statusText,config:c,request:x})})}catch(Q){if(I&&I(),C&&C.aborted&&C.reason instanceof D){const te=C.reason;throw te.config=c,x&&(te.request=x),Q!==te&&(te.cause=Q),te}throw Q&&Q.name==="TypeError"&&/Load failed|fetch/i.test(Q.message)?Object.assign(new D("Network Error",D.ERR_NETWORK,c,x,Q&&Q.response),{cause:Q.cause||Q}):D.from(Q,Q&&Q.code,c,x,Q&&Q.response)}}},ry=new Map,Bf=e=>{let t=e&&e.env||{};const{fetch:n,Request:r,Response:o}=t,l=[r,o,n];let i=l.length,s=i,u,a,d=ry;for(;s--;)u=l[s],a=d.get(u),a===void 0&&d.set(u,a=s?new Map:ny(t)),d=a;return a};Bf();const Us={http:Sm,xhr:Xm,fetch:{get:Bf}};h.forEach(Us,(e,t)=>{if(e){try{Object.defineProperty(e,"name",{__proto__:null,value:t})}catch{}Object.defineProperty(e,"adapterName",{__proto__:null,value:t})}});const ia=e=>`- ${e}`,oy=e=>h.isFunction(e)||e===null||e===!1;function ly(e,t){e=h.isArray(e)?e:[e];const{length:n}=e;let r,o;const l={};for(let i=0;i`adapter ${u} `+(a===!1?"is not supported by the environment":"is not available in the build"));let s=n?i.length>1?`since : +`+i.map(ia).join(` +`):" "+ia(i[0]):"as no adapter specified";throw new D("There is no suitable adapter to dispatch the request "+s,"ERR_NOT_SUPPORT")}return o}const $f={getAdapter:ly,adapters:Us};function Ul(e){if(e.cancelToken&&e.cancelToken.throwIfRequested(),e.signal&&e.signal.aborted)throw new Lr(null,e)}function sa(e){return Ul(e),e.headers=Qe.from(e.headers),e.data=Il.call(e,e.transformRequest),["post","put","patch"].indexOf(e.method)!==-1&&e.headers.setContentType("application/x-www-form-urlencoded",!1),$f.getAdapter(e.adapter||Fs.adapter,e)(e).then(function(r){Ul(e),e.response=r;try{r.data=Il.call(e,e.transformResponse,r)}finally{delete e.response}return r.headers=Qe.from(r.headers),r},function(r){if(!If(r)&&(Ul(e),r&&r.response)){e.response=r.response;try{r.response.data=Il.call(e,e.transformResponse,r.response)}finally{delete e.response}r.response.headers=Qe.from(r.response.headers)}return Promise.reject(r)})}const sl={};["object","boolean","number","function","string","symbol"].forEach((e,t)=>{sl[e]=function(r){return typeof r===e||"a"+(t<1?"n ":" ")+e}});const ua={};sl.transitional=function(t,n,r){function o(l,i){return"[Axios v"+Is+"] Transitional option '"+l+"'"+i+(r?". "+r:"")}return(l,i,s)=>{if(t===!1)throw new D(o(i," has been removed"+(n?" in "+n:"")),D.ERR_DEPRECATED);return n&&!ua[i]&&(ua[i]=!0,console.warn(o(i," has been deprecated since v"+n+" and will be removed in the near future"))),t?t(l,i,s):!0}};sl.spelling=function(t){return(n,r)=>(console.warn(`${r} is likely a misspelling of ${t}`),!0)};function iy(e,t,n){if(typeof e!="object")throw new D("options must be an object",D.ERR_BAD_OPTION_VALUE);const r=Object.keys(e);let o=r.length;for(;o-- >0;){const l=r[o],i=Object.prototype.hasOwnProperty.call(t,l)?t[l]:void 0;if(i){const s=e[l],u=s===void 0||i(s,l,e);if(u!==!0)throw new D("option "+l+" must be "+u,D.ERR_BAD_OPTION_VALUE);continue}if(n!==!0)throw new D("Unknown option "+l,D.ERR_BAD_OPTION)}}const co={assertOptions:iy,validators:sl},Be=co.validators;class Mo{constructor(t){this.defaults=t||{},this.interceptors={request:new bu,response:new bu}}async request(t,n){try{return await this._request(t,n)}catch(r){if(r instanceof Error){let o={};Error.captureStackTrace?Error.captureStackTrace(o):o=new Error;const l=(()=>{if(!o.stack)return"";const i=o.stack.indexOf(` +`);return i===-1?"":o.stack.slice(i+1)})();try{if(!r.stack)r.stack=l;else if(l){const i=l.indexOf(` +`),s=i===-1?-1:l.indexOf(` +`,i+1),u=s===-1?"":l.slice(s+1);String(r.stack).endsWith(u)||(r.stack+=` +`+l)}}catch{}}throw r}}_request(t,n){typeof t=="string"?(n=n||{},n.url=t):n=t||{},n=tn(this.defaults,n);const{transitional:r,paramsSerializer:o,headers:l}=n;r!==void 0&&co.assertOptions(r,{silentJSONParsing:Be.transitional(Be.boolean),forcedJSONParsing:Be.transitional(Be.boolean),clarifyTimeoutError:Be.transitional(Be.boolean),legacyInterceptorReqResOrdering:Be.transitional(Be.boolean)},!1),o!=null&&(h.isFunction(o)?n.paramsSerializer={serialize:o}:co.assertOptions(o,{encode:Be.function,serialize:Be.function},!0)),n.allowAbsoluteUrls!==void 0||(this.defaults.allowAbsoluteUrls!==void 0?n.allowAbsoluteUrls=this.defaults.allowAbsoluteUrls:n.allowAbsoluteUrls=!0),co.assertOptions(n,{baseUrl:Be.spelling("baseURL"),withXsrfToken:Be.spelling("withXSRFToken")},!0),n.method=(n.method||this.defaults.method||"get").toLowerCase();let i=l&&h.merge(l.common,l[n.method]);l&&h.forEach(["delete","get","head","post","put","patch","query","common"],S=>{delete l[S]}),n.headers=Qe.concat(i,l);const s=[];let u=!0;this.interceptors.request.forEach(function(v){if(typeof v.runWhen=="function"&&v.runWhen(n)===!1)return;u=u&&v.synchronous;const k=n.transitional||Ds;k&&k.legacyInterceptorReqResOrdering?s.unshift(v.fulfilled,v.rejected):s.push(v.fulfilled,v.rejected)});const a=[];this.interceptors.response.forEach(function(v){a.push(v.fulfilled,v.rejected)});let d,m=0,y;if(!u){const S=[sa.bind(this),void 0];for(S.unshift(...s),S.push(...a),y=S.length,d=Promise.resolve(n);m {if(!r._listeners)return;let l=r._listeners.length;for(;l-- >0;)r._listeners[l](o);r._listeners=null}),this.promise.then=o=>{let l;const i=new Promise(s=>{r.subscribe(s),l=s}).then(o);return i.cancel=function(){r.unsubscribe(l)},i},t(function(l,i,s){r.reason||(r.reason=new Lr(l,i,s),n(r.reason))})}throwIfRequested(){if(this.reason)throw this.reason}subscribe(t){if(this.reason){t(this.reason);return}this._listeners?this._listeners.push(t):this._listeners=[t]}unsubscribe(t){if(!this._listeners)return;const n=this._listeners.indexOf(t);n!==-1&&this._listeners.splice(n,1)}toAbortSignal(){const t=new AbortController,n=r=>{t.abort(r)};return this.subscribe(n),t.signal.unsubscribe=()=>this.unsubscribe(n),t.signal}static source(){let t;return{token:new Ms(function(o){t=o}),cancel:t}}}const sy=Ms;function uy(e){return function(n){return e.apply(null,n)}}function ay(e){return h.isObject(e)&&e.isAxiosError===!0}const Fi={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511,WebServerIsDown:521,ConnectionTimedOut:522,OriginIsUnreachable:523,TimeoutOccurred:524,SslHandshakeFailed:525,InvalidSslCertificate:526};Object.entries(Fi).forEach(([e,t])=>{Fi[t]=e});const cy=Fi;function Hf(e){const t=new fo(e),n=Nf(fo.prototype.request,t);return h.extend(n,fo.prototype,t,{allOwnKeys:!0}),h.extend(n,t,null,{allOwnKeys:!0}),n.create=function(o){return Hf(tn(e,o))},n}const ee=Hf(Fs);ee.Axios=fo;ee.CanceledError=Lr;ee.CancelToken=sy;ee.isCancel=If;ee.VERSION=Is;ee.toFormData=il;ee.AxiosError=D;ee.Cancel=ee.CanceledError;ee.all=function(t){return Promise.all(t)};ee.spread=uy;ee.isAxiosError=ay;ee.mergeConfig=tn;ee.AxiosHeaders=Qe;ee.formToJSON=e=>Ff(h.isHTMLForm(e)?new FormData(e):e);ee.getAdapter=$f.getAdapter;ee.HttpStatusCode=cy;ee.default=ee;const Je=ee;function fy(){const[e,t]=we.useState(""),[n,r]=we.useState(null),[o,l]=we.useState([]),[i,s]=we.useState(!1),[u,a]=we.useState(null),[d,m]=we.useState([]),[y,E]=we.useState(!1),[S,v]=we.useState({enabled:!1,triggers:{onGrab:!1,onDownload:!1,onImport:!1,onUpgrade:!1},stats:null}),[k,c]=we.useState({enabled:!1,triggers:{onGrab:!1,onDownload:!1,onImport:!1,onUpgrade:!1},stats:null}),[f,p]=we.useState(null),[w,_]=we.useState(!1);we.useEffect(()=>{O(),_e()},[]);const O=async()=>{try{const g=await Je.get("/api/emby/sessions");m(g.data);const C=g.data.find(x=>x.NowPlayingItem||x.Active);C&&(t(C.Id),P(C.Id))}catch(g){a("Failed to fetch Emby sessions. Make sure Emby is running and configured."),console.error(g)}},P=async g=>{s(!0),a(null);try{const C=await Je.get(`/api/dashboard/user-downloads/${g}`);r(C.data.user),l(C.data.downloads)}catch(C){a("Failed to fetch downloads. Make sure all services are configured."),console.error(C)}finally{s(!1)}},L=g=>{const C=g.target.value;t(C),C&&P(C)},B=g=>{if(!g)return"N/A";const C=["B","KB","MB","GB","TB"],x=Math.floor(Math.log(g)/Math.log(1024));return Math.round(g/Math.pow(1024,x)*100)/100+" "+C[x]},z=g=>g?new Date(g).toLocaleString():"N/A",J=g=>{if(!g)return"Never";const C=Math.floor((Date.now()-g)/1e3);if(C<60)return`${C}s ago`;const x=Math.floor(C/60);if(x<60)return`${x}m ago`;const I=Math.floor(x/60);return I<24?`${I}h ago`:`${Math.floor(I/24)}d ago`},je=async()=>{try{const g=await Je.get("/api/dashboard/webhook-metrics");return p(g.data),g.data}catch{return null}},_e=async()=>{var g,C;try{const x=je();let I=!1,W={onGrab:!1,onDownload:!1,onImport:!1,onUpgrade:!1};try{const oe=(await Je.get("/api/sonarr/notifications")).data.find(wt=>wt.name==="Sofarr");I=!!oe,oe&&(W={onGrab:oe.onGrab,onDownload:oe.onDownload,onImport:oe.onImport,onUpgrade:oe.onUpgrade})}catch{}let Q=!1,te={onGrab:!1,onDownload:!1,onImport:!1,onUpgrade:!1};try{const oe=(await Je.get("/api/radarr/notifications")).data.find(wt=>wt.name==="Sofarr");Q=!!oe,oe&&(te={onGrab:oe.onGrab,onDownload:oe.onDownload,onImport:oe.onImport,onUpgrade:oe.onUpgrade})}catch{}const se=await x,Ce=se?Object.entries(se.instances||{}):[],de=((g=Ce.find(([Re])=>Re.includes("sonarr")))==null?void 0:g[1])||null,j=((C=Ce.find(([Re])=>Re.includes("radarr")))==null?void 0:C[1])||null;v({enabled:I,triggers:W,stats:de}),c({enabled:Q,triggers:te,stats:j})}catch(x){console.error("Failed to fetch webhook status:",x)}},ve=async()=>{_(!0);try{await Je.post("/api/sonarr/notifications/sofarr-webhook"),await _e()}catch(g){console.error("Failed to enable Sonarr webhook:",g),alert("Failed to enable Sonarr webhook. Check console for details.")}finally{_(!1)}},Bt=async()=>{_(!0);try{await Je.post("/api/radarr/notifications/sofarr-webhook"),await _e()}catch(g){console.error("Failed to enable Radarr webhook:",g),alert("Failed to enable Radarr webhook. Check console for details.")}finally{_(!1)}},Ge=async()=>{_(!0);try{const C=(await Je.get("/api/sonarr/notifications")).data.find(x=>x.name==="Sofarr");C?(await Je.post("/api/sonarr/notifications/test",{id:C.id}),await _e(),alert("Sonarr webhook test sent successfully!")):alert("Sofarr webhook not configured for Sonarr.")}catch(g){console.error("Failed to test Sonarr webhook:",g),alert("Failed to test Sonarr webhook. Check console for details.")}finally{_(!1)}},$t=async()=>{_(!0);try{const C=(await Je.get("/api/radarr/notifications")).data.find(x=>x.name==="Sofarr");C?(await Je.post("/api/radarr/notifications/test",{id:C.id}),await _e(),alert("Radarr webhook test sent successfully!")):alert("Sofarr webhook not configured for Radarr.")}catch(g){console.error("Failed to test Radarr webhook:",g),alert("Failed to test Radarr webhook. Check console for details.")}finally{_(!1)}};return A("div",{className:"app",children:[A("header",{className:"app-header",children:[R("h1",{children:"Media Download Dashboard"}),n&&A("div",{className:"user-info",children:[R("span",{className:"user-label",children:"Current User:"}),R("span",{className:"user-name",children:n})]})]}),A("div",{className:"controls",children:[R("label",{htmlFor:"session-select",children:"Select Emby Session:"}),A("select",{id:"session-select",value:e,onChange:L,className:"session-select",children:[R("option",{value:"",children:"-- Select Session --"}),d.map(g=>A("option",{value:g.Id,children:[g.UserName," - ",g.Client," ",g.NowPlayingItem?`(Playing: ${g.NowPlayingItem.Name})`:"(Idle)"]},g.Id))]}),R("button",{onClick:O,className:"refresh-btn",children:"Refresh Sessions"})]}),u&&R("div",{className:"error-message",children:u}),i&&R("div",{className:"loading",children:"Loading downloads..."}),!i&&!u&&A("div",{className:"downloads-container",children:[R("h2",{children:"Your Downloads"}),o.length===0?A("div",{className:"no-downloads",children:[R("p",{children:"No downloads found for your user."}),R("p",{children:'Make sure your shows and movies are tagged with "user:yourusername" in Sonarr/Radarr.'})]}):R("div",{className:"downloads-list",children:o.map((g,C)=>A("div",{className:`download-card ${g.type}`,children:[g.coverArt&&R("div",{className:"download-cover",children:R("img",{src:g.coverArt,alt:g.movieName||g.seriesName||g.title})}),A("div",{className:"download-info",children:[A("div",{className:"download-header",children:[R("span",{className:`download-type ${g.type}`,children:g.type==="series"?"📺 Series":"🎬 Movie"}),R("span",{className:`download-status ${g.status}`,children:g.status})]}),R("h3",{className:"download-title",children:g.title}),g.seriesName&&A("p",{className:"download-series",children:["Series: ",g.seriesName]}),g.movieName&&A("p",{className:"download-movie",children:["Movie: ",g.movieName]}),A("div",{className:"download-details",children:[A("div",{className:"detail-item",children:[R("span",{className:"detail-label",children:"Size:"}),R("span",{className:"detail-value",children:B(g.size)})]}),g.progress&&A("div",{className:"detail-item",children:[R("span",{className:"detail-label",children:"Progress:"}),A("span",{className:"detail-value",children:[g.progress,"%"]})]}),g.speed&&A("div",{className:"detail-item",children:[R("span",{className:"detail-label",children:"Speed:"}),R("span",{className:"detail-value",children:g.speed})]}),g.eta&&A("div",{className:"detail-item",children:[R("span",{className:"detail-label",children:"ETA:"}),R("span",{className:"detail-value",children:g.eta})]}),g.completedAt&&A("div",{className:"detail-item",children:[R("span",{className:"detail-label",children:"Completed:"}),R("span",{className:"detail-value",children:z(g.completedAt)})]})]})]})]},C))})]}),A("div",{className:"webhooks-section",children:[A("div",{className:"webhooks-header",onClick:()=>E(!y),children:[R("h2",{children:"⚡ Webhooks Configuration"}),R("span",{className:`webhooks-toggle ${y?"expanded":""}`,children:"▼"})]}),y&&A("div",{className:"webhooks-content",children:[w&&R("div",{className:"loading",children:"Loading webhook status..."}),A("div",{className:"webhook-instance",children:[R("h3",{children:"Sonarr"}),A("div",{className:"webhook-status",children:[R("span",{className:`status-indicator ${S.enabled?"enabled":"disabled"}`,children:S.enabled?"● Enabled":"○ Disabled"}),!S.enabled&&R("button",{onClick:ve,className:"enable-webhook-btn",disabled:w,children:"Enable Sofarr Webhooks"}),S.enabled&&R("button",{onClick:Ge,className:"test-webhook-btn",disabled:w,children:"Test"})]}),S.enabled&&A("div",{className:"webhook-triggers",children:[A("div",{className:"trigger-item",children:[R("span",{className:"trigger-label",children:"On Grab"}),R("span",{className:`trigger-value ${S.triggers.onGrab?"active":"inactive"}`,children:S.triggers.onGrab?"✓":"✗"})]}),A("div",{className:"trigger-item",children:[R("span",{className:"trigger-label",children:"On Download"}),R("span",{className:`trigger-value ${S.triggers.onDownload?"active":"inactive"}`,children:S.triggers.onDownload?"✓":"✗"})]}),A("div",{className:"trigger-item",children:[R("span",{className:"trigger-label",children:"On Import"}),R("span",{className:`trigger-value ${S.triggers.onImport?"active":"inactive"}`,children:S.triggers.onImport?"✓":"✗"})]}),A("div",{className:"trigger-item",children:[R("span",{className:"trigger-label",children:"On Upgrade"}),R("span",{className:`trigger-value ${S.triggers.onUpgrade?"active":"inactive"}`,children:S.triggers.onUpgrade?"✓":"✗"})]})]}),S.stats&&A("div",{className:"webhook-stats",children:[R("div",{className:"webhook-stats-title",children:"Statistics"}),A("div",{className:"webhook-stats-grid",children:[A("div",{className:"webhook-stat",children:[R("span",{className:"webhook-stat-label",children:"Events Received"}),R("span",{className:"webhook-stat-value",children:S.stats.eventsReceived??0})]}),A("div",{className:"webhook-stat",children:[R("span",{className:"webhook-stat-label",children:"Polls Skipped"}),R("span",{className:"webhook-stat-value",children:S.stats.pollsSkipped??0})]}),A("div",{className:"webhook-stat",children:[R("span",{className:"webhook-stat-label",children:"Last Event"}),R("span",{className:"webhook-stat-value",children:J(S.stats.lastWebhookTimestamp)})]})]})]})]}),A("div",{className:"webhook-instance",children:[R("h3",{children:"Radarr"}),A("div",{className:"webhook-status",children:[R("span",{className:`status-indicator ${k.enabled?"enabled":"disabled"}`,children:k.enabled?"● Enabled":"○ Disabled"}),!k.enabled&&R("button",{onClick:Bt,className:"enable-webhook-btn",disabled:w,children:"Enable Sofarr Webhooks"}),k.enabled&&R("button",{onClick:$t,className:"test-webhook-btn",disabled:w,children:"Test"})]}),k.enabled&&A("div",{className:"webhook-triggers",children:[A("div",{className:"trigger-item",children:[R("span",{className:"trigger-label",children:"On Grab"}),R("span",{className:`trigger-value ${k.triggers.onGrab?"active":"inactive"}`,children:k.triggers.onGrab?"✓":"✗"})]}),A("div",{className:"trigger-item",children:[R("span",{className:"trigger-label",children:"On Download"}),R("span",{className:`trigger-value ${k.triggers.onDownload?"active":"inactive"}`,children:k.triggers.onDownload?"✓":"✗"})]}),A("div",{className:"trigger-item",children:[R("span",{className:"trigger-label",children:"On Import"}),R("span",{className:`trigger-value ${k.triggers.onImport?"active":"inactive"}`,children:k.triggers.onImport?"✓":"✗"})]}),A("div",{className:"trigger-item",children:[R("span",{className:"trigger-label",children:"On Upgrade"}),R("span",{className:`trigger-value ${k.triggers.onUpgrade?"active":"inactive"}`,children:k.triggers.onUpgrade?"✓":"✗"})]})]}),k.stats&&A("div",{className:"webhook-stats",children:[R("div",{className:"webhook-stats-title",children:"Statistics"}),A("div",{className:"webhook-stats-grid",children:[A("div",{className:"webhook-stat",children:[R("span",{className:"webhook-stat-label",children:"Events Received"}),R("span",{className:"webhook-stat-value",children:k.stats.eventsReceived??0})]}),A("div",{className:"webhook-stat",children:[R("span",{className:"webhook-stat-label",children:"Polls Skipped"}),R("span",{className:"webhook-stat-value",children:k.stats.pollsSkipped??0})]}),A("div",{className:"webhook-stat",children:[R("span",{className:"webhook-stat-label",children:"Last Event"}),R("span",{className:"webhook-stat-value",children:J(k.stats.lastWebhookTimestamp)})]})]})]})]})]})]}),R("footer",{className:"app-footer",children:R("p",{children:'Ensure your media is tagged with "user:username" in Sonarr/Radarr to match downloads to users.'})})]})}Ml.createRoot(document.getElementById("root")).render(R(id.StrictMode,{children:R(fy,{})})); diff --git a/public/index.html b/public/index.html index 68f1457..02a2df5 100644 --- a/public/index.html +++ b/public/index.html @@ -1,126 +1,14 @@ - - - - sofarr - Your Downloads Dashboard - - - - + + + +Media Download Dashboard + - - - --- --
- - - - - -- - - + + + + + diff --git a/public/style.css b/public/style.css index 622fe4f..8aacd85 100644 --- a/public/style.css +++ b/public/style.css @@ -1,1518 +1 @@ -/* ===== Splash Screen ===== */ -.splash-screen { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - display: flex; - align-items: center; - justify-content: center; - background: #f8f9fa; - z-index: 9999; - opacity: 1; - transition: opacity 0.4s ease-out; -} - -.splash-screen.fade-out { - opacity: 0; -} - -.splash-logo { - max-width: 280px; - width: 60%; - animation: splashPulse 1.8s ease-in-out infinite; -} - -@keyframes splashPulse { - 0%, 100% { transform: scale(1); opacity: 1; } - 50% { transform: scale(1.03); opacity: 0.85; } -} - -/* ===== Theme Variables ===== */ -:root, [data-theme="light"] { - /* Page background — clean off-white matching logo backdrop */ - --bg-gradient-start: #e8eef3; - --bg-gradient-end: #d4dee8; - - /* Surfaces */ - --surface: #ffffff; - --surface-alt: #f0f4f7; - - /* Typography — charcoal from logo, all meet WCAG AA on white */ - --text-primary: #2b2f33; /* ~14:1 on white */ - --text-secondary: #4d5760; /* ~7.5:1 on white */ - --text-muted: #6b7784; /* ~4.6:1 on white — AA compliant */ - - /* Borders */ - --border: #c8d3db; - - /* Accent — primary teal from couch outline */ - --accent: #1f7d94; /* ~4.6:1 on white — AA compliant */ - --accent-hover: #165f70; /* darker for hover */ - --accent-light: #e0f0f4; /* very light teal tint for backgrounds */ - - /* Series — steel blue from sofa body */ - --series-color: #1e6b8a; /* ~5.0:1 on white — AA */ - --series-bg: #dceef5; - - /* Movie — warm coral (complementary to teal, accessible) */ - --movie-color: #b5451b; /* ~5.5:1 on white — AA */ - --movie-bg: #fdeee8; - - /* Torrent — mid teal-green */ - --torrent-color: #1a7a6e; /* ~4.7:1 on white — AA */ - --torrent-bg: #ddf2ef; - - /* State colours */ - --success: #2e7d32; /* ~7.1:1 on white — AA */ - --success-bg: #e8f5e9; - --info: #1565c0; /* ~7.3:1 on white — AA */ - --info-bg: #e3f0fb; - --danger: #c62828; /* ~6.5:1 on white — AA */ - --danger-bg: #fdecea; - --danger-border: #f5c6c2; - - /* Progress bar */ - --progress-bg: #eaf2f5; - --progress-border: #c8d3db; - --progress-fill-start: #1f7d94; - --progress-fill-end: #2da0bc; - - /* Shadows */ - --shadow: rgba(30, 60, 80, 0.10); - --shadow-strong: rgba(30, 60, 80, 0.18); - - /* Footer — dark text on light page background */ - --footer-text: #4d5760; - - /* Inputs */ - --input-bg: #ffffff; - --select-bg: #ffffff; - - /* Unmatched tag — amber, accessible on its bg */ - --unmatched-tag-bg: #fff3e0; - --unmatched-tag-color: #7a4000; /* ~7.1:1 on #fff3e0 — AA */ -} - -[data-theme="dark"] { - --bg-gradient-start: #1a1a2e; - --bg-gradient-end: #16213e; - --surface: #1e1e2f; - --surface-alt: #2a2a3d; - --text-primary: #e0e0e0; - --text-secondary: #a0a0b0; - --text-muted: #707080; - --border: #3a3a4d; - --accent: #7c8cf0; - --accent-hover: #6b7ce0; - --accent-light: #2a2a4d; - --series-color: #7c8cf0; - --series-bg: #2a2a4d; - --movie-color: #f080c0; - --movie-bg: #3d2035; - --torrent-color: #4dd0c8; - --torrent-bg: #1a3d3a; - --success: #66bb6a; - --success-bg: #1a3d1e; - --info: #64b5f6; - --info-bg: #1a2d3d; - --danger: #ef5350; - --danger-bg: #3d1a1a; - --danger-border: #5a2a2a; - --progress-bg: #2a2020; - --progress-border: #4a3030; - --progress-fill-start: #66bb6a; - --progress-fill-end: #81c784; - --shadow: rgba(0, 0, 0, 0.3); - --shadow-strong: rgba(0, 0, 0, 0.4); - --footer-text: rgba(200, 200, 220, 0.8); - --input-bg: #2a2a3d; - --select-bg: #2a2a3d; - --unmatched-tag-bg: #3d2a00; - --unmatched-tag-color: #ffb74d; -} - -[data-theme="mono"] { - --bg-gradient-start: #222222; - --bg-gradient-end: #333333; - --surface: #1a1a1a; - --surface-alt: #252525; - --text-primary: #d0d0d0; - --text-secondary: #909090; - --text-muted: #606060; - --border: #404040; - --accent: #b0b0b0; - --accent-hover: #c8c8c8; - --accent-light: #303030; - --series-color: #c0c0c0; - --series-bg: #303030; - --movie-color: #c0c0c0; - --movie-bg: #303030; - --torrent-color: #c0c0c0; - --torrent-bg: #303030; - --success: #a0a0a0; - --success-bg: #2a2a2a; - --info: #a0a0a0; - --info-bg: #2a2a2a; - --danger: #909090; - --danger-bg: #2a2a2a; - --danger-border: #484848; - --progress-bg: #2a2a2a; - --progress-border: #404040; - --progress-fill-start: #808080; - --progress-fill-end: #a0a0a0; - --shadow: rgba(0, 0, 0, 0.4); - --shadow-strong: rgba(0, 0, 0, 0.5); - --footer-text: rgba(180, 180, 180, 0.7); - --input-bg: #252525; - --select-bg: #252525; - --unmatched-tag-bg: #2a2a2a; - --unmatched-tag-color: #a0a0a0; -} - -/* ===== Base ===== */ -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -body { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - background: linear-gradient(135deg, var(--bg-gradient-start) 0%, var(--bg-gradient-end) 100%); - min-height: 100vh; - transition: background 0.3s; -} - -.app { - min-height: 100vh; - padding: 16px; - max-width: 1200px; - margin: 0 auto; -} - -/* ===== Header ===== */ -.app-header { - background: var(--surface); - padding: 14px 20px; - border-radius: 8px; - box-shadow: 0 2px 4px var(--shadow); - margin-bottom: 12px; - display: flex; - justify-content: space-between; - align-items: center; - flex-wrap: wrap; - gap: 12px; - transition: background 0.3s; -} - -.app-header h1 { - color: var(--text-primary); - font-size: 1.4rem; -} - -.header-controls { - display: flex; - align-items: center; - gap: 14px; -} - -.user-info { - display: flex; - align-items: center; - gap: 8px; - background: var(--surface-alt); - padding: 6px 14px; - border-radius: 16px; - font-size: 0.85rem; -} - -.user-label { - color: var(--text-muted); - font-weight: 500; -} - -.user-name { - color: var(--accent); - font-weight: bold; - font-size: 0.9rem; -} - -.logout-btn { - padding: 4px 12px; - background: var(--danger); - color: white; - border: none; - border-radius: 4px; - cursor: pointer; - font-size: 0.8rem; - transition: opacity 0.2s; -} - -.logout-btn:hover { - opacity: 0.85; -} - -/* ===== Theme Switcher ===== */ -.theme-switcher { - display: flex; - align-items: center; - gap: 4px; - background: var(--surface-alt); - padding: 3px; - border-radius: 16px; -} - -.theme-btn { - padding: 4px 10px; - border: none; - border-radius: 14px; - cursor: pointer; - font-size: 0.75rem; - background: transparent; - color: var(--text-muted); - transition: all 0.2s; -} - -.theme-btn.active { - background: var(--accent); - color: white; -} - -.theme-btn:hover:not(.active) { - color: var(--text-primary); -} - -/* ===== Refresh Control ===== */ -.refresh-control { - display: flex; - align-items: center; - gap: 6px; -} - -.refresh-control label { - color: var(--text-muted); - font-size: 0.8rem; -} - -.refresh-control select { - padding: 4px 8px; - border: 1px solid var(--border); - border-radius: 4px; - background: var(--select-bg); - color: var(--text-primary); - cursor: pointer; - font-size: 0.8rem; -} - -/* ===== Error / Loading ===== */ -.error-message { - background: var(--danger-bg); - color: var(--danger); - padding: 10px 14px; - border-radius: 6px; - margin-bottom: 12px; - border-left: 3px solid var(--danger); - font-size: 0.9rem; -} - -.loading { - text-align: center; - padding: 30px; - color: var(--footer-text); - font-size: 1rem; -} - -/* ===== Downloads Container ===== */ -.downloads-container { - background: var(--surface); - padding: 16px 20px; - border-radius: 8px; - box-shadow: 0 2px 4px var(--shadow); - transition: background 0.3s; -} - -.downloads-container h2 { - color: var(--text-primary); - margin-bottom: 12px; - font-size: 1.1rem; -} - -.no-downloads { - text-align: center; - padding: 30px; - color: var(--text-secondary); - font-size: 0.9rem; -} - -.no-downloads p { - margin: 6px 0; -} - -.downloads-list { - display: flex; - flex-direction: column; - gap: 8px; -} - -/* ===== Download Card (Compact) ===== */ -.download-card { - border: 1px solid var(--border); - border-radius: 6px; - padding: 10px 14px; - display: flex; - gap: 12px; - align-items: flex-start; - transition: box-shadow 0.2s, background 0.3s; - background: var(--surface); -} - -.download-card:hover { - box-shadow: 0 2px 8px var(--shadow); -} - -.download-card.series { - border-left: 3px solid var(--series-color); -} - -.download-card.movie { - border-left: 3px solid var(--movie-color); -} - -.download-card.torrent { - border-left: 3px solid var(--torrent-color); -} - -/* ===== Cover Art ===== */ -.download-cover { - flex-shrink: 0; - width: 50px; - border-radius: 4px; - overflow: hidden; - box-shadow: 0 1px 4px var(--shadow-strong); -} - -.download-cover img { - width: 100%; - height: auto; - display: block; -} - -/* ===== Download Info ===== */ -.download-info { - flex: 1; - min-width: 0; -} - -.download-header { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: 4px; - margin-bottom: 4px; -} - -.download-type { - padding: 2px 8px; - border-radius: 10px; - font-size: 0.7rem; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.3px; -} - -.download-type.series { - background: var(--series-bg); - color: var(--series-color); -} - -.download-type.movie { - background: var(--movie-bg); - color: var(--movie-color); -} - -.download-type.torrent { - background: var(--torrent-bg); - color: var(--torrent-color); -} - -.download-status { - padding: 2px 8px; - border-radius: 10px; - font-size: 0.7rem; - font-weight: 600; - text-transform: capitalize; -} - -.download-status.downloading, -.download-status.Downloading { - background: var(--success-bg); - color: var(--success); -} - -.download-status.completed, -.download-status.Completed { - background: var(--info-bg); - color: var(--info); -} - -.download-status.failed, -.download-status.Failed { - background: var(--danger-bg); - color: var(--danger); -} - -.download-title { - color: var(--text-primary); - margin-bottom: 2px; - font-size: 0.9rem; - font-weight: 600; - overflow-wrap: break-word; - word-break: break-word; - overflow: hidden; -} - -.download-series, -.download-movie { - color: var(--text-secondary); - margin-bottom: 6px; - font-style: italic; - font-size: 0.8rem; -} - -.episode-info { - color: var(--text-secondary); - font-size: 0.78rem; - margin: -2px 0 6px; -} - -.episode-info.multi-episode { - cursor: help; - text-decoration: underline dotted; - position: relative; -} - -.episode-info.multi-episode:hover::after { - content: attr(data-tooltip); - position: absolute; - left: 0; - top: 100%; - z-index: 20; - background: var(--surface); - color: var(--text-primary); - border: 1px solid var(--border); - border-radius: 6px; - padding: 8px 10px; - font-size: 0.75rem; - white-space: pre-line; - box-shadow: 0 4px 12px rgba(0,0,0,0.15); - max-width: 320px; - pointer-events: none; -} - -/* ===== Detail Row (Inline) ===== */ -.download-details { - display: flex; - flex-wrap: wrap; - gap: 4px 6px; - padding-top: 6px; - border-top: 1px solid var(--border); - align-items: center; -} - -.detail-item { - display: inline-flex; - align-items: baseline; - gap: 3px; - font-size: 0.78rem; - background: var(--bg-secondary, rgba(0,0,0,0.04)); - border-radius: 4px; - padding: 2px 6px; - white-space: nowrap; -} - -.detail-item.availability-warning .detail-value { - color: var(--danger, #e53e3e); - font-weight: 700; -} - -.detail-label { - color: var(--text-muted); - text-transform: uppercase; - letter-spacing: 0.3px; - font-size: 0.65rem; - font-weight: 600; -} - -.detail-value { - color: var(--text-primary); - font-weight: 500; -} - -/* ===== Progress Bar (Compact) ===== */ -.progress-item { - flex-basis: 100%; - display: flex; - align-items: center; - background: none; - padding: 0; - white-space: normal; - border-radius: 0; -} - -.progress-container { - display: flex; - flex: 1; - align-items: center; - gap: 8px; -} - -.progress-bar { - flex: 1; - height: 10px; - background: var(--progress-bg); - border-radius: 5px; - overflow: hidden; - position: relative; - border: 1px solid var(--progress-border); -} - -.progress-segment { - position: absolute; - top: 0; - left: 0; - height: 100%; - transition: width 0.3s ease; -} - -.progress-segment.downloaded { - background: linear-gradient(90deg, var(--progress-fill-start) 0%, var(--progress-fill-end) 100%); -} - -.progress-text { - font-weight: 600; - color: var(--text-primary); - font-size: 0.78rem; - white-space: nowrap; -} - -.missing-text { - color: var(--danger); - font-size: 0.72rem; - font-weight: 500; - overflow-wrap: break-word; - word-break: break-word; -} - -/* ===== Main Tabs ===== */ -.main-tabs { - max-width: 1200px; - margin: 16px auto 0; - padding: 0 16px; -} - -.tab-bar { - display: flex; - gap: 4px; - border-bottom: 2px solid var(--border); - margin-bottom: 0; -} - -.tab-btn { - background: none; - border: none; - border-bottom: 3px solid transparent; - margin-bottom: -2px; - padding: 10px 20px; - font-size: 0.95rem; - font-weight: 600; - color: var(--text-secondary); - cursor: pointer; - transition: color 0.2s, border-color 0.2s; - border-radius: 4px 4px 0 0; -} - -.tab-btn:hover { - color: var(--text-primary); - background: var(--surface); -} - -.tab-btn.active { - color: var(--accent); - border-bottom-color: var(--accent); - background: var(--surface); -} - -.tab-panel { - padding-top: 0; -} - -/* ===== Recently Completed History ===== */ -.history-container { - max-width: unset; - margin: 0; - padding: 0; -} - -.history-header { - display: flex; - align-items: center; - gap: 12px; - margin-bottom: 12px; - flex-wrap: wrap; -} - -.history-header h2 { - margin: 0; - font-size: 1.2rem; - color: var(--text-primary); - flex: 1 1 auto; -} - -.history-controls { - display: flex; - align-items: center; - gap: 6px; - flex-wrap: nowrap; -} - -.history-days-label { - font-size: 0.85rem; - color: var(--text-secondary); -} - -.history-days-input { - width: 52px; - padding: 3px 6px; - border: 1px solid var(--border); - border-radius: 4px; - background: var(--surface); - color: var(--text-primary); - font-size: 0.85rem; - text-align: center; -} - -.history-refresh-btn { - background: none; - border: 1px solid var(--border); - border-radius: 4px; - color: var(--text-secondary); - cursor: pointer; - font-size: 1rem; - padding: 2px 7px; - line-height: 1.4; - transition: background 0.15s, color 0.15s; -} - -.history-refresh-btn:hover { - background: var(--hover-bg); - color: var(--text-primary); -} - -.history-toggle-label { - display: inline-flex; - align-items: center; - gap: 5px; - font-size: 0.82rem; - color: var(--text-secondary); - cursor: pointer; - user-select: none; - margin-left: 4px; - position: relative; -} - -.history-toggle-label[data-tooltip]:hover::after { - content: attr(data-tooltip); - position: absolute; - left: 0; - top: calc(100% + 6px); - z-index: 20; - background: var(--surface); - color: var(--text-primary); - border: 1px solid var(--border); - border-radius: 6px; - padding: 8px 10px; - font-size: 0.75rem; - white-space: pre-line; - box-shadow: 0 4px 12px rgba(0,0,0,0.15); - max-width: 280px; - pointer-events: none; -} - -.history-toggle-label input[type="checkbox"] { - cursor: pointer; - accent-color: var(--accent, #2980b9); -} - -.history-loading, -.history-error, -.no-history { - color: var(--text-secondary); - font-size: 0.9rem; - padding: 8px 0; -} - -.history-error { - color: var(--error, #e74c3c); -} - -.history-list { - display: flex; - flex-direction: column; - gap: 8px; -} - -.history-card { - display: flex; - gap: 12px; - background: var(--surface); - border: 1px solid var(--border); - border-radius: 8px; - padding: 10px 12px; - transition: background 0.2s; - align-items: flex-start; -} - -.history-card.failed { - border-left: 3px solid var(--error, #e74c3c); -} - -.history-card.imported { - border-left: 3px solid var(--success, #27ae60); -} - -.history-cover { - flex: 0 0 48px; - width: 48px; -} - -.history-cover img { - width: 48px; - height: 68px; - object-fit: cover; - border-radius: 4px; - display: block; -} - -.history-info { - flex: 1 1 auto; - min-width: 0; -} - -.history-card-header { - display: flex; - flex-wrap: wrap; - gap: 5px; - align-items: center; - margin-bottom: 4px; -} - -.history-type-badge, -.history-outcome-badge, -.history-instance-badge, -.history-upgrade-badge { - font-size: 0.72rem; - font-weight: 600; - padding: 2px 7px; - border-radius: 10px; - white-space: nowrap; -} - -.history-upgrade-badge { - background: #e67e22; - color: #fff; - cursor: default; -} - -.history-type-badge.series { - background: var(--badge-series-bg, #2980b9); - color: #fff; -} - -.history-type-badge.movie { - background: var(--badge-movie-bg, #8e44ad); - color: #fff; -} - -.history-outcome-badge.imported { - background: var(--success, #27ae60); - color: #fff; -} - -.history-outcome-badge.failed { - background: var(--error, #e74c3c); - color: #fff; -} - -.history-instance-badge { - background: var(--tag-bg, #ecf0f1); - color: var(--text-secondary); - border: 1px solid var(--border); -} - -.history-title { - font-size: 0.9rem; - font-weight: 600; - margin: 0 0 2px; - color: var(--text-primary); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.history-media-name { - font-size: 0.82rem; - color: var(--text-secondary); - margin: 0 0 4px; -} - -.history-details { - display: flex; - flex-wrap: wrap; - gap: 5px; - margin-top: 4px; -} - -.history-failure-message { - font-size: 0.78rem; - color: var(--error, #e74c3c); - background: var(--error-bg, rgba(231, 76, 60, 0.08)); - border-radius: 4px; - padding: 3px 7px; - flex-basis: 100%; -} - -@media (max-width: 480px) { - .history-cover { - display: none; - } - .history-title { - white-space: normal; - } -} - -/* ===== Footer ===== */ -.app-footer { - margin-top: 12px; - text-align: center; - color: var(--footer-text); - font-size: 0.8rem; -} - -.app-footer p { - opacity: 0.8; -} - -.app-version { - font-size: 0.72rem; - opacity: 0.5; - margin-top: 4px; - color: inherit; - text-decoration: none; - display: inline-block; -} - -.app-version:hover { - opacity: 0.8; - text-decoration: underline; - text-underline-offset: 2px; -} - -.title-link { - color: inherit; - text-decoration: none; - display: inline-flex; - align-items: center; - gap: 8px; -} - -.title-link:hover { - text-decoration: underline; - text-underline-offset: 3px; -} - -.title-logo { - width: 56px; - height: 56px; - display: block; - flex-shrink: 0; -} - -/* ===== Login ===== */ -.login-container { - display: flex; - justify-content: center; - align-items: center; - min-height: 100vh; - padding: 20px; - opacity: 1; - transition: opacity 0.3s ease-out; -} - -.login-container.fade-out { - opacity: 0; -} - -.login-box { - background: var(--surface); - padding: 36px; - border-radius: 10px; - box-shadow: 0 4px 6px var(--shadow); - width: 100%; - max-width: 380px; - transition: background 0.3s; - text-align: center; -} - -.login-logo { - max-width: 180px; - width: 60%; - margin-bottom: 12px; -} - -.login-subtitle { - color: var(--text-secondary); - margin-bottom: 24px; - font-size: 0.85rem; -} - -.form-group { - margin-bottom: 16px; - text-align: left; -} - -.form-group label { - display: block; - color: var(--text-primary); - font-weight: 500; - margin-bottom: 6px; - font-size: 0.9rem; -} - -.form-group input { - width: 100%; - padding: 10px; - border: 1px solid var(--border); - border-radius: 4px; - font-size: 0.95rem; - background: var(--input-bg); - color: var(--text-primary); -} - -.form-group input:focus { - outline: none; - border-color: var(--accent); -} - -.form-group--checkbox { - margin-bottom: 20px; -} - -.checkbox-label { - display: flex; - align-items: center; - gap: 8px; - cursor: pointer; - font-size: 0.9rem; - color: var(--text-secondary); - user-select: none; -} - -.checkbox-label input[type="checkbox"] { - width: 16px; - height: 16px; - accent-color: var(--accent); - cursor: pointer; - flex-shrink: 0; -} - -.checkbox-label span { - line-height: 1; -} - -.login-btn { - width: 100%; - padding: 10px; - background: var(--accent); - color: white; - border: none; - border-radius: 5px; - cursor: pointer; - font-size: 0.95rem; - font-weight: 500; - transition: background 0.2s; -} - -.login-btn:hover { - background: var(--accent-hover); -} - -/* ===== Admin Controls ===== */ -.admin-controls { - display: flex; - align-items: center; -} - -.toggle-label { - display: flex; - align-items: center; - gap: 6px; - cursor: pointer; - font-size: 0.8rem; - color: var(--text-secondary); - background: var(--surface-alt); - padding: 4px 12px; - border-radius: 14px; -} - -.toggle-label input[type="checkbox"] { - width: 14px; - height: 14px; - cursor: pointer; - accent-color: var(--accent); -} - -/* ===== Arr Links (Admin) ===== */ -.arr-link { - color: var(--accent); - text-decoration: none; - border-bottom: 1px dotted var(--accent); -} - -.arr-link:hover { - opacity: 0.8; - border-bottom-style: solid; -} - -/* ===== Download Paths (Admin) ===== */ -.download-paths { - flex-basis: 100%; - display: flex; - flex-direction: column; - gap: 2px; - margin-top: 2px; -} - -.path-item { - font-size: 0.7rem; - font-family: 'SF Mono', 'Fira Code', 'Fira Mono', Menlo, Consolas, monospace; - color: var(--text-muted); - overflow-wrap: break-word; - word-break: break-all; - overflow: hidden; -} - -.path-label { - font-weight: 600; - color: var(--text-secondary); - font-size: 0.65rem; - text-transform: uppercase; - letter-spacing: 0.3px; -} - -.path-value { - color: var(--text-muted); -} - -/* ===== Import Issue Badge ===== */ -.import-issue-badge { - padding: 2px 8px; - border-radius: 10px; - font-size: 0.65rem; - font-weight: 600; - background: #ffebee; - color: #c62828; - cursor: help; - position: relative; - white-space: nowrap; -} - -.import-issue-badge:hover::after { - content: attr(data-tooltip); - position: absolute; - top: calc(100% + 6px); - left: 0; - z-index: 20; - background: var(--surface); - color: var(--text-primary); - border: 1px solid var(--border); - border-radius: 6px; - padding: 8px 10px; - font-size: 0.75rem; - font-weight: 400; - white-space: pre-line; - max-width: 320px; - box-shadow: 0 4px 12px rgba(0,0,0,0.15); - line-height: 1.4; - pointer-events: none; -} - -.blocklist-search-btn { - font-size: 0.68rem; - font-weight: 600; - padding: 2px 8px; - border-radius: 10px; - border: 1px solid var(--error, #e74c3c); - background: transparent; - color: var(--error, #e74c3c); - cursor: pointer; - white-space: nowrap; - transition: background 0.15s, color 0.15s; -} - -.blocklist-search-btn:hover:not(:disabled) { - background: var(--error, #e74c3c); - color: #fff; -} - -.blocklist-search-btn:disabled { - opacity: 0.6; - cursor: default; -} - -.blocklist-search-btn.success { - border-color: var(--success, #27ae60); - color: var(--success, #27ae60); -} - -.blocklist-search-btn.error { - background: var(--error, #e74c3c); - color: #fff; -} - -.download-user-badge { - padding: 2px 8px; - border-radius: 10px; - font-size: 0.65rem; - font-weight: 600; - text-transform: capitalize; - background: var(--accent-light); - color: var(--accent); - margin-left: auto; - white-space: nowrap; -} - -.download-user-badge.unmatched { - background: var(--unmatched-tag-bg); - color: var(--unmatched-tag-color); - margin-left: 0; -} - -/* ===== Status Button ===== */ -.status-btn { - padding: 4px 12px; - border: 1px solid var(--border); - border-radius: 5px; - background: var(--surface); - color: var(--text-secondary); - cursor: pointer; - font-size: 0.8rem; - font-weight: 500; - transition: background 0.2s, color 0.2s; -} - -.status-btn:hover { - background: var(--accent); - color: white; - border-color: var(--accent); -} - -/* ===== Status Panel ===== */ -.status-panel { - background: var(--surface); - border: 1px solid var(--border); - border-radius: 10px; - padding: 20px; - margin-bottom: 16px; - box-shadow: 0 2px 4px var(--shadow); -} - -.status-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 16px; -} - -.status-header h3 { - margin: 0; - color: var(--text-primary); - font-size: 1.1rem; -} - -.status-close { - background: none; - border: none; - font-size: 1.4rem; - color: var(--text-secondary); - cursor: pointer; - padding: 0 4px; - line-height: 1; -} - -.status-close:hover { - color: var(--text-primary); -} - -.status-grid { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 16px; -} - -.status-card { - background: var(--background); - border: 1px solid var(--border); - border-radius: 8px; - padding: 14px; -} - -.status-card-wide { - grid-column: 1 / -1; -} - -.status-card-title { - font-weight: 600; - font-size: 0.85rem; - color: var(--text-primary); - margin-bottom: 10px; - padding-bottom: 6px; - border-bottom: 1px solid var(--border); -} - -.status-row { - display: flex; - justify-content: space-between; - padding: 3px 0; - font-size: 0.8rem; - color: var(--text-secondary); -} - -.status-row span:last-child { - font-weight: 500; - color: var(--text-primary); -} - -.status-table { - width: 100%; - border-collapse: collapse; - font-size: 0.78rem; -} - -.status-table th { - text-align: left; - padding: 4px 8px; - color: var(--text-secondary); - font-weight: 600; - font-size: 0.7rem; - text-transform: uppercase; - letter-spacing: 0.3px; - border-bottom: 1px solid var(--border); -} - -.status-table td { - padding: 5px 8px; - color: var(--text-primary); - border-bottom: 1px solid var(--border); -} - -.status-table code { - font-size: 0.75rem; - background: var(--surface); - padding: 1px 4px; - border-radius: 3px; -} - -.status-expired { - color: #c62828; - font-weight: 600; - font-size: 0.7rem; -} - -.status-fg-badge { - background: #fff3e0; - color: #e65100; - padding: 1px 8px; - border-radius: 8px; - font-size: 0.75rem; - font-weight: 600; -} - -.status-row-sub { - padding-left: 12px; - font-size: 0.75rem; - opacity: 0.8; -} - -.status-row-sub span:first-child { - font-style: italic; -} - -.status-timings { - display: flex; - flex-direction: column; - gap: 6px; -} - -.timing-row { - display: flex; - align-items: center; - gap: 8px; - font-size: 0.78rem; -} - -.timing-label { - width: 110px; - flex-shrink: 0; - color: var(--text-secondary); - white-space: nowrap; -} - -.timing-bar-bg { - flex: 1; - height: 8px; - background: var(--border); - border-radius: 4px; - overflow: hidden; -} - -.timing-bar { - height: 100%; - background: var(--accent); - border-radius: 4px; - min-width: 2px; - transition: width 0.3s ease; -} - -.timing-value { - width: 50px; - flex-shrink: 0; - text-align: right; - color: var(--text-primary); - font-weight: 500; - font-size: 0.75rem; -} - -.status-loading, .status-error { - text-align: center; - padding: 20px; - color: var(--text-secondary); - font-size: 0.9rem; -} - -.status-error { - color: #c62828; -} - -/* ===== Mobile ===== */ -@media (max-width: 768px) { - .app { - padding: 10px; - } - - .app-header { - flex-direction: column; - align-items: flex-start; - padding: 10px 12px; - gap: 8px; - } - - .header-controls { - width: 100%; - flex-wrap: wrap; - gap: 8px; - } - - .user-info { - width: 100%; - justify-content: space-between; - box-sizing: border-box; - } - - .admin-controls { - width: 100%; - flex-wrap: wrap; - gap: 6px; - } - - .downloads-container { - padding: 12px; - } - - .download-card { - padding: 8px 10px; - } - - .download-cover { - width: 40px; - } - - .progress-container { - flex-wrap: wrap; - } - - .status-grid { - grid-template-columns: 1fr; - } - - .status-table { - font-size: 0.72rem; - } - - .status-table th, - .status-table td { - padding: 4px 4px; - } - - .status-table td code { - word-break: break-all; - } - - .timing-label { - width: 90px; - } - - .timing-value { - width: 40px; - } - - .import-issue-badge:hover::after { - left: auto; - right: 0; - max-width: calc(100vw - 24px); - } -} - -/* ===== Very small screens (≤ 400px) ===== */ -@media (max-width: 400px) { - .app { - padding: 6px; - } - - .download-cover { - display: none; - } - - .theme-switcher { - flex-shrink: 0; - } - - .user-info { - font-size: 0.78rem; - padding: 5px 10px; - } - - .download-card { - padding: 8px; - } - - .timing-label { - width: 75px; - font-size: 0.7rem; - } -} +*{margin:0;padding:0;box-sizing:border-box}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);min-height:100vh}.app{min-height:100vh;padding:20px;max-width:1200px;margin:0 auto}.app-header{background:white;padding:30px;border-radius:10px;box-shadow:0 4px 6px #0000001a;margin-bottom:20px;display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:20px}.app-header h1{color:#333;font-size:2rem}.user-info{display:flex;align-items:center;gap:10px;background:#f0f0f0;padding:10px 20px;border-radius:20px}.user-label{color:#666;font-weight:500}.user-name{color:#667eea;font-weight:700;font-size:1.1rem}.controls{background:white;padding:20px;border-radius:10px;box-shadow:0 4px 6px #0000001a;margin-bottom:20px;display:flex;gap:15px;align-items:center;flex-wrap:wrap}.controls label{color:#333;font-weight:500}.session-select{flex:1;min-width:200px;padding:10px;border:2px solid #e0e0e0;border-radius:5px;font-size:1rem;cursor:pointer}.session-select:focus{outline:none;border-color:#667eea}.refresh-btn{padding:10px 20px;background:#667eea;color:#fff;border:none;border-radius:5px;cursor:pointer;font-size:1rem;transition:background .3s}.refresh-btn:hover{background:#5568d3}.error-message{background:#fee;color:#c33;padding:15px;border-radius:10px;margin-bottom:20px;border-left:4px solid #c33}.loading{text-align:center;padding:40px;color:#fff;font-size:1.2rem}.downloads-container{background:white;padding:30px;border-radius:10px;box-shadow:0 4px 6px #0000001a}.downloads-container h2{color:#333;margin-bottom:20px;font-size:1.5rem}.no-downloads{text-align:center;padding:40px;color:#666}.no-downloads p{margin:10px 0}.downloads-list{display:grid;gap:20px}.download-card{border:2px solid #e0e0e0;border-radius:10px;padding:20px;transition:transform .2s,box-shadow .2s;display:flex;gap:20px;align-items:flex-start}.download-cover{flex-shrink:0;width:80px;border-radius:6px;overflow:hidden;box-shadow:0 2px 8px #00000026}.download-cover img{width:100%;height:auto;display:block}.download-info{flex:1;min-width:0}.download-card:hover{transform:translateY(-2px);box-shadow:0 6px 12px #0000001a}.download-card.series{border-left:4px solid #667eea}.download-card.movie{border-left:4px solid #f093fb}.download-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:15px}.download-type{padding:5px 15px;border-radius:20px;font-size:.9rem;font-weight:500}.download-type.series{background:#e8eaf6;color:#667eea}.download-type.movie{background:#fce4ec;color:#f093fb}.download-status{padding:5px 15px;border-radius:20px;font-size:.9rem;font-weight:500;text-transform:capitalize}.download-status.downloading{background:#e8f5e9;color:#4caf50}.download-status.completed{background:#e3f2fd;color:#2196f3}.download-status.failed{background:#ffebee;color:#f44336}.download-title{color:#333;margin-bottom:10px;font-size:1.2rem}.download-series,.download-movie{color:#666;margin-bottom:15px;font-style:italic}.download-details{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:15px;padding-top:15px;border-top:1px solid #e0e0e0}.detail-item{display:flex;flex-direction:column;gap:5px}.detail-label{color:#999;font-size:.85rem;text-transform:uppercase;letter-spacing:.5px}.detail-value{color:#333;font-weight:500}.app-footer{margin-top:20px;text-align:center;color:#fff;font-size:.9rem}.app-footer p{opacity:.9}@media (max-width: 768px){.app-header{flex-direction:column;align-items:flex-start}.controls{flex-direction:column;align-items:stretch}.download-details{grid-template-columns:1fr}}.webhooks-section{background:white;border-radius:10px;box-shadow:0 4px 6px #0000001a;margin-bottom:20px;overflow:hidden}.webhooks-header{padding:20px 30px;background:#f8f9fa;border-bottom:2px solid #e0e0e0;cursor:pointer;display:flex;justify-content:space-between;align-items:center;transition:background .3s}.webhooks-header:hover{background:#f0f1f2}.webhooks-header h2{color:#333;font-size:1.3rem;margin:0}.webhooks-toggle{font-size:1.2rem;color:#666;transition:transform .3s}.webhooks-toggle.expanded{transform:rotate(180deg)}.webhooks-content{padding:20px 30px}.webhook-instance{padding:20px 0;border-bottom:1px solid #e0e0e0}.webhook-instance:last-child{border-bottom:none}.webhook-instance h3{color:#333;font-size:1.1rem;margin-bottom:15px}.webhook-status{display:flex;align-items:center;gap:15px;margin-bottom:15px}.status-indicator{font-size:1rem;font-weight:500;padding:5px 15px;border-radius:20px}.status-indicator.enabled{background:#e8f5e9;color:#4caf50}.status-indicator.disabled{background:#f5f5f5;color:#999}.enable-webhook-btn{padding:8px 16px;background:#667eea;color:#fff;border:none;border-radius:5px;cursor:pointer;font-size:.95rem;transition:background .3s}.enable-webhook-btn:hover{background:#5568d3}.enable-webhook-btn:disabled{background:#ccc;cursor:not-allowed}.test-webhook-btn{padding:8px 16px;background:#f093fb;color:#fff;border:none;border-radius:5px;cursor:pointer;font-size:.95rem;transition:background .3s}.test-webhook-btn:hover{background:#d97ed8}.test-webhook-btn:disabled{background:#ccc;cursor:not-allowed}.webhook-triggers{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px;padding-top:15px;border-top:1px solid #e0e0e0}.trigger-item{display:flex;justify-content:space-between;align-items:center}.trigger-label{color:#666;font-size:.9rem}.trigger-value{font-weight:500;font-size:1.1rem}.trigger-value.active{color:#4caf50}.trigger-value.inactive{color:#999}.webhook-stats{margin-top:15px;padding-top:15px;border-top:1px solid #e0e0e0}.webhook-stats-title{color:#999;font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.6px;margin-bottom:10px}.webhook-stats-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:10px}.webhook-stat{display:flex;flex-direction:column;gap:3px}.webhook-stat-label{color:#999;font-size:.8rem}.webhook-stat-value{color:#333;font-size:.95rem;font-weight:500} diff --git a/server/routes/dashboard.js b/server/routes/dashboard.js index c6b389e..e72fa29 100644 --- a/server/routes/dashboard.js +++ b/server/routes/dashboard.js @@ -803,6 +803,17 @@ router.get('/status', requireAuth, (req, res) => { } }); +// Webhook metrics — exposes global and per-instance webhook metrics for the +// Webhooks Configuration panel. Available to all authenticated users. +router.get('/webhook-metrics', requireAuth, (req, res) => { + try { + const { getGlobalWebhookMetrics } = require('../utils/cache'); + res.json(getGlobalWebhookMetrics()); + } catch (err) { + res.status(500).json({ error: 'Failed to get webhook metrics', details: err.message }); + } +}); + // Cover art proxy — fetches external poster images server-side so the // browser loads them from 'self' and the CSP img-src stays tight. // Requires authentication. Only proxies http/https URLs.