@serifpersia/dango 3.3.4 → 3.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/client/dist/assets/AnimeCard-CXx2EIN7.js +1 -0
- package/client/dist/assets/{AnimeInfo-0huPAq0O.js → AnimeInfo-C6ehrfYW.js} +1 -1
- package/client/dist/assets/{AnimeInfoPage-Dqr5QH6R.js → AnimeInfoPage-pgnMg0On.js} +2 -2
- package/client/dist/assets/{Asmr-B6ZiqkmU.js → Asmr-DfA8xB-U.js} +1 -1
- package/client/dist/assets/{AsmrResetProgressModal-Cqsoo3XC.js → AsmrResetProgressModal-QUNnEh9C.js} +1 -1
- package/client/dist/assets/AvSyncCalibrator-Bs4iejCG.js +10 -0
- package/client/dist/assets/Home-Csx6zT32.js +1 -0
- package/client/dist/assets/{Insights-ZlgPrzGD.js → Insights-MW8oRqeX.js} +1 -1
- package/client/dist/assets/{LibraryListPage-CCiee-Ot.js → LibraryListPage-VYaHXgXt.js} +1 -1
- package/client/dist/assets/{ListeningList-ctAz_6Zi.js → ListeningList-BzbQwmh0.js} +1 -1
- package/client/dist/assets/{Manga-BI9WMTx5.js → Manga-223panCD.js} +1 -1
- package/client/dist/assets/{MangaInfoPage-DcrEr7Sk.js → MangaInfoPage-DBqX-Ord.js} +1 -1
- package/client/dist/assets/{MangaReadPage-SYg63m48.js → MangaReadPage-DuXdVyTd.js} +1 -1
- package/client/dist/assets/{MangaResetProgressModal-DX-1PS4h.js → MangaResetProgressModal-6C3iaR6g.js} +1 -1
- package/client/dist/assets/{Mature-Dqh_9SA3.js → Mature-3VlywJMR.js} +1 -1
- package/client/dist/assets/{MediaCard-Be1ST9oj.js → MediaCard-xfJv6irD.js} +1 -1
- package/client/dist/assets/{Music-zsPwT8_5.js → Music-DkIeCRq1.js} +1 -1
- package/client/dist/assets/{OptionListMenu-Drc_vybW.js → OptionListMenu-JQ_--ggT.js} +1 -1
- package/client/dist/assets/Player-Czg_D7FN.js +56 -0
- package/client/dist/assets/{PlayerSettings-Cwoji-P7.js → PlayerSettings-KrFECely.js} +1 -1
- package/client/dist/assets/{QueueOptionsButton-B6BMq66e.js → QueueOptionsButton-BKNDfpCl.js} +1 -1
- package/client/dist/assets/{QueueRail-VxpUDBSm.js → QueueRail-Cgljhm64.js} +1 -1
- package/client/dist/assets/{Radio-B2Q_Egj7.js → Radio-wbxhaiqy.js} +1 -1
- package/client/dist/assets/{ReadingList-O0QPwXu7.js → ReadingList-DNJAx_LW.js} +1 -1
- package/client/dist/assets/{ResetProgressModal-CR_ovLAu.js → ResetProgressModal-By-iSYwL.js} +1 -1
- package/client/dist/assets/{Search-C8e2nlDD.js → Search-63TcSgOa.js} +1 -1
- package/client/dist/assets/{Settings-BgPWBl2V.js → Settings-BeS0llCE.js} +1 -1
- package/client/dist/assets/{SkeletonGrid-CtHKKMLj.js → SkeletonGrid-CnE_aoEU.js} +1 -1
- package/client/dist/assets/{Trackers-Bfoiyuzy.js → Trackers-ACFHfLXZ.js} +1 -1
- package/client/dist/assets/Tv-BCmNLUsp.js +4 -0
- package/client/dist/assets/{TvInfo-D_scgw_h.js → TvInfo-fFNHV1RJ.js} +1 -1
- package/client/dist/assets/{TvPopup-YTI7dEbJ.js → TvPopup-DYKTHRrD.js} +1 -1
- package/client/dist/assets/{TvSearch-CxU33UOf.js → TvSearch-CpenLEBz.js} +1 -1
- package/client/dist/assets/TvWatchlist-CTUZAvfa.js +1 -0
- package/client/dist/assets/{Watchlist-P6YMZUdF.js → Watchlist-B10pIG1F.js} +1 -1
- package/client/dist/assets/{hls-C4cG9wQw.js → hls-Cbou9Eb-.js} +1 -1
- package/client/dist/assets/index-CfvzoNYQ.js +178 -0
- package/client/dist/assets/{useAnimeInfoData-DeuwDSnI.js → useAnimeInfoData-D-vEehTG.js} +1 -1
- package/client/dist/assets/{useAsmr-CbMVRjmV.js → useAsmr-B-3EYd-B.js} +1 -1
- package/client/dist/assets/{useAsmrPopup-D91Q3CBg.js → useAsmrPopup-D9BxuTDg.js} +1 -1
- package/client/dist/assets/{useMangaLibrary-BPvFb1lU.js → useMangaLibrary-DtRKgk2x.js} +1 -1
- package/client/dist/assets/{useMangaPopup-BOL2mQJs.js → useMangaPopup-BNWJ5pR2.js} +1 -1
- package/client/dist/assets/{useProviders-BsRGONMA.js → useProviders-jxh6fvMH.js} +1 -1
- package/client/dist/assets/{useTv-D37MfTHA.js → useTv-CP4mofvR.js} +1 -1
- package/client/dist/assets/{useTvLibrary-Cwxgy_Bg.js → useTvLibrary-DeGkJuvp.js} +1 -1
- package/client/dist/index.html +1 -1
- package/package.json +2 -2
- package/server/dist/controllers/tv-library.controller.js +9 -5
- package/server/dist/repositories/tv.repository.js +10 -8
- package/server/dist/sync.js +19 -1
- package/server/package.json +1 -1
- package/client/dist/assets/AnimeCard-B5A20jAI.js +0 -1
- package/client/dist/assets/AvSyncCalibrator-C8ZoIwMY.js +0 -10
- package/client/dist/assets/Home-thJhPfs1.js +0 -1
- package/client/dist/assets/Player-BEtAYps2.js +0 -56
- package/client/dist/assets/Tv-Ca0fCdko.js +0 -3
- package/client/dist/assets/TvWatchlist-B4X1fWEH.js +0 -1
- package/client/dist/assets/index-IZgh1beL.js +0 -178
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{d as r,A as V,h as U,u as e,q as te,S as ee,T as Te,o as Re,a as De,g as ge,_ as Ie}from"./vendor-core-8R2fFbyN.js";import{d as Pe,B as D,M as G,h as xe,T as F,z as me,D as ie,E as Le,F as Oe,q as de,u as Ae,G as Ue,w as pe,x as Me,H as Ee,I as $e,V as je,J as Ge,K as Ke,L as He}from"./index-IZgh1beL.js";import{u as ue}from"./vendor-query-BXRECSI6.js";import{I as q}from"./vendor-icons-CDMuNDeL.js";const oe={"title-preference-container":"_title-preference-container_sdqgs_1","toggle-button":"_toggle-button_sdqgs_21","toggle-label":"_toggle-label_sdqgs_51"},ce=["name","nativeName","englishName"],le={name:"Default (Romaji)",nativeName:"Native",englishName:"English"},Fe=()=>{const{titlePreference:t,setTitlePreference:n,loading:o}=Pe(),[i,l]=r(le[t]),[w,b]=r(!1),d=V(null);U(()=>{o||l(le[t])},[t,o]);const s=async()=>{if(w)return;b(!0);const g=(ce.indexOf(t)+1)%ce.length,p=ce[g],h=le[p];d.current&&(d.current.style.transform="translateX(-100%)",d.current.style.opacity="0"),setTimeout(async()=>{l(h),n(p),d.current&&(d.current.style.transition="none",d.current.style.transform="translateX(100%)",d.current.style.opacity="0",d.current.offsetWidth,d.current.style.transition="transform 0.3s ease-out, opacity 0.3s ease-out",d.current.style.transform="translateX(0)",d.current.style.opacity="1");try{await fetch("/api/settings",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:"titlePreference",value:p})})}catch(C){console.error("Error saving title preference:",C)}finally{b(!1)}},300)};return o?e("p",{children:"Loading title preference..."}):e("div",{className:oe["title-preference-container"],children:[e("h4",{children:"Anime Title Display Preference"}),e("button",{onClick:s,className:oe["toggle-button"],disabled:w,children:e("span",{ref:d,className:oe["toggle-label"],children:i})})]})},ze="_settingsHeader_14a5d_1",Be="_pageTitle_14a5d_6",We="_pageSubtitle_14a5d_14",qe="_settingsLayout_14a5d_20",Ve="_sidebar_14a5d_27",Je="_sidebarIndicator_14a5d_35",Ye="_sidebarItem_14a5d_50",Qe="_active_14a5d_72",Xe="_mainContent_14a5d_80",Ze="_tabContent_14a5d_85",et="_sectionCard_14a5d_103",tt="_settingItem_14a5d_127",at="_settingRow_14a5d_132",nt="_controls_14a5d_145",st="_status_14a5d_151",m={settingsHeader:ze,pageTitle:Be,pageSubtitle:We,settingsLayout:qe,sidebar:Ve,sidebarIndicator:Je,sidebarItem:Ye,active:Qe,mainContent:Xe,tabContent:Ze,sectionCard:et,settingItem:tt,settingRow:at,controls:nt,status:st},rt="_sectionCard_wt900_12",it="_title_wt900_22",ot="_signIn_wt900_29",ct="_userInfo_wt900_36",lt="_warning_wt900_58",dt="_formGroup_wt900_65",ut="_label_wt900_69",ht="_inputWrapper_wt900_79",gt="_input_wt900_79",mt="_select_wt900_103",pt="_actions_wt900_140",yt="_hr_wt900_148",y={sectionCard:rt,title:it,signIn:ot,userInfo:ct,warning:lt,formGroup:dt,label:ut,inputWrapper:ht,input:gt,select:mt,actions:pt,hr:yt},ft=()=>{const[t,n]=r(!0),[o,i]=r(!1),[l,w]=r(!1),[b,d]=r(null),[s,u]=r({status:"idle"}),[g,p]=r(!1),[h,C]=r(""),[k,f]=r(!1),I=V(null),[T,P]=r({show:!1,message:"",type:"info"}),N=()=>{I.current&&(window.clearInterval(I.current),I.current=null)},L=te(S=>{w(S.authenticated),d(S.user||S.device.user||null),u(S.device),p(!!S.hasCustomClientId)},[]),O=te(async()=>{const M=await(await fetch("/api/auth/github/status")).json();L(M)},[L]),E=async()=>{try{const M=await(await fetch("/api/auth/github/poll")).json();u(M),M.status==="success"?(N(),await O(),P({show:!0,message:"GitHub authentication complete. Sync has been initialized.",type:"success"})):M.status==="error"&&(N(),P({show:!0,message:M.error||"GitHub authentication failed.",type:"error"}))}catch{N(),P({show:!0,message:"Failed to poll GitHub authentication status.",type:"error"})}},_=(S=5)=>{N(),I.current=window.setInterval(E,Math.max(S,5)*1e3)};U(()=>(O().catch(()=>{P({show:!0,message:"Failed to load GitHub sync status.",type:"error"})}).finally(()=>n(!1)),N),[O]);const v=async()=>{i(!0);try{const S=await fetch("/api/auth/github/start",{method:"POST"}),M=await S.json();if(!S.ok)throw new Error("Failed to start GitHub authentication.");u(M),_(M.verification?.interval)}catch(S){P({show:!0,message:S instanceof Error?S.message:"Failed to start GitHub authentication.",type:"error"})}finally{i(!1)}},R=async()=>{try{await fetch("/api/auth/github/logout",{method:"POST"}),w(!1),d(null),u({status:"idle"}),P({show:!0,message:"Signed out of GitHub sync.",type:"success"})}catch{P({show:!0,message:"Failed to sign out of GitHub.",type:"error"})}},$=async()=>{f(!0);try{if(!(await fetch("/api/auth/github/auth",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({clientId:h})})).ok)throw new Error("save failed");C(""),await O(),P({show:!0,message:"Custom GitHub auth saved.",type:"success"})}catch{P({show:!0,message:"Failed to save override.",type:"error"})}finally{f(!1)}},K=async()=>{f(!0);try{await fetch("/api/auth/github/auth",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({clientId:""})}),C(""),await O(),P({show:!0,message:"Custom auth cleared. Using dango defaults.",type:"success"})}catch{P({show:!0,message:"Failed to clear override.",type:"error"})}finally{f(!1)}};return t?e("div",{style:{color:"var(--text-secondary)",padding:"1.5rem"},children:"Loading..."}):e("div",{className:y.sectionCard,children:[e("h3",{className:y.title,children:"GitHub Cloud Sync"}),e("p",{className:y.signIn,children:"Sync local data through a private GitHub repository named dango-sync-data."}),l&&b?e("div",{className:y.userInfo,children:[e("p",{children:["Signed in as: ",e("strong",{children:b.name||b.login})]}),e(D,{variant:"danger",onClick:R,children:"Sign Out"})]}):e("div",{className:y.signIn,children:e(D,{onClick:v,disabled:o||s.status==="pending",children:o||s.status==="pending"?"Waiting for GitHub...":"Sign in with GitHub"})}),s.status==="pending"&&s.verification&&e(ee,{children:[e("hr",{className:y.hr}),e("div",{className:y.formGroup,children:[e("label",{className:y.label,children:"Verification URL"}),e("div",{className:y.inputWrapper,children:[e("input",{className:y.input,value:s.verification.verification_uri,readOnly:!0}),e(D,{onClick:()=>{const S=s.verification?.verification_uri;S&&/^https?:\/\//i.test(S)&&window.open(S,"_blank","noopener,noreferrer")},children:"Open"})]})]}),e("div",{className:y.formGroup,children:[e("label",{className:y.label,children:"Device Code"}),e("input",{className:y.input,value:s.verification.user_code,readOnly:!0})]})]}),s.status==="error"&&e("p",{className:y.warning,children:s.error}),e("details",{style:{marginTop:"1rem",fontSize:"var(--font-size-sm)"},children:[e("summary",{style:{cursor:"pointer",color:"var(--text-secondary)"},children:["Advanced: use your own auth ",g?"(override active)":""]}),e("div",{className:y.formGroup,style:{marginTop:"0.75rem"},children:[e("label",{className:y.label,children:"Client ID (optional)"}),e("input",{className:y.input,value:h,onChange:S=>C(S.currentTarget.value),placeholder:"Your GitHub OAuth app ID"})]}),e("div",{className:y.actions,children:[e(D,{onClick:$,disabled:k,children:"Save override"}),e(D,{variant:"secondary",onClick:K,disabled:k,children:"Use dango defaults"})]})]}),e(G,{isOpen:T.show,onClose:()=>P(S=>({...S,show:!1})),width:"sm",children:[e(G.Body,{children:e("p",{children:T.message})}),e(G.Actions,{children:e(D,{onClick:()=>P(S=>({...S,show:!1})),children:"OK"})})]})]})},wt=()=>{const[t,n]=r(!0),[o,i]=r(null),[l,w]=r(!1),[b,d]=r(!1),[s,u]=r(""),[g,p]=r(""),[h,C]=r(""),[k,f]=r(!1),[I,T]=r({show:!1,message:"",type:"info"}),P=async()=>{try{const R=await(await fetch("/api/auth/user")).json();i(R?.email?R:null)}catch{i(null)}},N=async()=>{try{const[v,R]=await Promise.all([fetch("/api/auth/config-status"),fetch("/api/auth/google-auth")]),$=await v.json(),K=await R.json();w(!!$.hasConfig),d(!!(K.hasCustomWorkerUrl||K.hasCustomClientId||K.hasClientSecret))}catch(v){console.error("Failed to fetch config status",v)}};U(()=>{(async()=>{n(!0),await Promise.all([P(),N()]);try{new URLSearchParams(window.location.search).get("google_auth")==="success"&&(await P(),window.history.replaceState(null,"",window.location.pathname))}catch{}n(!1)})();const R=$=>{$.origin===window.location.origin&&typeof $.data=="object"&&$.data!==null&&$.data.type==="GOOGLE_AUTH_SUCCESS"&&(i($.data.user),window.location.reload())};return window.addEventListener("message",R),()=>window.removeEventListener("message",R)},[]);const L=async()=>{try{const R=await(await fetch("/api/auth/google/login",{method:"POST"})).json();if(R.authenticated){window.location.reload();return}if(R.url){if(typeof window.DangoBridge<"u"){window.location.href=R.url;return}const K=600,S=700,M=window.innerWidth/2-K/2,ae=window.innerHeight/2-S/2;window.open(R.url,"GoogleAuth",`width=${K},height=${S},top=${ae},left=${M}`)}else throw new Error("Auth URL not available")}catch{T({show:!0,message:"Authentication failed. Ensure server is configured correctly.",type:"error"})}},O=async()=>{try{await fetch("/api/auth/logout",{method:"POST"}),i(null),T({show:!0,message:"Successfully signed out.",type:"success"}),window.location.reload()}catch(v){console.error("Sign out failed",v),T({show:!0,message:"Failed to sign out.",type:"error"})}},E=async()=>{f(!0);try{if(!(await fetch("/api/auth/google-auth",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({workerUrl:s,clientId:g,clientSecret:h})})).ok)throw new Error("save failed");u(""),p(""),C(""),await N(),T({show:!0,message:"Custom auth saved. Restart may be required.",type:"success"})}catch{T({show:!0,message:"Failed to save override.",type:"error"})}finally{f(!1)}},_=async()=>{f(!0);try{await fetch("/api/auth/google-auth",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({workerUrl:"",clientId:"",clientSecret:""})}),u(""),p(""),C(""),await N(),T({show:!0,message:"Custom auth cleared. Using dango defaults.",type:"success"})}catch{T({show:!0,message:"Failed to clear override.",type:"error"})}finally{f(!1)}};return t?e("div",{style:{color:"var(--text-secondary)",padding:"1.5rem"},children:"Loading..."}):e("div",{className:y.sectionCard,children:[e("h3",{className:y.title,children:"Google Drive Sync"}),o?e("div",{className:y.userInfo,children:[e("p",{children:["Signed in as: ",e("strong",{children:o.name})," (",o.email,")"]}),e(D,{variant:"danger",onClick:O,children:"Sign Out"})]}):e("div",{className:y.signIn,children:[e("p",{children:"Sign in with your Google account to enable synchronization features."}),e(D,{onClick:L,disabled:!l,children:"Sign in with Google"}),!l&&e("p",{className:y.warning,children:"Google sync is not configured on the server."})]}),e("details",{style:{marginTop:"1rem",fontSize:"var(--font-size-sm)"},children:[e("summary",{style:{cursor:"pointer",color:"var(--text-secondary)"},children:["Advanced: use your own auth ",b?"(override active)":""]}),e("div",{className:y.formGroup,style:{marginTop:"0.75rem"},children:[e("label",{className:y.label,children:"Worker URL (optional)"}),e("input",{className:y.input,value:s,onChange:v=>u(v.currentTarget.value),placeholder:"https://your-worker.workers.dev"})]}),e("div",{className:y.formGroup,children:[e("label",{className:y.label,children:"Client ID (optional)"}),e("input",{className:y.input,value:g,onChange:v=>p(v.currentTarget.value),placeholder:"Your Google OAuth client ID"})]}),e("div",{className:y.formGroup,children:[e("label",{className:y.label,children:"Client Secret (optional)"}),e("input",{type:"password",className:y.input,value:h,onChange:v=>C(v.currentTarget.value),placeholder:"Your Google OAuth secret"})]}),e("div",{className:y.actions,children:[e(D,{onClick:E,disabled:k,children:"Save override"}),e(D,{variant:"secondary",onClick:_,disabled:k,children:"Use dango defaults"})]})]}),e(G,{isOpen:I.show,onClose:()=>T(v=>({...v,show:!1})),width:"sm",children:[e(G.Body,{children:e("p",{children:I.message})}),e(G.Actions,{children:e(D,{onClick:()=>T(v=>({...v,show:!1})),children:"OK"})})]})]})},vt="_sectionCard_1pqo4_1",bt="_settingItem_1pqo4_26",_t="_settingRow_1pqo4_31",kt="_modalOverlay_1pqo4_38",St="_modal_1pqo4_38",Ct="_modalActions_1pqo4_73",Nt="_modalSecondary_1pqo4_79",Tt="_modalPrimary_1pqo4_89",j={sectionCard:vt,settingItem:bt,settingRow:_t,modalOverlay:kt,modal:St,modalActions:Ct,modalSecondary:Nt,modalPrimary:Tt},Rt={anime:{heading:"Watchlist Preferences",blurb:"Customize your experience when managing your watchlist and series entries.",skipKey:"skipRemoveConfirmation",ignoreKey:"ignoreAdultContent",listOnlyKey:"cwWatchlistOnly",skipLabel:"Skip confirmation when removing from watchlist",ignoreLabel:"Hide adult content from continue watching",listOnlyLabel:"Only show continue watching for shows in watchlist",listNoun:"watchlist",continueNoun:"continue watching",adultCountUrl:"/api/continue-watching/adult-count",purgeUrl:"/api/continue-watching/purge-adult",purgeDoneText:t=>`Removed ${t??0} entries from continue watching`,invalidateKeys:[["allContinueWatching"]]},manga:{heading:"Reading List Preferences",blurb:"Customize your experience when managing your reading list and manga entries.",skipKey:"mangaSkipRemoveConfirmation",ignoreKey:"mangaIgnoreAdultContent",listOnlyKey:"mangaCwWatchlistOnly",skipLabel:"Skip confirmation when removing from reading list",ignoreLabel:"Hide adult content from continue reading",listOnlyLabel:"Only show continue reading for manga in reading list",listNoun:"reading list",continueNoun:"continue reading",adultCountUrl:"/api/manga/continue-reading/adult-count",purgeUrl:"/api/manga/continue-reading/purge-adult",purgeDoneText:t=>`Removed ${t??0} entries from continue reading`,invalidateKeys:[["manga-continue-reading"]]},tv:{heading:"TV Watchlist Preferences",blurb:"Customize your experience when managing your TV watchlist and series entries.",skipKey:"tvSkipRemoveConfirmation",ignoreKey:"tvIgnoreAdultContent",listOnlyKey:"tvCwWatchlistOnly",skipLabel:"Skip confirmation when removing from TV watchlist",ignoreLabel:"Hide adult content from continue watching",listOnlyLabel:"Only show continue watching for shows in TV watchlist",listNoun:"TV watchlist",continueNoun:"continue watching",adultCountUrl:"/api/tv/continue-watching/adult-count",purgeUrl:"/api/tv/continue-watching/purge-adult",purgeDoneText:t=>`Removed ${t??0} entries from continue watching`,invalidateKeys:[["tv-continue-watching"]]},asmr:{heading:"Listening List Preferences",blurb:"Customize your experience when managing your listening list and work entries.",skipKey:"asmrSkipRemoveConfirmation",ignoreKey:"asmrIgnoreAdultContent",listOnlyKey:"asmrCwWatchlistOnly",skipLabel:"Skip confirmation when removing from listening list",ignoreLabel:"Hide adult content from continue listening",listOnlyLabel:"Only show continue listening for works in listening list",listNoun:"listening list",continueNoun:"continue listening",adultCountUrl:"/api/asmr/continue-listening/adult-count",purgeUrl:"/api/asmr/continue-listening/purge-adult",purgeDoneText:t=>`Removed ${t??0} entries from continue listening`,invalidateKeys:[["asmr-continue-listening"]]}},Dt=(t,n)=>{if(t==null)return n;const o=String(t);return o==="true"||o==="1"?!0:o==="false"||o==="0"?!1:n},ye=(t,n,o)=>{const[i,l]=r(n),[w,b]=r(!1),d=ue();return U(()=>{(async()=>{try{const p=await(await fetch(`/api/settings?key=${t}`)).json();l(Dt(p.value,n))}catch(g){console.error("Failed to fetch setting",g)}})()},[t,n]),{value:i,setValue:l,isUpdating:w,toggle:async()=>{if(w)return;b(!0);const u=!i;l(u);try{await fetch("/api/settings",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:t,value:u})});for(const g of o)d.invalidateQueries({queryKey:g})}catch(g){console.error("Error saving setting:",g),l(!u)}finally{b(!1)}}}},It=()=>{const{contentType:t}=xe(),n=Rt[t],[o,i]=r(!1),[l,w]=r(!0),[b,d]=r(!1),s=ye(n.ignoreKey,!0,n.invalidateKeys),u=ye(n.listOnlyKey,!1,n.invalidateKeys),[g,p]=r(null),[h,C]=r(!1),k=ue();U(()=>{w(!0),(async()=>{try{const O=await(await fetch(`/api/settings?key=${n.skipKey}`)).json();String(O.value)==="true"||String(O.value)==="1"?i(!0):i(!1)}catch(L){console.error("Failed to fetch setting",L)}finally{w(!1)}})()},[n.skipKey]);const f=async()=>{if(b)return;d(!0);const N=!o;i(N);try{await fetch("/api/settings",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:n.skipKey,value:N})})}catch(L){console.error("Error saving setting:",L),i(!N)}finally{d(!1)}},I=async()=>{if(!s.isUpdating){if(s.value)try{const L=await(await fetch(n.adultCountUrl)).json();if(typeof L.count=="number"&&L.count>0){p(L.count);return}}catch(N){console.error("Failed to fetch adult count",N)}s.toggle()}},T=()=>{p(null),s.toggle()},P=async()=>{if(!h){C(!0);try{const L=await(await fetch(n.purgeUrl,{method:"POST"})).json();me.success(n.purgeDoneText(L.removed));for(const O of n.invalidateKeys)k.invalidateQueries({queryKey:O})}catch(N){console.error("Failed to purge adult entries",N),me.error("Failed to remove adult entries")}finally{C(!1),p(null)}s.toggle()}};return l?e("div",{children:"Loading settings..."}):e("div",{className:j.sectionCard,children:[e("h3",{children:n.heading}),e("p",{children:n.blurb}),e("div",{className:j.settingItem,children:e("div",{className:j.settingRow,children:[e("label",{htmlFor:"skip-confirmation-toggle",children:n.skipLabel}),e(F,{isChecked:o,onChange:f,id:"skip-confirmation-toggle",disabled:b})]})}),e("div",{className:j.settingItem,children:e("div",{className:j.settingRow,children:[e("label",{htmlFor:"ignore-adult-toggle",children:n.ignoreLabel}),e(F,{isChecked:s.value,onChange:I,id:"ignore-adult-toggle",disabled:s.isUpdating})]})}),e("div",{className:j.settingItem,children:e("div",{className:j.settingRow,children:[e("label",{htmlFor:"cw-watchlist-only-toggle",children:n.listOnlyLabel}),e(F,{isChecked:u.value,onChange:u.toggle,id:"cw-watchlist-only-toggle",disabled:u.isUpdating})]})}),g!==null&&e("div",{className:j.modalOverlay,onClick:()=>p(null),children:e("div",{className:j.modal,onClick:N=>N.stopPropagation(),children:[e("h4",{children:"Show adult entries?"}),e("p",{children:[g," adult ",g===1?"entry":"entries"," not in your"," ",n.listNoun," ",g===1?"is":"are"," currently hidden from"," ",n.continueNoun,". You can purge ",g===1?"it":"them"," from the database instead of showing ",g===1?"it":"them","."]}),e("div",{className:j.modalActions,children:[e("button",{type:"button",className:j.modalSecondary,onClick:T,disabled:h,children:"Show them"}),e("button",{type:"button",className:j.modalPrimary,onClick:P,disabled:h,children:h?"Purging...":`Purge ${g}`})]})]})})]})},Pt="_sectionCard_jkggs_1",xt="_statsGrid_jkggs_26",Lt="_statCard_jkggs_33",Ot="_statLabel_jkggs_43",At="_statValue_jkggs_51",Ut="_statMeta_jkggs_57",Mt="_statusBanner_jkggs_63",Et="_statusSuccess_jkggs_74",$t="_statusUpdating_jkggs_80",jt="_statusError_jkggs_86",Gt="_sha_jkggs_92",Kt="_settingItem_jkggs_99",Ht="_settingRow_jkggs_104",Ft="_settingTitle_jkggs_111",zt="_settingSubtitle_jkggs_117",Bt="_actionsRow_jkggs_124",x={sectionCard:Pt,statsGrid:xt,statCard:Lt,statLabel:Ot,statValue:At,statMeta:Ut,statusBanner:Mt,statusSuccess:Et,statusUpdating:$t,statusError:jt,sha:Gt,settingItem:Kt,settingRow:Ht,settingTitle:Ft,settingSubtitle:zt,actionsRow:Bt},Wt=()=>{const[t,n]=r(null),[o,i]=r(!0),[l,w]=r(!1),[b,d]=r(!1),s=V(null),u=async()=>{try{const k=await fetch("/api/settings/offline-db");if(k.ok){const f=await k.json();return n(f),f}}catch(k){console.error("Failed to fetch offline DB info:",k)}finally{i(!1)}return null};U(()=>(u(),()=>{s.current&&window.clearInterval(s.current)}),[]),U(()=>{t?.isRefreshing?s.current||(s.current=window.setInterval(async()=>{const k=await u();k&&!k.isRefreshing&&s.current&&(window.clearInterval(s.current),s.current=null)},2e3)):s.current&&(window.clearInterval(s.current),s.current=null)},[t?.isRefreshing]);const g=async()=>{if(!t||l)return;const k=!t.autoUpdateEnabled;w(!0),n({...t,autoUpdateEnabled:k});try{(await fetch("/api/settings/offline-db/auto-update",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({enabled:k})})).ok||n({...t,autoUpdateEnabled:!k})}catch(f){console.error("Failed to update auto update setting:",f),n({...t,autoUpdateEnabled:!k})}finally{w(!1)}},p=async()=>{if(!(t?.isRefreshing||b)){d(!0);try{(await fetch("/api/settings/offline-db/update",{method:"POST"})).ok&&n(f=>f?{...f,isRefreshing:!0,lastStatus:"updating",lastMessage:"Downloading database..."}:null)}catch(k){console.error("Failed to trigger offline DB update:",k)}finally{d(!1)}}},h=k=>{if(!k)return"Never";try{return new Date(k).toLocaleString(void 0,{dateStyle:"medium",timeStyle:"short"})}catch{return k}},C=t?.isRefreshing||b;return e("div",{className:x.sectionCard,children:[e("h3",{children:"Offline Metadata Database"}),e("p",{children:"Local MAL to AniList ID map used for instant imports and metadata enrichment without hitting rate-limited APIs. Updates automatically every Saturday in the background."}),e("div",{className:x.statsGrid,children:[e("div",{className:x.statCard,children:[e("span",{className:x.statLabel,children:"MAL Mapped"}),e("span",{className:x.statValue,children:o?"—":(t?.totalMalMapped??0).toLocaleString()})]}),e("div",{className:x.statCard,children:[e("span",{className:x.statLabel,children:"Release"}),e("span",{className:x.statMeta,children:o?"—":t?.releaseTag??"Never"})]}),e("div",{className:x.statCard,children:[e("span",{className:x.statLabel,children:"Last Checked"}),e("span",{className:x.statMeta,children:o?"—":h(t?.lastCheckedAt??null)})]}),e("div",{className:x.statCard,children:[e("span",{className:x.statLabel,children:"Last Updated"}),e("span",{className:x.statMeta,children:o?"—":h(t?.lastUpdatedAt??null)})]})]}),t?.lastMessage&&e("div",{className:`${x.statusBanner} ${t.lastStatus==="failed"?x.statusError:t.lastStatus==="updating"?x.statusUpdating:x.statusSuccess}`,children:[e("span",{children:t.lastMessage}),t.contentSha256&&e("span",{className:x.sha,children:["sha:",t.contentSha256.slice(0,12)]})]}),e("div",{className:x.settingItem,children:e("div",{className:x.settingRow,children:[e("div",{children:[e("span",{className:x.settingTitle,children:"Weekly Automatic Updates (Saturdays)"}),e("div",{className:x.settingSubtitle,children:"Download and index new database releases in the background. Catches up on startup if the server was offline."})]}),e(F,{id:"offline-db-auto-update-toggle",isChecked:t?t.autoUpdateEnabled:!0,onChange:g,disabled:o||l})]})}),e("div",{className:x.actionsRow,children:e(D,{onClick:p,disabled:o||C,children:C?"Updating Database...":"Update Offline Database Now"})})]})},qt="_sectionCard_1g4qx_1",Vt="_dangerCard_1g4qx_26",Jt="_status_1g4qx_34",Yt="_warningText_1g4qx_40",Qt="_ackLabel_1g4qx_44",Z={sectionCard:qt,dangerCard:Vt,status:Jt,warningText:Yt,ackLabel:Qt},Xt=()=>{const t=ue(),[n,o]=r(!1),[i,l]=r(!1),[w,b]=r(!1),[d,s]=r(""),u=()=>{l(!1),s(""),o(!0)},g=()=>{w||(o(!1),l(!1))},p=async()=>{if(!(!i||w)){b(!0),s("");try{const h=await fetch("/api/database/clear",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({confirm:!0})}),C=await h.json();if(!h.ok)throw new Error(C.error||"Failed to clear database");const k=C.deleted,f=C.deletedManga,I=C.deletedTv,T=C.deletedAsmr,P=Object.values(k).reduce((E,_)=>E+(_||0),0)+Object.values(f??{}).reduce((E,_)=>E+(_||0),0)+Object.values(I??{}).reduce((E,_)=>E+(_||0),0)+Object.values(T??{}).reduce((E,_)=>E+(_||0),0),N=(f?.manga_library??0)+(f?.manga_progress??0),L=(I?.tv_library??0)+(I?.tv_progress??0),O=(T?.asmr_library??0)+(T?.asmr_progress??0);s(`Library cleared — ${k.watchlist??0} watchlist entries, ${N} manga rows, ${L} TV rows, ${O} ASMR rows and ${P} total rows removed.`),t.invalidateQueries({queryKey:["watchlist"]}),t.invalidateQueries({queryKey:["allContinueWatching"]}),t.invalidateQueries({queryKey:["manga-library"]}),t.invalidateQueries({queryKey:["manga-library-ids"]}),t.invalidateQueries({queryKey:["manga-continue-reading"]}),t.invalidateQueries({queryKey:["tv-library"]}),t.invalidateQueries({queryKey:["tv-library-ids"]}),t.invalidateQueries({queryKey:["tv-continue-watching"]}),t.invalidateQueries({queryKey:["asmr-library"]}),t.invalidateQueries({queryKey:["asmr-library-ids"]}),t.invalidateQueries({queryKey:["asmr-continue-listening"]}),o(!1)}catch(h){s(h.message)}finally{b(!1),l(!1)}}};return e("div",{className:`${Z.sectionCard} ${Z.dangerCard}`,children:[e("h3",{children:"Danger Zone"}),e("p",{children:"Permanently delete your library (watchlist, watched episodes, queue, cached show metadata, manga reading list and reading progress, TV watchlist and watch progress, ASMR listening list and listening progress) to start fresh. Your settings, sync state and the offline metadata cache are preserved."}),e(D,{variant:"danger",onClick:u,children:"Clear Library Data"}),d&&e("p",{className:Z.status,children:d}),e(G,{isOpen:n,onClose:g,title:"Clear library data?",width:"sm",children:[e(G.Body,{children:[e("p",{className:Z.warningText,children:"This permanently deletes everything in your library. It acts on the active database (dev or prod, per server config) and cannot be undone. Settings, sync state and the offline metadata cache are kept."}),e("label",{className:Z.ackLabel,children:[e("input",{type:"checkbox",checked:i,onChange:h=>l(h.target.checked),disabled:w}),e("span",{children:"I understand this permanently deletes my library"})]})]}),e(G.Actions,{children:[e(D,{variant:"secondary",onClick:g,disabled:w,children:"Cancel"}),e(D,{variant:"danger",onClick:p,disabled:!i||w,children:w?"Clearing...":"Yes, delete everything"})]})]})]})},Zt=()=>{const[t,n]=r(""),[o,i]=r([]),[l,w]=r(null),[b,d]=r(!0),[s,u]=r({show:!1,message:"",type:"info"}),g=async()=>{try{d(!0);const C=await(await fetch("/api/auth/settings/rclone")).json();n(C.remote||""),i(C.availableRemotes||[]),w(C.activeRemote||null)}catch(h){console.error("Failed to fetch Rclone settings",h)}finally{d(!1)}};U(()=>{g()},[]);const p=async()=>{try{if((await fetch("/api/auth/settings/rclone",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({remote:t})})).ok)u({show:!0,message:"Rclone configuration saved successfully. You must restart the server for these changes to take effect.",type:"success"}),g();else throw new Error("Failed to save")}catch{u({show:!0,message:"Failed to save Rclone configuration.",type:"error"})}};return b?e("div",{style:{color:"var(--text-secondary)",padding:"1.5rem"},children:"Loading..."}):e("div",{className:y.sectionCard,children:[e("h3",{className:y.title,children:"Rclone Cloud Sync"}),e("p",{className:y.signIn,children:"Configure which Rclone remote to use for database synchronization."}),l?e("div",{className:y.userInfo,children:e("p",{children:["Current Active Remote: ",e("strong",{children:l})]})}):e("p",{className:y.warning,style:{marginBottom:"1.5rem"},children:"Rclone sync is not currently active. Ensure rclone is installed and a remote is configured."}),e("div",{className:y.formGroup,children:[e("label",{className:y.label,children:"Remote Name"}),e("div",{className:y.inputWrapper,children:e("select",{className:y.select,value:t,onChange:h=>n(h.target.value),children:[e("option",{value:"",children:"(Disabled / None)"}),o.map(h=>e("option",{value:h,children:h},h)),t&&!o.includes(t)&&e("option",{value:t,children:[t," (Manual)"]})]})}),e("p",{className:y.warning,style:{marginTop:"12px"},children:[e("strong",{children:"Note:"})," You can choose which provider is active using the selector at the top of the page."]})]}),e("div",{className:y.actions,children:e(D,{onClick:p,children:"Save Rclone Settings"})}),e(G,{isOpen:s.show,onClose:()=>u(h=>({...h,show:!1})),width:"sm",children:[e(G.Body,{children:e("p",{children:s.message})}),e(G.Actions,{children:e(D,{onClick:()=>u(h=>({...h,show:!1})),children:"OK"})})]})]})},ea=()=>{const[t,n]=r(null),[o,i]=r(!0),l=async()=>{try{const u=await(await fetch("/api/auth/settings/sync")).json();n(u)}catch(s){console.error("Failed to fetch sync settings",s)}finally{i(!1)}};U(()=>{l()},[]);const w=async s=>{const u=s.target.value;try{const g=await fetch("/api/auth/settings/sync",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({provider:u})});if(g.ok){const p=await g.json();n(h=>h?{...h,activeProvider:p.activeProvider}:null),await l(),ie.success(`Sync provider updated to ${u==="default"?"Default Order":u}`)}else ie.error("Failed to update sync provider")}catch{ie.error("Error updating sync provider")}};if(o||!t)return null;const b=[{value:"default",label:"Default (Priority Based)"}];t.authenticatedProviders.github&&b.push({value:"github",label:"GitHub"}),t.authenticatedProviders.google&&b.push({value:"google",label:"Google Drive"}),t.authenticatedProviders.rclone&&b.push({value:"rclone",label:"Rclone"}),b.push({value:"none",label:"None (Local Only)"});const d=s=>s==="none"?"Local Only (No Sync)":s==="google"?"Google Drive":s==="github"?"GitHub":s==="rclone"?"Rclone":s;return e("div",{className:m.sectionCard,children:[e("h3",{children:"Active Sync Provider"}),e("p",{children:'Choose which provider to use for synchronization. "Default" uses the first available provider you are logged into.'}),e("div",{style:{marginBottom:"1.5rem",padding:"0.75rem",background:"rgba(255, 255, 255, 0.03)",borderRadius:"var(--radius-md)",borderLeft:"4px solid var(--accent)",fontSize:"var(--font-size-sm)"},children:["Current Status:"," ",e("strong",{style:{color:"var(--accent-light)",textTransform:"capitalize"},children:d(t.actualActiveProvider)})]}),e("div",{className:m.settingRow,children:[e("label",{htmlFor:"sync-provider-select",children:"Selected Preference"}),e("select",{id:"sync-provider-select",value:t.activeProvider,onChange:w,style:{padding:"0.5rem",borderRadius:"var(--radius-md)",background:"rgba(255, 255, 255, 0.05)",color:"var(--text-primary)",border:"1px solid var(--glass-border)",fontSize:"var(--font-size-sm)",minWidth:"220px",outline:"none",cursor:"pointer"},children:b.map(s=>e("option",{value:s.value,children:s.label},s.value))})]})]})};function ta(){return"javascript:"+encodeURIComponent(`(function(){
|
|
1
|
+
import{d as r,A as V,h as U,u as e,q as te,S as ee,T as Te,o as Re,a as De,g as ge,_ as Ie}from"./vendor-core-8R2fFbyN.js";import{d as Pe,B as D,M as G,h as xe,T as F,z as me,D as ie,E as Le,F as Oe,q as de,u as Ae,G as Ue,w as pe,x as Me,H as Ee,I as $e,V as je,J as Ge,K as Ke,L as He}from"./index-CfvzoNYQ.js";import{u as ue}from"./vendor-query-BXRECSI6.js";import{I as q}from"./vendor-icons-CDMuNDeL.js";const oe={"title-preference-container":"_title-preference-container_sdqgs_1","toggle-button":"_toggle-button_sdqgs_21","toggle-label":"_toggle-label_sdqgs_51"},ce=["name","nativeName","englishName"],le={name:"Default (Romaji)",nativeName:"Native",englishName:"English"},Fe=()=>{const{titlePreference:t,setTitlePreference:n,loading:o}=Pe(),[i,l]=r(le[t]),[w,b]=r(!1),d=V(null);U(()=>{o||l(le[t])},[t,o]);const s=async()=>{if(w)return;b(!0);const g=(ce.indexOf(t)+1)%ce.length,p=ce[g],h=le[p];d.current&&(d.current.style.transform="translateX(-100%)",d.current.style.opacity="0"),setTimeout(async()=>{l(h),n(p),d.current&&(d.current.style.transition="none",d.current.style.transform="translateX(100%)",d.current.style.opacity="0",d.current.offsetWidth,d.current.style.transition="transform 0.3s ease-out, opacity 0.3s ease-out",d.current.style.transform="translateX(0)",d.current.style.opacity="1");try{await fetch("/api/settings",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:"titlePreference",value:p})})}catch(C){console.error("Error saving title preference:",C)}finally{b(!1)}},300)};return o?e("p",{children:"Loading title preference..."}):e("div",{className:oe["title-preference-container"],children:[e("h4",{children:"Anime Title Display Preference"}),e("button",{onClick:s,className:oe["toggle-button"],disabled:w,children:e("span",{ref:d,className:oe["toggle-label"],children:i})})]})},ze="_settingsHeader_14a5d_1",Be="_pageTitle_14a5d_6",We="_pageSubtitle_14a5d_14",qe="_settingsLayout_14a5d_20",Ve="_sidebar_14a5d_27",Je="_sidebarIndicator_14a5d_35",Ye="_sidebarItem_14a5d_50",Qe="_active_14a5d_72",Xe="_mainContent_14a5d_80",Ze="_tabContent_14a5d_85",et="_sectionCard_14a5d_103",tt="_settingItem_14a5d_127",at="_settingRow_14a5d_132",nt="_controls_14a5d_145",st="_status_14a5d_151",m={settingsHeader:ze,pageTitle:Be,pageSubtitle:We,settingsLayout:qe,sidebar:Ve,sidebarIndicator:Je,sidebarItem:Ye,active:Qe,mainContent:Xe,tabContent:Ze,sectionCard:et,settingItem:tt,settingRow:at,controls:nt,status:st},rt="_sectionCard_wt900_12",it="_title_wt900_22",ot="_signIn_wt900_29",ct="_userInfo_wt900_36",lt="_warning_wt900_58",dt="_formGroup_wt900_65",ut="_label_wt900_69",ht="_inputWrapper_wt900_79",gt="_input_wt900_79",mt="_select_wt900_103",pt="_actions_wt900_140",yt="_hr_wt900_148",y={sectionCard:rt,title:it,signIn:ot,userInfo:ct,warning:lt,formGroup:dt,label:ut,inputWrapper:ht,input:gt,select:mt,actions:pt,hr:yt},ft=()=>{const[t,n]=r(!0),[o,i]=r(!1),[l,w]=r(!1),[b,d]=r(null),[s,u]=r({status:"idle"}),[g,p]=r(!1),[h,C]=r(""),[k,f]=r(!1),I=V(null),[T,P]=r({show:!1,message:"",type:"info"}),N=()=>{I.current&&(window.clearInterval(I.current),I.current=null)},L=te(S=>{w(S.authenticated),d(S.user||S.device.user||null),u(S.device),p(!!S.hasCustomClientId)},[]),O=te(async()=>{const M=await(await fetch("/api/auth/github/status")).json();L(M)},[L]),E=async()=>{try{const M=await(await fetch("/api/auth/github/poll")).json();u(M),M.status==="success"?(N(),await O(),P({show:!0,message:"GitHub authentication complete. Sync has been initialized.",type:"success"})):M.status==="error"&&(N(),P({show:!0,message:M.error||"GitHub authentication failed.",type:"error"}))}catch{N(),P({show:!0,message:"Failed to poll GitHub authentication status.",type:"error"})}},_=(S=5)=>{N(),I.current=window.setInterval(E,Math.max(S,5)*1e3)};U(()=>(O().catch(()=>{P({show:!0,message:"Failed to load GitHub sync status.",type:"error"})}).finally(()=>n(!1)),N),[O]);const v=async()=>{i(!0);try{const S=await fetch("/api/auth/github/start",{method:"POST"}),M=await S.json();if(!S.ok)throw new Error("Failed to start GitHub authentication.");u(M),_(M.verification?.interval)}catch(S){P({show:!0,message:S instanceof Error?S.message:"Failed to start GitHub authentication.",type:"error"})}finally{i(!1)}},R=async()=>{try{await fetch("/api/auth/github/logout",{method:"POST"}),w(!1),d(null),u({status:"idle"}),P({show:!0,message:"Signed out of GitHub sync.",type:"success"})}catch{P({show:!0,message:"Failed to sign out of GitHub.",type:"error"})}},$=async()=>{f(!0);try{if(!(await fetch("/api/auth/github/auth",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({clientId:h})})).ok)throw new Error("save failed");C(""),await O(),P({show:!0,message:"Custom GitHub auth saved.",type:"success"})}catch{P({show:!0,message:"Failed to save override.",type:"error"})}finally{f(!1)}},K=async()=>{f(!0);try{await fetch("/api/auth/github/auth",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({clientId:""})}),C(""),await O(),P({show:!0,message:"Custom auth cleared. Using dango defaults.",type:"success"})}catch{P({show:!0,message:"Failed to clear override.",type:"error"})}finally{f(!1)}};return t?e("div",{style:{color:"var(--text-secondary)",padding:"1.5rem"},children:"Loading..."}):e("div",{className:y.sectionCard,children:[e("h3",{className:y.title,children:"GitHub Cloud Sync"}),e("p",{className:y.signIn,children:"Sync local data through a private GitHub repository named dango-sync-data."}),l&&b?e("div",{className:y.userInfo,children:[e("p",{children:["Signed in as: ",e("strong",{children:b.name||b.login})]}),e(D,{variant:"danger",onClick:R,children:"Sign Out"})]}):e("div",{className:y.signIn,children:e(D,{onClick:v,disabled:o||s.status==="pending",children:o||s.status==="pending"?"Waiting for GitHub...":"Sign in with GitHub"})}),s.status==="pending"&&s.verification&&e(ee,{children:[e("hr",{className:y.hr}),e("div",{className:y.formGroup,children:[e("label",{className:y.label,children:"Verification URL"}),e("div",{className:y.inputWrapper,children:[e("input",{className:y.input,value:s.verification.verification_uri,readOnly:!0}),e(D,{onClick:()=>{const S=s.verification?.verification_uri;S&&/^https?:\/\//i.test(S)&&window.open(S,"_blank","noopener,noreferrer")},children:"Open"})]})]}),e("div",{className:y.formGroup,children:[e("label",{className:y.label,children:"Device Code"}),e("input",{className:y.input,value:s.verification.user_code,readOnly:!0})]})]}),s.status==="error"&&e("p",{className:y.warning,children:s.error}),e("details",{style:{marginTop:"1rem",fontSize:"var(--font-size-sm)"},children:[e("summary",{style:{cursor:"pointer",color:"var(--text-secondary)"},children:["Advanced: use your own auth ",g?"(override active)":""]}),e("div",{className:y.formGroup,style:{marginTop:"0.75rem"},children:[e("label",{className:y.label,children:"Client ID (optional)"}),e("input",{className:y.input,value:h,onChange:S=>C(S.currentTarget.value),placeholder:"Your GitHub OAuth app ID"})]}),e("div",{className:y.actions,children:[e(D,{onClick:$,disabled:k,children:"Save override"}),e(D,{variant:"secondary",onClick:K,disabled:k,children:"Use dango defaults"})]})]}),e(G,{isOpen:T.show,onClose:()=>P(S=>({...S,show:!1})),width:"sm",children:[e(G.Body,{children:e("p",{children:T.message})}),e(G.Actions,{children:e(D,{onClick:()=>P(S=>({...S,show:!1})),children:"OK"})})]})]})},wt=()=>{const[t,n]=r(!0),[o,i]=r(null),[l,w]=r(!1),[b,d]=r(!1),[s,u]=r(""),[g,p]=r(""),[h,C]=r(""),[k,f]=r(!1),[I,T]=r({show:!1,message:"",type:"info"}),P=async()=>{try{const R=await(await fetch("/api/auth/user")).json();i(R?.email?R:null)}catch{i(null)}},N=async()=>{try{const[v,R]=await Promise.all([fetch("/api/auth/config-status"),fetch("/api/auth/google-auth")]),$=await v.json(),K=await R.json();w(!!$.hasConfig),d(!!(K.hasCustomWorkerUrl||K.hasCustomClientId||K.hasClientSecret))}catch(v){console.error("Failed to fetch config status",v)}};U(()=>{(async()=>{n(!0),await Promise.all([P(),N()]);try{new URLSearchParams(window.location.search).get("google_auth")==="success"&&(await P(),window.history.replaceState(null,"",window.location.pathname))}catch{}n(!1)})();const R=$=>{$.origin===window.location.origin&&typeof $.data=="object"&&$.data!==null&&$.data.type==="GOOGLE_AUTH_SUCCESS"&&(i($.data.user),window.location.reload())};return window.addEventListener("message",R),()=>window.removeEventListener("message",R)},[]);const L=async()=>{try{const R=await(await fetch("/api/auth/google/login",{method:"POST"})).json();if(R.authenticated){window.location.reload();return}if(R.url){if(typeof window.DangoBridge<"u"){window.location.href=R.url;return}const K=600,S=700,M=window.innerWidth/2-K/2,ae=window.innerHeight/2-S/2;window.open(R.url,"GoogleAuth",`width=${K},height=${S},top=${ae},left=${M}`)}else throw new Error("Auth URL not available")}catch{T({show:!0,message:"Authentication failed. Ensure server is configured correctly.",type:"error"})}},O=async()=>{try{await fetch("/api/auth/logout",{method:"POST"}),i(null),T({show:!0,message:"Successfully signed out.",type:"success"}),window.location.reload()}catch(v){console.error("Sign out failed",v),T({show:!0,message:"Failed to sign out.",type:"error"})}},E=async()=>{f(!0);try{if(!(await fetch("/api/auth/google-auth",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({workerUrl:s,clientId:g,clientSecret:h})})).ok)throw new Error("save failed");u(""),p(""),C(""),await N(),T({show:!0,message:"Custom auth saved. Restart may be required.",type:"success"})}catch{T({show:!0,message:"Failed to save override.",type:"error"})}finally{f(!1)}},_=async()=>{f(!0);try{await fetch("/api/auth/google-auth",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({workerUrl:"",clientId:"",clientSecret:""})}),u(""),p(""),C(""),await N(),T({show:!0,message:"Custom auth cleared. Using dango defaults.",type:"success"})}catch{T({show:!0,message:"Failed to clear override.",type:"error"})}finally{f(!1)}};return t?e("div",{style:{color:"var(--text-secondary)",padding:"1.5rem"},children:"Loading..."}):e("div",{className:y.sectionCard,children:[e("h3",{className:y.title,children:"Google Drive Sync"}),o?e("div",{className:y.userInfo,children:[e("p",{children:["Signed in as: ",e("strong",{children:o.name})," (",o.email,")"]}),e(D,{variant:"danger",onClick:O,children:"Sign Out"})]}):e("div",{className:y.signIn,children:[e("p",{children:"Sign in with your Google account to enable synchronization features."}),e(D,{onClick:L,disabled:!l,children:"Sign in with Google"}),!l&&e("p",{className:y.warning,children:"Google sync is not configured on the server."})]}),e("details",{style:{marginTop:"1rem",fontSize:"var(--font-size-sm)"},children:[e("summary",{style:{cursor:"pointer",color:"var(--text-secondary)"},children:["Advanced: use your own auth ",b?"(override active)":""]}),e("div",{className:y.formGroup,style:{marginTop:"0.75rem"},children:[e("label",{className:y.label,children:"Worker URL (optional)"}),e("input",{className:y.input,value:s,onChange:v=>u(v.currentTarget.value),placeholder:"https://your-worker.workers.dev"})]}),e("div",{className:y.formGroup,children:[e("label",{className:y.label,children:"Client ID (optional)"}),e("input",{className:y.input,value:g,onChange:v=>p(v.currentTarget.value),placeholder:"Your Google OAuth client ID"})]}),e("div",{className:y.formGroup,children:[e("label",{className:y.label,children:"Client Secret (optional)"}),e("input",{type:"password",className:y.input,value:h,onChange:v=>C(v.currentTarget.value),placeholder:"Your Google OAuth secret"})]}),e("div",{className:y.actions,children:[e(D,{onClick:E,disabled:k,children:"Save override"}),e(D,{variant:"secondary",onClick:_,disabled:k,children:"Use dango defaults"})]})]}),e(G,{isOpen:I.show,onClose:()=>T(v=>({...v,show:!1})),width:"sm",children:[e(G.Body,{children:e("p",{children:I.message})}),e(G.Actions,{children:e(D,{onClick:()=>T(v=>({...v,show:!1})),children:"OK"})})]})]})},vt="_sectionCard_1pqo4_1",bt="_settingItem_1pqo4_26",_t="_settingRow_1pqo4_31",kt="_modalOverlay_1pqo4_38",St="_modal_1pqo4_38",Ct="_modalActions_1pqo4_73",Nt="_modalSecondary_1pqo4_79",Tt="_modalPrimary_1pqo4_89",j={sectionCard:vt,settingItem:bt,settingRow:_t,modalOverlay:kt,modal:St,modalActions:Ct,modalSecondary:Nt,modalPrimary:Tt},Rt={anime:{heading:"Watchlist Preferences",blurb:"Customize your experience when managing your watchlist and series entries.",skipKey:"skipRemoveConfirmation",ignoreKey:"ignoreAdultContent",listOnlyKey:"cwWatchlistOnly",skipLabel:"Skip confirmation when removing from watchlist",ignoreLabel:"Hide adult content from continue watching",listOnlyLabel:"Only show continue watching for shows in watchlist",listNoun:"watchlist",continueNoun:"continue watching",adultCountUrl:"/api/continue-watching/adult-count",purgeUrl:"/api/continue-watching/purge-adult",purgeDoneText:t=>`Removed ${t??0} entries from continue watching`,invalidateKeys:[["allContinueWatching"]]},manga:{heading:"Reading List Preferences",blurb:"Customize your experience when managing your reading list and manga entries.",skipKey:"mangaSkipRemoveConfirmation",ignoreKey:"mangaIgnoreAdultContent",listOnlyKey:"mangaCwWatchlistOnly",skipLabel:"Skip confirmation when removing from reading list",ignoreLabel:"Hide adult content from continue reading",listOnlyLabel:"Only show continue reading for manga in reading list",listNoun:"reading list",continueNoun:"continue reading",adultCountUrl:"/api/manga/continue-reading/adult-count",purgeUrl:"/api/manga/continue-reading/purge-adult",purgeDoneText:t=>`Removed ${t??0} entries from continue reading`,invalidateKeys:[["manga-continue-reading"]]},tv:{heading:"TV Watchlist Preferences",blurb:"Customize your experience when managing your TV watchlist and series entries.",skipKey:"tvSkipRemoveConfirmation",ignoreKey:"tvIgnoreAdultContent",listOnlyKey:"tvCwWatchlistOnly",skipLabel:"Skip confirmation when removing from TV watchlist",ignoreLabel:"Hide adult content from continue watching",listOnlyLabel:"Only show continue watching for shows in TV watchlist",listNoun:"TV watchlist",continueNoun:"continue watching",adultCountUrl:"/api/tv/continue-watching/adult-count",purgeUrl:"/api/tv/continue-watching/purge-adult",purgeDoneText:t=>`Removed ${t??0} entries from continue watching`,invalidateKeys:[["tv-continue-watching"]]},asmr:{heading:"Listening List Preferences",blurb:"Customize your experience when managing your listening list and work entries.",skipKey:"asmrSkipRemoveConfirmation",ignoreKey:"asmrIgnoreAdultContent",listOnlyKey:"asmrCwWatchlistOnly",skipLabel:"Skip confirmation when removing from listening list",ignoreLabel:"Hide adult content from continue listening",listOnlyLabel:"Only show continue listening for works in listening list",listNoun:"listening list",continueNoun:"continue listening",adultCountUrl:"/api/asmr/continue-listening/adult-count",purgeUrl:"/api/asmr/continue-listening/purge-adult",purgeDoneText:t=>`Removed ${t??0} entries from continue listening`,invalidateKeys:[["asmr-continue-listening"]]}},Dt=(t,n)=>{if(t==null)return n;const o=String(t);return o==="true"||o==="1"?!0:o==="false"||o==="0"?!1:n},ye=(t,n,o)=>{const[i,l]=r(n),[w,b]=r(!1),d=ue();return U(()=>{(async()=>{try{const p=await(await fetch(`/api/settings?key=${t}`)).json();l(Dt(p.value,n))}catch(g){console.error("Failed to fetch setting",g)}})()},[t,n]),{value:i,setValue:l,isUpdating:w,toggle:async()=>{if(w)return;b(!0);const u=!i;l(u);try{await fetch("/api/settings",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:t,value:u})});for(const g of o)d.invalidateQueries({queryKey:g})}catch(g){console.error("Error saving setting:",g),l(!u)}finally{b(!1)}}}},It=()=>{const{contentType:t}=xe(),n=Rt[t],[o,i]=r(!1),[l,w]=r(!0),[b,d]=r(!1),s=ye(n.ignoreKey,!0,n.invalidateKeys),u=ye(n.listOnlyKey,!1,n.invalidateKeys),[g,p]=r(null),[h,C]=r(!1),k=ue();U(()=>{w(!0),(async()=>{try{const O=await(await fetch(`/api/settings?key=${n.skipKey}`)).json();String(O.value)==="true"||String(O.value)==="1"?i(!0):i(!1)}catch(L){console.error("Failed to fetch setting",L)}finally{w(!1)}})()},[n.skipKey]);const f=async()=>{if(b)return;d(!0);const N=!o;i(N);try{await fetch("/api/settings",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:n.skipKey,value:N})})}catch(L){console.error("Error saving setting:",L),i(!N)}finally{d(!1)}},I=async()=>{if(!s.isUpdating){if(s.value)try{const L=await(await fetch(n.adultCountUrl)).json();if(typeof L.count=="number"&&L.count>0){p(L.count);return}}catch(N){console.error("Failed to fetch adult count",N)}s.toggle()}},T=()=>{p(null),s.toggle()},P=async()=>{if(!h){C(!0);try{const L=await(await fetch(n.purgeUrl,{method:"POST"})).json();me.success(n.purgeDoneText(L.removed));for(const O of n.invalidateKeys)k.invalidateQueries({queryKey:O})}catch(N){console.error("Failed to purge adult entries",N),me.error("Failed to remove adult entries")}finally{C(!1),p(null)}s.toggle()}};return l?e("div",{children:"Loading settings..."}):e("div",{className:j.sectionCard,children:[e("h3",{children:n.heading}),e("p",{children:n.blurb}),e("div",{className:j.settingItem,children:e("div",{className:j.settingRow,children:[e("label",{htmlFor:"skip-confirmation-toggle",children:n.skipLabel}),e(F,{isChecked:o,onChange:f,id:"skip-confirmation-toggle",disabled:b})]})}),e("div",{className:j.settingItem,children:e("div",{className:j.settingRow,children:[e("label",{htmlFor:"ignore-adult-toggle",children:n.ignoreLabel}),e(F,{isChecked:s.value,onChange:I,id:"ignore-adult-toggle",disabled:s.isUpdating})]})}),e("div",{className:j.settingItem,children:e("div",{className:j.settingRow,children:[e("label",{htmlFor:"cw-watchlist-only-toggle",children:n.listOnlyLabel}),e(F,{isChecked:u.value,onChange:u.toggle,id:"cw-watchlist-only-toggle",disabled:u.isUpdating})]})}),g!==null&&e("div",{className:j.modalOverlay,onClick:()=>p(null),children:e("div",{className:j.modal,onClick:N=>N.stopPropagation(),children:[e("h4",{children:"Show adult entries?"}),e("p",{children:[g," adult ",g===1?"entry":"entries"," not in your"," ",n.listNoun," ",g===1?"is":"are"," currently hidden from"," ",n.continueNoun,". You can purge ",g===1?"it":"them"," from the database instead of showing ",g===1?"it":"them","."]}),e("div",{className:j.modalActions,children:[e("button",{type:"button",className:j.modalSecondary,onClick:T,disabled:h,children:"Show them"}),e("button",{type:"button",className:j.modalPrimary,onClick:P,disabled:h,children:h?"Purging...":`Purge ${g}`})]})]})})]})},Pt="_sectionCard_jkggs_1",xt="_statsGrid_jkggs_26",Lt="_statCard_jkggs_33",Ot="_statLabel_jkggs_43",At="_statValue_jkggs_51",Ut="_statMeta_jkggs_57",Mt="_statusBanner_jkggs_63",Et="_statusSuccess_jkggs_74",$t="_statusUpdating_jkggs_80",jt="_statusError_jkggs_86",Gt="_sha_jkggs_92",Kt="_settingItem_jkggs_99",Ht="_settingRow_jkggs_104",Ft="_settingTitle_jkggs_111",zt="_settingSubtitle_jkggs_117",Bt="_actionsRow_jkggs_124",x={sectionCard:Pt,statsGrid:xt,statCard:Lt,statLabel:Ot,statValue:At,statMeta:Ut,statusBanner:Mt,statusSuccess:Et,statusUpdating:$t,statusError:jt,sha:Gt,settingItem:Kt,settingRow:Ht,settingTitle:Ft,settingSubtitle:zt,actionsRow:Bt},Wt=()=>{const[t,n]=r(null),[o,i]=r(!0),[l,w]=r(!1),[b,d]=r(!1),s=V(null),u=async()=>{try{const k=await fetch("/api/settings/offline-db");if(k.ok){const f=await k.json();return n(f),f}}catch(k){console.error("Failed to fetch offline DB info:",k)}finally{i(!1)}return null};U(()=>(u(),()=>{s.current&&window.clearInterval(s.current)}),[]),U(()=>{t?.isRefreshing?s.current||(s.current=window.setInterval(async()=>{const k=await u();k&&!k.isRefreshing&&s.current&&(window.clearInterval(s.current),s.current=null)},2e3)):s.current&&(window.clearInterval(s.current),s.current=null)},[t?.isRefreshing]);const g=async()=>{if(!t||l)return;const k=!t.autoUpdateEnabled;w(!0),n({...t,autoUpdateEnabled:k});try{(await fetch("/api/settings/offline-db/auto-update",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({enabled:k})})).ok||n({...t,autoUpdateEnabled:!k})}catch(f){console.error("Failed to update auto update setting:",f),n({...t,autoUpdateEnabled:!k})}finally{w(!1)}},p=async()=>{if(!(t?.isRefreshing||b)){d(!0);try{(await fetch("/api/settings/offline-db/update",{method:"POST"})).ok&&n(f=>f?{...f,isRefreshing:!0,lastStatus:"updating",lastMessage:"Downloading database..."}:null)}catch(k){console.error("Failed to trigger offline DB update:",k)}finally{d(!1)}}},h=k=>{if(!k)return"Never";try{return new Date(k).toLocaleString(void 0,{dateStyle:"medium",timeStyle:"short"})}catch{return k}},C=t?.isRefreshing||b;return e("div",{className:x.sectionCard,children:[e("h3",{children:"Offline Metadata Database"}),e("p",{children:"Local MAL to AniList ID map used for instant imports and metadata enrichment without hitting rate-limited APIs. Updates automatically every Saturday in the background."}),e("div",{className:x.statsGrid,children:[e("div",{className:x.statCard,children:[e("span",{className:x.statLabel,children:"MAL Mapped"}),e("span",{className:x.statValue,children:o?"—":(t?.totalMalMapped??0).toLocaleString()})]}),e("div",{className:x.statCard,children:[e("span",{className:x.statLabel,children:"Release"}),e("span",{className:x.statMeta,children:o?"—":t?.releaseTag??"Never"})]}),e("div",{className:x.statCard,children:[e("span",{className:x.statLabel,children:"Last Checked"}),e("span",{className:x.statMeta,children:o?"—":h(t?.lastCheckedAt??null)})]}),e("div",{className:x.statCard,children:[e("span",{className:x.statLabel,children:"Last Updated"}),e("span",{className:x.statMeta,children:o?"—":h(t?.lastUpdatedAt??null)})]})]}),t?.lastMessage&&e("div",{className:`${x.statusBanner} ${t.lastStatus==="failed"?x.statusError:t.lastStatus==="updating"?x.statusUpdating:x.statusSuccess}`,children:[e("span",{children:t.lastMessage}),t.contentSha256&&e("span",{className:x.sha,children:["sha:",t.contentSha256.slice(0,12)]})]}),e("div",{className:x.settingItem,children:e("div",{className:x.settingRow,children:[e("div",{children:[e("span",{className:x.settingTitle,children:"Weekly Automatic Updates (Saturdays)"}),e("div",{className:x.settingSubtitle,children:"Download and index new database releases in the background. Catches up on startup if the server was offline."})]}),e(F,{id:"offline-db-auto-update-toggle",isChecked:t?t.autoUpdateEnabled:!0,onChange:g,disabled:o||l})]})}),e("div",{className:x.actionsRow,children:e(D,{onClick:p,disabled:o||C,children:C?"Updating Database...":"Update Offline Database Now"})})]})},qt="_sectionCard_1g4qx_1",Vt="_dangerCard_1g4qx_26",Jt="_status_1g4qx_34",Yt="_warningText_1g4qx_40",Qt="_ackLabel_1g4qx_44",Z={sectionCard:qt,dangerCard:Vt,status:Jt,warningText:Yt,ackLabel:Qt},Xt=()=>{const t=ue(),[n,o]=r(!1),[i,l]=r(!1),[w,b]=r(!1),[d,s]=r(""),u=()=>{l(!1),s(""),o(!0)},g=()=>{w||(o(!1),l(!1))},p=async()=>{if(!(!i||w)){b(!0),s("");try{const h=await fetch("/api/database/clear",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({confirm:!0})}),C=await h.json();if(!h.ok)throw new Error(C.error||"Failed to clear database");const k=C.deleted,f=C.deletedManga,I=C.deletedTv,T=C.deletedAsmr,P=Object.values(k).reduce((E,_)=>E+(_||0),0)+Object.values(f??{}).reduce((E,_)=>E+(_||0),0)+Object.values(I??{}).reduce((E,_)=>E+(_||0),0)+Object.values(T??{}).reduce((E,_)=>E+(_||0),0),N=(f?.manga_library??0)+(f?.manga_progress??0),L=(I?.tv_library??0)+(I?.tv_progress??0),O=(T?.asmr_library??0)+(T?.asmr_progress??0);s(`Library cleared — ${k.watchlist??0} watchlist entries, ${N} manga rows, ${L} TV rows, ${O} ASMR rows and ${P} total rows removed.`),t.invalidateQueries({queryKey:["watchlist"]}),t.invalidateQueries({queryKey:["allContinueWatching"]}),t.invalidateQueries({queryKey:["manga-library"]}),t.invalidateQueries({queryKey:["manga-library-ids"]}),t.invalidateQueries({queryKey:["manga-continue-reading"]}),t.invalidateQueries({queryKey:["tv-library"]}),t.invalidateQueries({queryKey:["tv-library-ids"]}),t.invalidateQueries({queryKey:["tv-continue-watching"]}),t.invalidateQueries({queryKey:["asmr-library"]}),t.invalidateQueries({queryKey:["asmr-library-ids"]}),t.invalidateQueries({queryKey:["asmr-continue-listening"]}),o(!1)}catch(h){s(h.message)}finally{b(!1),l(!1)}}};return e("div",{className:`${Z.sectionCard} ${Z.dangerCard}`,children:[e("h3",{children:"Danger Zone"}),e("p",{children:"Permanently delete your library (watchlist, watched episodes, queue, cached show metadata, manga reading list and reading progress, TV watchlist and watch progress, ASMR listening list and listening progress) to start fresh. Your settings, sync state and the offline metadata cache are preserved."}),e(D,{variant:"danger",onClick:u,children:"Clear Library Data"}),d&&e("p",{className:Z.status,children:d}),e(G,{isOpen:n,onClose:g,title:"Clear library data?",width:"sm",children:[e(G.Body,{children:[e("p",{className:Z.warningText,children:"This permanently deletes everything in your library. It acts on the active database (dev or prod, per server config) and cannot be undone. Settings, sync state and the offline metadata cache are kept."}),e("label",{className:Z.ackLabel,children:[e("input",{type:"checkbox",checked:i,onChange:h=>l(h.target.checked),disabled:w}),e("span",{children:"I understand this permanently deletes my library"})]})]}),e(G.Actions,{children:[e(D,{variant:"secondary",onClick:g,disabled:w,children:"Cancel"}),e(D,{variant:"danger",onClick:p,disabled:!i||w,children:w?"Clearing...":"Yes, delete everything"})]})]})]})},Zt=()=>{const[t,n]=r(""),[o,i]=r([]),[l,w]=r(null),[b,d]=r(!0),[s,u]=r({show:!1,message:"",type:"info"}),g=async()=>{try{d(!0);const C=await(await fetch("/api/auth/settings/rclone")).json();n(C.remote||""),i(C.availableRemotes||[]),w(C.activeRemote||null)}catch(h){console.error("Failed to fetch Rclone settings",h)}finally{d(!1)}};U(()=>{g()},[]);const p=async()=>{try{if((await fetch("/api/auth/settings/rclone",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({remote:t})})).ok)u({show:!0,message:"Rclone configuration saved successfully. You must restart the server for these changes to take effect.",type:"success"}),g();else throw new Error("Failed to save")}catch{u({show:!0,message:"Failed to save Rclone configuration.",type:"error"})}};return b?e("div",{style:{color:"var(--text-secondary)",padding:"1.5rem"},children:"Loading..."}):e("div",{className:y.sectionCard,children:[e("h3",{className:y.title,children:"Rclone Cloud Sync"}),e("p",{className:y.signIn,children:"Configure which Rclone remote to use for database synchronization."}),l?e("div",{className:y.userInfo,children:e("p",{children:["Current Active Remote: ",e("strong",{children:l})]})}):e("p",{className:y.warning,style:{marginBottom:"1.5rem"},children:"Rclone sync is not currently active. Ensure rclone is installed and a remote is configured."}),e("div",{className:y.formGroup,children:[e("label",{className:y.label,children:"Remote Name"}),e("div",{className:y.inputWrapper,children:e("select",{className:y.select,value:t,onChange:h=>n(h.target.value),children:[e("option",{value:"",children:"(Disabled / None)"}),o.map(h=>e("option",{value:h,children:h},h)),t&&!o.includes(t)&&e("option",{value:t,children:[t," (Manual)"]})]})}),e("p",{className:y.warning,style:{marginTop:"12px"},children:[e("strong",{children:"Note:"})," You can choose which provider is active using the selector at the top of the page."]})]}),e("div",{className:y.actions,children:e(D,{onClick:p,children:"Save Rclone Settings"})}),e(G,{isOpen:s.show,onClose:()=>u(h=>({...h,show:!1})),width:"sm",children:[e(G.Body,{children:e("p",{children:s.message})}),e(G.Actions,{children:e(D,{onClick:()=>u(h=>({...h,show:!1})),children:"OK"})})]})]})},ea=()=>{const[t,n]=r(null),[o,i]=r(!0),l=async()=>{try{const u=await(await fetch("/api/auth/settings/sync")).json();n(u)}catch(s){console.error("Failed to fetch sync settings",s)}finally{i(!1)}};U(()=>{l()},[]);const w=async s=>{const u=s.target.value;try{const g=await fetch("/api/auth/settings/sync",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({provider:u})});if(g.ok){const p=await g.json();n(h=>h?{...h,activeProvider:p.activeProvider}:null),await l(),ie.success(`Sync provider updated to ${u==="default"?"Default Order":u}`)}else ie.error("Failed to update sync provider")}catch{ie.error("Error updating sync provider")}};if(o||!t)return null;const b=[{value:"default",label:"Default (Priority Based)"}];t.authenticatedProviders.github&&b.push({value:"github",label:"GitHub"}),t.authenticatedProviders.google&&b.push({value:"google",label:"Google Drive"}),t.authenticatedProviders.rclone&&b.push({value:"rclone",label:"Rclone"}),b.push({value:"none",label:"None (Local Only)"});const d=s=>s==="none"?"Local Only (No Sync)":s==="google"?"Google Drive":s==="github"?"GitHub":s==="rclone"?"Rclone":s;return e("div",{className:m.sectionCard,children:[e("h3",{children:"Active Sync Provider"}),e("p",{children:'Choose which provider to use for synchronization. "Default" uses the first available provider you are logged into.'}),e("div",{style:{marginBottom:"1.5rem",padding:"0.75rem",background:"rgba(255, 255, 255, 0.03)",borderRadius:"var(--radius-md)",borderLeft:"4px solid var(--accent)",fontSize:"var(--font-size-sm)"},children:["Current Status:"," ",e("strong",{style:{color:"var(--accent-light)",textTransform:"capitalize"},children:d(t.actualActiveProvider)})]}),e("div",{className:m.settingRow,children:[e("label",{htmlFor:"sync-provider-select",children:"Selected Preference"}),e("select",{id:"sync-provider-select",value:t.activeProvider,onChange:w,style:{padding:"0.5rem",borderRadius:"var(--radius-md)",background:"rgba(255, 255, 255, 0.05)",color:"var(--text-primary)",border:"1px solid var(--glass-border)",fontSize:"var(--font-size-sm)",minWidth:"220px",outline:"none",cursor:"pointer"},children:b.map(s=>e("option",{value:s.value,children:s.label},s.value))})]})]})};function ta(){return"javascript:"+encodeURIComponent(`(function(){
|
|
2
2
|
if(!/(^|\\.)discord\\.com$/.test(location.hostname)){alert('Dango: use this bookmarklet while on discord.com');return}
|
|
3
3
|
var t=null;
|
|
4
4
|
try{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{u as e,g as t}from"./vendor-core-8R2fFbyN.js";import{u as l}from"./index-
|
|
1
|
+
import{u as e,g as t}from"./vendor-core-8R2fFbyN.js";import{u as l}from"./index-CfvzoNYQ.js";const a="_skeletonCard_1b0hr_1",i="_poster_1b0hr_11",c="_line_1b0hr_20",_="_info_1b0hr_38",d="_short_1b0hr_54",h="_horizontal_1b0hr_60",m="_vertical_1b0hr_78",v="_lowEnd_1b0hr_97",o={skeletonCard:a,poster:i,line:c,"skeleton-wave":"_skeleton-wave_1b0hr_1",info:_,short:d,horizontal:h,vertical:m,lowEnd:v},b=({layout:n="vertical"})=>{const{lowEndMode:r}=l();return e("div",{className:`${o.skeletonCard} ${o[n]} ${r?o.lowEnd:""}`,children:[e("div",{className:o.poster}),e("div",{className:o.info,children:[e("div",{className:o.line}),e("div",{className:`${o.line} ${o.short}`})]})]})},k=({count:n=14,layout:r="vertical"})=>e("div",{className:"grid-container",children:Array.from({length:n}).map((p,s)=>e(b,{layout:r},s))}),E=t.memo(k);export{b as A,E as S};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{d as a,h as me,g as ce,A as le,q as je,u as e,S as I}from"./vendor-core-8R2fFbyN.js";import{u as ue,b as de,a as R}from"./vendor-query-BXRECSI6.js";import{z as s,W as Se,B as pe}from"./index-
|
|
1
|
+
import{d as a,h as me,g as ce,A as le,q as je,u as e,S as I}from"./vendor-core-8R2fFbyN.js";import{u as ue,b as de,a as R}from"./vendor-query-BXRECSI6.js";import{z as s,W as Se,B as pe}from"./index-CfvzoNYQ.js";import{I as h}from"./vendor-icons-CDMuNDeL.js";function Ce(){const B=ue(),[r,m]=a(!1);return me(()=>{const g=new URLSearchParams(window.location.search),u=g.get("anilist");if(u){const i=g.get("user"),b=g.get("reason");window.history.replaceState(null,"",window.location.pathname),u==="success"?(s.success(i?`Connected to AniList as ${decodeURIComponent(i)}`:"Connected to AniList"),B.invalidateQueries({queryKey:["trackerStatus"]})):s.error(b?decodeURIComponent(b):"AniList authentication failed");return}const w=new URLSearchParams(window.location.hash.substring(1)),c=w.get("access_token"),D=g.get("code");if(!c&&!D){const i=w.get("error");i&&(s.error(`AniList error: ${i}`),window.history.replaceState(null,"",window.location.pathname));return}const j=window.location.origin+window.location.pathname;window.history.replaceState(null,"",window.location.pathname),m(!0),s("Connecting to AniList..."),fetch("/api/tracker/anilist/auth",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(c?{token:c}:{code:D,redirectUri:j})}).then(async i=>{const b=await i.json().catch(()=>({}));if(!i.ok)throw new Error(b.error||"Authentication failed");s.success(`Connected to AniList as ${b.user?.name??"AniList user"}`),B.invalidateQueries({queryKey:["trackerStatus"]})}).catch(i=>{s.error(i instanceof Error?i.message:"Failed to authenticate with AniList")}).finally(()=>{m(!1)})},[B]),r}const Te="_header_j1lbh_1",xe="_fadeIn_j1lbh_1",Le="_pageTitle_j1lbh_6",Ae="_pageSubtitle_j1lbh_14",Pe="_importCard_j1lbh_20",Ee="_slideUpIn_j1lbh_1",Be="_cardHeader_j1lbh_37",De="_uploadArea_j1lbh_55",Me="_fileInputWrapper_j1lbh_59",Oe="_fileInput_j1lbh_59",Fe="_fileDisplay_j1lbh_87",$e="_fileIcon_j1lbh_95",Ue="_fileName_j1lbh_100",Re="_browseButton_j1lbh_109",qe="_optionsArea_j1lbh_120",Ke="_checkboxLabel_j1lbh_128",He="_checkbox_j1lbh_128",Qe="_checkboxCustom_j1lbh_141",Ge="_optionText_j1lbh_169",We="_optionTitle_j1lbh_175",ze="_optionDesc_j1lbh_181",Je="_actions_j1lbh_187",Xe="_importBtn_j1lbh_195",Ve="_cancelBtn_j1lbh_201",Ye="_statusMessage_j1lbh_215",Ze="_success_j1lbh_225",en="_error_j1lbh_231",nn="_progressSection_j1lbh_237",tn="_progressBar_j1lbh_242",sn="_progressFill_j1lbh_250",an="_progressInfo_j1lbh_257",on="_progressCount_j1lbh_264",rn="_progressTitle_j1lbh_271",cn="_sourceBadge_j1lbh_289",ln="_anilist_j1lbh_301",dn="_kitsu_j1lbh_307",pn="_offline_j1lbh_313",hn="_skipped_j1lbh_319",mn="_cardTitleRow_j1lbh_324",un="_anilistIcon_j1lbh_334",_n="_malIcon_j1lbh_340",gn="_badgeOnline_j1lbh_346",bn="_badgeOffline_j1lbh_358",fn="_connectedProfile_j1lbh_370",yn="_avatar_j1lbh_379",wn="_connectedInfo_j1lbh_386",Nn="_connectedName_j1lbh_394",kn="_connectedHint_j1lbh_400",vn="_loginPrompt_j1lbh_405",In="_loginSection_j1lbh_413",jn="_fieldLabel_j1lbh_419",Sn="_helpText_j1lbh_438",Cn="_loginText_j1lbh_455",Tn="_primaryBtn_j1lbh_464",xn="_secondaryBtn_j1lbh_465",Ln="_syncBtn_j1lbh_466",An="_divider_j1lbh_518",Pn="_actionSection_j1lbh_524",En="_inputGroup_j1lbh_538",Bn="_input_j1lbh_538",Dn="_syncSummary_j1lbh_559",Mn="_syncErrors_j1lbh_565",On="_spin_j1lbh_569",Fn="_radioGroup_j1lbh_598",$n="_radioLabel_j1lbh_604",Un="_syncHint_j1lbh_642",Rn="_importLoading_j1lbh_649",n={header:Te,fadeIn:xe,pageTitle:Le,pageSubtitle:Ae,importCard:Pe,slideUpIn:Ee,cardHeader:Be,uploadArea:De,fileInputWrapper:Me,fileInput:Oe,fileDisplay:Fe,fileIcon:$e,fileName:Ue,browseButton:Re,optionsArea:qe,checkboxLabel:Ke,checkbox:He,checkboxCustom:Qe,optionText:Ge,optionTitle:We,optionDesc:ze,actions:Je,importBtn:Xe,cancelBtn:Ve,statusMessage:Ye,success:Ze,error:en,progressSection:nn,progressBar:tn,progressFill:sn,progressInfo:an,progressCount:on,progressTitle:rn,sourceBadge:cn,anilist:ln,kitsu:dn,offline:pn,skipped:hn,cardTitleRow:mn,anilistIcon:un,malIcon:_n,badgeOnline:gn,badgeOffline:bn,connectedProfile:fn,avatar:yn,connectedInfo:wn,connectedName:Nn,connectedHint:kn,loginPrompt:vn,loginSection:In,fieldLabel:jn,helpText:Sn,loginText:Cn,primaryBtn:Tn,secondaryBtn:xn,syncBtn:Ln,divider:An,actionSection:Pn,inputGroup:En,input:Bn,syncSummary:Dn,syncErrors:Mn,spin:On,radioGroup:Fn,radioLabel:$n,syncHint:Un,importLoading:Rn},W="tracker_anilist_client_id",he="49887".trim(),Gn=()=>{const{setIsOpen:B}=Se(),r=ue();ce.useEffect(()=>{document.title="Trackers - dango"},[]);const[m,g]=a(""),[u,w]=a("username"),[c,D]=a(null),[j,i]=a(""),b=Ce(),{data:z,isLoading:_e}=de({queryKey:["trackerStatus"],queryFn:async()=>{const t=await fetch("/api/tracker/status");if(!t.ok)throw new Error("Failed to load tracker status");return t.json()}}),{data:N}=de({queryKey:["anilistClientId"],queryFn:async()=>(await(await fetch(`/api/settings?key=${W}`)).json()).value||""}),J=le(!1);ce.useEffect(()=>{J.current||N!==void 0&&(N&&i(N),J.current=!0)},[N]);const S=z?.anilist?.connected??!1;me(()=>{S&&w("sync")},[S]);const M=z?.anilist?.user??null,q=!!he,ge=(N||"").trim(),be=async()=>{const t=j.trim(),o=t||he;if(!o){s.error("Enter your AniList client ID first");return}const _=async(y,Q)=>{if(!(await fetch("/api/settings",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:y,value:Q})})).ok)throw new Error(`Failed to save ${y}`)};try{t?t!==N&&await _(W,t):q&&ge&&await _(W,""),r.invalidateQueries({queryKey:["anilistClientId"]})}catch(y){s.error(y.message);return}const p=window.location.origin+window.location.pathname,A=encodeURIComponent(p);window.location.href=`https://anilist.co/api/v2/oauth/authorize?client_id=${encodeURIComponent(o)}&response_type=token&state=${A}`},X=R({mutationFn:async()=>{const t=await fetch("/api/tracker/anilist/disconnect",{method:"POST"});if(!t.ok)throw new Error("Failed to disconnect");return t.json()},onSuccess:()=>{r.invalidateQueries({queryKey:["trackerStatus"]}),s.success("Disconnected from AniList")},onError:t=>s.error(t.message)}),O=R({mutationFn:async()=>{const t=await fetch("/api/tracker/sync",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({provider:"anilist"})}),o=await t.json();if(!t.ok)throw new Error(o.error||"Sync failed");return o.summary},onSuccess:t=>{r.invalidateQueries({queryKey:["watchlist"]}),r.invalidateQueries({queryKey:["allContinueWatching"]}),D(t),s.success(`Sync complete — pushed ${t.pushed}, pulled ${t.pulled}, merged ${t.merged}, unchanged ${t.unchanged}`,{duration:6e3})},onError:t=>s.error(t.message)}),k=R({mutationFn:async()=>{if(!m.trim())throw new Error("Please enter a username");const t=await fetch("/api/tracker/anilist/import",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:m.trim(),erase:f})}),o=await t.json();if(!t.ok)throw new Error(o.error||"Import failed");return o.count},onSuccess:t=>{r.invalidateQueries({queryKey:["watchlist"]}),r.invalidateQueries({queryKey:["allContinueWatching"]}),s.success(`Imported ${t} anime entries from AniList`),g("")},onError:t=>s.error(t.message)}),[C,V]=a(""),d=R({mutationFn:async t=>{if(!C.trim())throw new Error("Please enter a MAL username");const o=await fetch("/api/tracker/mal/import",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:C.trim(),erase:t.erase,useOfflineDb:t.useOfflineDb,skipFallback:t.skipFallback})}),_=await o.json();if(!o.ok)throw new Error(_.error||"Import failed");return _.count},onSuccess:t=>{r.invalidateQueries({queryKey:["watchlist"]}),r.invalidateQueries({queryKey:["allContinueWatching"]}),s.success(`Imported ${t} anime entries from MAL`),V("")},onError:t=>s.error(t.message)}),[f,Y]=a(!1),[T,fe]=a(!0),[x,ye]=a(!1),[Z,ee]=a(""),[v,ne]=a(!1),[l,te]=a(null),[K,se]=a(null),[ae,F]=a(""),H=le(null),we=t=>{t.target.files&&t.target.files.length>0?ee(t.target.files[0].name):ee("")},Ne=je(async()=>{const t=document.getElementById("malFile");if(!t.files||t.files.length===0){F("Please select a file first.");return}const o=t.files[0];ne(!0),te(null),se(null),F("");const _=new AbortController;H.current=_;try{const p=new FormData;p.append("xmlfile",o),p.append("erase",String(f)),p.append("useOfflineDb",String(T)),p.append("skipFallback",String(x));const A=await fetch("/api/import/mal-xml",{method:"POST",body:p,signal:_.signal});if(!A.ok){const G=await A.text();let P="Failed to import";try{P=JSON.parse(G).error||P}catch{}throw new Error(P)}const y=A.body?.getReader();if(!y)throw new Error("No response stream");const Q=new TextDecoder;let $="",U="";for(;;){const{done:G,value:P}=await y.read();if(G)break;$+=Q.decode(P,{stream:!0});const oe=$.split(`
|
|
2
2
|
`);$=oe.pop()||"";for(const E of oe)if(E.startsWith("event: "))U=E.slice(7).trim();else if(E.startsWith("data: ")){const Ie=E.slice(6);try{const re=JSON.parse(Ie);U==="progress"?te(re):U==="complete"&&se(re)}catch{}}else E===""&&(U="")}r.invalidateQueries({queryKey:["watchlist"]})}catch(p){p instanceof DOMException&&p.name==="AbortError"?F("Import cancelled."):F(p.message)}finally{ne(!1),H.current=null}},[f,T,x,r]),ke=()=>{H.current?.abort(),fetch("/api/import/mal-xml/cancel",{method:"POST"}).catch(()=>{})},ve=l?Math.round(l.current/l.total*100):0,[L,ie]=a("username");return e("div",{className:"page-container",children:[e("div",{className:n.header,children:[e("h1",{className:n.pageTitle,children:"Trackers"}),e("p",{className:n.pageSubtitle,children:"Import & sync your anime watchlists with tracking services"})]}),e("div",{className:n.importCard,children:[e("div",{className:n.cardHeader,children:e("div",{className:n.cardTitleRow,children:[e(h,{name:"anilist",className:n.anilistIcon}),e("h3",{children:"AniList"}),_e?null:S?e("span",{className:n.badgeOnline,children:"Connected"}):e("span",{className:n.badgeOffline,children:"Not connected"})]})}),S&&M?e("div",{className:n.connectedProfile,children:[M.avatar&&e("img",{src:M.avatar,alt:"Avatar",className:n.avatar,loading:"lazy",decoding:"async"}),e("div",{className:n.connectedInfo,children:[e("span",{className:n.connectedName,children:M.name}),e("span",{className:n.connectedHint,children:"2-way sync is ready"})]}),e("button",{className:n.secondaryBtn,onClick:()=>X.mutate(),disabled:X.isPending,children:[e(h,{name:"sign-out-alt"})," Disconnect"]})]}):e("div",{className:n.loginSection,children:[e("p",{className:n.loginText,children:["Log in with AniList to enable bidirectional progress & status synchronization.",b&&e("span",{style:{marginLeft:8,color:"var(--accent)"},children:"Finishing login…"})]}),e("div",{className:n.fieldLabel,children:["AniList client ID — defaults to Dango's app"," ",e("a",{href:"https://anilist.co/settings/developer",target:"_blank",rel:"noopener noreferrer",children:["create your own app ",e(h,{name:"external-link-alt",size:9})]})]}),e("div",{className:n.inputGroup,children:[e("input",{type:"text",placeholder:"Client ID",value:j,onChange:t=>i(t.target.value),className:n.input}),e("button",{className:n.primaryBtn,onClick:be,disabled:!(j.trim()||q),children:[e(h,{name:"external-link-alt"})," Connect"]})]}),e("p",{className:n.helpText,children:q?e(I,{children:["By default uses Dango's client. To use your own AniList app: create it at"," ",e("a",{href:"https://anilist.co/settings/developer",target:"_blank",rel:"noopener noreferrer",children:"anilist.co/settings/developer"}),", set its ",e("strong",{children:"Redirect URL"})," to"," ",e("code",{children:window.location.port==="5173"?`${window.location.protocol}//${window.location.hostname}:3000/api/tracker/anilist/callback`:`${window.location.origin}/api/tracker/anilist/callback`}),", then paste only the ",e("strong",{children:"Client ID"})," above (leave empty to use Dango's)."]}):e(I,{children:["No shipped client in this build — create your own app at"," ",e("a",{href:"https://anilist.co/settings/developer",target:"_blank",rel:"noopener noreferrer",children:"anilist.co/settings/developer"}),", set ",e("strong",{children:"Redirect URL"})," to"," ",e("code",{children:window.location.port==="5173"?`${window.location.protocol}//${window.location.hostname}:3000/api/tracker/anilist/callback`:`${window.location.origin}/api/tracker/anilist/callback`}),", then paste the ",e("strong",{children:"Client ID"})," above."]})})]}),S&&e(I,{children:[e("hr",{className:n.divider}),e("div",{className:n.radioGroup,children:[e("label",{className:n.radioLabel,children:[e("input",{type:"radio",name:"anilistMode",value:"username",checked:u==="username",onChange:()=>w("username")}),e("span",{children:"Quick Import"})]}),e("label",{className:n.radioLabel,children:[e("input",{type:"radio",name:"anilistMode",value:"sync",checked:u==="sync",onChange:()=>w("sync")}),e("span",{children:"Two-way Sync"})]})]}),u==="username"?e("div",{className:n.inputGroup,children:e("input",{type:"text",placeholder:"Enter AniList username",value:m,onChange:t=>g(t.target.value),className:n.input,disabled:k.isPending,onKeyDown:t=>{t.key==="Enter"&&m.trim()&&k.mutate()}})}):e("p",{className:n.syncHint,children:"Merges progress non-destructively: pushes shows and episodes you watched on dango to AniList, and pulls anything you updated on AniList into dango."}),u==="username"&&e("div",{className:n.optionsArea,children:e("label",{className:n.checkboxLabel,children:[e("input",{type:"checkbox",checked:f,onChange:t=>Y(t.target.checked),className:n.checkbox,disabled:k.isPending}),e("span",{className:n.checkboxCustom}),e("div",{className:n.optionText,children:[e("span",{className:n.optionTitle,children:"Erase current watchlist"}),e("span",{className:n.optionDesc,children:"Delete existing watchlist before importing."})]})]})}),u==="username"?e("button",{className:n.syncBtn,onClick:()=>k.mutate(),disabled:!m.trim()||k.isPending,children:[e(h,{name:"download"}),k.isPending?"Importing...":"Start Import"]}):e(I,{children:[e("button",{className:n.syncBtn,onClick:()=>O.mutate(),disabled:O.isPending,children:[e(h,{name:"sync-alt",className:O.isPending?n.spin:""}),O.isPending?"Syncing...":"Start Sync"]}),c&&e("div",{className:n.syncSummary,children:["Pushed: ",c.pushed," · Pulled: ",c.pulled," · Merged:"," ",c.merged," · Unchanged: ",c.unchanged,c.errors.length>0&&e("span",{className:n.syncErrors,children:[" ","· ",c.errors.length," error",c.errors.length>1?"s":""]})]})]}),e("p",{style:{fontSize:"0.75rem",color:"var(--text-tertiary)",marginTop:"8px"},children:["AniList ",e("code",{children:"Rewatching (REPEATING)"})," is not tracked — entries with this status are ignored."]})]})]}),e("div",{className:n.importCard,children:[e("div",{className:n.cardHeader,children:e("div",{className:n.cardTitleRow,children:[e(h,{name:"myanimelist",className:n.malIcon}),e("h3",{children:"MyAnimeList"})]})}),e("div",{className:n.radioGroup,children:[e("label",{className:n.radioLabel,children:[e("input",{type:"radio",name:"malMode",value:"username",checked:L==="username",onChange:()=>ie("username")}),e("span",{children:"Username"})]}),e("label",{className:n.radioLabel,children:[e("input",{type:"radio",name:"malMode",value:"xml",checked:L==="xml",onChange:()=>ie("xml")}),e("span",{children:"XML File"})]})]}),L==="username"?e(I,{children:[e("div",{className:n.inputGroup,children:e("input",{type:"text",placeholder:"Enter MAL username",value:C,onChange:t=>V(t.target.value),className:n.input,disabled:d.isPending,onKeyDown:t=>{t.key==="Enter"&&C.trim()&&d.mutate({erase:f,useOfflineDb:T,skipFallback:x})}})}),d.isPending&&e("div",{className:n.importLoading,children:[e(h,{name:"sync-alt",className:n.spin}),e("span",{children:"Importing from MAL..."})]})]}):e("div",{className:n.uploadArea,children:e("div",{className:n.fileInputWrapper,children:[e("input",{type:"file",id:"malFile",accept:".xml,application/xml",className:n.fileInput,onChange:we,disabled:v}),e("div",{className:n.fileDisplay,children:[e(h,{name:"file-alt",className:n.fileIcon}),e("span",{className:n.fileName,children:Z||"Choose XML file..."})]}),e("label",{htmlFor:"malFile",className:n.browseButton,children:"Browse"})]})}),e("div",{className:n.optionsArea,children:[e("label",{className:n.checkboxLabel,children:[e("input",{type:"checkbox",checked:f,onChange:t=>Y(t.target.checked),className:n.checkbox,disabled:v||d.isPending}),e("span",{className:n.checkboxCustom}),e("div",{className:n.optionText,children:[e("span",{className:n.optionTitle,children:"Erase current watchlist"}),e("span",{className:n.optionDesc,children:"Delete existing watchlist before importing."})]})]}),e("label",{className:n.checkboxLabel,children:[e("input",{type:"checkbox",checked:T,onChange:t=>fe(t.target.checked),className:n.checkbox,disabled:v||d.isPending}),e("span",{className:n.checkboxCustom}),e("div",{className:n.optionText,children:[e("span",{className:n.optionTitle,children:"Use offline database (fast)"}),e("span",{className:n.optionDesc,children:"Match by MAL ID locally first — instant and avoids AniList rate limits."})]})]}),e("label",{className:n.checkboxLabel,children:[e("input",{type:"checkbox",checked:x,onChange:t=>ye(t.target.checked),className:n.checkbox,disabled:v||d.isPending}),e("span",{className:n.checkboxCustom}),e("div",{className:n.optionText,children:[e("span",{className:n.optionTitle,children:"Skip online fallback"}),e("span",{className:n.optionDesc,children:"Only import offline matches. Unmatched titles are skipped without API calls."})]})]})]}),L==="username"?e("button",{className:n.syncBtn,onClick:()=>d.mutate({erase:f,useOfflineDb:T,skipFallback:x}),disabled:!C.trim()||d.isPending,children:[e(h,{name:"download"}),d.isPending?"Importing...":"Start Import"]}):e("div",{className:n.actions,children:v?e(pe,{onClick:ke,className:n.cancelBtn,children:"Cancel Import"}):e(pe,{onClick:Ne,className:n.importBtn,disabled:!Z,children:[e(h,{name:"upload"})," Start Import"]})}),L==="username"&&d.isError&&e("div",{className:`${n.statusMessage} ${n.error}`,children:d.error.message}),v&&l&&e("div",{className:n.progressSection,children:[e("div",{className:n.progressBar,children:e("div",{className:n.progressFill,style:{width:`${ve}%`}})}),e("div",{className:n.progressInfo,children:[e("span",{className:n.progressCount,children:[l.current," / ",l.total]}),e("span",{className:n.progressTitle,children:l.found?e(I,{children:[l.matchedTitle,e("span",{className:`${n.sourceBadge} ${n[l.source||"anilist"]}`,children:l.source==="kitsu"?"Kitsu":l.source==="offline"?"Offline DB":"AniList"})]}):e("span",{className:n.skipped,children:["Skipped: ",l.title]})})]})]}),K&&e("div",{className:`${n.statusMessage} ${n.success}`,children:["Import complete! Imported: ",K.imported,", Skipped: ",K.skipped,"."]}),ae&&e("div",{className:`${n.statusMessage} ${n.error}`,children:ae})]})]})};export{Gn as default};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{d as b,A as I,h as v,u as t,S as Oe,n as Er,o as Nr,a as wr,T as Ee,q as T}from"./vendor-core-8R2fFbyN.js";import{e as Tn,z as Ir,M as tn,B as _e}from"./index-CfvzoNYQ.js";import{I as A}from"./vendor-icons-CDMuNDeL.js";import{M as Mr,t as Zn,f as wn,d as Br,C as Ar,S as Lr,U as Pr,a as $r,p as In,u as Rr,c as Dr,b as Or,l as Vr,q as Fr,i as xn,v as zr,w as Wr,x as Qn,s as En,e as Ur,g as Hr,h as jr,r as qr,j as st,k as Kr,E as Yr,A as Gr,P as Jr,m as be,o as Qr}from"./AvSyncCalibrator-Bs4iejCG.js";import{O as rn,S as Xr,a as Zr,A as es}from"./OptionListMenu-JQ_--ggT.js";import{u as ts}from"./useMatureConsent-CT7-KfzG.js";import{u as ns}from"./useProviders-jxh6fvMH.js";import{d as rs,g as ss,h as as,f as os,e as is,j as ls,k as cs}from"./useTvLibrary-DeGkJuvp.js";import{l as ds,c as us}from"./hls-Cbou9Eb-.js";import{u as ms}from"./useIsMobile-Dm_b6Ob3.js";import{S as hs}from"./SynopsisText-BcpwT5iw.js";import"./vendor-query-BXRECSI6.js";const ps="_fullscreenFlat_oxcpx_1",gs="_timeDisplay_oxcpx_15",fs="_bottomControls_oxcpx_19",bs="_leftControls_oxcpx_23",vs="_rightControls_oxcpx_24",ys="_controlBtn_oxcpx_28",Ss="_controlsOverlay_oxcpx_47",_s="_hidden_oxcpx_67",Cs="_topControls_oxcpx_73",ks="_backBtn_oxcpx_93",Ts="_videoTitleInfo_oxcpx_113",xs="_animeTitle_oxcpx_119",Es="_episodeLabel_oxcpx_127",Ns="_speedBoostBadge_oxcpx_134",ws="_progressBarContainer_oxcpx_180",Is="_progressBar_oxcpx_180",Ms="_thumb_oxcpx_199",Bs="_bufferedBar_oxcpx_217",As="_watchedBar_oxcpx_227",Ls="_scrubbing_oxcpx_252",Ps="_timeBubble_oxcpx_256",$s="_bottomControlsRow_oxcpx_270",Rs="_active_oxcpx_323",Ds="_settingsPanel_oxcpx_398",Os="_settingsHeader_oxcpx_417",Vs="_settingsBackBtn_oxcpx_425",Fs="_settingsTitle_oxcpx_443",zs="_settingsContent_oxcpx_454",Ws="_currentValue_oxcpx_463",Us="_menuItem_oxcpx_478",Hs="_menuNote_oxcpx_511",a={fullscreenFlat:ps,timeDisplay:gs,bottomControls:fs,leftControls:bs,rightControls:vs,controlBtn:ys,controlsOverlay:Ss,hidden:_s,topControls:Cs,backBtn:ks,videoTitleInfo:Ts,animeTitle:xs,episodeLabel:Es,speedBoostBadge:Ns,progressBarContainer:ws,progressBar:Is,thumb:Ms,bufferedBar:Bs,watchedBar:As,scrubbing:Ls,timeBubble:Ps,bottomControlsRow:$s,active:Rs,settingsPanel:Ds,settingsHeader:Os,settingsBackBtn:Vs,settingsTitle:Fs,settingsContent:zs,currentValue:Ws,menuItem:Us,menuNote:Hs},nn=-1e4,Nn=1e4,Xn=500,js=({classes:h,delayMs:k,onDelayChange:F})=>{const[$,r]=b(null),j=$??k,q=I(F);q.current=F;const B=I(k);B.current=k;const i=I(null);i.current=$,v(()=>{r(null)},[k]),v(()=>()=>{const U=i.current;U!==null&&U!==B.current&&q.current(U)},[]);const re=U=>{B.current=U,i.current=null,q.current(U),r(null)},se=U=>{const f=i.current??B.current,ue=Math.max(nn,Math.min(Nn,f+U));re(ue)};return t(Oe,{children:[t("div",{style:{display:"flex",gap:6,padding:"0.5rem 0.75rem 0.25rem"},children:[t("button",{type:"button",className:h.item,onClick:()=>se(-Xn),"aria-label":"Show subtitles 0.5 seconds earlier",style:{flex:1,justifyContent:"center"},children:t("span",{children:"-0.5s"})}),t("button",{type:"button",className:h.item,onClick:()=>se(Xn),"aria-label":"Show subtitles 0.5 seconds later",style:{flex:1,justifyContent:"center"},children:t("span",{children:"+0.5s"})}),t("button",{type:"button",className:h.item,onClick:()=>re(0),disabled:j===0,"aria-label":"Reset subtitle timing",style:{flex:1,justifyContent:"center"},children:t("span",{children:"Reset"})})]}),t(Mr,{label:"Subtitle timing",display:Zn(j),min:nn,max:Nn,step:100,value:j,percent:(j-nn)/(Nn-nn)*100,onChange:U=>{const f=Math.round(U);i.current=f,r(f)},onCommit:()=>{const U=i.current;U!==null&&re(U)}}),t("div",{className:h.note,children:"Positive delays subtitles (show later). Negative shows them earlier. 0.0s is default."})]})},qs=({classes:h,tracks:k,selected:F,onChange:$})=>t(rn,{classes:h,options:k.map((r,j)=>({key:String(j),label:r.label||r.language,selected:j===F})),onSelect:r=>$(Number(r))}),Ks=({player:h,title:k,episodeLabel:F,audioTracks:$,selectedAudioTrack:r,onAudioTrackChange:j,subtitles:q,selectedSubtitle:B,onSubtitleChange:i,streams:re,qualityIdx:se,onQualityChange:U,onBack:f,children:ue,movyServers:K=[],selectedMovyServer:St="atlanta",onMovyServerSelect:me,isMovySource:Ve=!1,videoDelayEnabled:_t=!1,onVideoDelayToggle:sn,videoDelayMs:Mt=0,onVideoDelayChange:Bt,onCalibrateAvSync:ae,subtitleDelayMs:Ct=0,onSubtitleDelayChange:At})=>{const{state:x,refs:we,actions:E}=h,N=we.videoRef,{subtitleFontSize:Ie,subtitlePosition:Me,subtitleBgOpacity:Ce,subtitleBgColor:Fe,subtitleTextColor:he,subtitleEdge:ze,subtitleBold:X}=x,[C,J]=b(null),Lt=I(null),[We,at]=b(0);v(()=>{const o=N.current;if(!o)return;const c=()=>at(o.clientHeight||0);c();const Ae=new ResizeObserver(c);return Ae.observe(o),()=>Ae.disconnect()},[N,re]);const pe=(o,c)=>{try{localStorage.setItem(o,String(c))}catch{}},an=(o,c)=>{switch(o){case"fontSize":typeof c=="number"&&(E.setSubtitleFontSize(c),pe("subtitleFontSize",c));break;case"position":typeof c=="number"&&(E.setSubtitlePosition(c),pe("subtitlePosition",c));break;case"bgOpacity":typeof c=="number"&&(E.setSubtitleBgOpacity(c),pe("subtitleBgOpacity",c));break;case"bgColor":typeof c=="string"&&(E.setSubtitleBgColor(c),pe("subtitleBgColor",c));break;case"textColor":typeof c=="string"&&(E.setSubtitleTextColor(c),pe("subtitleTextColor",c));break;case"edge":(c==="shadow"||c==="outline"||c==="none")&&(E.setSubtitleEdge(c),pe("subtitleEdge",c));break;case"bold":typeof c=="boolean"&&(E.setSubtitleBold(c),pe("subtitleBold",c));break}};v(()=>{const o="tv-player-subtitle-style";let c=document.getElementById(o);c||(c=document.createElement("style"),c.id=o,document.head.appendChild(c));const Ae={fontSize:Ie,position:Me,bgOpacity:Ce,bgColor:Fe,textColor:he,edge:ze,bold:X},Z=N.current,Wt=wn(Ie,We||Z?.clientHeight||720);if(c.textContent=Br({...Ae,fontSize:Wt}),Z){const Ut=()=>{const w=Number(Me);return isNaN(w)?0:Math.max(0,Math.min(100,w))},Tt=(w,z)=>{try{const d=w;d.snapToLines=!1,d.line=z}catch{}},ln=()=>{const w=Wt*16,z=Z.videoHeight||Z.clientHeight||720,d=Z.videoWidth||Z.clientWidth||1280;return{step:w*1.3/z*100,chars:Math.max(20,Math.floor(d/(w*.55)))}},ct=w=>{const z=Math.max(0,Math.min(100,100-Ut())),d=Array.from(w.activeCues??[]);if(d.length<=1){d.forEach(ye=>Tt(ye,z));return}const{step:Ge,chars:Y}=ln();let xt=z;for(let ye=d.length-1;ye>=0;ye--){const dn=String(d[ye].text??"").replace(/<[^>]*>/g,"").split(`
|
|
2
|
+
`).reduce((jt,mt)=>jt+Math.max(1,Math.ceil(mt.length/Y)),0),Ht=xt-dn*Ge;Tt(d[ye],Math.max(0,Ht)),xt=Ht-Ge*.4}},Ke=()=>{const w=Math.max(0,Math.min(100,100-Ut()));Array.from(Z.textTracks).forEach(z=>{z.cues&&(Array.from(z.cues).forEach(d=>Tt(d,w)),z.mode==="showing"&&ct(z))})};Ke();const Q=w=>{const z=w.target;z.mode==="showing"&&ct(z)},dt=()=>{Array.from(Z.textTracks).forEach(w=>{w.removeEventListener("cuechange",Q),w.addEventListener("cuechange",Q)}),Ke()};Array.from(Z.textTracks).forEach(w=>{w.addEventListener("cuechange",Q)}),Z.textTracks.addEventListener("addtrack",dt);const ut=Array.from(Z.querySelectorAll("track")),Ye=()=>Ke();return ut.forEach(w=>w.addEventListener("load",Ye)),()=>{Array.from(Z.textTracks).forEach(w=>{w.removeEventListener("cuechange",Q)}),Z.textTracks.removeEventListener("addtrack",dt),ut.forEach(w=>w.removeEventListener("load",Ye))}}},[Ie,Me,Ce,Fe,he,ze,X,B,q,N,We]);const kt=o=>{const c=N.current;!c||isNaN(x.duration)||x.duration===0||(c.currentTime=o*x.duration)},Ue=()=>{N.current&&(E.setIsScrubbing(!0),E.wasPlayingBeforeScrub.current=!N.current.paused,N.current.pause())},oe=o=>{const c=N.current;c&&x.duration&&(c.currentTime=o*x.duration)},Pt=()=>{E.setIsScrubbing(!1),E.wasPlayingBeforeScrub.current&&N.current?.play().catch(()=>{})},$t=o=>{const c=N.current;c&&(c.volume=o,c.muted=o===0,localStorage.setItem("playerVolume",o.toString()))},Rt=()=>{E.toggleMute()},Be=q.length>0,y=B>=0,u=()=>{J("main"),E.setShowControls(!0)},ie=()=>{if(y){i(-1);return}let o=null;try{o=localStorage.getItem("tvLastSubtitle")}catch{}i(In(q,{lastKey:o,enabled:!0}))},te=()=>{J(null)},Dt=()=>t(Oe,{children:[re.length>1&&t("button",{className:a.menuItem,onClick:()=>J("quality"),children:[t("span",{children:"Quality"}),t("span",{className:a.currentValue,children:re[se]?.quality||"Auto"})]}),Ve&&K.length>0&&t("button",{className:a.menuItem,onClick:()=>J("server"),children:[t("span",{style:{display:"flex",alignItems:"center",gap:6},children:[t(A,{name:"server",size:12})," Movy Server"]}),t("span",{className:a.currentValue,style:{textTransform:"capitalize"},children:St})]}),Be&&t("button",{className:a.menuItem,onClick:()=>J("subtitles"),children:[t("span",{children:"Subtitles"}),t("span",{className:a.currentValue,children:y?q[B]?.label||q[B]?.language:"Off"})]}),Be&&t("button",{className:a.menuItem,onClick:()=>J("subtitle-style"),children:[t("span",{children:"Subtitle Style"}),t("span",{className:a.currentValue,children:[Ie.toFixed(1),"x · ",Me]})]}),Be&&t("button",{className:a.menuItem,onClick:()=>J("subtitle-timing"),children:[t("span",{children:"Subtitle Timing"}),t("span",{className:a.currentValue,children:Zn(Ct)})]}),$.length>0&&t("button",{className:a.menuItem,onClick:()=>J("audio"),children:[t("span",{children:"Audio Track"}),t("span",{className:a.currentValue,children:$[r]?.label||$[r]?.language})]}),t("button",{className:a.menuItem,onClick:()=>J("av-sync"),children:[t("span",{children:"A/V Sync"}),t("span",{className:a.currentValue,children:_t?`${Mt}ms`:"Off"})]})]}),Ot=()=>t(rn,{classes:{item:a.menuItem,active:a.active},options:re.map((o,c)=>({key:String(c),label:o.quality,selected:c===se})),onSelect:o=>U(Number(o))}),He=()=>t(rn,{classes:{item:a.menuItem,active:a.active},options:[{key:"off",label:"Off",selected:!y},...q.map((o,c)=>({key:String(c),label:o.label||o.language,selected:c===B}))],onSelect:o=>i(o==="off"?-1:Number(o))}),Vt=()=>t(Zr,{classes:{item:a.menuItem,active:a.active},values:{fontSize:Ie,position:Me,bgOpacity:Ce,bgColor:Fe,textColor:he,edge:ze,bold:X},onChange:an}),je=()=>t(js,{classes:{item:a.menuItem,active:a.active,note:a.menuNote},delayMs:Ct,onDelayChange:o=>At?.(o)}),ot=()=>t(qs,{classes:{item:a.menuItem,active:a.active},tracks:$,selected:r,onChange:j}),on=()=>t(rn,{classes:{item:a.menuItem,active:a.active},options:K.map(o=>({key:o,label:t("span",{style:{textTransform:"capitalize"},children:o}),selected:St===o})),onSelect:o=>me?.(o)}),it=()=>t(es,{classes:{item:a.menuItem,active:a.active,note:a.menuNote},enabled:_t,delayMs:Mt,onToggle:o=>sn?.(o),onDelayChange:o=>Bt?.(o),onCalibrate:()=>{J(null),ae?.()}}),ve=x.isMuted?t(A,{name:"volume-mute"}):x.volume<.5?t(A,{name:"volume-down"}):t(A,{name:"volume-up"}),qe=t("div",{className:`${a.controlsOverlay} ${!x.showControls&&!C?a.hidden:""}`,"data-speed-boost-ignore":"true",style:{pointerEvents:"none",background:"none"},children:t("div",{className:a.topControls,onClick:o=>o.stopPropagation(),children:[t("button",{className:a.backBtn,onClick:f,title:"Back","aria-label":"Back",children:t(A,{name:"chevron-left"})}),t("div",{className:a.videoTitleInfo,children:[t("span",{className:a.animeTitle,children:k}),F&&t("span",{className:a.episodeLabel,children:F})]})]})}),lt=t(Ar,{isPlaying:x.isPlaying,onTogglePlay:E.togglePlay,onSkipBack:()=>E.seek(-10),onSkipForward:()=>E.seek(10)}),ge=t("div",{className:`${a.controlsOverlay} ${!x.showControls&&!C?a.hidden:""}`,"data-speed-boost-ignore":"true",style:{pointerEvents:"none",background:"none",justifyContent:"flex-end"},children:t("div",{className:a.bottomControls,onClick:o=>o.stopPropagation(),children:[t(Lr,{classes:{container:a.progressBarContainer,scrubbing:a.scrubbing,timeBubble:a.timeBubble,bar:a.progressBar,buffered:a.bufferedBar,watched:a.watchedBar,thumb:a.thumb},videoRef:N,duration:x.duration,formatTime:Tn,isScrubbing:x.isScrubbing,buffered:"full",onSeek:kt,onScrubStart:Ue,onScrubMove:oe,onScrubEnd:Pt,timeLabelRef:Lt}),t("div",{className:a.bottomControlsRow,children:[t("div",{className:a.leftControls,children:[t("button",{className:a.controlBtn,onClick:E.togglePlay,"aria-label":x.isPlaying?"Pause":"Play",children:x.isPlaying?t(A,{name:"pause"}):t(A,{name:"play"})}),t(Pr,{muted:x.isMuted,volume:x.volume,volumeIcon:ve,buttonClassName:a.controlBtn,onToggleMute:Rt,onVolumeChange:$t,onExpandedChange:o=>E.setShowVolumeSlider(o)}),t("span",{className:a.timeDisplay,ref:Lt,children:[Tn(0)," / ",Tn(x.duration)]})]}),t("div",{className:a.rightControls,children:[Be&&t("button",{className:`${a.controlBtn} ${y?a.active:""}`,onClick:ie,"aria-label":y?"Turn subtitles off":"Turn subtitles on",children:t(A,{name:"closed-captioning"})}),t("button",{className:`${a.controlBtn} ${C?a.active:""}`,onClick:()=>C?te():u(),"aria-label":"Settings",children:t(A,{name:"cog"})}),t("button",{className:a.controlBtn,onClick:E.toggleFullscreen,"aria-label":x.isFullscreen?"Exit Fullscreen":"Fullscreen",children:x.isFullscreen?t(A,{name:"compress"}):t(A,{name:"expand"})})]})]})]})}),Ft=C?t("div",{"data-speed-boost-ignore":"true",onClick:o=>o.stopPropagation(),children:t(Xr,{classes:{panel:a.settingsPanel,header:a.settingsHeader,backBtn:a.settingsBackBtn,title:a.settingsTitle,content:a.settingsContent},title:C==="main"?"Settings":C==="subtitle-style"?"Subtitle Style":C==="subtitle-timing"?"Subtitle Timing":C==="audio"?"Audio Track":C==="server"?"Movy Server":C==="av-sync"?"A/V Sync":C.charAt(0).toUpperCase()+C.slice(1),onBack:()=>C==="main"?te():J("main"),children:[C==="main"&&Dt(),C==="quality"&&Ot(),C==="subtitles"&&He(),C==="subtitle-style"&&Vt(),C==="subtitle-timing"&&je(),C==="audio"&&ot(),C==="server"&&on(),C==="av-sync"&&it()]})}):null,zt=x.isSpeedBoostActive?t("div",{className:a.speedBoostBadge,"aria-hidden":"true",children:[t("span",{children:"2x"}),t(A,{name:"forward",size:12})]}):null;return t($r,{player:h,topBar:qe,centerControls:lt,bottomBar:ge,settingsPanel:Ft,overlays:zt,isInteracting:!!C,className:x.isFullscreen?a.fullscreenFlat:"",children:ue})};function Ys(h,k,F){const $=()=>{const j=Array.isArray(h.audioTracks)?h.audioTracks.length:0,q=F.getWant(),B=j>0?Math.min(Math.max(0,q),j-1):q;h.audioTrack=B,B!==q&&F.onResolve(B)},r=(j,q)=>{const B=F.getWant(),i=Array.isArray(h.audioTracks)?h.audioTracks.length:0;if(q.id!==B&&B>=0&&B<i){h.audioTrack!==B&&(h.audioTrack=B);return}F.onResolve(q.id)};return h.on(k.MANIFEST_PARSED,$),h.on(k.AUDIO_TRACK_SWITCHED,r),()=>{h.off(k.MANIFEST_PARSED,$),h.off(k.AUDIO_TRACK_SWITCHED,r)}}const Gs="_page_263ma_1",Js="_header_263ma_7",Qs="_pageTitle_263ma_11",Xs="_searchForm_263ma_21",Zs="_searchInput_263ma_27",ea="_searchBtn_263ma_42",ta="_suggestions_263ma_58",na="_suggestionPill_263ma_65",ra="_statusMsg_263ma_81",sa="_error_263ma_87",aa="_textOnly_263ma_91",oa="_spinner_263ma_96",ia="_spin_263ma_96",la="_grid_263ma_110",ca="_skeletonCard_263ma_116",da="_skeletonThumb_263ma_121",ua="_skeletonLine_263ma_127",ma="_shimmer_263ma_134",ha="_backBtn_263ma_154",pa="_meta_263ma_172",ga="_headerActions_263ma_180",fa="_watchlistBtn_263ma_187",ba="_active_263ma_205",va="_year_263ma_215",ya="_rating_263ma_220",Sa="_typeBadge_263ma_229",_a="_tv_263ma_237",Ca="_movie_263ma_242",ka="_tvSeries_263ma_247",Ta="_tvMiniSeries_263ma_252",xa="_overview_263ma_257",Ea="_controls_263ma_264",Na="_controlLabel_263ma_272",wa="_select_263ma_282",Ia="_playerSection_263ma_293",Ma="_video_263ma_297",Ba="_videoHidden_263ma_319",Aa="_delayCanvas_263ma_324",La="_delayCanvasActive_263ma_337",Pa="_subtitleOverlay_263ma_341",$a="_videoIframe_263ma_360",Ra="_retryButton_263ma_368",Da="_sidebarSeason_263ma_383",Oa="_mobileSeasonRow_263ma_399",Va="_sidebarPosterCard_263ma_413",Fa="_sidebarPosterMeta_263ma_428",za="_providerSelectWrap_263ma_445",Wa="_genreRow_263ma_457",Ua="_genreChip_263ma_464",Ha="_metaRow_263ma_474",ja="_detailGrid_263ma_483",qa="_detailItem_263ma_490",Ka="_imdbLink_263ma_512",m={page:Gs,header:Js,pageTitle:Qs,searchForm:Xs,searchInput:Zs,searchBtn:ea,suggestions:ta,suggestionPill:na,statusMsg:ra,error:sa,textOnly:aa,spinner:oa,spin:ia,grid:la,skeletonCard:ca,skeletonThumb:da,skeletonLine:ua,shimmer:ma,backBtn:ha,meta:pa,headerActions:ga,watchlistBtn:fa,active:ba,year:va,rating:ya,typeBadge:Sa,tv:_a,movie:Ca,tvSeries:ka,tvMiniSeries:Ta,overview:xa,controls:Ea,controlLabel:Na,select:wa,playerSection:Ia,video:Ma,videoHidden:Ba,delayCanvas:Aa,delayCanvasActive:La,subtitleOverlay:Pa,videoIframe:$a,retryButton:Ra,sidebarSeason:Da,mobileSeasonRow:Oa,sidebarPosterCard:Va,sidebarPosterMeta:Fa,providerSelectWrap:za,genreRow:Wa,genreChip:Ua,metaRow:Ha,detailGrid:ja,detailItem:qa,imdbLink:Ka},Ya=[],lo=()=>{const{id:h}=Er(),[k]=Nr(),F=wr(),$=k.get("type"),[r,j]=b(null),[q,B]=b(!1),[i,re]=b(()=>parseInt(k.get("s")||"1",10)||1),[se,U]=b([]),[f,ue]=b(()=>parseInt(k.get("e")||"1",10)||1),[K,St]=b(()=>{try{return localStorage.getItem("tvProvider")||""}catch{return""}}),[me,Ve]=b([]),{options:_t,isFallback:sn,isLoading:Mt}=ns(),Bt=Ee(()=>_t.filter(e=>(e.kind??"tv")==="tv").map(e=>({id:e.value,label:e.label,tier:e.tier==="embed"?"embed":"direct",servers:e.servers})),[_t]),ae=sn||Bt.length===0?Ya:Bt,Ct=ae.filter(e=>e.tier==="direct"),At=ae.filter(e=>e.tier==="embed"),[x,we]=b(!1),[E,N]=b(""),[Ie,Me]=b([]),[Ce,Fe]=b(0),[he,ze]=b([]),[X,C]=b(-1),[J,Lt]=b("all"),[We,at]=b(0),[pe,an]=b(""),[kt,Ue]=b(""),[oe,Pt]=b(()=>{try{return localStorage.getItem("movyServer")||""}catch{return""}}),$t=I([]);v(()=>{$t.current=me},[me]);const Rt=I(Ce);v(()=>{Rt.current=Ce},[Ce]);const Be=I(X);v(()=>{Be.current=X},[X]);const y=Rr({skipIntervals:[]}),u=y.refs.videoRef;Dr(y,me.length>0||kt!=="");const ie=I(null),te=I([]),Dt=I(null),Ot=I(null),[He,Vt]=b(()=>{try{const e=Number(localStorage.getItem("playerVideoDelayMs"));if(Number.isFinite(e)&&e>=0&&e<=500)return Math.round(e)}catch{}return 180}),[je,ot]=b(()=>{try{return localStorage.getItem("playerVideoDelayEnabled")==="true"}catch{return!1}}),[on,it]=b(!1),[ve,qe]=b(!1),lt=I(null),ge=I(null),Ft=(e,n)=>{try{localStorage.setItem("playerVideoDelayMs",String(e)),localStorage.setItem("playerVideoDelayEnabled",String(n))}catch{}},zt=e=>{const n=Math.max(0,Math.min(500,Math.round(e)));Vt(n);try{localStorage.setItem("playerVideoDelayMs",String(n))}catch{}},[o,c]=b(()=>{try{const e=Number(localStorage.getItem("tvSubtitleDelayMs"));if(Number.isFinite(e)&&e>=-1e4&&e<=1e4)return Math.round(e)}catch{}return 0}),Ae=I(o);Ae.current=o;const Z=T(e=>{const n=Math.max(-1e4,Math.min(1e4,Math.round(e)));if(Ae.current!==n){Ae.current=n,c(n);try{localStorage.setItem("tvSubtitleDelayMs",String(n))}catch{}}},[]),Wt=()=>{lt.current={enabled:je,ms:He},ot(!0);try{localStorage.setItem("playerVideoDelayEnabled","true")}catch{}it(!0)},Ut=()=>{const e=lt.current;lt.current=null,e&&(Vt(e.ms),ot(e.enabled),Ft(e.ms,e.enabled)),qe(!1),it(!1)},Tt=()=>{lt.current=null,ot(!0),Ft(He,!0),qe(!1),it(!1)},ln=()=>{if(ve){qe(!1);return}const e=u.current;e&&!isNaN(e.currentTime)&&(ge.current=e.currentTime),qe(!0)},ct=je?He:0;Or({videoRef:u,canvasRef:Dt,delayMs:ct,enabled:je});const Ke=je,Q=Ke||o!==0,dt=I(Q);dt.current=Q;const ut=T(()=>{if(!dt.current)return;const e=u.current;e&&Array.from(e.textTracks).forEach(n=>{n.mode!=="hidden"&&(n.mode="hidden")})},[u]),{hasConsent:Ye,grant:w}=ts(),z=I("");z.current||(z.current=`tv-${Date.now()}-${Math.random().toString(36).slice(2)}`);const d=$==="movie",Ge=h?rs($||"tv",h):"",Y=Ge,xt=ss(),ye=as(),{toggle:cn,bookmarkedIds:dn,pending:Ht}=os(),{data:jt}=is(r?Ge:void 0),mt=jt?!!jt.inLibrary:Ge?dn.has(Ge):!1,er=T(()=>{!r||!h||cn({tmdbId:Number(h),mediaType:$||"tv",title:r.title,poster:r.poster,year:r.year,adult:r.adult})},[r,h,$,cn]),{data:Je,isFetched:Mn}=ls(Y||void 0,i,f),qt=Ee(()=>se.map(e=>e.episode_number).sort((e,n)=>e-n),[se]),Qe=qt.indexOf(f),un=Qe>0?qt[Qe-1]:null,P=Qe>=0&&Qe<qt.length-1?qt[Qe+1]:null,Kt=Ee(()=>(r?.seasons??[]).map(e=>e.season_number).filter(e=>Number.isFinite(e)).sort((e,n)=>e-n),[r]),fe=Ee(()=>{if(d||P!=null)return null;const e=Kt.indexOf(i);return e>=0&&e<Kt.length-1?Kt[e+1]:(r?.number_of_seasons??0)>i?i+1:null},[d,P,Kt,i,r?.number_of_seasons]),Bn=Je?.currentTime??0,An=Je?.duration??0,mn=Je?.completed===!0||Je?.completed===1||xn(Bn,An),[Le,Ne]=b(!1),ke=I(!1);v(()=>{ke.current=!1,Ne(!1)},[Y,i,f]);const[Pe,Yt]=b(!1),[ht,Ln]=b(0),[Xe,Pn]=b(!1),[pt,Ze]=b(!1),[tr,$n]=b(""),[Gt,nr]=b(!1),[rr,hn]=b(!1),sr=ms(),[gt,ar]=b(Vr),or=T(e=>{ar(e),Fr(e)},[]),le=I(!1),et=I(null),pn=I(0),Rn=I(!1),Dn=I(0),ee=I(null),On=I(""),ir=Qn(Bn,An),Et=!le.current&&!ke.current&&(Pe||Le||pt||mn||ir),ft=I(Et);ft.current=Et;const bt=I(!1);v(()=>{bt.current=Xe},[Xe]);const lr=e=>{const n=Math.floor(e/3600),s=Math.floor(e%3600/60),l=Math.floor(e%60);return n>0?`${n}:${String(s).padStart(2,"0")}:${String(l).padStart(2,"0")}`:`${s}:${String(l).padStart(2,"0")}`},$e=T((e,n)=>{if(!Y||!n||n<30)return;const s=xn(e,n),l=s?n:e;Math.abs(l-pn.current)<10&&!s||(pn.current=l,xt.mutate({mediaId:Y,season:i,episode:f,currentTime:Math.floor(l),duration:Math.floor(n),completed:s,title:r?.title??null,poster:r?.poster??null,backdrop:r?.backdrop??null,year:r?.year??null,overview:r?.overview??null,tmdbId:r?.id??null,mediaType:$||"tv",adult:r?.adult?1:0}))},[Y,i,f,xt,r,$]),Te=T((e,n)=>{qe(!1),it(!1);const s=new URLSearchParams(k);s.set("type",k.get("type")||"tv"),s.set("s",String(e)),s.set("e",String(n)),F(`${window.location.pathname}?${s.toString()}`)},[k,F]),cr=T(()=>{if(ve)return;const e=u.current;!e||e.paused||e.ended||(et.current&&clearTimeout(et.current),et.current=setTimeout(()=>{$e(e.currentTime,e.duration||0)},5e3))},[$e,u,ve]),dr=T(()=>{const e=u.current;if(!e||!r)return;et.current&&clearTimeout(et.current),$e(e.currentTime,e.duration||0),Rn.current=!0;const n=zr({seekInduced:Date.now()-Dn.current<Wr,autoplayEnabled:gt,hasNext:!d&&P!=null,isFinal:d||P==null});n==="advance"&&P!=null?(ue(P),Te(i,P)):n==="prompt-next"?(ke.current=!1,le.current=!0,Ne(!0)):n==="prompt-complete"&&($n(d?r.title:`${r.title} — Season ${i}`),Ze(!0),ke.current=!0,le.current=!0)},[d,r,i,P,gt,$e,Te,u]),ur=T(()=>{Rn.current=!1,y.actions.onPlay()},[y.actions]),mr=T(()=>{y.actions.onPause();const e=u.current;e&&!e.ended&&$e(e.currentTime,e.duration||0)},[y.actions,$e,u]),hr=T(()=>{y.actions.onLoadedMetadata();const e=u.current;if(e){try{const n=parseFloat(localStorage.getItem("playerVolume")||"");isNaN(n)||(e.volume=Math.max(0,Math.min(1,n))),e.muted=localStorage.getItem("playerMuted")==="true"}catch{}if(ee.current!=null&&ee.current>0){try{e.currentTime=ee.current}catch{}ee.current=null}}},[y.actions,u]),vt=T(()=>{const e=u.current;if(e&&ee.current!=null&&ee.current>0){try{e.currentTime=ee.current}catch{}ee.current=null}},[u]),pr=T(()=>{ht>0&&(ee.current=ht);const e=u.current;if(e&&ht>0){try{e.currentTime=ht,ee.current=null}catch{}e.play().catch(()=>{})}Yt(!1),le.current=!0},[ht,u]),Vn=T(()=>{ee.current=null;const e=u.current;e&&(e.currentTime=0,e.play().catch(()=>{})),Yt(!1),le.current=!0},[u]),gr=T(()=>{ke.current=!0,Ne(!1),le.current=!0},[]),fr=T(()=>{ke.current=!0,Ne(!1),le.current=!0,ee.current=null;const e=u.current;if(e){try{e.currentTime=0}catch{}e.play().catch(()=>{})}},[u]),br=T(()=>{P!=null&&(ke.current=!0,Ne(!1),le.current=!0,ue(P),Te(i,P))},[P,i,Te]),Fn=T(()=>{fe!=null&&(ke.current=!0,Ne(!1),Ze(!1),le.current=!0,re(fe),ue(1),Te(fe,1))},[fe,Te]),vr=T(async()=>{if(Y)try{await ye.mutateAsync({id:Y,status:"Completed"}),Ze(!1),Ne(!1),F("/")}catch{}},[Y,ye,F]);v(()=>{le.current=!1,Yt(!1),Ln(0),Pn(!1),bt.current=!1,ee.current=null,On.current=`${Y}:${i}:${f}`,pn.current=0},[Y,i,f]),v(()=>{Mn&&(Pn(!0),bt.current=!0)},[Mn,Y,i,f]),v(()=>{if(!Je||le.current)return;const e=Je,n=e.currentTime??0,s=e.duration??0;Qn(n,s)&&(Ln(n),Yt(!0))},[Je,Y,i,f]),v(()=>{if(!(!Xe||le.current||ke.current)&&!(Pe||pt||Le)&&mn){if(d){Ne(!0);return}if(!(!r||Qe<0||se.length===0)){if(P==null&&fe==null){r&&se.length>0&&($n(`${r.title} — Season ${i}`),Ze(!0),ke.current=!0,le.current=!0);return}Ne(!0)}}},[Xe,mn,Pe,pt,Le,d,P,fe,r,Qe,se.length,Y,i,f]),v(()=>{(Pe||Le)&&u.current&&u.current.pause()},[Pe,Le,u]),v(()=>{const e=u.current;return()=>{et.current&&clearTimeout(et.current),e&&!e.ended&&$e(e.currentTime,e.duration||0)}},[$e,u]);const gn=T(e=>{let n=null,s=!0;try{n=localStorage.getItem("tvLastSubtitle"),s=localStorage.getItem("tvSubtitlesEnabled")!=="false"}catch{}return In(e,{lastKey:n,enabled:s})},[]),fn=T(e=>{if(!(e<0))try{localStorage.setItem("tvSubtitlesEnabled","true"),localStorage.setItem("tvSelectedSubtitle",String(e))}catch{}},[]),zn=T(e=>{if(e.length===0)return 0;let n=null;try{n=localStorage.getItem("tvLastAudio")}catch{}if(n){const s=e.findIndex(S=>En(S)===n);if(s>=0)return s;const l=n.indexOf("|||"),p=l>=0?n.slice(0,l):n,R=l>=0?n.slice(l+3):n,g=e.findIndex(S=>S.language===p||S.label===R);if(g>=0)return g}return In(e,{lastKey:null,enabled:!0})},[]),bn=Ee(()=>ae.find(e=>e.id===K),[ae,K]),W=bn?.tier==="embed",ne=Ee(()=>bn?.servers??[],[bn]),{data:Wn}=cs(Y||void 0),Un=Ee(()=>(Wn?.progress??[]).filter(n=>n.season===i&&(n.completed===!0||n.completed===1||xn(n.currentTime,n.duration))).map(n=>String(n.episode)),[Wn,i]),Hn=Ee(()=>se.map(e=>({id:String(e.episode_number),label:`Episode ${e.episode_number}`,sublabel:e.name||void 0,thumbnail:e.still_path?`https://image.tmdb.org/t/p/w185${e.still_path}`:void 0})),[se]),jn=Ee(()=>(r?.genres??[]).map(e=>e.name).slice(0,5),[r]),vn=Ee(()=>[r?.year,r?.status,r?.number_of_seasons?`${r.number_of_seasons} Season${r.number_of_seasons>1?"s":""}`:null,r?.number_of_episodes?`${r.number_of_episodes} Episodes`:null].filter(Boolean),[r]);v(()=>{if(ae.length!==0&&!ae.some(e=>e.id===K)){const e=ae.find(n=>n.tier==="direct")?.id??ae[0].id;St(e);try{localStorage.setItem("tvProvider",e)}catch{}}},[ae,K]),v(()=>{if(ne.length!==0&&!ne.includes(oe)){Pt(ne[0]);try{localStorage.setItem("movyServer",ne[0])}catch{}}},[ne,oe]),v(()=>{if(!h){j(null),Ve([]),N(""),Ue("");return}const e=Number(h),n=$||"tv";B(!0),j(null),Ve([]),N(""),Ue("");const s=parseInt(k.get("s")||"",10),l=parseInt(k.get("e")||"",10);re(isNaN(s)?1:s),ue(isNaN(l)?1:l),at(0),fetch(`/api/tv/details/${n}/${e}`).then(p=>p.json()).then(p=>{j(p),B(!1),p.seasons&&p.seasons.length>0&&isNaN(s)&&re(p.seasons[0].season_number)}).catch(()=>{B(!1)})},[h,$,k]),v(()=>{if(!r||!h)return;if(!(r.seasons!==void 0||r.number_of_seasons!==void 0)){U([]);return}const n=parseInt(k.get("e")||"",10);fetch(`/api/tv/episodes/${h}/${i}`).then(s=>s.json()).then(s=>{if(U(s.episodes||[]),s.episodes?.length>0){const l=!isNaN(n)&&s.episodes.find(p=>p.episode_number===n)?n:s.episodes[0].episode_number;ue(l)}}).catch(()=>{})},[r,h,i,k]),v(()=>{!r||!h||d||fetch(`/api/tv/episodes/${h}/${i}`).then(e=>e.json()).then(e=>{const n=e.episodes||[];U(n),n.length>0&&!n.find(s=>s.episode_number===f)&&ue(n[0].episode_number)}).catch(()=>{})},[i,r,h,d,f]),v(()=>{if(!W||!r||!h)return;fetch(`/api/tv/embed/${K}/${d?"movie":"tv"}/${h}?season=${i}&episode=${f}`).then(n=>n.json()).then(n=>{if(n.url)return Ue(n.url),fetch(`/api/resolve?url=${encodeURIComponent(n.url)}`).then(s=>s.json()).then(s=>{s.finalUrl&&Ue(s.finalUrl)})}).catch(()=>{})},[K,r,h,i,f,d,W]);const Jt=T(async()=>{if(!r||!h||!K||W||r.adult&&!Ye)return;$t.current.length>0?N(""):(we(!0),N(""),Ve([]),at(0),Me([]),ze([]));try{const n=d?"movie":"tv",s=new URLSearchParams({title:r.title||"",year:r.year||"",season:String(i),episode:String(f),totalSeasons:String(r.number_of_seasons||1),imdbId:r.imdb_id||""});ne.length>0&&oe&&s.set("server",oe);const p=await(await fetch(`/api/tv/sources/${K}/${n}/${h}?${s.toString()}`)).json();if(we(!1),!p.valid||!p.sources?.length){N(p.error?`${p.error}`:ne.length>0?`No streams from ${oe}. Try another server.`:"No streams available.");return}Ve(p.sources),Lt("all"),at(0),p.referer&&an(p.referer);const R=p.audioTracks||[];Me(R),Fe(R.length>0?zn(R):0);const g=p.subtitles||[];if(ze(g),g.length>0){const H=gn(g);C(H),fn(H)}else C(-1);fetch(`/api/tv/subtitles/${n}/${h}?season=${i}&episode=${f}`).then(H=>H.json()).then(H=>{const Se=Array.isArray(H.subtitles)?H.subtitles:[];Se.length!==0&&ze(L=>{const M=[...L,...Se.filter(_=>!L.some(D=>D.url===_.url))];if(L.length===0){const _=gn(M);C(_),fn(_)}return M})}).catch(()=>{}),N("")}catch{we(!1),N("Failed to load streams.")}},[r,h,K,i,f,d,W,Ye,ne,oe,gn,fn,zn]),yn=T(e=>{const n=e.toLowerCase();Pt(n);try{localStorage.setItem("movyServer",n)}catch{}N("")},[]),yr=T(e=>{St(e);try{localStorage.setItem("tvProvider",e)}catch{}},[]);v(()=>{K&&r&&!W&&Jt()},[K,r,Jt,W]),v(()=>{if(!u.current||(ie.current&&(ie.current.destroy(),ie.current=null),W))return;let e=!1;if(ve){const g=u.current;return g&&(g.pause(),g.removeAttribute("src"),g.load(),g.src="/av-sync-test.mp4",ft.current||g.play().catch(()=>{})),()=>{e=!0}}const n=J==="all"?me:me.filter(g=>g.type===J),s=n[We]?.url||"";if(!s)return;const l=u.current;if(On.current===`${Y}:${i}:${f}`&&ee.current==null&&!ft.current)try{!l.ended&&l.currentTime>1&&(ee.current=l.currentTime)}catch{}l.pause(),l.removeAttribute("src"),l.load();const p=`/api/tv/stream-proxy?url=${encodeURIComponent(s)}&referer=${encodeURIComponent(pe)}`;n[We]?.type==="hls"?(async()=>{const g=await ds();if(!e)if(g&&g.isSupported()){const S=new g({enableWorker:!0});ie.current=S,S.on(g.Events.ERROR,(L,M)=>{M.fatal&&(N(`Stream failed (${M.details}). Try another source or reload.`),we(!1),S.destroy(),ie.current=null)}),S.loadSource(p),S.attachMedia(l);const H=()=>{let L=!1,M=0;try{L=localStorage.getItem("tvSubtitlesEnabled")==="true";const _=parseInt(localStorage.getItem("tvSelectedSubtitle")||"0",10);!isNaN(_)&&_>=0&&(M=_)}catch{}return{enabled:L,index:M}},Se=()=>{if(typeof S.subtitleTrack!="number")return;if(te.current.length>0){S.subtitleTrack=-1;return}const L=Array.isArray(S.subtitleTracks)?S.subtitleTracks:[];if(L.length===0){S.subtitleTrack=-1;return}const M=H();if(M.enabled){const _=M.index<L.length?M.index:0;S.subtitleTrack=_,C(_),ut()}else S.subtitleTrack=-1};Ys(S,g.Events,{getWant:()=>Rt.current,onResolve:L=>Fe(L)}),S.on(g.Events.MANIFEST_PARSED,()=>{Se(),ge.current!=null&&(l.currentTime=ge.current,ge.current=null),vt(),!ft.current&&bt.current&&l.play().catch(()=>{})}),S.on(g.Events.SUBTITLE_TRACKS_UPDATED,()=>{Se()}),S.on(g.Events.SUBTITLE_TRACK_SWITCH,(L,M)=>{if(te.current.length>0){if(M.id!==-1)try{S.subtitleTrack=-1}catch{}return}const _=Array.isArray(S.subtitleTracks)?S.subtitleTracks:[];if(_.length!==0){if(M.id===-1){const D=H();if(D.enabled){const G=D.index<_.length?D.index:0;S.subtitleTrack=G;return}}C(M.id),ut()}})}else us(l)&&(l.src=p,ge.current!=null&&(l.currentTime=ge.current,ge.current=null),vt(),!ft.current&&bt.current&&l.play().catch(()=>{N("Failed to play stream. Try another source.")}))})():(l.src=p,ge.current!=null&&(l.currentTime=ge.current,ge.current=null),vt(),!ft.current&&bt.current&&l.play().catch(()=>{N("Failed to play stream. Try another source.")}));const R=()=>{const H=l.error?.code===4?"Video source not supported or not found":"Failed to load video stream";N(`${H}. The source may be invalid or expired. Try switching source or reloading.`),we(!1)};return l.addEventListener("error",R),()=>{e=!0,l.removeEventListener("error",R)}},[me,We,J,K,pe,W,u,ve,Y,i,f,vt,ut]),v(()=>{if(!Xe||Pe||Le||pt||Et||W||ve)return;const e=u.current;!e||!e.paused||e.ended||e.readyState<1||(vt(),e.play().catch(()=>{}))},[Xe,Pe,Le,pt,Et,W,ve,vt,u]),v(()=>{const e=ie.current;!e||typeof e.audioTrack!="number"||(e.audioTrack=Ce)},[Ce]),v(()=>{const e=ie.current;!e||typeof e.subtitleTrack!="number"||!Array.isArray(e.subtitleTracks)||e.subtitleTracks.length===0||te.current.length>0||(X>=0?e.subtitleTrack=X:e.subtitleTrack=-1)},[X]),v(()=>{const e=u.current;if(!(!e||W)&&(e.querySelectorAll("track").forEach(n=>n.remove()),te.current=[],he.length!==0&&(he.forEach(n=>{const s=document.createElement("track");s.kind="subtitles",s.label=n.label||n.language||"Unknown",s.srclang=n.language||n.label||"en";const l=`/api/subtitle-proxy?url=${encodeURIComponent(n.url)}&referer=${encodeURIComponent(pe)}`;s.src=l,s.addEventListener("load",()=>{const p=te.current.indexOf(s),R=s.track;if(R&&p>=0){const g=p===Be.current;R.mode=g&&!dt.current?"showing":"hidden"}}),e.appendChild(s),te.current.push(s)}),he.length>0)))try{const n=ie.current;n&&typeof n.subtitleTrack=="number"&&n.subtitleTrack!==-1&&(n.subtitleTrack=-1)}catch{}},[he,pe,W,K,u]),v(()=>{const e=u.current;if(!e||W)return;const n=ie.current;te.current.length>0&&n&&typeof n.subtitleTrack=="number"&&Array.isArray(n.subtitleTracks)&&n.subtitleTracks.length>0&&(n.subtitleTrack=-1);const s=()=>{const R=wn(y.state.subtitleFontSize,e.clientHeight||720),g=Math.max(0,Math.min(100,100-y.state.subtitlePosition)),S=()=>{const _=R*16,D=e.videoHeight||e.clientHeight||720,G=e.videoWidth||e.clientWidth||1280;return{step:_*1.3/D*100,chars:Math.max(20,Math.floor(G/(_*.55)))}},H=(_,D)=>{const G=_;G.snapToLines=!1,G.line=D},Se=_=>{if(!_.cues)return;Array.from(_.cues).forEach(ce=>H(ce,g));const D=Array.from(_.activeCues??[]);if(D.length<=1){D.forEach(ce=>H(ce,g));return}const{step:G,chars:O}=S();let tt=g;for(let ce=D.length-1;ce>=0;ce--){const Re=String(D[ce].text??"").replace(/<[^>]*>/g,"").split(`
|
|
3
|
+
`).reduce((Zt,wt)=>Zt+Math.max(1,Math.ceil(wt.length/O)),0);tt=Math.max(0,tt-Re*G),H(D[ce],tt),tt-=G*.4}},L=te.current;if(L.length>0){L.forEach((_,D)=>{const G=_.track;if(!G)return;const O=D===X;G.mode=O&&!Q?"showing":"hidden",O&&!Q&&Se(G)});return}const M=Array.from(e.textTracks);M.length!==0&&M.forEach((_,D)=>{const G=D===X;_.mode=G&&!Q?"showing":"hidden",G&&!Q&&Se(_)})};s();const l=()=>s();e.textTracks.addEventListener("addtrack",l),e.addEventListener("loadedmetadata",s,{once:!0});const p=window.setTimeout(s,600);return()=>{e.textTracks.removeEventListener("addtrack",l),e.removeEventListener("loadedmetadata",s),window.clearTimeout(p)}},[X,he,W,K,u,Q,y.state.subtitleFontSize,y.state.subtitlePosition]),v(()=>{if(!Q)return;const e=u.current,n=Ot.current;if(!e||!n)return;const s=o/1e3,l=ct/1e3,p=new Set;let R=[],g=-1,S=-1,H=-1,Se=-1,L=0,M=0,_=!1;const D=()=>{const V=Be.current;if(V<0)return null;const De=te.current;return De.length>0?De[V]?.track??null:Array.from(e.textTracks)[V]??null},G=(V,De)=>{const de=V.cues;if(!de||de.length===0)return Array.from(V.activeCues??[]);let nt=0,rt=de.length;for(;nt<rt;){const xe=nt+rt>>>1;de[xe].endTime+s<De?nt=xe+1:rt=xe}const It=[];for(let xe=nt;xe<de.length;xe++){const en=de[xe];if(en.startTime+s>De)break;en.endTime+s>=De&&It.push(en)}return It},O=()=>{const V=D(),De=e.currentTime-l,de=V?G(V,De):[],nt=e.clientWidth,rt=e.clientHeight,It=e.videoWidth,xe=e.videoHeight;if(de.length===R.length&&de.every((_n,Cn)=>_n===R[Cn])&&nt===g&&rt===S&&It===H&&xe===Se||(R=de,g=nt,S=rt,H=It,Se=xe,n.textContent="",de.length===0))return;const Gn={fontSize:wn(y.state.subtitleFontSize,rt),position:y.state.subtitlePosition,bgOpacity:y.state.subtitleBgOpacity,bgColor:y.state.subtitleBgColor,textColor:y.state.subtitleTextColor,edge:y.state.subtitleEdge,bold:y.state.subtitleBold},kr=Ur(Gn),Tr=Hr(e,Gn.position);de.forEach((_n,Cn)=>{const Jn=String(_n.text??"");if(!jr(Jn).trim())return;const kn=document.createElement("div"),xr=(de.length-1-Cn)*1.7;kn.style.cssText=`${kr}
|
|
4
|
+
bottom: calc(${Tr}px + ${xr}em);`,kn.innerHTML=qr(Jn),n.appendChild(kn)})},tt=()=>{Array.from(e.textTracks).forEach(V=>{p.has(V)||(p.add(V),V.addEventListener("cuechange",O))})},ce=()=>{tt(),O()},Sn=()=>{if(_||M)return;const V=()=>{M=0,!(_||e.paused||e.ended)&&(O(),Sn())};M=window.requestAnimationFrame(V)},Re=e,Zt=()=>{L=0,O(),!_&&Re.requestVideoFrameCallback&&(L=Re.requestVideoFrameCallback(Zt))},wt=()=>{O(),Re.requestVideoFrameCallback?L||(L=Re.requestVideoFrameCallback(Zt)):Sn()};tt(),e.textTracks.addEventListener("addtrack",ce),e.textTracks.addEventListener("removetrack",ce),e.addEventListener("timeupdate",O),e.addEventListener("seeked",O),e.addEventListener("loadedmetadata",O),e.addEventListener("play",wt);const Kn=Array.from(e.querySelectorAll("track"));Kn.forEach(V=>V.addEventListener("load",O));const Yn=typeof ResizeObserver>"u"?null:new ResizeObserver(()=>O());return Yn?.observe(e),O(),wt(),()=>{_=!0,p.forEach(V=>V.removeEventListener("cuechange",O)),e.textTracks.removeEventListener("addtrack",ce),e.textTracks.removeEventListener("removetrack",ce),e.removeEventListener("timeupdate",O),e.removeEventListener("seeked",O),e.removeEventListener("loadedmetadata",O),e.removeEventListener("play",wt),Kn.forEach(V=>V.removeEventListener("load",O)),Yn?.disconnect(),M&&window.cancelAnimationFrame(M),L&&Re.cancelVideoFrameCallback&&Re.cancelVideoFrameCallback(L),n.textContent=""}},[Q,o,X,he,ct,u,y.state.subtitleFontSize,y.state.subtitlePosition,y.state.subtitleBgOpacity,y.state.subtitleBgColor,y.state.subtitleTextColor,y.state.subtitleEdge,y.state.subtitleBold]);const Qt=()=>{j(null),Ve([]),Ue(""),F(-1)},Sr=T(e=>{re(e),ue(1),Te(e,1)},[Te]),Xt=!d&&r?.seasons&&r.seasons.length>1?t("label",{className:m.sidebarSeason,children:[t("span",{children:"Season"}),t("select",{value:i,onChange:e=>Sr(parseInt(e.target.value,10)||1),className:m.select,children:r.seasons.map(e=>t("option",{value:e.season_number,children:["Season ",e.season_number," (",e.episode_count," ep)"]},e.season_number))})]}):null,yt=T(e=>{const n=parseInt(e,10);isNaN(n)||(ue(n),Te(i,n)),hn(!1)},[i,Te]);v(()=>{if(d)return;const e=n=>{n.target.closest('input, textarea, button, select, a, [role="button"], [contenteditable="true"]')||n.key.toLowerCase()==="n"&&(P!=null?yt(String(P)):Ir.error("No next episode available"))};return document.addEventListener("keydown",e),()=>{document.removeEventListener("keydown",e)}},[d,P,yt]);const _r=e=>{Fe(e);try{const s=Ie[e];s&&localStorage.setItem("tvLastAudio",En(s))}catch{}const n=ie.current;n&&n.audioTrack!==void 0&&(n.audioTrack=e)},Cr=e=>{C(e);try{if(e===-1)localStorage.setItem("tvSubtitlesEnabled","false");else{localStorage.setItem("tvSubtitlesEnabled","true"),localStorage.setItem("tvSelectedSubtitle",String(e));const p=he[e];p&&localStorage.setItem("tvLastSubtitle",En(p))}}catch{}const n=u.current,s=ie.current;if(s&&typeof s.subtitleTrack=="number"&&Array.isArray(s.subtitleTracks)&&s.subtitleTracks.length>0&&(s.subtitleTrack=te.current.length>0||e<0?-1:e),!n)return;const l=te.current;if(l.length>0){l.forEach((p,R)=>{const g=p.track;if(!g)return;const S=R===e;g.mode=S&&!Q?"showing":"hidden"});return}Array.from(n.textTracks).forEach((p,R)=>{const g=R===e;p.mode=g&&!Q?"showing":"hidden"})},Nt=T(()=>{if(!r)return;const e=u.current,n=d?"":`S${String(i).padStart(2,"0")}E${String(f).padStart(2,"0")}`;fetch("/api/discord/tv",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({title:r.title,episodeLabel:n,isPlaying:e?!e.paused&&!e.ended:!0,thumbnail:r.poster,currentTime:e?e.currentTime:0,duration:e&&e.duration||0,isAdult:r.adult===!0,sessionId:z.current})}).catch(()=>{}),fetch("/api/discord/heartbeat",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sessionId:z.current})}).catch(()=>{})},[r,d,i,f,u]);v(()=>{if(!r)return;Nt();const e=window.setInterval(()=>{const n=u.current;(!n||!n.paused)&&Nt()},15e3);return()=>window.clearInterval(e)},[Nt,r,u]),v(()=>{if(!r||W||x||E||me.length===0)return;const e=u.current;if(!e)return;const n=()=>Nt();return e.addEventListener("play",n),e.addEventListener("pause",n),e.addEventListener("seeked",n),()=>{e.removeEventListener("play",n),e.removeEventListener("pause",n),e.removeEventListener("seeked",n)}},[r,W,x,E,me,Nt,u]),v(()=>{const e=z.current,n=()=>{const l=JSON.stringify({sessionId:e});navigator.sendBeacon?(navigator.sendBeacon("/api/discord/clear",new Blob([l],{type:"application/json"})),navigator.sendBeacon("/api/discord/heartbeat",new Blob([JSON.stringify({sessionId:e,bye:!0})],{type:"application/json"}))):fetch("/api/discord/clear",{method:"POST",headers:{"Content-Type":"application/json"},body:l,keepalive:!0}).catch(()=>{})},s=()=>n();return window.addEventListener("pagehide",s),window.addEventListener("beforeunload",s),()=>{window.removeEventListener("pagehide",s),window.removeEventListener("beforeunload",s),n()}},[]);const qn=J==="all"?me:me.filter(e=>e.type===J);return v(()=>{if(!r){document.title="TV & Movies - dango";return}document.title=d?`${r.title} - dango`:`${r.title} - Season ${i} Episode ${f} - dango`},[r,d,i,f]),v(()=>{if(!r||d)return;const e=new URLSearchParams(k),n=e.get("s"),s=e.get("e"),l=String(i),p=String(f);n===l&&s===p||(e.set("type",k.get("type")||"tv"),e.set("s",l),e.set("e",p),F(`${window.location.pathname}?${e.toString()}`,{replace:!0}))},[r,d,i,f,k,F]),t("div",{className:st.playerPageLayout,children:[t("aside",{className:st.episodeSidebar,children:r?d?t("div",{className:m.sidebarPosterCard,children:[r.poster&&t("img",{src:`https://image.tmdb.org/t/p/w342${r.poster}`,alt:r.title,loading:"lazy",decoding:"async"}),t("div",{className:m.sidebarPosterMeta,children:[t("strong",{children:r.title}),t("span",{children:r.year})]})]}):t(Kr,{episodes:Hn,currentEpisode:String(f),watchedEpisodes:Un,onEpisodeClick:yt,header:Xt}):d?t("div",{className:m.statusMsg,children:[t(A,{name:"spinner",className:m.spinner})," Loading..."]}):t(Yr,{variant:"sidebar"})}),t("div",{className:st.playerMain,children:[r&&t("div",{className:m.playerSection,onContextMenu:e=>e.preventDefault(),style:r.adult&&!Ye?{filter:"blur(14px)",pointerEvents:"none",userSelect:"none"}:void 0,children:[x&&!W&&t("div",{className:m.statusMsg,children:[t(A,{name:"spinner",className:m.spinner})," Loading stream..."]}),W&&kt?t("iframe",{src:kt,className:m.videoIframe,allow:"autoplay; fullscreen",allowFullScreen:!0}):!W&&!x&&qn.length>0?t(Oe,{children:[E&&t("div",{className:`${m.statusMsg} ${m.error}`,style:{flexDirection:"column",alignItems:"stretch",gap:8},children:[t("div",{style:{display:"flex",alignItems:"center",gap:8,flexWrap:"wrap"},children:[t("span",{style:{flex:1},children:E}),t("button",{className:m.retryButton,onClick:Jt,children:"Retry"})]}),ne.length>0&&t("div",{style:{display:"flex",flexWrap:"wrap",gap:6,alignItems:"center",marginTop:4},children:[t("span",{style:{fontSize:"0.8rem",opacity:.9,fontWeight:600},children:"Servers:"}),ne.map(e=>t("button",{onClick:()=>yn(e),className:m.retryButton,style:{padding:"4px 8px",fontSize:"0.75rem",textTransform:"capitalize",background:oe===e?"var(--accent)":void 0,color:oe===e?"white":void 0},children:e},e))]})]}),t(Ks,{player:y,title:r.title,episodeLabel:d?void 0:`S${i} E${f}`,audioTracks:Ie,selectedAudioTrack:Ce,onAudioTrackChange:_r,subtitles:he,selectedSubtitle:X,onSubtitleChange:Cr,streams:qn,qualityIdx:We,onQualityChange:at,onBack:Qt,movyServers:ne,selectedMovyServer:oe,onMovyServerSelect:yn,isMovySource:ne.length>0,videoDelayEnabled:je,onVideoDelayToggle:e=>{ot(e);try{localStorage.setItem("playerVideoDelayEnabled",String(e))}catch{}},videoDelayMs:He,onVideoDelayChange:zt,onCalibrateAvSync:Wt,subtitleDelayMs:o,onSubtitleDelayChange:Z,children:[t("video",{ref:u,autoPlay:Xe&&!Et,playsInline:!0,disablePictureInPicture:!0,className:`${m.video} ${Ke?m.videoHidden:""}`,onTimeUpdate:cr,onEnded:()=>{ve||dr()},onPlay:ur,onPause:mr,onSeeked:()=>{Dn.current=Date.now()},onLoadedMetadata:hr,onVolumeChange:y.actions.onVolumeChange,onContextMenu:e=>e.preventDefault(),onError:()=>{N("Video failed to load. Try another server or reload."),we(!1)}}),t("canvas",{ref:Dt,className:`${m.delayCanvas} ${Ke?m.delayCanvasActive:""}`}),Q&&t("div",{ref:Ot,className:m.subtitleOverlay}),t(Gr,{isOpen:on,ms:He,onChange:zt,onApply:Tt,onClose:Ut,testClipActive:ve,onTestClip:ln})]})]}):E&&!W?t("div",{className:`${m.statusMsg} ${m.error}`,style:{flexDirection:"column",alignItems:"stretch",gap:8},children:[t("div",{style:{display:"flex",alignItems:"center",gap:8,flexWrap:"wrap"},children:[t("span",{style:{flex:1},children:E}),t("button",{className:m.retryButton,onClick:Jt,children:"Retry"})]}),ne.length>0&&t("div",{style:{display:"flex",flexWrap:"wrap",gap:6,alignItems:"center",marginTop:4},children:[t("span",{style:{fontSize:"0.8rem",opacity:.9,fontWeight:600},children:"Servers:"}),ne.map(e=>t("button",{onClick:()=>yn(e),className:m.retryButton,style:{padding:"4px 8px",fontSize:"0.75rem",textTransform:"capitalize",background:oe===e?"var(--accent)":void 0,color:oe===e?"white":void 0},children:e},e))]})]}):null]}),r&&t(Jr,{showTheater:!1}),Xt&&t("div",{className:m.mobileSeasonRow,children:Xt}),r&&t("div",{className:m.providerSelectWrap,children:t("label",{className:m.controlLabel,children:["Source",t("select",{value:K,onChange:e=>yr(e.target.value),className:m.select,disabled:ae.length===0,children:Mt?t("option",{value:"",children:"Loading…"}):ae.length===0?t("option",{value:"",children:"No providers available"}):t(Oe,{children:[Ct.length>0&&t("optgroup",{label:"Direct HLS",children:Ct.map(e=>t("option",{value:e.id,children:e.label},e.id))}),At.length>0&&t("optgroup",{label:"Embeds",children:At.map(e=>t("option",{value:e.id,children:e.label},e.id))})]})})]})}),r&&t("div",{className:st.playerInfoContainer,children:[t("div",{className:st.playerInfoHeader,children:[t("div",{className:st.playerAnimeCard,children:r.poster&&t("img",{src:`https://image.tmdb.org/t/p/w342${r.poster}`,alt:r.title,loading:"lazy",decoding:"async"})}),t("div",{className:st.videoTitleSection,children:[t("div",{className:be.titleContainer,children:[t("h1",{children:r.title}),t("div",{className:m.meta,children:[t("span",{className:m.year,children:r.year}),r.vote_average!=null&&r.vote_average>0&&t("span",{className:m.rating,children:[t(A,{name:"star",size:12}),Number(r.vote_average).toFixed(1)]}),t("span",{className:`${m.typeBadge} ${m[d?"movie":"tv"]}`,children:d?"Movie":"TV Show"})]}),jn.length>0&&t("div",{className:m.genreRow,children:jn.map(e=>t("span",{className:m.genreChip,children:e},e))}),vn.length>0&&t("div",{className:m.metaRow,children:vn.map((e,n)=>t("span",{children:[e,n<vn.length-1?" · ":""]},`${e}-${n}`))})]}),t("div",{className:be.controls,children:[t("button",{className:`${be.watchlistBtn} ${mt?be.inList:""}`,onClick:er,disabled:Ht,type:"button",children:[mt?t(A,{name:"check",size:14}):t(A,{name:"plus",size:14}),mt?"In Watchlist":"Add to Watchlist"]}),!d&&t(Oe,{children:[t("button",{className:`${be.watchlistBtn}`,onClick:()=>un!=null&&yt(String(un)),disabled:un==null,type:"button",children:[t(A,{name:"chevron-left",size:14}),"Prev EP"]}),t("button",{className:`${be.watchlistBtn}`,onClick:()=>P!=null&&yt(String(P)),disabled:P==null,type:"button",children:["Next EP",t(A,{name:"chevron-right",size:14})]}),!d&&t("button",{className:`${be.watchlistBtn} ${be.modeToggleBtn} ${gt?be.modeToggleActive:""}`,onClick:()=>or(!gt),type:"button","aria-pressed":gt,children:gt?"AUTOPLAY: ON":"AUTOPLAY: OFF"}),sr&&t("button",{className:`${be.watchlistBtn}`,onClick:()=>hn(!0),type:"button",children:[t(A,{name:"list-ul",size:14}),"Episodes"]})]})]})]})]}),t("div",{className:be.descriptionSection,children:[t("h3",{children:"Synopsis"}),t(hs,{text:r.overview,emptyText:"No description available."})]}),t("button",{className:be.detailsToggleBtn,onClick:()=>nr(!Gt),type:"button",children:[Gt?t(A,{name:"chevron-up"}):t(A,{name:"chevron-down"}),Gt?"Hide Details":"Show Details"]}),Gt&&t("div",{className:m.detailGrid,children:[r.first_air_date&&t("div",{className:m.detailItem,children:[t("strong",{children:d?"Release Date":"First Air Date"}),t("span",{children:r.first_air_date})]}),r.last_air_date&&t("div",{className:m.detailItem,children:[t("strong",{children:"Last Air Date"}),t("span",{children:r.last_air_date})]}),r.networks&&r.networks.length>0&&t("div",{className:m.detailItem,children:[t("strong",{children:"Networks"}),t("span",{children:r.networks.map(e=>e.name).join(", ")})]}),r.created_by&&r.created_by.length>0&&t("div",{className:m.detailItem,children:[t("strong",{children:"Created By"}),t("span",{children:r.created_by.map(e=>e.name).join(", ")})]}),r.episode_run_time&&r.episode_run_time.length>0&&t("div",{className:m.detailItem,children:[t("strong",{children:"Episode Runtime"}),t("span",{children:[r.episode_run_time[0]," min"]})]}),r.imdb_id&&t("div",{className:m.detailItem,children:[t("strong",{children:"IMDb"}),t("a",{href:`https://www.imdb.com/title/${r.imdb_id}`,target:"_blank",rel:"noopener noreferrer",className:m.imdbLink,children:"View on IMDb"})]})]})]}),!d&&t(Qr,{isOpen:rr,onClose:()=>hn(!1),episodes:Hn,currentEpisode:String(f),watchedEpisodes:Un,onEpisodeClick:yt,header:Xt}),r?.adult&&!Ye&&t(tn,{isOpen:!0,title:"Content Warning",onClose:Qt,children:t("div",{style:{padding:"1rem",textAlign:"center"},children:[t("p",{children:"This title contains mature content intended for adult audiences."}),t("p",{children:["By proceeding, you confirm that you are ",t("strong",{children:"18 years of age or older"})," ","(or the age of majority in your jurisdiction) and wish to view this content."]}),t("div",{style:{marginTop:"1rem",display:"flex",gap:"10px",justifyContent:"center"},children:[t(_e,{variant:"secondary",onClick:Qt,children:"Go Back"}),t(_e,{onClick:w,children:"I'm 18+, Continue"})]})]})}),t(tn,{isOpen:Pe,onClose:Vn,title:"Resume Watching",children:t("div",{style:{padding:"1rem",textAlign:"center"},children:[t("p",{children:["You were at ",t("strong",{children:lr(ht)})]}),t("div",{style:{marginTop:"1rem",display:"flex",gap:"10px",justifyContent:"center"},children:[t(_e,{variant:"secondary",onClick:Vn,children:"Start from Beginning"}),t(_e,{onClick:pr,children:"Resume"})]})]})}),t(tn,{isOpen:Le,onClose:gr,title:d?"Movie Completed":"Episode Completed",children:t("div",{style:{padding:"1rem",textAlign:"center"},children:[t("p",{children:d?t(Oe,{children:"You've already watched this movie."}):t(Oe,{children:["You've already watched"," ",t("strong",{children:["Season ",i," Episode ",f]}),". Would you like to continue?"]})}),t("div",{style:{marginTop:"1rem",display:"flex",gap:"10px",justifyContent:"center",flexWrap:"wrap"},children:[t(_e,{variant:"secondary",onClick:fr,children:"Replay"}),P!=null?t(_e,{onClick:br,children:["Watch EP ",P]}):fe!=null?t(_e,{onClick:Fn,children:["Start Season ",fe]}):null]})]})}),t(tn,{isOpen:pt,onClose:()=>Ze(!1),title:d?"Movie Completed!":fe!=null?"Season Complete!":"Show Completed!",children:t("div",{style:{padding:"1rem",textAlign:"center"},children:[t(A,{name:"check-circle",size:48,style:{color:"var(--accent-lighter)",marginBottom:"0.5rem"}}),t("p",{style:{fontSize:"1.1rem",fontWeight:600},children:tr}),t("p",{style:{color:"var(--text-secondary)"},children:d?"You finished this movie!":fe!=null?`You finished Season ${i}.`:"Congratulations! You finished all available episodes."}),t("div",{style:{marginTop:"1rem",display:"flex",gap:"10px",justifyContent:"center",flexWrap:"wrap"},children:[t(_e,{variant:"secondary",onClick:()=>Ze(!1),children:"Close"}),fe!=null?t(_e,{onClick:Fn,children:["Start Season ",fe]}):t(Oe,{children:[t(_e,{onClick:()=>{Ze(!1),Qt()},children:"Back to Details"}),mt&&t(_e,{onClick:vr,disabled:ye.isPending,children:ye.isPending?"Saving...":"Move to Completed"})]})]})]})}),!r&&t("div",{className:m.statusMsg,children:[t(A,{name:"spinner",className:m.spinner})," Loading..."]})]})]})};export{lo as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as z,a as E,o as R,d as l,h as C,T,u as e,g as F}from"./vendor-core-8R2fFbyN.js";import{I as a}from"./vendor-icons-CDMuNDeL.js";import{B as w}from"./index-
|
|
1
|
+
import{n as z,a as E,o as R,d as l,h as C,T,u as e,g as F}from"./vendor-core-8R2fFbyN.js";import{I as a}from"./vendor-icons-CDMuNDeL.js";import{B as w}from"./index-CfvzoNYQ.js";import{u as q}from"./useMatureConsent-CT7-KfzG.js";import{n as j,d as U,e as H,f as J,t as I}from"./useTvLibrary-DeGkJuvp.js";import"./vendor-query-BXRECSI6.js";const K="_container_198yg_1",Q="_heroSection_198yg_11",X="_bannerContainer_198yg_17",Y="_banner_198yg_17",Z="_bannerOverlay_198yg_37",ee="_heroContent_198yg_49",ne="_posterContainer_198yg_62",te="_poster_198yg_62",se="_infoGlass_198yg_86",ae="_title_198yg_100",oe="_quickMeta_198yg_110",ie="_metaItem_198yg_118",re="_iconStar_198yg_126",le="_iconTv_198yg_130",ce="_iconType_198yg_134",de="_genres_198yg_139",me="_genre_198yg_139",_e="_metaRow_198yg_156",he="_metaValue_198yg_164",ge="_metaDivider_198yg_168",ve="_synopsisSection_198yg_173",pe="_sectionTitleSmall_198yg_179",ye="_synopsis_198yg_173",ue="_actions_198yg_196",ke="_watchBtn_198yg_202",Ne="_watchlistBtn_198yg_226",be="_active_198yg_250",Se="_seasonPickerLabel_198yg_256",fe="_seasonSelect_198yg_267",Ce="_detailsToggleBtn_198yg_286",Te="_expandedContent_198yg_304",we="_detailGrid_198yg_309",Ie="_detailItem_198yg_315",Be="_imdbLink_198yg_333",De="_heroSkeleton_198yg_343",Me="_skeletonBanner_198yg_347",Le="_skeletonContent_198yg_354",$e="_skeletonPoster_198yg_365",Pe="_skeletonInfo_198yg_373",Ge="_skeletonTitle_198yg_380",xe="_skeletonMeta_198yg_388",Oe="_skeletonDesc_198yg_396",Ae="_skeletonActions_198yg_404",Ve="_errorState_198yg_413",We="_matureOverlay_198yg_434",ze="_matureContent_198yg_444",n={container:K,heroSection:Q,bannerContainer:X,banner:Y,bannerOverlay:Z,heroContent:ee,posterContainer:ne,poster:te,infoGlass:se,title:ae,quickMeta:oe,metaItem:ie,iconStar:re,iconTv:le,iconType:ce,genres:de,genre:me,metaRow:_e,metaValue:he,metaDivider:ge,synopsisSection:ve,sectionTitleSmall:pe,synopsis:ye,actions:ue,watchBtn:ke,watchlistBtn:Ne,active:be,seasonPickerLabel:Se,seasonSelect:fe,detailsToggleBtn:Ce,expandedContent:Te,detailGrid:we,detailItem:Ie,imdbLink:Be,heroSkeleton:De,skeletonBanner:Me,skeletonContent:Le,skeletonPoster:$e,skeletonInfo:Pe,skeletonTitle:Ge,skeletonMeta:xe,skeletonDesc:Oe,skeletonActions:Ae,errorState:Ve,matureOverlay:We,matureContent:ze};function He(){const{id:o}=z(),c=E(),[B]=R(),i=j(B.get("type")),{hasConsent:D}=q(),[t,M]=l(null),[L,m]=l(!0),[p,y]=l(""),[d,$]=l(!1),[_,P]=l(1),G=U(i,o),x=Number(o),{data:O}=H(t?G:void 0),h=!!O?.inLibrary,{toggle:A}=J();C(()=>{o&&(m(!0),y(""),fetch(`/api/tv/details/${i}/${o}`).then(s=>{if(!s.ok)throw new Error("Failed to load details");return s.json()}).then(s=>{M(s),m(!1)}).catch(s=>{y(s.message),m(!1)}))},[o,i]),C(()=>{document.title=t?.title?`${t.title} - dango`:"TV & Movies - dango"},[t?.title]);const V=()=>{!o||!t||c(r?I(i,o):I(i,o,_,1))},W=()=>{t&&A({tmdbId:x,mediaType:i,title:t.title,poster:t.poster,year:t.year,adult:t.adult})},r=i==="movie",g=!r,u=t?.backdrop?`https://image.tmdb.org/t/p/w1280${t.backdrop}`:"",k=t?.poster?`https://image.tmdb.org/t/p/w500${t.poster}`:"",N=T(()=>t?.genres?t.genres.map(s=>s.name).slice(0,5):[],[t?.genres]),b=T(()=>t?.seasons?t.seasons.filter(s=>s.season_number>0):[],[t?.seasons]),v=[t?.year,t?.status,g&&t?.number_of_seasons?`${t.number_of_seasons} Season${t.number_of_seasons>1?"s":""}`:null,g&&t?.number_of_episodes?`${t.number_of_episodes} Episodes`:null].filter(Boolean);if(L)return e("div",{className:n.container,children:e("div",{className:n.heroSkeleton,children:[e("div",{className:n.skeletonBanner}),e("div",{className:n.skeletonContent,children:[e("div",{className:n.skeletonPoster}),e("div",{className:n.skeletonInfo,children:[e("div",{className:n.skeletonTitle}),e("div",{className:n.skeletonMeta}),e("div",{className:n.skeletonDesc}),e("div",{className:n.skeletonActions})]})]})]})});if(p||!t)return e("div",{className:n.container,children:e("div",{className:n.errorState,children:[e(a,{name:"exclamation-triangle",size:48}),e("h2",{children:"Failed to load details"}),e("p",{children:p||"Something went wrong"}),e(w,{onClick:()=>c(-1),children:"Go Back"})]})});const S=t.adult&&!D;return e("div",{className:n.container,style:S?{filter:"blur(14px)",pointerEvents:"none",userSelect:"none"}:void 0,children:[e("div",{className:n.heroSection,children:[e("div",{className:n.bannerContainer,children:[u&&e("div",{className:n.banner,style:{backgroundImage:`url(${u})`}}),e("div",{className:n.bannerOverlay})]}),e("div",{className:n.heroContent,children:[e("div",{className:n.posterContainer,children:k&&e("img",{src:k,alt:t.title,className:n.poster,decoding:"async"})}),e("div",{className:n.infoGlass,children:[e("div",{className:n.topInfo,children:[e("h1",{className:n.title,children:t.title}),e("div",{className:n.quickMeta,children:[t.vote_average!=null&&t.vote_average>0&&e("div",{className:n.metaItem,children:[e(a,{name:"star",className:n.iconStar}),e("span",{children:Number(t.vote_average).toFixed(1)})]}),e("div",{className:n.metaItem,children:[e(a,{name:"tv",className:n.iconTv}),e("span",{children:r?"Movie":"TV Show"})]}),t.vote_count!=null&&e("div",{className:n.metaItem,children:[e(a,{name:"users",className:n.iconType}),e("span",{children:[t.vote_count.toLocaleString()," votes"]})]})]}),N.length>0&&e("div",{className:n.genres,children:N.map(s=>e("span",{className:n.genre,children:s},s))})]}),v.length>0&&e("div",{className:n.metaRow,children:v.map((s,f)=>e(F.Fragment,{children:[e("span",{className:n.metaValue,children:s}),f<v.length-1&&e("span",{className:n.metaDivider,children:"·"})]},f))}),t.overview&&e("div",{className:n.synopsisSection,children:[e("h2",{className:n.sectionTitleSmall,children:"Synopsis"}),e("p",{className:n.synopsis,children:t.overview})]}),e("div",{className:n.actions,children:[e("button",{className:n.watchBtn,onClick:V,children:[e(a,{name:"play",size:14}),r?"Watch Now":`Start S${_}`]}),e("button",{className:`${n.watchlistBtn} ${h?n.active:""}`,onClick:W,children:[h?e(a,{name:"check",size:14}):e(a,{name:"plus",size:14}),h?"In Watchlist":"Add to Watchlist"]})]}),g&&b.length>1&&e("label",{className:n.seasonPickerLabel,children:[e("span",{children:"Season"}),e("select",{value:_,onChange:s=>P(parseInt(s.target.value,10)||1),className:n.seasonSelect,children:b.map(s=>e("option",{value:s.season_number,children:["Season ",s.season_number," (",s.episode_count," Episodes)"]},s.season_number))})]}),e("button",{className:n.detailsToggleBtn,onClick:()=>$(!d),children:[d?e(a,{name:"chevron-up"}):e(a,{name:"chevron-down"}),d?"Hide Details":"Show Details"]}),d&&e("div",{className:n.expandedContent,children:e("div",{className:n.detailGrid,children:[t.first_air_date&&e("div",{className:n.detailItem,children:[e("strong",{children:r?"Release Date":"First Air Date"}),e("span",{children:t.first_air_date})]}),t.last_air_date&&e("div",{className:n.detailItem,children:[e("strong",{children:"Last Air Date"}),e("span",{children:t.last_air_date})]}),t.networks&&t.networks.length>0&&e("div",{className:n.detailItem,children:[e("strong",{children:"Networks"}),e("span",{children:t.networks.map(s=>s.name).join(", ")})]}),t.created_by&&t.created_by.length>0&&e("div",{className:n.detailItem,children:[e("strong",{children:"Created By"}),e("span",{children:t.created_by.map(s=>s.name).join(", ")})]}),t.episode_run_time&&t.episode_run_time.length>0&&e("div",{className:n.detailItem,children:[e("strong",{children:"Episode Runtime"}),e("span",{children:[t.episode_run_time[0]," min"]})]}),t.imdb_id&&e("div",{className:n.detailItem,children:[e("strong",{children:"IMDb"}),e("a",{href:`https://www.imdb.com/title/${t.imdb_id}`,target:"_blank",rel:"noopener noreferrer",className:n.imdbLink,children:"View on IMDb"})]})]})})]})]})]}),S&&e("div",{className:n.matureOverlay,children:e("div",{className:n.matureContent,children:[e(a,{name:"exclamation-triangle",size:48}),e("h2",{children:"Content Warning"}),e("p",{children:"This content may contain mature themes."}),e(w,{onClick:()=>c("/"),children:"Go Back"})]})})]})}export{He as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{A as T,d as v,h as P,T as z,u as e,S as W,L as p}from"./vendor-core-8R2fFbyN.js";import{I as i}from"./vendor-icons-CDMuNDeL.js";import{f as B,d as D,c as L,t as M}from"./useTvLibrary-
|
|
1
|
+
import{A as T,d as v,h as P,T as z,u as e,S as W,L as p}from"./vendor-core-8R2fFbyN.js";import{I as i}from"./vendor-icons-CDMuNDeL.js";import{f as B,d as D,c as L,t as M}from"./useTvLibrary-DeGkJuvp.js";import{p as s,a as S}from"./MediaCard-xfJv6irD.js";const E=({item:a,anchorRect:m,onMouseEnter:u,onMouseLeave:g,onRequestClose:l})=>{const d=T(!1),[n,f]=v(null),[N,c]=v(!0),{toggle:y,bookmarkedIds:_}=B(),w=D(a.type,a.id),o=_.has(w);P(()=>{let t=!1;return c(!0),fetch(`/api/tv/details/${a.type}/${a.id}`).then(r=>{if(!r.ok)throw new Error("Failed");return r.json()}).then(r=>{t||(f({overview:r.overview,genres:r.genres,vote_average:r.vote_average,vote_count:r.vote_count,status:r.status,number_of_seasons:r.number_of_seasons,number_of_episodes:r.number_of_episodes}),c(!1))}).catch(()=>{t||c(!1)}),()=>{t=!0}},[a.id,a.type]);const h=z(()=>n?.genres?n.genres.slice(0,4).map(t=>t.name):[],[n?.genres]),I=L(a.type,a.id),b=M(a.type,a.id),k=t=>{t.preventDefault(),t.stopPropagation(),y({tmdbId:a.id,mediaType:a.type,title:a.title,poster:a.image,year:a.year})};return e(S,{anchorRect:m,onMouseEnter:()=>{d.current=!0,u()},onMouseLeave:()=>{d.current=!1,g()},onRequestClose:l,children:[e("div",{className:s.header,children:e("div",{className:s.title,children:a.title})}),e("div",{className:s.body,children:N?e("div",{className:s.loading,children:[e("div",{className:s.spinner}),e("span",{children:"Fetching details..."})]}):e(W,{children:[e("div",{className:s.metaRow,children:[n?.vote_average!=null&&n.vote_average>0&&e("div",{className:s.metaItem,children:[e(i,{name:"star",className:s.scoreIcon,size:14}),e("span",{children:Number(n.vote_average).toFixed(1)})]}),e("div",{className:s.metaItem,children:[e(i,{name:"tv",size:14}),e("span",{children:a.type==="tv"?"TV Show":"Movie"})]}),a.year&&e("div",{className:s.metaItem,children:e("span",{children:a.year})}),n?.status&&e("div",{className:s.metaItem,children:e("span",{children:n.status})})]}),h.length>0&&e("div",{className:s.genres,children:h.map(t=>e("span",{className:s.genre,children:t},t))}),n?.overview&&e("div",{className:s.synopsis,children:n.overview.length>200?n.overview.slice(0,200)+"...":n.overview})]})}),e("div",{className:s.footer,children:[e("div",{className:s.primaryAction,children:e(p,{to:b,className:s.watchBtn,onClick:l,children:[e(i,{name:"play",size:14}),"Watch now"]})}),e("div",{className:s.secondaryActions,children:[e("button",{className:`${s.watchlistBtn} ${o?s.active:""}`,onClick:k,children:[o?e(i,{name:"check",size:12}):e(i,{name:"plus",size:12}),e("span",{children:o?"Remove":"Watchlist"})]}),e(p,{to:I,className:s.detailsBtn,onClick:l,children:[e(i,{name:"info-circle",size:12}),e("span",{children:"Details"})]})]})]})]})};export{E as T};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{h as D,o as ae,A as te,d as c,T as I,q as A,u as a}from"./vendor-core-8R2fFbyN.js";import{I as d}from"./vendor-icons-CDMuNDeL.js";import{a as ne,T as re}from"./useTv-
|
|
1
|
+
import{h as D,o as ae,A as te,d as c,T as I,q as A,u as a}from"./vendor-core-8R2fFbyN.js";import{I as d}from"./vendor-icons-CDMuNDeL.js";import{a as ne,T as re}from"./useTv-CP4mofvR.js";import{S as se}from"./SkeletonGrid-CnE_aoEU.js";import{u as le,Q as ie,B as _}from"./index-CfvzoNYQ.js";import{E as oe}from"./ErrorMessage-z4f4WGgP.js";import{s as t}from"./Search.module-CMEai-B-.js";import"./MediaCard-xfJv6irD.js";import"./vendor-ui-CUDCvRS_.js";import"./useIsMobile-Dm_b6Ob3.js";import"./TvPopup-DYKTHRrD.js";import"./useTvLibrary-DeGkJuvp.js";import"./vendor-query-BXRECSI6.js";const ce=[{value:"multi",label:"All"},{value:"tv",label:"TV Shows"},{value:"movie",label:"Movies"}],de=[{value:"popularity.desc",label:"Popularity"},{value:"vote_average.desc",label:"Top Rated"},{value:"primary_release_date.desc",label:"Newest"},{value:"primary_release_date.asc",label:"Oldest"},{value:"vote_count.desc",label:"Most Voted"}],V={10759:"Action & Adventure",16:"Animation",35:"Comedy",80:"Crime",99:"Documentary",18:"Drama",10751:"Family",10762:"Kids",9648:"Mystery",10765:"Sci-Fi & Fantasy",37:"Western"},W={28:"Action",12:"Adventure",16:"Animation",35:"Comedy",80:"Crime",99:"Documentary",18:"Drama",10751:"Family",14:"Fantasy",36:"History",27:"Horror",9648:"Mystery",10749:"Romance",878:"Sci-Fi",53:"Thriller",10752:"War",37:"Western"},M=new Date().getFullYear(),me=[{value:"ALL",label:"All Years"},...Array.from({length:M-1980+1},(i,h)=>({value:String(M-h),label:String(M-h)}))];function Ae(){D(()=>{document.title="Search TV & Movies - dango"},[]);const[i,h]=ae(),{lowEndMode:Y}=le(),k=te(null),[v,Q]=c(i.get("q")||""),[g,H]=c(i.get("q")||""),[s,y]=c(parseInt(i.get("page")||"1",10)||1),[o,K]=c(i.get("type")||"multi"),[x,O]=c(i.get("genre")||""),[f,$]=c(i.get("year")||"ALL"),[b,F]=c(i.get("sort_by")||"popularity.desc"),[N,U]=c(!1),[m,S]=c(()=>{const e={},n=i.get("genre")||"";return n&&(e[n]="include"),e}),P=I(()=>{if(o==="tv")return Object.entries(V).map(([n,r])=>({id:n,name:r}));if(o==="movie")return Object.entries(W).map(([n,r])=>({id:n,name:r}));const e=new Map;for(const[n,r]of Object.entries(V))e.set(n,r);for(const[n,r]of Object.entries(W))e.set(n,r);return Array.from(e.entries()).map(([n,r])=>({id:n,name:r}))},[o]),w=I(()=>Object.entries(m).filter(([,n])=>n==="include").map(([n])=>n).join(","),[m]),{data:B,isLoading:p,isError:J,error:X}=ne({query:g,type:o,genre:w,year:f,sort_by:b,page:s}),T=B?.results||[],Z=B?.total_pages||0,E=B?.total_results||0,R=s<Math.min(Z,500),u=A((e={})=>{const n=new URLSearchParams,r=e.q!==void 0?e.q:g,l=e.type!==void 0?e.type:o,j=e.year!==void 0?e.year:f,q=e.sort!==void 0?e.sort:b,z=e.page!==void 0?e.page:String(s),G=e.genre!==void 0?e.genre:w;r.trim()&&n.set("q",r.trim()),l!=="multi"&&n.set("type",l),G&&n.set("genre",G),j!=="ALL"&&n.set("year",j),q!=="popularity.desc"&&n.set("sort_by",q),z!=="1"&&n.set("page",z),h(n,{replace:!0})},[g,o,f,b,s,w,h]),L=A(()=>{ie(),y(1),H(v),u({q:v,page:"1"}),window.scrollTo({top:0,behavior:"smooth"})},[v,u]),C=A(e=>{if(y(e),u({page:String(e)}),k.current){const n=k.current.getBoundingClientRect().top+window.scrollY-100;window.scrollTo({top:n,behavior:"smooth"})}},[u]),ee=A(e=>{S(n=>{const r=n[e],l={...n};return r==="include"?l[e]="exclude":r==="exclude"?delete l[e]:l[e]="include",l}),y(1)},[]);return D(()=>{const n=Object.entries(m).filter(([,r])=>r==="include").map(([r])=>r).join(",");n!==x&&(O(n),u({genre:n,page:"1"}))},[m,x,O,u]),a("div",{className:"page-container",children:[a("div",{className:t.header,children:[a("h1",{className:t.pageTitle,children:"Search TV & Movies"}),a("p",{className:t.pageSubtitle,children:"Discover trending shows, movies, and more powered by TMDB"})]}),a("div",{className:t.filterContainer,children:[a("div",{className:t.searchBarWrapper,children:[a("div",{className:t.inputIconWrapper,children:[a(d,{name:"search",className:t.searchIcon}),a("input",{type:"text","data-virtual-keyboard":"true",className:t.searchInput,placeholder:"Search titles...",value:v,onInput:e=>Q(e.currentTarget.value),onKeyDown:e=>e.key==="Enter"&&L()})]}),a("div",{className:t.searchActions,children:[a("select",{value:o,onChange:e=>{K(e.target.value),S({})},className:t.providerSelect,"aria-label":"Media type",children:ce.map(e=>a("option",{value:e.value,children:e.label},e.value))}),a(_,{onClick:L,className:t.searchBtn,children:"Search"}),a("button",{className:`${t.filterToggleBtn} ${N?t.active:""}`,onClick:()=>U(!N),children:[a(d,{name:"filter",size:14}),a("span",{children:"Filters"}),N?a(d,{name:"chevron-up",size:12}):a(d,{name:"chevron-down",size:12})]})]})]}),a("div",{className:`${t.advancedFilters} ${N?t.show:""}`,children:[a("div",{className:t.filterDivider}),a("div",{className:t.filterGrid,children:[a("div",{className:t.filterItem,children:[a("label",{children:"Sort By"}),a("select",{value:b,onChange:e=>F(e.currentTarget.value),children:de.map(e=>a("option",{value:e.value,children:e.label},e.value))})]}),a("div",{className:t.filterItem,children:[a("label",{children:"Year"}),a("select",{value:f,onChange:e=>$(e.currentTarget.value),children:me.map(e=>a("option",{value:e.value,children:e.label},e.value))})]})]}),P.length>0&&a("div",{className:t.genreSection,children:[a("label",{className:t.genreLabel,children:"Genres"}),a("div",{className:t.genreContainer,children:P.map(e=>a("button",{className:`${t.genreButton} ${t[m[e.id]||""]}`,onClick:()=>ee(e.id),children:e.name},e.id))})]}),a("div",{className:t.filterActions,children:[a(_,{variant:"secondary",onClick:()=>{S({}),$("ALL"),F("popularity.desc"),y(1),u({genre:"",year:"ALL",sort:"popularity.desc",page:"1"})},children:"Reset All"}),a(_,{onClick:L,className:t.searchBtn,children:"Apply Filters"})]})]})]}),J&&a(oe,{message:X?.message||"Search failed"}),Object.keys(m).length>0&&a("div",{style:{display:"flex",flexWrap:"wrap",gap:"8px",marginBottom:"1.5rem"},children:[a("span",{style:{fontSize:"0.8rem",color:"var(--text-muted)",fontWeight:600},children:"Active Filters:"}),Object.entries(m).map(([e,n])=>{const r=P.find(l=>l.id===e)?.name||e;return a("span",{className:`badge ${n==="include"?"badge-primary":"badge-danger"}`,style:{display:"inline-flex",alignItems:"center",gap:"6px"},children:[n==="include"?`+ ${r}`:`- ${r}`,a("button",{onClick:()=>{const l={...m};delete l[e],S(l)},style:{background:"none",border:"none",color:"inherit",cursor:"pointer"},children:"✕"})]},e)})]}),a("div",{className:t.resultsHeader,ref:k,children:[a("h2",{className:t.resultsTitle,children:[g?`Results for "${g}"`:w?"Browsing genres":o==="tv"?"Popular TV Shows":o==="movie"?"Popular Movies":"Trending",E>0&&a("span",{style:{fontWeight:400,color:"var(--text-tertiary)",fontSize:"0.85em",marginLeft:"0.5em"},children:["(",E.toLocaleString(),")"]})]}),T.length>0&&a("div",{className:t.pagination,children:[a("button",{className:t.pageBtn,onClick:()=>C(s-1),disabled:s===1||p,"aria-label":"Previous page",children:a(d,{name:"chevron-left",size:14})}),a("span",{className:t.pageInfo,children:["Page ",a("strong",{children:s})]}),a("button",{className:t.pageBtn,onClick:()=>C(s+1),disabled:!R||p,"aria-label":"Next page",children:a(d,{name:"chevron-right",size:14})})]})]}),a("div",{className:`${t.resultsGrid} ${Y?t.lowEnd:""}`,children:p?a(se,{}):T.map(e=>a(re,{item:{id:e.id,title:e.title,year:e.year,type:e.type,image:e.image,vote_average:e.vote_average,adult:e.adult}},`${e.type}-${e.id}`))}),!p&&T.length===0&&a("div",{className:t.noResults,children:[a(d,{name:"search",size:48,className:t.noResultsIcon}),a("h3",{children:"No results found"}),a("p",{children:"Try adjusting your search or filters to find what you're looking for."})]}),T.length>0&&a("div",{className:t.bottomPagination,children:a("div",{className:t.pagination,children:[a("button",{className:t.pageBtn,onClick:()=>C(s-1),disabled:s===1||p,children:[a(d,{name:"chevron-left",size:14}),a("span",{children:"Previous"})]}),a("span",{className:t.pageInfo,children:["Page ",a("strong",{children:s})]}),a("button",{className:t.pageBtn,onClick:()=>C(s+1),disabled:!R||p,children:[a("span",{children:"Next"}),a(d,{name:"chevron-right",size:14})]})]})})]})}export{Ae as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{n as U,d as v,h as y,T as x,u as l}from"./vendor-core-8R2fFbyN.js";import{M as N}from"./MediaCard-xfJv6irD.js";import{L as _}from"./LibraryListPage-VYaHXgXt.js";import{R as K}from"./ResetProgressModal-By-iSYwL.js";import{T as O}from"./TvPopup-DYKTHRrD.js";import{e as u}from"./index-CfvzoNYQ.js";import{l as Q,u as Y,a as q,b as z,h as G,m as Z,o as j,p as D,t as S,i as I,T as k}from"./useTvLibrary-DeGkJuvp.js";import"./vendor-ui-CUDCvRS_.js";import"./vendor-icons-CDMuNDeL.js";import"./useIsMobile-Dm_b6Ob3.js";import"./SkeletonGrid-CnE_aoEU.js";import"./ErrorMessage-z4f4WGgP.js";import"./Watchlist.module-XGtVQr1d.js";import"./vendor-query-BXRECSI6.js";const H=["All","Continue Watching",...k],P=24;function ce(){const{filter:d="All"}=U(),[T,g]=v(1),[s,p]=v(null),[h,c]=v(!1);y(()=>{document.title="TV Watchlist - dango"},[]),y(()=>{g(1)},[d]);const o=d==="Continue Watching",r=Q(o?"All":d,T,P),i=Y(100),b=q(),w=z(),C=G(),W=Z(),B=j(),E=D(),M=x(()=>o?(i.data?.data??[]).map(e=>{const a=e.currentTime??0,t=e.duration??0,f=e.season??e.lastSeason??1,R=e.episode??e.lastEpisode??1,n=e.mediaType==="movie",m=n?"Movie":`S${f} E${R}`,L=e.completed===!0||e.completed===1||t>0&&a>=t*.8;return{key:e.id,libId:e.id,tmdbId:e.tmdbId,mediaType:e.mediaType,title:e.title,poster:e.poster||"",year:e.year,adult:I({adult:e.adult===1}),status:e.status,badge:m,progressPercent:L?100:t>0?a/t*100:0,progressLabel:t>0?L?"Watched":n?`${u(a)} / ${u(t)}`:`${m} · ${u(a)} / ${u(t)}`:m,watchTarget:S(e.mediaType,e.tmdbId,n?void 0:f,n?void 0:R)}}):(r.data?.data??[]).map(e=>({key:e.id,libId:e.id,tmdbId:e.tmdbId,mediaType:e.mediaType,title:e.title,poster:e.poster||"",year:e.year,adult:I({adult:e.adult===1}),status:e.status,badge:e.lastSeason&&e.lastEpisode?`S${e.lastSeason} E${e.lastEpisode}`:void 0,progressPercent:void 0,progressLabel:void 0,watchTarget:S(e.mediaType,e.tmdbId,e.lastSeason??void 0,e.lastEpisode??void 0)})),[o,i.data,r.data]),A=o?i.data?.total??0:r.data?.total??0,V=o?i.isLoading:r.isLoading,$=o?i.error:r.error,F=()=>{s&&(w.mutate({mediaId:s.libId}),h&&b.mutate(s.libId),p(null),c(!1))};return l(_,{headerTitle:"My TV Watchlist",headerSubtitle:"Track and manage your movies and shows",filters:H,filterBy:d,filterBasePath:"/tv-watchlist",continueFilter:"Continue Watching",statusOptions:[...k],entries:M,total:A,isLoading:V,error:$,page:T,pageSize:P,onPageChange:g,emptyTitle:"Your TV watchlist is looking a bit empty",emptyFilteredText:"No titles match this filter.",emptyAllText:"Let's find something to watch!",browseLabel:"Browse TV & Movies",browseTarget:"/tv",removeListLabel:"Remove from TV Watchlist",listNoun:"TV watchlist",skipConfirmKey:"tvSkipRemoveConfirmation",onBulkStatus:(e,a)=>W.mutate({ids:e,status:a}),onBulkRemove:e=>{o?E.mutate(e):B.mutate(e)},onStatusChange:(e,a)=>C.mutate({id:e,status:a}),onRemoveItem:e=>b.mutate(e),renderCard:e=>l(N,{item:{id:e.libId,title:e.title,thumbnail:e.poster,typeBadge:e.mediaType==="movie"?"Movie":"TV",chapterBadge:e.badge??null,isAdult:e.adult},linkTo:e.watchTarget,hoverIcon:"play",progress:e.progressPercent!==void 0&&e.progressLabel?{percent:e.progressPercent,label:e.progressLabel}:void 0,showProgress:o,metaRow:e.year?l("span",{style:{opacity:.75},children:e.year}):void 0,onRemove:o?()=>p(e):void 0,renderPopup:(a,t)=>l(O,{item:{id:e.tmdbId??0,title:e.title||"",year:e.year||"",type:e.mediaType||"tv",image:e.poster||""},anchorRect:a,onMouseEnter:t.onMouseEnter,onMouseLeave:t.onMouseLeave,onRequestClose:t.close})}),modals:l(K,{isOpen:!!s,itemName:s?.title,progressKind:"watch",listLabel:"my TV watchlist",alsoRemove:h,onAlsoRemoveChange:c,onClose:()=>{p(null),c(!1)},onConfirm:F})})}export{ce as default};
|