@serifpersia/dango 3.3.4
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/LICENSE +21 -0
- package/README.md +258 -0
- package/client/dist/assets/AnimeCard-B5A20jAI.js +1 -0
- package/client/dist/assets/AnimeInfo-0huPAq0O.js +1 -0
- package/client/dist/assets/AnimeInfo-BFWtHlPC.css +1 -0
- package/client/dist/assets/AnimeInfoPage-Dqr5QH6R.js +2 -0
- package/client/dist/assets/AnimeMetaDetails-BPvv5xIl.js +1 -0
- package/client/dist/assets/AnimeMetaDetails-BwNQnRCd.css +1 -0
- package/client/dist/assets/Asmr-B6ZiqkmU.js +2 -0
- package/client/dist/assets/Asmr-Cq2ua6Zk.css +1 -0
- package/client/dist/assets/Asmr.module-ChUXDZKx.js +1 -0
- package/client/dist/assets/AsmrResetProgressModal-Cqsoo3XC.js +1 -0
- package/client/dist/assets/AvSyncCalibrator-C1_iBSyL.css +1 -0
- package/client/dist/assets/AvSyncCalibrator-C8ZoIwMY.js +10 -0
- package/client/dist/assets/ErrorMessage-CXoRbrLN.css +1 -0
- package/client/dist/assets/ErrorMessage-z4f4WGgP.js +1 -0
- package/client/dist/assets/Home-DtRtTuI9.css +1 -0
- package/client/dist/assets/Home-thJhPfs1.js +1 -0
- package/client/dist/assets/Insights-DKtoVe6L.css +1 -0
- package/client/dist/assets/Insights-ZlgPrzGD.js +1 -0
- package/client/dist/assets/LibraryListPage-CCiee-Ot.js +1 -0
- package/client/dist/assets/ListeningList-ctAz_6Zi.js +1 -0
- package/client/dist/assets/Manga-BI9WMTx5.js +1 -0
- package/client/dist/assets/Manga-Dp_-l1Pw.css +1 -0
- package/client/dist/assets/Manga.module-BcfOdsNP.js +1 -0
- package/client/dist/assets/MangaInfoPage-DcrEr7Sk.js +1 -0
- package/client/dist/assets/MangaReadPage-SYg63m48.js +1 -0
- package/client/dist/assets/MangaResetProgressModal-DX-1PS4h.js +1 -0
- package/client/dist/assets/Map-CXFqXmsZ.css +1 -0
- package/client/dist/assets/Map-Dj51g5zL.js +1 -0
- package/client/dist/assets/Mature-DJmUUtlF.css +1 -0
- package/client/dist/assets/Mature-Dqh_9SA3.js +1 -0
- package/client/dist/assets/MediaCard-Be1ST9oj.js +1 -0
- package/client/dist/assets/MediaCard-DB6Yjgky.css +1 -0
- package/client/dist/assets/Music-BGH_0voi.css +1 -0
- package/client/dist/assets/Music-zsPwT8_5.js +1 -0
- package/client/dist/assets/OptionListMenu-Drc_vybW.js +1 -0
- package/client/dist/assets/Player-B036Ic3m.css +1 -0
- package/client/dist/assets/Player-BEtAYps2.js +56 -0
- package/client/dist/assets/PlayerRedirect-D70t8VUW.js +1 -0
- package/client/dist/assets/PlayerSettings-Bj6SsmQ2.css +1 -0
- package/client/dist/assets/PlayerSettings-Cwoji-P7.js +1 -0
- package/client/dist/assets/QueueOptionsButton-B6BMq66e.js +1 -0
- package/client/dist/assets/QueueOptionsButton-CM15uQn8.css +1 -0
- package/client/dist/assets/QueueRail-BUYEjdaq.css +1 -0
- package/client/dist/assets/QueueRail-VxpUDBSm.js +1 -0
- package/client/dist/assets/Radio-B2Q_Egj7.js +1 -0
- package/client/dist/assets/Radio-CCHNFN7R.css +1 -0
- package/client/dist/assets/Radio.module-DGSZLpKM.js +1 -0
- package/client/dist/assets/ReadingList-O0QPwXu7.js +1 -0
- package/client/dist/assets/ResetProgressModal-CR_ovLAu.js +1 -0
- package/client/dist/assets/Search-C8e2nlDD.js +1 -0
- package/client/dist/assets/Search-Cs45oAwI.css +1 -0
- package/client/dist/assets/Search.module-CMEai-B-.js +1 -0
- package/client/dist/assets/Settings-AuFxQcJF.css +1 -0
- package/client/dist/assets/Settings-BgPWBl2V.js +21 -0
- package/client/dist/assets/SkeletonGrid-CtHKKMLj.js +1 -0
- package/client/dist/assets/SkeletonGrid-DhPYefXr.css +1 -0
- package/client/dist/assets/SynopsisText-BcpwT5iw.js +1 -0
- package/client/dist/assets/SynopsisText-CYv2W3yR.css +1 -0
- package/client/dist/assets/Trackers-Bfoiyuzy.js +2 -0
- package/client/dist/assets/Trackers-D5XBOCDp.css +1 -0
- package/client/dist/assets/Tv-Ca0fCdko.js +3 -0
- package/client/dist/assets/Tv-CuEl3Iol.css +1 -0
- package/client/dist/assets/TvInfo-Bu36xJyO.css +1 -0
- package/client/dist/assets/TvInfo-D_scgw_h.js +1 -0
- package/client/dist/assets/TvPopup-YTI7dEbJ.js +1 -0
- package/client/dist/assets/TvSearch-CxU33UOf.js +1 -0
- package/client/dist/assets/TvWatchlist-B4X1fWEH.js +1 -0
- package/client/dist/assets/VirtualKeyboard-6ZNTym4R.js +1 -0
- package/client/dist/assets/VirtualKeyboard-KIPc5ZGH.css +1 -0
- package/client/dist/assets/Watchlist-BiDEU0iV.css +1 -0
- package/client/dist/assets/Watchlist-P6YMZUdF.js +1 -0
- package/client/dist/assets/Watchlist.module-XGtVQr1d.js +1 -0
- package/client/dist/assets/hls-BOLXTnjL.js +42 -0
- package/client/dist/assets/hls-C4cG9wQw.js +1 -0
- package/client/dist/assets/index-BOKlZEHq.js +30354 -0
- package/client/dist/assets/index-CUm1meqr.css +1 -0
- package/client/dist/assets/index-IZgh1beL.js +178 -0
- package/client/dist/assets/useAnimeInfoData-DeuwDSnI.js +1 -0
- package/client/dist/assets/useAsmr-CbMVRjmV.js +1 -0
- package/client/dist/assets/useAsmrPopup-D91Q3CBg.js +1 -0
- package/client/dist/assets/useIsMobile-Dm_b6Ob3.js +1 -0
- package/client/dist/assets/useMangaLibrary-BPvFb1lU.js +1 -0
- package/client/dist/assets/useMangaPopup-BOL2mQJs.js +1 -0
- package/client/dist/assets/useMatureConsent-CT7-KfzG.js +1 -0
- package/client/dist/assets/useProviders-BsRGONMA.js +1 -0
- package/client/dist/assets/useTv-D37MfTHA.js +1 -0
- package/client/dist/assets/useTvLibrary-Cwxgy_Bg.js +1 -0
- package/client/dist/assets/vendor-core-8R2fFbyN.js +1 -0
- package/client/dist/assets/vendor-icons-CDMuNDeL.js +1 -0
- package/client/dist/assets/vendor-query-BXRECSI6.js +1 -0
- package/client/dist/assets/vendor-ui-CUDCvRS_.js +1 -0
- package/client/dist/av-sync-test.mp4 +0 -0
- package/client/dist/favicon.ico +0 -0
- package/client/dist/index.html +46 -0
- package/client/dist/logo-mochi.png +0 -0
- package/client/dist/logo-sakura.png +0 -0
- package/client/dist/logo.png +0 -0
- package/client/dist/placeholder.svg +4 -0
- package/client/dist/robots.txt +3 -0
- package/orchestrator.js +534 -0
- package/package.json +85 -0
- package/server/dist/app-auth.js +177 -0
- package/server/dist/config.js +175 -0
- package/server/dist/controllers/asmr-library.controller.js +288 -0
- package/server/dist/controllers/auth.controller.js +225 -0
- package/server/dist/controllers/data.controller.js +766 -0
- package/server/dist/controllers/insights.controller.js +198 -0
- package/server/dist/controllers/manga-library.controller.js +296 -0
- package/server/dist/controllers/music.controller.js +698 -0
- package/server/dist/controllers/proxy.controller.js +820 -0
- package/server/dist/controllers/settings.controller.js +609 -0
- package/server/dist/controllers/tv-library.controller.js +310 -0
- package/server/dist/controllers/watchlist.controller.js +1015 -0
- package/server/dist/db.js +145 -0
- package/server/dist/discord-gateway.js +391 -0
- package/server/dist/discord-rpc.js +427 -0
- package/server/dist/github-sync.js +512 -0
- package/server/dist/google.js +748 -0
- package/server/dist/lib/anilist.js +1549 -0
- package/server/dist/lib/anischedule.js +194 -0
- package/server/dist/lib/discord-roles-sync.service.js +130 -0
- package/server/dist/lib/ipc.js +24 -0
- package/server/dist/lib/kitsu.js +544 -0
- package/server/dist/lib/mal.js +934 -0
- package/server/dist/lib/migration.js +329 -0
- package/server/dist/lib/offline-db.js +401 -0
- package/server/dist/lib/temp-ids.js +3 -0
- package/server/dist/lib/tmdb.js +72 -0
- package/server/dist/lib/tracker/anilist-tracker.js +245 -0
- package/server/dist/lib/tracker/sync.service.js +496 -0
- package/server/dist/lib/ytmusic.js +125 -0
- package/server/dist/logger.js +16 -0
- package/server/dist/providers/manga/manga.types.js +7 -0
- package/server/dist/providers/provider.interface.js +1 -0
- package/server/dist/providers/remote-loader.js +574 -0
- package/server/dist/providers/remote-types.js +117 -0
- package/server/dist/providers/title-matching.js +225 -0
- package/server/dist/providers/tv.types.js +1 -0
- package/server/dist/rclone.js +120 -0
- package/server/dist/repositories/asmr.repository.js +123 -0
- package/server/dist/repositories/insights.repository.js +85 -0
- package/server/dist/repositories/library.repository.js +108 -0
- package/server/dist/repositories/mal-cache.repository.js +55 -0
- package/server/dist/repositories/manga.repository.js +138 -0
- package/server/dist/repositories/notifications.repository.js +41 -0
- package/server/dist/repositories/queue.repository.js +61 -0
- package/server/dist/repositories/settings.repository.js +12 -0
- package/server/dist/repositories/shows-meta.repository.js +42 -0
- package/server/dist/repositories/temp-show-ids.repository.js +51 -0
- package/server/dist/repositories/tv.repository.js +151 -0
- package/server/dist/repositories/watched-episodes.repository.js +52 -0
- package/server/dist/repositories/watchlist.repository.js +71 -0
- package/server/dist/request-logger.js +16 -0
- package/server/dist/routes/asmr-library.routes.js +23 -0
- package/server/dist/routes/asmr.routes.js +81 -0
- package/server/dist/routes/auth.routes.js +25 -0
- package/server/dist/routes/data.routes.js +47 -0
- package/server/dist/routes/discord-gateway.routes.js +51 -0
- package/server/dist/routes/insights.routes.js +34 -0
- package/server/dist/routes/lan-auth.routes.js +46 -0
- package/server/dist/routes/manga-library.routes.js +23 -0
- package/server/dist/routes/manga.routes.js +141 -0
- package/server/dist/routes/music.routes.js +20 -0
- package/server/dist/routes/providers.routes.js +17 -0
- package/server/dist/routes/proxy.routes.js +12 -0
- package/server/dist/routes/radio.routes.js +138 -0
- package/server/dist/routes/settings.routes.js +24 -0
- package/server/dist/routes/tracker.routes.js +164 -0
- package/server/dist/routes/translate.routes.js +88 -0
- package/server/dist/routes/tv-library.routes.js +23 -0
- package/server/dist/routes/tv.routes.js +629 -0
- package/server/dist/routes/watchlist.routes.js +341 -0
- package/server/dist/scripts/backfill-episode-duration.js +42 -0
- package/server/dist/server.js +529 -0
- package/server/dist/shipped-defaults.js +7 -0
- package/server/dist/sync-config.js +23 -0
- package/server/dist/sync-payload.js +91 -0
- package/server/dist/sync.js +1128 -0
- package/server/dist/utils/cache.utils.js +25 -0
- package/server/dist/utils/cookie.utils.js +13 -0
- package/server/dist/utils/db-utils.js +9 -0
- package/server/dist/utils/env.utils.js +77 -0
- package/server/dist/utils/http.utils.js +70 -0
- package/server/dist/utils/machine-id.js +40 -0
- package/server/dist/utils/megaplay.utils.js +41 -0
- package/server/dist/utils/request-context.js +2 -0
- package/server/dist/utils/security.utils.js +94 -0
- package/server/package.json +44 -0
|
@@ -0,0 +1,21 @@
|
|
|
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(){
|
|
2
|
+
if(!/(^|\\.)discord\\.com$/.test(location.hostname)){alert('Dango: use this bookmarklet while on discord.com');return}
|
|
3
|
+
var t=null;
|
|
4
|
+
try{
|
|
5
|
+
window.webpackChunkdiscord_app.push([[Symbol()],{},function(req){
|
|
6
|
+
if(!req.c)return;
|
|
7
|
+
var ms=Object.values(req.c);
|
|
8
|
+
for(var i=0;i<ms.length;i++){var m=ms[i];
|
|
9
|
+
try{
|
|
10
|
+
if(!m.exports||m.exports===window)continue;
|
|
11
|
+
if(typeof m.exports.getToken==='function'){var x=m.exports.getToken();if(x){t=x;return}}
|
|
12
|
+
for(var k in m.exports){try{var ex=m.exports[k];if(ex&&typeof ex.getToken==='function'&&ex[Symbol.toStringTag]!=='IntlMessagesProxy'){var y=ex.getToken();if(y){t=y;return}}}catch(e1){}}
|
|
13
|
+
}catch(e2){}}
|
|
14
|
+
}]);
|
|
15
|
+
window.webpackChunkdiscord_app.pop();
|
|
16
|
+
}catch(e3){}
|
|
17
|
+
if(!t){alert('Dango: could not grab your token. Make sure you are logged in to Discord in this tab, then run the bookmarklet again.');return}
|
|
18
|
+
function copyFallback(){var a=document.createElement('textarea');a.value=t;a.style.position='fixed';a.style.opacity='0';document.body.appendChild(a);a.select();try{document.execCommand('copy')}catch(e4){}document.body.removeChild(a)}
|
|
19
|
+
var done=function(){window.close();setTimeout(function(){if(!window.closed){alert('Dango: token copied to clipboard! Could not close this tab, so just close it, go back to Dango Settings, paste the token and press Save.')}},250)};
|
|
20
|
+
if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(t).then(done,function(){copyFallback();done()})}else{copyFallback();done()}
|
|
21
|
+
})()`)}const aa=()=>{const t=Te(ta,[]);return e("div",{style:{marginTop:"0.9rem",paddingTop:"0.9rem",borderTop:"1px dashed var(--border-color)"},children:[e("h4",{style:{margin:"0 0 0.35rem",fontSize:"0.95rem"},children:"Grab the token automatically (bookmarklet)"}),e("p",{style:{margin:"0 0 0.6rem",fontSize:"0.85rem",color:"var(--text-secondary)"},children:"Set this up once and you never have to dig through DevTools: the bookmarklet copies your Discord token to the clipboard and closes the Discord tab — then you just paste it above and press Save."}),e("ol",{style:{margin:"0 0 0.75rem",paddingLeft:"1.25rem",fontSize:"0.85rem",color:"var(--text-secondary)",display:"grid",gap:"0.3rem"},children:[e("li",{children:["Drag the ",e("strong",{style:{color:"var(--text-primary)"},children:"Dango Token Grabber"})," ","button below onto your bookmarks bar (press ",e("kbd",{children:"Ctrl"}),"+",e("kbd",{children:"Shift"}),"+",e("kbd",{children:"B"})," ","first if the bar is hidden)."]}),e("li",{children:["Click ",e("strong",{style:{color:"var(--text-primary)"},children:"Open Discord"})," and log in (skip this if you are already logged in)."]}),e("li",{children:["On the Discord tab, click the"," ",e("strong",{style:{color:"var(--text-primary)"},children:"Dango Token Grabber"})," bookmark. The token lands in your clipboard and the tab closes on its own — come back here, paste it above and press ",e("strong",{children:"Save"}),"."]})]}),e("div",{style:{display:"flex",gap:"0.5rem",alignItems:"center",flexWrap:"wrap"},children:[e("a",{href:t,onClick:i=>{i.preventDefault(),alert("Drag this button onto your bookmarks bar instead of clicking it, then click it while you are on discord.com.")},title:"Drag me to your bookmarks bar",draggable:!0,style:{display:"inline-flex",alignItems:"center",padding:"0.4rem 0.8rem",borderRadius:"999px",border:"1px dashed var(--accent)",background:"var(--bg-secondary)",color:"var(--text-primary)",fontSize:"0.85rem",textDecoration:"none",cursor:"grab",userSelect:"none"},children:[e(q,{name:"bookmark",style:{marginRight:"0.45rem",color:"var(--accent)"}}),"Dango Token Grabber"]}),e("a",{className:"btn btn-secondary btn-sm",href:"https://discord.com/channels/@me",target:"_blank",rel:"noopener noreferrer",children:"Open Discord"}),e(D,{variant:"ghost",size:"sm",onClick:async()=>{try{await navigator.clipboard.writeText(t),alert('Bookmarklet code copied. Create a new bookmark on your bookmarks bar, name it "Dango Token" and paste the code as its URL.')}catch{alert(`Could not copy automatically. Right-click the "Dango Token Grabber" button and choose "Copy link address" instead, then paste that into a new bookmark's URL.`)}},children:"Copy code"})]}),e("p",{style:{margin:"0.5rem 0 0",fontSize:"0.75rem",color:"var(--text-tertiary)"},children:`"Copy code" is a fallback for browsers that won't drag bookmarklets: create any bookmark, then paste the copied code as its URL.`})]})},na="_sectionCard_1ag4p_1",sa="_settingItem_1ag4p_25",ra="_field_1ag4p_30",ia="_input_1ag4p_43",oa="_actions_1ag4p_63",ca="_status_1ag4p_69",z={sectionCard:na,settingItem:sa,field:ra,input:ia,actions:oa,status:ca},la=()=>{const[t,n]=r(!1),[o,i]=r(""),[l,w]=r(""),[b,d]=r(!0),[s,u]=r(!1),[g,p]=r("");U(()=>{(async()=>{try{const T=await(await fetch("/api/auth/app-status")).json();n(T.hasPassword)}catch{console.error("Failed to fetch LAN auth status")}finally{d(!1)}})()},[]);const h=async()=>{if(p(""),o!==l){p("Passwords do not match");return}if(o.length<4){p("Password must be at least 4 characters");return}u(!0);try{const f=await fetch("/api/auth/app-setup",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({password:o})}),I=await f.json();if(!f.ok){p(I.error||"Failed to update password");return}n(I.hasPassword),i(""),w(""),p(I.hasPassword?"Password set successfully":"Password removed")}catch{p("Network error")}finally{u(!1)}},C=async()=>{u(!0);try{const f=await fetch("/api/auth/app-setup",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({password:""})}),I=await f.json();if(!f.ok){p(I.error||"Failed to remove password");return}n(!1),i(""),w(""),p("Password removed")}catch{p("Network error")}finally{u(!1)}},k=async()=>{u(!0);try{await fetch("/api/auth/app-logout",{method:"POST"}),p("Logged out"),window.location.reload()}catch{p("Logout failed")}finally{u(!1)}};return b?e("div",{className:z.sectionCard,children:e("p",{children:"Loading..."})}):e("div",{className:z.sectionCard,children:[e("h3",{children:"LAN Lock"}),e("p",{children:"Require a password to access this instance from any device, including this one. Sessions persist across server restarts until logout or password change."}),e("div",{className:z.settingItem,children:[e("div",{className:z.field,children:[e("label",{htmlFor:"lan-password",children:"New Password"}),e("input",{id:"lan-password",type:"password",value:o,onChange:f=>i(f.target.value),placeholder:t?"Leave empty to keep current password":"Enter a password...",className:z.input})]}),e("div",{className:z.field,children:[e("label",{htmlFor:"lan-confirm-password",children:"Confirm Password"}),e("input",{id:"lan-confirm-password",type:"password",value:l,onChange:f=>w(f.target.value),placeholder:"Confirm password...",className:z.input})]}),e("div",{className:z.actions,children:[e(D,{variant:"primary",onClick:h,loading:s,disabled:s,children:t?"Update Password":"Set Password"}),t&&e(D,{variant:"danger",onClick:k,loading:s,disabled:s,children:"Logout"}),t&&e(D,{variant:"secondary",onClick:C,loading:s,disabled:s,children:"Remove Password"})]}),g&&e("p",{className:z.status,children:g})]})]})},da=()=>{const{theme:t,setTheme:n,loading:o}=Le();return e("div",{children:[e("h4",{style:{margin:"0 0 0.25rem",fontSize:"1rem"},children:"Palette"}),e("p",{style:{margin:"0 0 0.75rem",fontSize:"0.85rem",color:"var(--text-secondary)"},children:"Taro is the default. Pick a palette that suits you."}),e("div",{role:"radiogroup","aria-label":"Palette",style:{display:"grid",gridTemplateColumns:"repeat(auto-fit, minmax(150px, 1fr))",gap:"0.6rem"},children:Oe.map(i=>{const l=t===i.id;return e("button",{role:"radio","aria-checked":l,disabled:o,onClick:()=>n(i.id),style:{display:"flex",gap:"0.6rem",alignItems:"center",textAlign:"left",padding:"0.65rem 0.75rem",borderRadius:"10px",cursor:"pointer",background:l?"var(--accent-subtle)":"var(--bg-tertiary)",border:l?"1px solid var(--accent)":"1px solid var(--border-primary)",color:"var(--text-primary)"},children:[e("span",{"aria-hidden":!0,style:{width:26,height:26,borderRadius:"50%",flex:"none",background:i.swatch,border:"1px solid rgba(0,0,0,0.35)"}}),e("span",{style:{minWidth:0},children:[e("span",{style:{display:"block",fontSize:"0.85rem",fontWeight:700},children:i.label}),e("span",{style:{display:"block",fontSize:"0.75rem",color:"var(--text-secondary)",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"},children:i.blurb})]})]},i.id)})})]})},ua="_card_13wyw_1",ha="_cardHeader_13wyw_9",ga="_discordBadge_13wyw_16",ma="_cardTitle_13wyw_27",pa="_cardSub_13wyw_34",ya="_description_13wyw_40",fa="_divider_13wyw_47",wa="_statsRow_13wyw_54",va="_statBox_13wyw_61",ba="_statValue_13wyw_71",_a="_statLabel_13wyw_78",ka="_rolePreview_13wyw_86",Sa="_badge_13wyw_93",Ca="_badgeRank_13wyw_100",Na="_badgeDere_13wyw_106",Ta="_progressSection_13wyw_112",Ra="_progressLabel_13wyw_116",Da="_progressTrack_13wyw_124",Ia="_progressFill_13wyw_132",Pa="_tierList_13wyw_139",xa="_dereSection_13wyw_147",La="_sectionHeading_13wyw_152",Oa="_dereGrid_13wyw_161",Aa="_dereCard_13wyw_167",Ua="_dereCardActive_13wyw_178",Ma="_dereName_13wyw_184",Ea="_dereGenre_13wyw_194",$a="_actions_13wyw_199",ja="_btnPrimary_13wyw_205",Ga="_btnSecondary_13wyw_234",Ka="_statusMsg_13wyw_257",Ha="_statusSuccess_13wyw_264",Fa="_statusError_13wyw_270",za="_statusInfo_13wyw_276",Ba="_userRow_13wyw_283",Wa="_avatar_13wyw_294",qa="_avatarPlaceholder_13wyw_302",Va="_userName_13wyw_314",Ja="_userId_13wyw_320",Ya="_notice_13wyw_325",Qa="_shareList_13wyw_332",Xa="_btnUnlink_13wyw_340",c={card:ua,cardHeader:ha,discordBadge:ga,cardTitle:ma,cardSub:pa,description:ya,divider:fa,statsRow:wa,statBox:va,statValue:ba,statLabel:_a,rolePreview:ka,badge:Sa,badgeRank:Ca,badgeDere:Na,progressSection:Ta,progressLabel:Ra,progressTrack:Da,progressFill:Ia,tierList:Pa,dereSection:xa,sectionHeading:La,dereGrid:Oa,dereCard:Aa,dereCardActive:Ua,dereName:Ma,dereGenre:Ea,actions:$a,btnPrimary:ja,btnSecondary:Ga,statusMsg:Ka,statusSuccess:Ha,statusError:Fa,statusInfo:za,userRow:Ba,avatar:Wa,avatarPlaceholder:qa,userName:Va,userId:Ja,notice:Ya,shareList:Qa,btnUnlink:Xa},B=[{label:"F-Rank",hours:0},{label:"E-Rank",hours:5},{label:"D-Rank",hours:20},{label:"C-Rank",hours:50},{label:"B-Rank",hours:100},{label:"A-Rank",hours:200},{label:"S-Rank",hours:400}],fe={fantasy:"Kamidere",action:"Kamidere",isekai:"Kamidere",magic:"Kamidere","super power":"Megadere",adventure:"Himedere","martial arts":"Himedere",family:"Himedere",comedy:"Bakadere",shounen:"Bakadere",parody:"Bakadere",sports:"Undere",music:"Deredere",romance:"Deredere",ecchi:"Deredere",harem:"Deredere",drama:"Dandere","slice of life":"Dandere",yuri:"Dandere","school life":"Dandere","high school":"Tsundere",school:"Tsundere",military:"Tsundere",shoujo:"Tsundere",seinen:"Kuudere","sci-fi":"Kuudere","science fiction":"Kuudere",mystery:"Kuudere",mecha:"Kuudere",josei:"Kuudere",psychological:"Yandere",horror:"Yandere",thriller:"Sadodere",supernatural:"Dorodere",demons:"Dorodere",game:"Oujidere",historical:"Kanedere"};function Za(t){return fe[(t||"").toLowerCase().trim()]||"Tsundere"}function en(t){const n=new Set;for(const o of t){const i=fe[o.toLowerCase().trim()];i&&n.add(i)}return[...n]}const tn=[{name:"Tsundere",genres:"Romance, School, Shoujo, Military, High School"},{name:"Yandere",genres:"Psychological, Horror"},{name:"Kuudere",genres:"Seinen, Sci-Fi, Mystery, Mecha, Josei"},{name:"Dandere",genres:"Drama, Slice of Life, Yuri, School Life"},{name:"Deredere",genres:"Romance, Ecchi, Harem, Music"},{name:"Bakadere",genres:"Comedy, Shounen, Parody"},{name:"Kamidere",genres:"Fantasy, Action, Isekai, Magic"},{name:"Dorodere",genres:"Supernatural, Demons"},{name:"Himedere",genres:"Adventure, Martial Arts, Family"},{name:"Sadodere",genres:"Thriller"},{name:"Undere",genres:"Sports"},{name:"Megadere",genres:"Super Power"},{name:"Oujidere",genres:"Game"},{name:"Kanedere",genres:"Historical"}];function an(t){return t>=400?"S-Rank":t>=200?"A-Rank":t>=100?"B-Rank":t>=50?"C-Rank":t>=20?"D-Rank":t>=5?"E-Rank":"F-Rank"}function nn(t){const n=[...B].reverse().findIndex(u=>t>=u.hours),o=n===-1?0:B.length-1-n,i=B[o].label,l=o<B.length-1?B[o+1]:null;if(!l)return{pct:100,current:i,next:"MAX",nextHours:0};const w=B[o].hours,b=B.length-1,d=(t-w)/(l.hours-w);return{pct:Math.min(100,(o+d)/b*100),current:i,next:l.label,nextHours:l.hours-t}}const se="dango_discord_user";function sn({workerUrl:t}){const[n,o]=r(()=>{try{const _=localStorage.getItem(se);if(_)return JSON.parse(_)}catch{}try{const v=new URLSearchParams(window.location.search).get("discord_user");if(v)return JSON.parse(v)}catch{}return null}),[i,l]=r(null),[w,b]=r(!1),[d,s]=r(null),[u,g]=r(()=>!n);U(()=>{const _=new URLSearchParams(window.location.search),v=_.get("discord_user");if(v){try{const R=JSON.parse(v);R&&R.id&&(o(R),g(!1),localStorage.setItem(se,JSON.stringify(R)),fetch("/api/discord-user",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({user:R})}).catch(()=>{}))}catch{}_.delete("discord_user"),window.history.replaceState(null,"",window.location.pathname+(_.toString()?`?${_.toString()}`:""))}},[]);const p=te(async()=>{if(n){g(!1);return}try{const _=await de("/api/discord-user");_.user&&(o(_.user),localStorage.setItem(se,JSON.stringify(_.user)))}catch{}finally{g(!1)}},[n]),h=te(async()=>{try{const _=await de("/api/insights/discord-sync-stats");l(_)}catch{}},[]);U(()=>{p(),h()},[p,h]);const C=()=>{localStorage.removeItem(se),o(null),s(null),fetch("/api/discord-user",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({user:null})}).catch(()=>{})},k=async()=>{if(!(!n||!i)){b(!0),s(null);try{const v=await(await fetch("/api/discord-sync-now",{method:"POST"})).json();v.success?s({type:"success",text:`✅ ${v.message}`}):s({type:"error",text:`❌ ${v.error||v.message||"Sync failed"}`})}catch{s({type:"error",text:"❌ Network error — check your connection"})}finally{b(!1)}}},f=i?Math.round(i.totalSeconds/3600):0,I=an(f),T=i?Za(i.topGenre):"—",P=i?.dere||(i?.genres?en(i.genres):[T]),{pct:N,next:L,nextHours:O}=nn(f),E=n?.avatar?`https://cdn.discordapp.com/avatars/${n.id}/${n.avatar}.${n.avatar.startsWith("a_")?"gif":"png"}?size=80`:null;return e(ee,{children:[e("div",{className:c.card,children:[e("div",{className:c.cardHeader,children:[e("div",{className:c.discordBadge,children:e("svg",{width:"20",height:"15",viewBox:"0 0 71 55",fill:"white","aria-hidden":"true",children:e("path",{d:"M60.1 4.9A58.5 58.5 0 0 0 45.5.3a.22.22 0 0 0-.23.11 40.8 40.8 0 0 0-1.8 3.7 54 54 0 0 0-16.2 0 37.5 37.5 0 0 0-1.83-3.7.23.23 0 0 0-.23-.11A58.3 58.3 0 0 0 10.9 4.9a.2.2 0 0 0-.1.08C1.58 18.73-1 32.23.31 45.55a.24.24 0 0 0 .09.17 58.8 58.8 0 0 0 17.7 8.95.23.23 0 0 0 .25-.08 42 42 0 0 0 3.61-5.88.22.22 0 0 0-.12-.31 38.7 38.7 0 0 1-5.53-2.64.23.23 0 0 1-.02-.37 29 29 0 0 0 1.1-.86.22.22 0 0 1 .23-.03c11.6 5.3 24.14 5.3 35.6 0a.22.22 0 0 1 .23.03c.36.3.73.58 1.1.86a.23.23 0 0 1-.02.37 36.4 36.4 0 0 1-5.53 2.64.22.22 0 0 0-.12.31 47.1 47.1 0 0 0 3.61 5.88.22.22 0 0 0 .25.08 58.6 58.6 0 0 0 17.72-8.95.23.23 0 0 0 .09-.16c1.47-15.27-2.47-28.65-10.46-40.47a.18.18 0 0 0-.09-.09ZM23.73 37.55c-3.49 0-6.37-3.21-6.37-7.15s2.82-7.15 6.37-7.15c3.58 0 6.42 3.24 6.37 7.15 0 3.94-2.82 7.15-6.37 7.15Zm23.54 0c-3.49 0-6.37-3.21-6.37-7.15s2.82-7.15 6.37-7.15c3.58 0 6.42 3.24 6.37 7.15 0 3.94-2.79 7.15-6.37 7.15Z"})})}),e("div",{children:[e("p",{className:c.cardTitle,children:"Discord Account"}),e("p",{className:c.cardSub,children:"Link your Discord to earn community roles"})]})]}),u?e("p",{className:c.notice,children:"Loading…"}):n?e(ee,{children:[e("div",{className:c.userRow,children:[E?e("img",{className:c.avatar,src:E,alt:n.username}):e("div",{className:c.avatarPlaceholder,children:"👤"}),e("div",{children:[e("p",{className:c.userName,children:n.username}),e("p",{className:c.userId,children:["ID: ",n.id]})]}),e("button",{className:c.btnUnlink,onClick:C,title:"Disconnect your Discord account",children:"Disconnect"})]}),e("p",{className:c.notice,children:"The following data is shared with the Dango community service to assign roles:"}),e("ul",{className:c.shareList,children:[e("li",{children:"Total watch time (hours)"}),e("li",{children:"Top 3 watched genres"}),e("li",{children:"Discord user ID + username"})]})]}):e(ee,{children:[e("p",{className:c.description,children:"Sign in with Discord (OAuth) to link your account. Only your public username and ID are stored — no email or DMs."}),e("div",{className:c.actions,children:[e("button",{className:c.btnPrimary,onClick:()=>{const _=encodeURIComponent(window.location.origin+"/settings?tab=community"),v=`${t}/auth/login?return_to=${_}`;window.location.href=v},children:"Login with Discord"}),e("a",{className:c.btnSecondary,href:"https://discord.gg/2FTSPXCsvn",target:"_blank",rel:"noopener noreferrer",children:"Join Server"})]})]})]}),e("div",{className:c.card,children:[e("div",{className:c.cardHeader,children:e("div",{children:[e("p",{className:c.cardTitle,children:"Your Roles"}),e("p",{className:c.cardSub,children:"Based on your current Dango watch history"})]})}),i?e(ee,{children:[e("div",{className:c.statsRow,children:[e("div",{className:c.statBox,children:[e("span",{className:c.statValue,children:[f,"h"]}),e("span",{className:c.statLabel,children:"Watch Time"})]}),e("div",{className:c.statBox,children:[e("span",{className:c.statValue,children:i.topGenre||"—"}),e("span",{className:c.statLabel,children:"Top Genre"})]})]}),e("div",{className:c.rolePreview,children:[e("span",{className:`${c.badge} ${c.badgeRank}`,children:I}),e("span",{className:`${c.badge} ${c.badgeDere}`,children:T})]}),e("div",{className:c.progressSection,children:[e("div",{className:c.progressLabel,children:[e("span",{children:["Progress to ",L]}),e("span",{children:L==="MAX"?"MAX":`${O}h remaining`})]}),e("div",{className:c.progressTrack,children:e("div",{className:c.progressFill,style:{width:`${N}%`}})}),e("div",{className:c.tierList,children:[e("span",{children:"0h (F)"}),e("span",{children:"5h (E)"}),e("span",{children:"20h (D)"}),e("span",{children:"50h (C)"}),e("span",{children:"100h (B)"}),e("span",{children:"200h (A)"}),e("span",{children:"400h (S)"})]})]}),e("div",{className:c.dereSection,children:[e("p",{className:c.sectionHeading,children:"Personality Archetypes"}),e("div",{className:c.dereGrid,children:tn.map(_=>{const v=P.includes(_.name);return e("div",{className:`${c.dereCard} ${v?c.dereCardActive:""}`,children:[e("span",{className:c.dereName,children:_.name}),e("span",{className:c.dereGenre,children:_.genres})]},_.name)})})]}),e("hr",{className:c.divider}),e("div",{className:c.actions,children:[e("button",{className:c.btnPrimary,onClick:k,disabled:!n||w,id:"discord-roles-sync-btn",children:w?"Syncing…":"Sync Roles"}),!n&&e("span",{style:{fontSize:"0.78rem",color:"var(--text-tertiary)",alignSelf:"center"},children:"Login first to sync"})]}),d&&e("p",{className:`${c.statusMsg} ${d.type==="success"?c.statusSuccess:d.type==="error"?c.statusError:c.statusInfo}`,children:d.text})]}):e("p",{className:c.notice,children:"No watch data yet — start watching to earn roles!"})]}),e("div",{className:c.card,children:[e("div",{className:c.cardHeader,children:e("div",{children:[e("p",{className:c.cardTitle,children:"Dango Discord Server"}),e("p",{className:c.cardSub,children:"Community, announcements and support"})]})}),e("div",{className:c.actions,children:e("a",{className:c.btnPrimary,href:"https://discord.gg/2FTSPXCsvn",target:"_blank",rel:"noopener noreferrer",children:"Join the Server"})})]})]})}function rn({variant:t="info",children:n,className:o=""}){return e("div",{className:`alert alert-${t} ${o}`,children:n})}const un=()=>{const[t,n]=Re(),o=De(),i=t.get("tab"),[l,w]=r(i&&["general","sync","watchlist","database","community"].includes(i)?i:"general"),[b,d]=r(""),s=V(null),u=V(null),g=V(new Map),[p,h]=r({top:0,height:0,left:0,width:0}),{lowEndMode:C,setLowEndMode:k}=Ae(),[f,I]=r(""),[T,P]=r(localStorage.getItem("telemetry_enabled")!=="false"),[N,L]=r(localStorage.getItem("installation_id")||"");U(()=>{fetch("/api/installation-id").then(a=>a.json()).then(a=>{a.id&&(L(a.id),localStorage.setItem("installation_id",a.id))}).catch(()=>{})},[]),U(()=>{de("/api/discord-roles-config").then(a=>{a.workerUrl&&I(a.workerUrl)}).catch(()=>{})},[]);const[O,E]=r(Ue),[_,v]=r(!0),{data:R}=pe("discordRPCEnabled"),$=Me(),[K,S]=r(!0),{data:M}=pe("discordRPCHideMature"),[ae,ne]=r(""),[J,re]=r(null);U(()=>{fetch("/api/discord/gateway/status").then(a=>a.json()).then(a=>{re(a),a.masked&&a.masked!=="none"&&ne(a.masked)}).catch(()=>{})},[]),U(()=>{R!==void 0&&v(R==="true"||R===!0||R===null)},[R]),U(()=>{M!==void 0&&S(M==="true"||M===!0||M===null)},[M]);const we=a=>{v(a),$.mutate({key:"discordRPCEnabled",value:String(a)})},ve=a=>{S(a),$.mutate({key:"discordRPCHideMature",value:String(a)})},be=a=>{P(a),localStorage.setItem("telemetry_enabled",String(a)),a?Ke():He()},_e=a=>{E(a),localStorage.setItem(je,String(a)),window.dispatchEvent(new CustomEvent(Ge))};ge.useEffect(()=>{document.title="Settings - dango"},[]),ge.useEffect(()=>{const a=t.get("tab");a&&["general","sync","watchlist","database","community"].includes(a)&&w(a)},[t]);const Y=a=>{w(a),n(a==="general"?{}:{tab:a})},Q=te(()=>{const a=g.current.get(l),A=u.current;if(a&&A){const W=A.getBoundingClientRect(),H=a.getBoundingClientRect(),X=window.matchMedia("(max-width: 900px)").matches;h(X?{top:H.top-W.top,height:H.height,left:H.left-W.left,width:H.width}:{top:H.top-W.top,height:H.height,left:0,width:0})}},[l]);Ie(()=>{Q()},[l,Q]),U(()=>{const a=()=>Q();window.addEventListener("resize",a);let A=!1;return document.fonts?.ready&&document.fonts.ready.then(()=>{A||Q()}),()=>{A=!0,window.removeEventListener("resize",a)}},[l,Q]);const ke=()=>{d("Exporting databases...");const a=window.DangoBridge;if(a?.downloadFile){a.downloadFile("/api/backup-db","dango-backup.json"),setTimeout(()=>{d("Databases exported successfully!")},1500);return}const A=document.createElement("a");A.href="/api/backup-db",A.download="dango-backup.json",document.body.appendChild(A),A.click(),A.remove(),setTimeout(()=>{d("Databases exported successfully!")},1500)},Se=async a=>{const A=a.target.files?.[0];if(!A)return;d("Importing databases...");const W=new FormData;W.append("dbfile",A);try{const H=await fetch("/api/restore-db",{method:"POST",body:W}),X=await H.json();if(H.ok){const he=Array.isArray(X.restored)?X.restored.join(", "):null;d(he?`Databases imported successfully (${he})!`:"Database imported successfully!"),setTimeout(()=>window.location.reload(),2e3)}else d(`Import failed: ${X.error}`)}catch{d("Import failed: An unexpected error occurred.")}finally{a.target.value=""}},Ce=()=>{s.current?.click()},Ne=()=>{switch(l){case"general":return e("div",{className:m.tabContent,children:e("div",{className:m.sectionCard,children:[e("h3",{children:"Appearance & Preferences"}),e("p",{children:"Configure how titles are displayed and other general preferences."}),e("div",{className:m.settingItem,children:e(Fe,{})}),e("div",{className:m.settingItem,style:{marginTop:"1.5rem"},children:e(da,{})}),e("div",{className:m.settingItem,style:{marginTop:"1.5rem"},children:e("div",{className:m.settingRow,children:[e("div",{style:{minWidth:0},children:[e("h4",{style:{margin:0,fontSize:"1rem"},children:"Low End Mode"}),e("p",{style:{margin:"0.25rem 0 0",fontSize:"0.85rem",color:"var(--text-secondary)"},children:"Disables animations and heavy visual effects for better performance on older hardware."})]}),e(F,{isChecked:C,onChange:a=>k(a.target.checked),id:"low-end-mode"})]})}),e("div",{className:m.settingItem,style:{marginTop:"1.5rem"},children:e("div",{className:m.settingRow,children:[e("div",{style:{minWidth:0},children:[e("h4",{style:{margin:0,fontSize:"1rem"},children:"Virtual Keyboard"}),e("p",{style:{margin:"0.25rem 0 0",fontSize:"0.85rem",color:"var(--text-secondary)"},children:"Shows an on-screen keyboard when text search fields are focused."})]}),e(F,{isChecked:O,onChange:a=>_e(a.target.checked),id:"virtual-keyboard-enabled"})]})}),e("div",{className:m.settingItem,style:{marginTop:"1.5rem"},children:e("div",{className:m.settingRow,children:[e("div",{style:{minWidth:0},children:[e("h4",{style:{margin:0,fontSize:"1rem"},children:"Discord Rich Presence"}),e("p",{style:{margin:"0.25rem 0 0",fontSize:"0.85rem",color:"var(--text-secondary)"},children:"Show your current anime and watch progress on your Discord profile status."})]}),e(F,{isChecked:_,onChange:a=>we(a.target.checked),id:"discord-rpc-enabled"})]})}),e("div",{style:{marginTop:"2rem"},children:e(la,{})}),_&&e("div",{className:m.settingItem,style:{marginTop:"1rem"},children:e("div",{className:m.settingRow,children:[e("div",{style:{minWidth:0},children:[e("h4",{style:{margin:0,fontSize:"1rem"},children:"Hide Mature Content"}),e("p",{style:{margin:"0.25rem 0 0",fontSize:"0.85rem",color:"var(--text-secondary)"},children:"Hide mature content (18+) from Discord Rich Presence."})]}),e(F,{isChecked:K,onChange:a=>ve(a.target.checked),id:"discord-hide-mature"})]})}),e("div",{className:m.settingItem,style:{marginTop:"1.5rem",background:"var(--bg-tertiary)",padding:"1rem",borderRadius:"8px",border:"1px solid var(--border-color)"},children:[e("div",{className:m.settingRow,children:e("div",{style:{minWidth:0},children:[e("h4",{style:{margin:0,fontSize:"1rem"},children:"Discord Mobile Presence (Gateway)"}),e("p",{style:{margin:"0.25rem 0 0.75rem",fontSize:"0.85rem",color:"var(--text-secondary)"},children:"Paste your Discord authentication token to enable presence on mobile devices. If no token is saved, the default desktop Rich Presence is used. The token is stored locally in your configuration and never shared."})]})}),e(rn,{variant:"warning",style:{marginTop:"1.25rem",paddingTop:"1.25rem"},children:[e("strong",{children:"Use at your own risk."})," This feature uses the Discord Gateway API with your user token, which violates Discord's Terms of Service. Discord may detect this usage and take action against your account, including phone number locks, temporary suspensions, or permanent bans. While the risk is generally low, it is not zero. Only use this if you understand and accept the risks."]}),e("div",{style:{marginTop:"0.75rem",display:"flex",gap:"0.5rem",alignItems:"center",flexWrap:"wrap"},children:[e("input",{type:"password",value:ae,onChange:a=>ne(a.target.value),placeholder:"Paste Discord token here...",style:{flex:"1 1 200px",padding:"0.5rem",borderRadius:"4px",border:"1px solid var(--border-color)",background:"var(--bg-primary)",color:"var(--text-primary)",fontFamily:"monospace",minWidth:0}}),e(D,{variant:"primary",size:"sm",onClick:async()=>{const a=await fetch("/api/discord/gateway/save",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:ae})}),A=await a.json();a.ok?(re({hasToken:!0,masked:A.masked,enabled:!0}),ne(A.masked)):alert(A.error||"Failed to save token")},children:"Save"}),e(D,{variant:"secondary",size:"sm",onClick:async()=>{await fetch("/api/discord/gateway/remove",{method:"POST"}),ne(""),re({hasToken:!1,masked:null,enabled:!1})},children:"Remove"})]}),J&&e("p",{style:{marginTop:"0.5rem",fontSize:"0.8rem",color:J.hasToken?"green":"var(--text-secondary)"},children:["Status:"," ",J.hasToken?`Token saved (${J.masked})`:"No token saved",J.enabled?" - Gateway active":""]}),e(aa,{})]}),e("div",{className:m.settingItem,style:{marginTop:"1.5rem"},children:[e("div",{className:m.settingRow,children:[e("div",{style:{minWidth:0},children:[e("h4",{style:{margin:0,fontSize:"1rem"},children:"Telemetry Tracking"}),e("p",{style:{margin:"0.25rem 0 0",fontSize:"0.85rem",color:"var(--text-secondary)"},children:"Share anonymous installation data to help track active users. Collected: Browser type and OS (e.g. 'Chrome on Windows'), App Version, First Seen/Last Seen timestamps, and timezone (e.g. 'Europe/Berlin'). No other personal information or usage habits are collected."})]}),e(F,{isChecked:T,onChange:a=>be(a.target.checked),id:"telemetry-enabled"})]}),T&&e("div",{style:{marginTop:"0.75rem",fontSize:"0.8rem",color:"var(--text-secondary)"},children:[e("p",{style:{margin:"0 0 0.5rem 0",fontWeight:"bold"},children:"Data currently being shared:"}),e("div",{style:{background:"var(--bg-tertiary)",padding:"0.5rem",borderRadius:"4px",wordBreak:"break-all",fontFamily:"monospace"},children:[e("p",{style:{margin:"0"},children:[e("strong",{children:"ID:"})," ",N||"Loading..."]}),e("p",{style:{margin:"0"},children:[e("strong",{children:"Version:"})," ",Ee.version]}),e("p",{style:{margin:"0"},children:[e("strong",{children:"Browser:"})," ",$e()]}),e("p",{style:{margin:"0"},children:[e("strong",{children:"Timezone:"})," ",Intl.DateTimeFormat().resolvedOptions().timeZone]})]})]}),e("div",{style:{marginTop:"1rem"},children:e(D,{variant:"secondary",size:"sm",onClick:()=>o("/map"),children:"View User Map"})})]}),localStorage.getItem("agreedToViewMature")==="true"&&e("div",{className:m.settingItem,style:{marginTop:"1.5rem"},children:e("div",{className:m.settingRow,children:[e("div",{style:{minWidth:0},children:[e("h4",{style:{margin:0,fontSize:"1rem"},children:"Mature Content"}),e("p",{style:{margin:"0.25rem 0 0",fontSize:"0.85rem",color:"var(--text-secondary)"},children:"You have previously agreed to view 18+ content. Toggle this off to re-enable the blur gate and filtering."})]}),e(F,{isChecked:!0,onChange:a=>{a.target.checked||(localStorage.removeItem("agreedToViewMature"),window.location.reload())},id:"mature-content-enabled"})]})})]})});case"sync":return e("div",{className:m.tabContent,children:[e(ea,{}),e(ft,{}),e(wt,{}),e(Zt,{})]});case"watchlist":return e("div",{className:m.tabContent,children:e(It,{})});case"database":return e("div",{className:m.tabContent,children:[e("div",{className:m.sectionCard,children:[e("h3",{children:"Database Management"}),e("p",{children:"Download a backup of all databases (anime, manga, TV and ASMR) or restore from a backup file. Legacy single-file anime (.db) backups can still be restored."}),e("div",{className:m.controls,children:[e(D,{onClick:ke,children:"Backup Database"}),e(D,{variant:"secondary",onClick:Ce,children:"Restore Database"})]}),e("input",{type:"file",ref:s,onChange:Se,style:{position:"absolute",width:1,height:1,opacity:0,overflow:"hidden"},accept:".json,.db,application/octet-stream"}),b&&e("p",{className:m.status,children:b})]}),e(Wt,{}),e(Xt,{})]});case"community":return e("div",{className:m.tabContent,children:f?e(sn,{workerUrl:f}):e("div",{className:m.sectionCard,children:[e("h3",{children:"Discord Community Roles"}),e("p",{children:"Discord Roles integration is not configured on this instance."})]})});default:return null}};return e("div",{className:"page-container",children:[e("div",{className:m.settingsHeader,children:[e("h1",{className:m.pageTitle,children:"Settings"}),e("p",{className:m.pageSubtitle,children:"Manage your preferences and data synchronization"})]}),e("div",{className:m.settingsLayout,children:[e("aside",{className:m.sidebar,ref:u,children:[e("div",{className:m.sidebarIndicator,style:{top:p.top,height:p.height,left:p.left,...p.width?{width:p.width}:{}}}),e("button",{ref:a=>{a&&g.current.set("general",a)},className:`${m.sidebarItem} ${l==="general"?m.active:""}`,onClick:()=>Y("general"),children:[e(q,{name:"cog"})," ",e("span",{children:"General"})]}),e("button",{ref:a=>{a&&g.current.set("sync",a)},className:`${m.sidebarItem} ${l==="sync"?m.active:""}`,onClick:()=>Y("sync"),children:[e(q,{name:"cloud"})," ",e("span",{children:"Synchronization"})]}),e("button",{ref:a=>{a&&g.current.set("watchlist",a)},className:`${m.sidebarItem} ${l==="watchlist"?m.active:""}`,onClick:()=>Y("watchlist"),children:[e(q,{name:"list"})," ",e("span",{children:"Watchlist"})]}),e("button",{ref:a=>{a&&g.current.set("database",a)},className:`${m.sidebarItem} ${l==="database"?m.active:""}`,onClick:()=>Y("database"),children:[e(q,{name:"database"})," ",e("span",{children:"Database"})]}),f&&e("button",{ref:a=>{a&&g.current.set("community",a)},className:`${m.sidebarItem} ${l==="community"?m.active:""}`,onClick:()=>Y("community"),children:[e(q,{name:"discord"})," ",e("span",{children:"Community"})]})]}),e("main",{className:m.mainContent,children:e("div",{className:m.tabContent,children:Ne()},l)})]})]})};export{un as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{u as e,g as t}from"./vendor-core-8R2fFbyN.js";import{u as l}from"./index-IZgh1beL.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};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
._skeletonCard_1b0hr_1{display:flex;flex-direction:column;background-color:var(--bg-secondary);border-radius:var(--radius-md);overflow:hidden;height:100%;border:1px solid var(--border-secondary)}._poster_1b0hr_11{width:100%;aspect-ratio:3 / 4;background-color:var(--bg-tertiary);position:relative;overflow:hidden}._poster_1b0hr_11:after,._line_1b0hr_20:after{content:"";position:absolute;inset:0;transform:translate(-100%);background-image:linear-gradient(90deg,#fff0 0,#ffffff0d 20%,#ffffff1f 60%,#fff0);animation:_skeleton-wave_1b0hr_1 1.8s infinite ease-in-out}._info_1b0hr_38{padding:var(--space-3);display:flex;flex-direction:column;gap:var(--space-2);flex-grow:1}._line_1b0hr_20{position:relative;overflow:hidden;height:18px;border-radius:var(--radius-sm);background-color:var(--bg-tertiary)}._line_1b0hr_20._short_1b0hr_54{width:60%;height:14px}@media(max-width:768px){._skeletonCard_1b0hr_1._horizontal_1b0hr_60{flex-direction:row;height:auto;min-height:100px}._skeletonCard_1b0hr_1._horizontal_1b0hr_60 ._poster_1b0hr_11{width:85px;height:100%;aspect-ratio:auto;flex-shrink:0}._skeletonCard_1b0hr_1._horizontal_1b0hr_60 ._info_1b0hr_38{padding:var(--space-2) var(--space-3);justify-content:center}._skeletonCard_1b0hr_1._vertical_1b0hr_78 ._poster_1b0hr_11{width:100%;aspect-ratio:3 / 4}._skeletonCard_1b0hr_1._vertical_1b0hr_78 ._info_1b0hr_38{padding:var(--space-2);align-items:center}._line_1b0hr_20{height:16px}._line_1b0hr_20._short_1b0hr_54{height:12px}}._skeletonCard_1b0hr_1._lowEnd_1b0hr_97{min-height:0}._skeletonCard_1b0hr_1._lowEnd_1b0hr_97 ._poster_1b0hr_11:after,._skeletonCard_1b0hr_1._lowEnd_1b0hr_97 ._line_1b0hr_20:after{animation:none}._skeletonCard_1b0hr_1._lowEnd_1b0hr_97 ._line_1b0hr_20{opacity:.6}._skeletonCard_1b0hr_1._lowEnd_1b0hr_97 ._info_1b0hr_38{padding:var(--space-3)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{d as m,u as e}from"./vendor-core-8R2fFbyN.js";import{u}from"./useIsMobile-Dm_b6Ob3.js";const _="_synopsisBlock_16qnf_1",g="_description_16qnf_7",f="_clamped_16qnf_15",y="_toggleButton_16qnf_24",s={synopsisBlock:_,description:g,clamped:f,toggleButton:y},B=180;function S({text:i,emptyText:c="No description available.",collapsedLines:l=2}){const a=u(),o=i?.trim()||"",n=a&&o.length>B,[d,p]=m(!1),t=!n||d;return o?e("div",{className:s.synopsisBlock,children:[e("p",{className:`${s.description} ${!t&&n?s.clamped:""}`,style:{"--synopsis-lines":String(l)},children:o}),n&&e("button",{type:"button",className:s.toggleButton,onClick:()=>p(r=>!r),"aria-expanded":t,children:t?"Show less":"Read more"})]}):e("p",{className:s.description,children:c})}export{S};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
._synopsisBlock_16qnf_1{display:flex;flex-direction:column;gap:.85rem}._description_16qnf_7{font-size:var(--font-size-base);color:var(--text-secondary);line-height:1.7;margin:0;white-space:pre-wrap}._clamped_16qnf_15{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;white-space:normal;-webkit-line-clamp:var(--synopsis-lines, 2);line-clamp:var(--synopsis-lines, 2)}._toggleButton_16qnf_24{align-self:flex-start;border:1px solid var(--border-primary);background:#ffffff0a;color:var(--text-primary);border-radius:var(--radius-full);padding:.45rem .9rem;font-size:var(--font-size-sm);font-weight:600;cursor:pointer;transition:all var(--transition-fast)}._toggleButton_16qnf_24:hover{border-color:var(--accent);color:var(--accent);background:#ffffff14}
|
|
@@ -0,0 +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-IZgh1beL.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
|
+
`);$=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 @@
|
|
|
1
|
+
._header_j1lbh_1{margin-bottom:var(--space-8);animation:_fadeIn_j1lbh_1 .8s var(--ease-smooth)}._pageTitle_j1lbh_6{font-size:var(--font-size-xl);font-weight:800;color:var(--text-primary);margin:0 0 var(--space-2);letter-spacing:-.02em}._pageSubtitle_j1lbh_14{color:var(--text-tertiary);font-size:var(--font-size-sm);margin:0}._importCard_j1lbh_20{background:var(--glass-bg);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);border:1px solid var(--glass-border);padding:var(--space-8);border-radius:var(--radius-xl);box-shadow:var(--glass-shadow);max-width:600px;margin:0 auto;animation:_slideUpIn_j1lbh_1 .8s var(--ease-smooth)}._importCard_j1lbh_20+._importCard_j1lbh_20{margin-top:var(--space-6)}._cardHeader_j1lbh_37{margin-bottom:var(--space-6)}._cardHeader_j1lbh_37 h3{margin:0 0 var(--space-2);font-size:var(--font-size-lg);font-weight:700;color:var(--text-primary)}._cardHeader_j1lbh_37 p{color:var(--text-secondary);font-size:var(--font-size-sm);margin:0;line-height:1.6}._uploadArea_j1lbh_55{margin-bottom:var(--space-6)}._fileInputWrapper_j1lbh_59{position:relative;display:flex;align-items:center;gap:var(--space-4);background:var(--bg-tertiary);border:1px dashed var(--border-secondary);border-radius:var(--radius-lg);padding:var(--space-4);transition:all var(--transition-fast)}._fileInputWrapper_j1lbh_59:hover{border-color:var(--accent);background:var(--bg-elevated)}._fileInput_j1lbh_59{position:absolute;top:0;left:0;width:100%;height:100%;opacity:0;cursor:pointer;z-index:2}._fileDisplay_j1lbh_87{flex:1;display:flex;align-items:center;gap:var(--space-3);overflow:hidden}._fileIcon_j1lbh_95{color:var(--text-tertiary);font-size:1.5rem}._fileName_j1lbh_100{color:var(--text-primary);font-size:var(--font-size-sm);font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}._browseButton_j1lbh_109{background:#ffffff0d;border:1px solid var(--border-primary);color:var(--text-secondary);padding:var(--space-2) var(--space-4);border-radius:var(--radius-md);font-size:var(--font-size-sm);font-weight:600;pointer-events:none}._optionsArea_j1lbh_120{margin-bottom:var(--space-6);padding:var(--space-4);background:color-mix(in srgb,var(--color-warning) 5%,transparent);border:1px solid color-mix(in srgb,var(--color-warning) 10%,transparent);border-radius:var(--radius-lg)}._checkboxLabel_j1lbh_128{display:flex;align-items:flex-start;gap:var(--space-3);cursor:pointer;position:relative}._checkbox_j1lbh_128{opacity:0;position:absolute}._checkboxCustom_j1lbh_141{width:20px;height:20px;border:2px solid var(--border-secondary);border-radius:4px;display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-top:2px;transition:all var(--transition-fast)}._checkbox_j1lbh_128:checked+._checkboxCustom_j1lbh_141{background:var(--color-warning);border-color:var(--color-warning)}._checkbox_j1lbh_128:checked+._checkboxCustom_j1lbh_141:after{content:"";width:5px;height:10px;border:solid var(--color-warning-text);border-width:0 2px 2px 0;transform:rotate(45deg);margin-bottom:2px}._optionText_j1lbh_169{display:flex;flex-direction:column;gap:4px}._optionTitle_j1lbh_175{color:var(--color-warning);font-weight:600;font-size:var(--font-size-sm)}._optionDesc_j1lbh_181{color:var(--text-tertiary);font-size:.8rem;line-height:1.4}._actions_j1lbh_187{display:flex;justify-content:flex-end;gap:var(--space-3);border-top:1px solid var(--border-primary);padding-top:var(--space-6)}._importBtn_j1lbh_195{display:flex;align-items:center;gap:var(--space-2)}._cancelBtn_j1lbh_201{display:flex;align-items:center;gap:var(--space-2);background:color-mix(in srgb,var(--color-danger) 15%,transparent);border-color:color-mix(in srgb,var(--color-danger) 30%,transparent);color:var(--color-danger)}._cancelBtn_j1lbh_201:hover{background:color-mix(in srgb,var(--color-danger) 25%,transparent);border-color:color-mix(in srgb,var(--color-danger) 50%,transparent)}._statusMessage_j1lbh_215{margin-top:var(--space-6);padding:var(--space-4);border-radius:var(--radius-md);font-size:var(--font-size-sm);font-weight:500;text-align:center;animation:_fadeIn_j1lbh_1 .3s ease}._statusMessage_j1lbh_215._success_j1lbh_225{background:color-mix(in srgb,var(--color-success) 10%,transparent);color:var(--color-success);border:1px solid color-mix(in srgb,var(--color-success) 20%,transparent)}._statusMessage_j1lbh_215._error_j1lbh_231{background:color-mix(in srgb,var(--color-danger) 10%,transparent);color:var(--color-danger);border:1px solid color-mix(in srgb,var(--color-danger) 20%,transparent)}._progressSection_j1lbh_237{margin-top:var(--space-6);animation:_fadeIn_j1lbh_1 .3s ease}._progressBar_j1lbh_242{height:6px;background:var(--bg-tertiary);border-radius:3px;overflow:hidden;margin-bottom:var(--space-3)}._progressFill_j1lbh_250{height:100%;background:linear-gradient(90deg,#6366f1,#8b5cf6);border-radius:3px;transition:width .3s ease}._progressInfo_j1lbh_257{display:flex;align-items:center;justify-content:space-between;gap:var(--space-3)}._progressCount_j1lbh_264{font-size:var(--font-size-sm);color:var(--text-tertiary);font-weight:500;white-space:nowrap}._progressTitle_j1lbh_271{display:flex;align-items:center;gap:var(--space-2);font-size:var(--font-size-sm);color:var(--text-primary);font-weight:500;text-align:right;overflow:hidden}._progressTitle_j1lbh_271>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:300px}._sourceBadge_j1lbh_289{display:inline-flex;align-items:center;padding:2px 8px;border-radius:10px;font-size:.7rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;flex-shrink:0}._sourceBadge_j1lbh_289._anilist_j1lbh_301{background:#6366f126;color:#818cf8;border:1px solid rgba(99,102,241,.3)}._sourceBadge_j1lbh_289._kitsu_j1lbh_307{background:#ec489926;color:#f472b6;border:1px solid rgba(236,72,153,.3)}._sourceBadge_j1lbh_289._offline_j1lbh_313{background:#22c55e26;color:#4ade80;border:1px solid rgba(34,197,94,.3)}._skipped_j1lbh_319{color:var(--text-tertiary);font-style:italic}._cardTitleRow_j1lbh_324{display:flex;align-items:center;gap:var(--space-3)}._cardTitleRow_j1lbh_324 h3{margin:0}._anilistIcon_j1lbh_334{font-size:1.5rem;color:#818cf8;flex-shrink:0}._malIcon_j1lbh_340{font-size:1.5rem;color:#2e51a2;flex-shrink:0}._badgeOnline_j1lbh_346{font-size:.7rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;padding:3px 10px;border-radius:var(--radius-full);background:color-mix(in srgb,var(--color-success) 12%,transparent);color:var(--color-success);border:1px solid color-mix(in srgb,var(--color-success) 25%,transparent)}._badgeOffline_j1lbh_358{font-size:.7rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;padding:3px 10px;border-radius:var(--radius-full);background:var(--bg-tertiary);color:var(--text-tertiary);border:1px solid var(--border-primary)}._connectedProfile_j1lbh_370{display:flex;align-items:center;gap:var(--space-4);padding:var(--space-4);background:var(--bg-tertiary);border-radius:var(--radius-lg)}._avatar_j1lbh_379{width:48px;height:48px;border-radius:50%;flex-shrink:0}._connectedInfo_j1lbh_386{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}._connectedName_j1lbh_394{color:var(--text-primary);font-weight:700;font-size:var(--font-size-sm)}._connectedHint_j1lbh_400{color:var(--color-success);font-size:.8rem}._loginPrompt_j1lbh_405{display:flex;align-items:center;justify-content:space-between;gap:var(--space-4);flex-wrap:wrap}._loginSection_j1lbh_413{display:flex;flex-direction:column;gap:var(--space-3)}._fieldLabel_j1lbh_419{font-size:var(--font-size-sm);font-weight:600;color:var(--text-primary)}._fieldLabel_j1lbh_419 a{color:var(--accent);text-decoration:none;display:inline-flex;align-items:center;gap:4px;margin-left:6px}._fieldLabel_j1lbh_419 a:hover{text-decoration:underline}._helpText_j1lbh_438{margin:0;font-size:.8rem;color:var(--text-tertiary);line-height:1.6}._helpText_j1lbh_438 code{background:var(--bg-tertiary);border:1px solid var(--border-primary);border-radius:4px;padding:1px 6px;font-size:.75rem;color:var(--text-secondary);word-break:break-all}._loginText_j1lbh_455{color:var(--text-secondary);font-size:var(--font-size-sm);margin:0;line-height:1.6;flex:1;min-width:220px}._primaryBtn_j1lbh_464,._secondaryBtn_j1lbh_465,._syncBtn_j1lbh_466{display:inline-flex;align-items:center;justify-content:center;gap:var(--space-2);padding:var(--space-2-5) var(--space-4);border-radius:var(--radius-md);font-weight:600;font-size:var(--font-size-sm);cursor:pointer;border:1px solid transparent;transition:all var(--transition-fast);flex-shrink:0}._primaryBtn_j1lbh_464{background:var(--accent);color:var(--accent-text)}._primaryBtn_j1lbh_464:hover{filter:brightness(1.1)}._secondaryBtn_j1lbh_465{background:#ffffff0d;border-color:var(--border-primary);color:var(--text-primary)}._secondaryBtn_j1lbh_465:hover:not(:disabled){background:var(--bg-elevated);border-color:var(--border-secondary)}._syncBtn_j1lbh_466{background:linear-gradient(135deg,#6366f1,#8b5cf6);color:#fff;padding:var(--space-3) var(--space-6)}._syncBtn_j1lbh_466:hover:not(:disabled){filter:brightness(1.1)}._primaryBtn_j1lbh_464:disabled,._secondaryBtn_j1lbh_465:disabled,._syncBtn_j1lbh_466:disabled{opacity:.5;cursor:not-allowed}._divider_j1lbh_518{border:0;border-top:1px solid var(--border-primary);margin:var(--space-6) 0}._actionSection_j1lbh_524 h4{margin:0 0 var(--space-1);color:var(--text-primary);font-size:var(--font-size-sm);font-weight:700}._actionSection_j1lbh_524 p{color:var(--text-secondary);font-size:var(--font-size-sm);margin:0 0 var(--space-4);line-height:1.6}._inputGroup_j1lbh_538{display:flex;gap:var(--space-2)}._input_j1lbh_538{flex:1;min-width:0;padding:var(--space-2-5) var(--space-3);border-radius:var(--radius-md);border:1px solid var(--border-primary);background:var(--bg-tertiary);color:var(--text-primary);font-size:var(--font-size-sm)}._input_j1lbh_538:focus{outline:none;border-color:var(--accent)}._syncSummary_j1lbh_559{margin-top:var(--space-3);font-size:.8rem;color:var(--text-tertiary)}._syncErrors_j1lbh_565{color:var(--color-danger)}._spin_j1lbh_569{animation:_spin_j1lbh_569 1s linear infinite}@keyframes _spin_j1lbh_569{to{transform:rotate(360deg)}}@keyframes _fadeIn_j1lbh_1{0%{opacity:0}to{opacity:1}}@keyframes _slideUpIn_j1lbh_1{0%{opacity:0;transform:translateY(30px)}to{opacity:1;transform:translateY(0)}}._radioGroup_j1lbh_598{display:flex;gap:var(--space-4);margin-bottom:var(--space-4)}._radioLabel_j1lbh_604{display:flex;align-items:center;gap:var(--space-2);font-size:var(--font-size-sm);color:var(--text-secondary);cursor:pointer;-webkit-user-select:none;user-select:none}._radioLabel_j1lbh_604 input[type=radio]{appearance:none;-webkit-appearance:none;width:16px;height:16px;border:2px solid var(--border-secondary);border-radius:50%;background:transparent;cursor:pointer;position:relative;flex-shrink:0}._radioLabel_j1lbh_604 input[type=radio]:checked{border-color:var(--accent)}._radioLabel_j1lbh_604 input[type=radio]:checked:after{content:"";position:absolute;top:3px;left:3px;width:6px;height:6px;border-radius:50%;background:var(--accent)}._syncHint_j1lbh_642{color:var(--text-secondary);font-size:var(--font-size-sm);margin:0 0 var(--space-4);line-height:1.6}._importLoading_j1lbh_649{display:flex;align-items:center;gap:var(--space-2);font-size:var(--font-size-sm);color:var(--text-secondary);margin-top:var(--space-3)}@media(max-width:600px){._importCard_j1lbh_20{padding:var(--space-6)}._fileInputWrapper_j1lbh_59{flex-direction:column;align-items:stretch;text-align:center}._fileDisplay_j1lbh_87{flex-direction:column}._browseButton_j1lbh_109{text-align:center}}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{u as t,d as v,A as D,h as f,S as Nt,n as kn,o as xn,a as Nn,T as _e,q as P}from"./vendor-core-8R2fFbyN.js";import{e as Ht,z as In,M as Ut,B as qe}from"./index-IZgh1beL.js";import{I}from"./vendor-icons-CDMuNDeL.js";import{f as an,d as En,C as wn,S as Bn,U as Pn,a as Mn,p as jt,u as An,c as $n,b as Ln,s as Wt,e as Rn,g as Dn,h as Vn,r as On,l as Be,i as Fn,E as zn,A as Hn,P as Un,j as ue,m as Wn}from"./AvSyncCalibrator-C8ZoIwMY.js";import{O as It,S as jn,a as Kn,A as qn}from"./OptionListMenu-Drc_vybW.js";import{u as Gn}from"./useMatureConsent-CT7-KfzG.js";import{u as Jn}from"./useProviders-BsRGONMA.js";import{d as Qn,g as Yn,f as Xn,e as Zn,h as er,j as tr}from"./useTvLibrary-Cwxgy_Bg.js";import{l as nr,c as rr}from"./hls-C4cG9wQw.js";import{u as sr}from"./useIsMobile-Dm_b6Ob3.js";import{S as ar}from"./SynopsisText-BcpwT5iw.js";import"./vendor-query-BXRECSI6.js";const or="_fullscreenFlat_oxcpx_1",ir="_timeDisplay_oxcpx_15",lr="_bottomControls_oxcpx_19",cr="_leftControls_oxcpx_23",dr="_rightControls_oxcpx_24",ur="_controlBtn_oxcpx_28",mr="_controlsOverlay_oxcpx_47",pr="_hidden_oxcpx_67",hr="_topControls_oxcpx_73",gr="_backBtn_oxcpx_93",fr="_videoTitleInfo_oxcpx_113",br="_animeTitle_oxcpx_119",vr="_episodeLabel_oxcpx_127",yr="_speedBoostBadge_oxcpx_134",_r="_progressBarContainer_oxcpx_180",Sr="_progressBar_oxcpx_180",Tr="_thumb_oxcpx_199",Cr="_bufferedBar_oxcpx_217",kr="_watchedBar_oxcpx_227",xr="_scrubbing_oxcpx_252",Nr="_timeBubble_oxcpx_256",Ir="_bottomControlsRow_oxcpx_270",Er="_active_oxcpx_323",wr="_settingsPanel_oxcpx_398",Br="_settingsHeader_oxcpx_417",Pr="_settingsBackBtn_oxcpx_425",Mr="_settingsTitle_oxcpx_443",Ar="_settingsContent_oxcpx_454",$r="_currentValue_oxcpx_463",Lr="_menuItem_oxcpx_478",Rr="_menuNote_oxcpx_511",o={fullscreenFlat:or,timeDisplay:ir,bottomControls:lr,leftControls:cr,rightControls:dr,controlBtn:ur,controlsOverlay:mr,hidden:pr,topControls:hr,backBtn:gr,videoTitleInfo:fr,animeTitle:br,episodeLabel:vr,speedBoostBadge:yr,progressBarContainer:_r,progressBar:Sr,thumb:Tr,bufferedBar:Cr,watchedBar:kr,scrubbing:xr,timeBubble:Nr,bottomControlsRow:Ir,active:Er,settingsPanel:wr,settingsHeader:Br,settingsBackBtn:Pr,settingsTitle:Mr,settingsContent:Ar,currentValue:$r,menuItem:Lr,menuNote:Rr},Dr=({classes:p,tracks:E,selected:z,onChange:V})=>t(It,{classes:p,options:E.map((r,G)=>({key:String(G),label:r.label||r.language,selected:G===z})),onSelect:r=>V(Number(r))}),Vr=({player:p,title:E,episodeLabel:z,audioTracks:V,selectedAudioTrack:r,onAudioTrackChange:G,subtitles:j,selectedSubtitle:M,onSubtitleChange:u,streams:me,qualityIdx:ce,onQualityChange:Ge,onBack:y,children:pe,movyServers:O=[],selectedMovyServer:Je="atlanta",onMovyServerSelect:X,isMovySource:Se=!1,videoDelayEnabled:Qe=!1,onVideoDelayToggle:Et,videoDelayMs:ct=0,onVideoDelayChange:dt,onCalibrateAvSync:J})=>{const{state:C,refs:ut,actions:x}=p,A=ut.videoRef,{subtitleFontSize:Z,subtitlePosition:$,subtitleBgOpacity:Pe,subtitleBgColor:Me,subtitleTextColor:se,subtitleEdge:Te,subtitleBold:ee}=C,[k,w]=v(null),de=D(null),[he,wt]=v(0);f(()=>{const a=A.current;if(!a)return;const l=()=>wt(a.clientHeight||0);l();const Ie=new ResizeObserver(l);return Ie.observe(a),()=>Ie.disconnect()},[A,me]);const te=(a,l)=>{try{localStorage.setItem(a,String(l))}catch{}},Ae=(a,l)=>{switch(a){case"fontSize":typeof l=="number"&&(x.setSubtitleFontSize(l),te("subtitleFontSize",l));break;case"position":typeof l=="number"&&(x.setSubtitlePosition(l),te("subtitlePosition",l));break;case"bgOpacity":typeof l=="number"&&(x.setSubtitleBgOpacity(l),te("subtitleBgOpacity",l));break;case"bgColor":typeof l=="string"&&(x.setSubtitleBgColor(l),te("subtitleBgColor",l));break;case"textColor":typeof l=="string"&&(x.setSubtitleTextColor(l),te("subtitleTextColor",l));break;case"edge":(l==="shadow"||l==="outline"||l==="none")&&(x.setSubtitleEdge(l),te("subtitleEdge",l));break;case"bold":typeof l=="boolean"&&(x.setSubtitleBold(l),te("subtitleBold",l));break}};f(()=>{const a="tv-player-subtitle-style";let l=document.getElementById(a);l||(l=document.createElement("style"),l.id=a,document.head.appendChild(l));const Ie={fontSize:Z,position:$,bgOpacity:Pe,bgColor:Me,textColor:se,edge:Te,bold:ee},H=A.current,ft=an(Z,he||H?.clientHeight||720);if(l.textContent=En({...Ie,fontSize:ft}),H){const bt=()=>{const h=Number($);return isNaN(h)?0:Math.max(0,Math.min(100,h))},Ze=(h,F)=>{try{const U=h;U.snapToLines=!1,U.line=F}catch{}},et=()=>{const h=ft*16,F=H.videoHeight||H.clientHeight||720,U=H.videoWidth||H.clientWidth||1280;return{step:h*1.3/F*100,chars:Math.max(20,Math.floor(U/(h*.55)))}},fe=h=>{const F=Math.max(0,Math.min(100,100-bt())),U=Array.from(h.activeCues??[]);if(U.length<=1){U.forEach(ae=>Ze(ae,F));return}const{step:vt,chars:Mt}=et();let tt=F;for(let ae=U.length-1;ae>=0;ae--){const nt=String(U[ae].text??"").replace(/<[^>]*>/g,"").split(`
|
|
2
|
+
`).reduce((oe,Fe)=>oe+Math.max(1,Math.ceil(Fe.length/Mt)),0),rt=tt-nt*vt;Ze(U[ae],Math.max(0,rt)),tt=rt-vt*.4}},be=()=>{const h=Math.max(0,Math.min(100,100-bt()));Array.from(H.textTracks).forEach(F=>{F.cues&&(Array.from(F.cues).forEach(U=>Ze(U,h)),F.mode==="showing"&&fe(F))})};be();const Oe=h=>{const F=h.target;F.mode==="showing"&&fe(F)},ve=()=>{Array.from(H.textTracks).forEach(h=>{h.removeEventListener("cuechange",Oe),h.addEventListener("cuechange",Oe)}),be()};Array.from(H.textTracks).forEach(h=>{h.addEventListener("cuechange",Oe)}),H.textTracks.addEventListener("addtrack",ve);const _=Array.from(H.querySelectorAll("track")),Ee=()=>be();return _.forEach(h=>h.addEventListener("load",Ee)),()=>{Array.from(H.textTracks).forEach(h=>{h.removeEventListener("cuechange",Oe)}),H.textTracks.removeEventListener("addtrack",ve),_.forEach(h=>h.removeEventListener("load",Ee))}}},[Z,$,Pe,Me,se,Te,ee,M,j,A,he]);const $e=a=>{const l=A.current;!l||isNaN(C.duration)||C.duration===0||(l.currentTime=a*C.duration)},Bt=()=>{A.current&&(x.setIsScrubbing(!0),x.wasPlayingBeforeScrub.current=!A.current.paused,A.current.pause())},Ye=a=>{const l=A.current;l&&C.duration&&(l.currentTime=a*C.duration)},Ce=()=>{x.setIsScrubbing(!1),x.wasPlayingBeforeScrub.current&&A.current?.play().catch(()=>{})},Q=a=>{const l=A.current;l&&(l.volume=a,l.muted=a===0,localStorage.setItem("playerVolume",a.toString()))},mt=()=>{x.toggleMute()},Le=j.length>0,ge=M>=0,Xe=()=>{w("main"),x.setShowControls(!0)},T=()=>{if(ge){u(-1);return}let a=null;try{a=localStorage.getItem("tvLastSubtitle")}catch{}u(jt(j,{lastKey:a,enabled:!0}))},d=()=>{w(null)},Y=()=>t(Nt,{children:[me.length>1&&t("button",{className:o.menuItem,onClick:()=>w("quality"),children:[t("span",{children:"Quality"}),t("span",{className:o.currentValue,children:me[ce]?.quality||"Auto"})]}),Se&&O.length>0&&t("button",{className:o.menuItem,onClick:()=>w("server"),children:[t("span",{style:{display:"flex",alignItems:"center",gap:6},children:[t(I,{name:"server",size:12})," Movy Server"]}),t("span",{className:o.currentValue,style:{textTransform:"capitalize"},children:Je})]}),Le&&t("button",{className:o.menuItem,onClick:()=>w("subtitles"),children:[t("span",{children:"Subtitles"}),t("span",{className:o.currentValue,children:ge?j[M]?.label||j[M]?.language:"Off"})]}),Le&&t("button",{className:o.menuItem,onClick:()=>w("subtitle-style"),children:[t("span",{children:"Subtitle Style"}),t("span",{className:o.currentValue,children:[Z.toFixed(1),"x · ",$]})]}),V.length>0&&t("button",{className:o.menuItem,onClick:()=>w("audio"),children:[t("span",{children:"Audio Track"}),t("span",{className:o.currentValue,children:V[r]?.label||V[r]?.language})]}),t("button",{className:o.menuItem,onClick:()=>w("av-sync"),children:[t("span",{children:"A/V Sync"}),t("span",{className:o.currentValue,children:Qe?`${ct}ms`:"Off"})]})]}),ne=()=>t(It,{classes:{item:o.menuItem,active:o.active},options:me.map((a,l)=>({key:String(l),label:a.quality,selected:l===ce})),onSelect:a=>Ge(Number(a))}),pt=()=>t(It,{classes:{item:o.menuItem,active:o.active},options:[{key:"off",label:"Off",selected:!ge},...j.map((a,l)=>({key:String(l),label:a.label||a.language,selected:l===M}))],onSelect:a=>u(a==="off"?-1:Number(a))}),ht=()=>t(Kn,{classes:{item:o.menuItem,active:o.active},values:{fontSize:Z,position:$,bgOpacity:Pe,bgColor:Me,textColor:se,edge:Te,bold:ee},onChange:Ae}),ke=()=>t(Dr,{classes:{item:o.menuItem,active:o.active},tracks:V,selected:r,onChange:G}),gt=()=>t(It,{classes:{item:o.menuItem,active:o.active},options:O.map(a=>({key:a,label:t("span",{style:{textTransform:"capitalize"},children:a}),selected:Je===a})),onSelect:a=>X?.(a)}),xe=()=>t(qn,{classes:{item:o.menuItem,active:o.active,note:o.menuNote},enabled:Qe,delayMs:ct,onToggle:a=>Et?.(a),onDelayChange:a=>dt?.(a),onCalibrate:()=>{w(null),J?.()}}),Re=C.isMuted?t(I,{name:"volume-mute"}):C.volume<.5?t(I,{name:"volume-down"}):t(I,{name:"volume-up"}),Pt=t("div",{className:`${o.controlsOverlay} ${!C.showControls&&!k?o.hidden:""}`,"data-speed-boost-ignore":"true",style:{pointerEvents:"none",background:"none"},children:t("div",{className:o.topControls,onClick:a=>a.stopPropagation(),children:[t("button",{className:o.backBtn,onClick:y,title:"Back","aria-label":"Back",children:t(I,{name:"chevron-left"})}),t("div",{className:o.videoTitleInfo,children:[t("span",{className:o.animeTitle,children:E}),z&&t("span",{className:o.episodeLabel,children:z})]})]})}),De=t(wn,{isPlaying:C.isPlaying,onTogglePlay:x.togglePlay,onSkipBack:()=>x.seek(-10),onSkipForward:()=>x.seek(10)}),re=t("div",{className:`${o.controlsOverlay} ${!C.showControls&&!k?o.hidden:""}`,"data-speed-boost-ignore":"true",style:{pointerEvents:"none",background:"none",justifyContent:"flex-end"},children:t("div",{className:o.bottomControls,onClick:a=>a.stopPropagation(),children:[t(Bn,{classes:{container:o.progressBarContainer,scrubbing:o.scrubbing,timeBubble:o.timeBubble,bar:o.progressBar,buffered:o.bufferedBar,watched:o.watchedBar,thumb:o.thumb},videoRef:A,duration:C.duration,formatTime:Ht,isScrubbing:C.isScrubbing,buffered:"full",onSeek:$e,onScrubStart:Bt,onScrubMove:Ye,onScrubEnd:Ce,timeLabelRef:de}),t("div",{className:o.bottomControlsRow,children:[t("div",{className:o.leftControls,children:[t("button",{className:o.controlBtn,onClick:x.togglePlay,"aria-label":C.isPlaying?"Pause":"Play",children:C.isPlaying?t(I,{name:"pause"}):t(I,{name:"play"})}),t(Pn,{muted:C.isMuted,volume:C.volume,volumeIcon:Re,buttonClassName:o.controlBtn,onToggleMute:mt,onVolumeChange:Q,onExpandedChange:a=>x.setShowVolumeSlider(a)}),t("span",{className:o.timeDisplay,ref:de,children:[Ht(0)," / ",Ht(C.duration)]})]}),t("div",{className:o.rightControls,children:[Le&&t("button",{className:`${o.controlBtn} ${ge?o.active:""}`,onClick:T,"aria-label":ge?"Turn subtitles off":"Turn subtitles on",children:t(I,{name:"closed-captioning"})}),t("button",{className:`${o.controlBtn} ${k?o.active:""}`,onClick:()=>k?d():Xe(),"aria-label":"Settings",children:t(I,{name:"cog"})}),t("button",{className:o.controlBtn,onClick:x.toggleFullscreen,"aria-label":C.isFullscreen?"Exit Fullscreen":"Fullscreen",children:C.isFullscreen?t(I,{name:"compress"}):t(I,{name:"expand"})})]})]})]})}),Ne=k?t("div",{"data-speed-boost-ignore":"true",onClick:a=>a.stopPropagation(),children:t(jn,{classes:{panel:o.settingsPanel,header:o.settingsHeader,backBtn:o.settingsBackBtn,title:o.settingsTitle,content:o.settingsContent},title:k==="main"?"Settings":k==="subtitle-style"?"Subtitle Style":k==="audio"?"Audio Track":k==="server"?"Movy Server":k==="av-sync"?"A/V Sync":k.charAt(0).toUpperCase()+k.slice(1),onBack:()=>k==="main"?d():w("main"),children:[k==="main"&&Y(),k==="quality"&&ne(),k==="subtitles"&&pt(),k==="subtitle-style"&&ht(),k==="audio"&&ke(),k==="server"&>(),k==="av-sync"&&xe()]})}):null,Ve=C.isSpeedBoostActive?t("div",{className:o.speedBoostBadge,"aria-hidden":"true",children:[t("span",{children:"2x"}),t(I,{name:"forward",size:12})]}):null;return t(Mn,{player:p,topBar:Pt,centerControls:De,bottomBar:re,settingsPanel:Ne,overlays:Ve,isInteracting:!!k,className:C.isFullscreen?o.fullscreenFlat:"",children:pe})};function Or(p,E,z){const V=()=>{const G=Array.isArray(p.audioTracks)?p.audioTracks.length:0,j=z.getWant(),M=G>0?Math.min(Math.max(0,j),G-1):j;p.audioTrack=M,M!==j&&z.onResolve(M)},r=(G,j)=>{const M=z.getWant(),u=Array.isArray(p.audioTracks)?p.audioTracks.length:0;if(j.id!==M&&M>=0&&M<u){p.audioTrack!==M&&(p.audioTrack=M);return}z.onResolve(j.id)};return p.on(E.MANIFEST_PARSED,V),p.on(E.AUDIO_TRACK_SWITCHED,r),()=>{p.off(E.MANIFEST_PARSED,V),p.off(E.AUDIO_TRACK_SWITCHED,r)}}const Fr="_page_263ma_1",zr="_header_263ma_7",Hr="_pageTitle_263ma_11",Ur="_searchForm_263ma_21",Wr="_searchInput_263ma_27",jr="_searchBtn_263ma_42",Kr="_suggestions_263ma_58",qr="_suggestionPill_263ma_65",Gr="_statusMsg_263ma_81",Jr="_error_263ma_87",Qr="_textOnly_263ma_91",Yr="_spinner_263ma_96",Xr="_spin_263ma_96",Zr="_grid_263ma_110",es="_skeletonCard_263ma_116",ts="_skeletonThumb_263ma_121",ns="_skeletonLine_263ma_127",rs="_shimmer_263ma_134",ss="_backBtn_263ma_154",as="_meta_263ma_172",os="_headerActions_263ma_180",is="_watchlistBtn_263ma_187",ls="_active_263ma_205",cs="_year_263ma_215",ds="_rating_263ma_220",us="_typeBadge_263ma_229",ms="_tv_263ma_237",ps="_movie_263ma_242",hs="_tvSeries_263ma_247",gs="_tvMiniSeries_263ma_252",fs="_overview_263ma_257",bs="_controls_263ma_264",vs="_controlLabel_263ma_272",ys="_select_263ma_282",_s="_playerSection_263ma_293",Ss="_video_263ma_297",Ts="_videoHidden_263ma_319",Cs="_delayCanvas_263ma_324",ks="_delayCanvasActive_263ma_337",xs="_subtitleOverlay_263ma_341",Ns="_videoIframe_263ma_360",Is="_retryButton_263ma_368",Es="_sidebarSeason_263ma_383",ws="_mobileSeasonRow_263ma_399",Bs="_sidebarPosterCard_263ma_413",Ps="_sidebarPosterMeta_263ma_428",Ms="_providerSelectWrap_263ma_445",As="_genreRow_263ma_457",$s="_genreChip_263ma_464",Ls="_metaRow_263ma_474",Rs="_detailGrid_263ma_483",Ds="_detailItem_263ma_490",Vs="_imdbLink_263ma_512",c={page:Fr,header:zr,pageTitle:Hr,searchForm:Ur,searchInput:Wr,searchBtn:jr,suggestions:Kr,suggestionPill:qr,statusMsg:Gr,error:Jr,textOnly:Qr,spinner:Yr,spin:Xr,grid:Zr,skeletonCard:es,skeletonThumb:ts,skeletonLine:ns,shimmer:rs,backBtn:ss,meta:as,headerActions:os,watchlistBtn:is,active:ls,year:cs,rating:ds,typeBadge:us,tv:ms,movie:ps,tvSeries:hs,tvMiniSeries:gs,overview:fs,controls:bs,controlLabel:vs,select:ys,playerSection:_s,video:Ss,videoHidden:Ts,delayCanvas:Cs,delayCanvasActive:ks,subtitleOverlay:xs,videoIframe:Ns,retryButton:Is,sidebarSeason:Es,mobileSeasonRow:ws,sidebarPosterCard:Bs,sidebarPosterMeta:Ps,providerSelectWrap:Ms,genreRow:As,genreChip:$s,metaRow:Ls,detailGrid:Rs,detailItem:Ds,imdbLink:Vs},Os=[],Xs=()=>{const{id:p}=kn(),[E]=xn(),z=Nn(),V=E.get("type"),[r,G]=v(null),[j,M]=v(!1),[u,me]=v(()=>parseInt(E.get("s")||"1",10)||1),[ce,Ge]=v([]),[y,pe]=v(()=>parseInt(E.get("e")||"1",10)||1),[O,Je]=v(()=>{try{return localStorage.getItem("tvProvider")||""}catch{return""}}),[X,Se]=v([]),{options:Qe,isFallback:Et,isLoading:ct}=Jn(),dt=_e(()=>Qe.filter(e=>(e.kind??"tv")==="tv").map(e=>({id:e.value,label:e.label,tier:e.tier==="embed"?"embed":"direct",servers:e.servers})),[Qe]),J=Et||dt.length===0?Os:dt,C=J.filter(e=>e.tier==="direct"),ut=J.filter(e=>e.tier==="embed"),[x,A]=v(!1),[Z,$]=v(""),[Pe,Me]=v([]),[se,Te]=v(0),[ee,k]=v([]),[w,de]=v(-1),[he,wt]=v("all"),[te,Ae]=v(0),[$e,Bt]=v(""),[Ye,Ce]=v(""),[Q,mt]=v(()=>{try{return localStorage.getItem("movyServer")||""}catch{return""}}),Le=D([]);f(()=>{Le.current=X},[X]);const ge=D(se);f(()=>{ge.current=se},[se]);const Xe=D(w);f(()=>{Xe.current=w},[w]);const T=An({skipIntervals:[]}),d=T.refs.videoRef;$n(T,X.length>0||Ye!=="");const Y=D(null),ne=D([]),pt=D(null),ht=D(null),[ke,gt]=v(()=>{try{const e=Number(localStorage.getItem("playerVideoDelayMs"));if(Number.isFinite(e)&&e>=0&&e<=500)return Math.round(e)}catch{}return 180}),[xe,Re]=v(()=>{try{return localStorage.getItem("playerVideoDelayEnabled")==="true"}catch{return!1}}),[Pt,De]=v(!1),[re,Ne]=v(!1),Ve=D(null),a=D(null),l=(e,n)=>{try{localStorage.setItem("playerVideoDelayMs",String(e)),localStorage.setItem("playerVideoDelayEnabled",String(n))}catch{}},Ie=e=>{const n=Math.max(0,Math.min(500,Math.round(e)));gt(n);try{localStorage.setItem("playerVideoDelayMs",String(n))}catch{}},H=()=>{Ve.current={enabled:xe,ms:ke},Re(!0);try{localStorage.setItem("playerVideoDelayEnabled","true")}catch{}De(!0)},ft=()=>{const e=Ve.current;Ve.current=null,e&&(gt(e.ms),Re(e.enabled),l(e.ms,e.enabled)),Ne(!1),De(!1)},bt=()=>{Ve.current=null,Re(!0),l(ke,!0),Ne(!1),De(!1)},Ze=()=>{if(re){Ne(!1);return}const e=d.current;e&&!isNaN(e.currentTime)&&(a.current=e.currentTime),Ne(!0)},et=xe?ke:0;Ln({videoRef:d,canvasRef:pt,delayMs:et,enabled:xe});const fe=xe,{hasConsent:be,grant:Oe}=Gn(),ve=D("");ve.current||(ve.current=`tv-${Date.now()}-${Math.random().toString(36).slice(2)}`);const _=V==="movie",Ee=p?Qn(V||"tv",p):"",h=Ee,F=Yn(),{toggle:U,bookmarkedIds:vt,pending:Mt}=Xn(),{data:tt}=Zn(r?Ee:void 0),ae=tt?!!tt.inLibrary:Ee?vt.has(Ee):!1,Kt=P(()=>{!r||!p||U({tmdbId:Number(p),mediaType:V||"tv",title:r.title,poster:r.poster,year:r.year,adult:r.adult})},[r,p,V,U]),{data:nt,isFetched:rt}=er(h||void 0,u,y),[oe,Fe]=v(!1),[ze,qt]=v(0),[st,Gt]=v(!1),[on,at]=v(!1),[ln,Jt]=v(""),[yt,cn]=v(!1),[dn,At]=v(!1),un=sr(),_t=D(!1),we=D(null),$t=D(0),Qt=D(!1),K=D(null),Yt=D(""),ot=D(!1);f(()=>{ot.current=oe},[oe]);const He=D(!1);f(()=>{He.current=st},[st]);const mn=e=>{const n=Math.floor(e/3600),s=Math.floor(e%3600/60),i=Math.floor(e%60);return n>0?`${n}:${String(s).padStart(2,"0")}:${String(i).padStart(2,"0")}`:`${s}:${String(i).padStart(2,"0")}`},ye=P((e,n)=>{!h||!n||n<30||Math.abs(e-$t.current)<10||($t.current=e,F.mutate({mediaId:h,season:u,episode:y,currentTime:Math.floor(e),duration:Math.floor(n),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:V||"tv",adult:r?.adult?1:0}))},[h,u,y,F,r,V]),Ue=P((e,n)=>{Ne(!1),De(!1);const s=new URLSearchParams(E);s.set("type",E.get("type")||"tv"),s.set("s",String(e)),s.set("e",String(n)),z(`${window.location.pathname}?${s.toString()}`)},[E,z]),pn=P(()=>{if(re)return;const e=d.current;!e||e.paused||e.ended||(we.current&&clearTimeout(we.current),we.current=setTimeout(()=>{ye(e.currentTime,e.duration||0)},5e3))},[ye,d,re]),hn=P(()=>{const e=d.current;if(e){if(we.current&&clearTimeout(we.current),ye(e.currentTime,e.duration||0),Qt.current=!0,_&&r)Jt(r.title),at(!0);else if(r){const n=y+1;ce.some(m=>m.episode_number===n)?(pe(n),Ue(u,n)):(Jt(`${r.title} — Season ${u}`),at(!0))}}},[_,r,y,u,ce,ye,Ue,d]),gn=P(()=>{Qt.current=!1,T.actions.onPlay()},[T.actions]),fn=P(()=>{T.actions.onPause();const e=d.current;e&&!e.ended&&ye(e.currentTime,e.duration||0)},[T.actions,ye,d]),bn=P(()=>{T.actions.onLoadedMetadata();const e=d.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(K.current!=null&&K.current>0){try{e.currentTime=K.current}catch{}K.current=null}}},[T.actions,d]),We=P(()=>{const e=d.current;if(e&&K.current!=null&&K.current>0){try{e.currentTime=K.current}catch{}K.current=null}},[d]),vn=P(()=>{ze>0&&(K.current=ze);const e=d.current;if(e&&ze>0){try{e.currentTime=ze,K.current=null}catch{}e.play().catch(()=>{})}Fe(!1),_t.current=!0},[ze,d]),Xt=P(()=>{K.current=null;const e=d.current;e&&(e.currentTime=0,e.play().catch(()=>{})),Fe(!1),_t.current=!0},[d]);f(()=>{_t.current=!1,Fe(!1),qt(0),Gt(!1),He.current=!1,K.current=null,Yt.current=`${h}:${u}:${y}`,$t.current=0},[h,u,y]),f(()=>{rt&&(Gt(!0),He.current=!0)},[rt,h,u,y]),f(()=>{if(!nt||_t.current)return;const e=nt,n=e.currentTime??0,s=e.duration??0;n>5&&(s<=0||n<s*.8)&&(qt(n),Fe(!0))},[nt,h,u,y]),f(()=>{oe&&d.current&&d.current.pause()},[oe,d]),f(()=>{const e=d.current;return()=>{we.current&&clearTimeout(we.current),e&&!e.ended&&ye(e.currentTime,e.duration||0)}},[ye,d]);const Lt=P(e=>{let n=null,s=!0;try{n=localStorage.getItem("tvLastSubtitle"),s=localStorage.getItem("tvSubtitlesEnabled")!=="false"}catch{}return jt(e,{lastKey:n,enabled:s})},[]),Rt=P(e=>{if(!(e<0))try{localStorage.setItem("tvSubtitlesEnabled","true"),localStorage.setItem("tvSelectedSubtitle",String(e))}catch{}},[]),Zt=P(e=>{if(e.length===0)return 0;let n=null;try{n=localStorage.getItem("tvLastAudio")}catch{}if(n){const s=e.findIndex(g=>Wt(g)===n);if(s>=0)return s;const i=n.indexOf("|||"),m=i>=0?n.slice(0,i):n,S=i>=0?n.slice(i+3):n,b=e.findIndex(g=>g.language===m||g.label===S);if(b>=0)return b}return jt(e,{lastKey:null,enabled:!0})},[]),Dt=_e(()=>J.find(e=>e.id===O),[J,O]),B=Dt?.tier==="embed",q=_e(()=>Dt?.servers??[],[Dt]),{data:en}=tr(h||void 0),tn=_e(()=>(en?.progress??[]).filter(n=>n.season===u&&n.duration>0&&n.currentTime>=n.duration*.8).map(n=>String(n.episode)),[en,u]),nn=_e(()=>ce.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})),[ce]),St=_e(()=>ce.map(e=>e.episode_number).sort((e,n)=>e-n),[ce]),it=St.indexOf(y),Vt=it>0?St[it-1]:null,je=it>=0&&it<St.length-1?St[it+1]:null,rn=_e(()=>(r?.genres??[]).map(e=>e.name).slice(0,5),[r]),Ot=_e(()=>[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]);f(()=>{if(J.length!==0&&!J.some(e=>e.id===O)){const e=J.find(n=>n.tier==="direct")?.id??J[0].id;Je(e);try{localStorage.setItem("tvProvider",e)}catch{}}},[J,O]),f(()=>{if(q.length!==0&&!q.includes(Q)){mt(q[0]);try{localStorage.setItem("movyServer",q[0])}catch{}}},[q,Q]),f(()=>{if(!p){G(null),Se([]),$(""),Ce("");return}const e=Number(p),n=V||"tv";M(!0),G(null),Se([]),$(""),Ce("");const s=parseInt(E.get("s")||"",10),i=parseInt(E.get("e")||"",10);me(isNaN(s)?1:s),pe(isNaN(i)?1:i),Ae(0),fetch(`/api/tv/details/${n}/${e}`).then(m=>m.json()).then(m=>{G(m),M(!1),m.seasons&&m.seasons.length>0&&isNaN(s)&&me(m.seasons[0].season_number)}).catch(()=>{M(!1)})},[p,V,E]),f(()=>{if(!r||!p)return;if(!(r.seasons!==void 0||r.number_of_seasons!==void 0)){Ge([]);return}const n=parseInt(E.get("e")||"",10);fetch(`/api/tv/episodes/${p}/${u}`).then(s=>s.json()).then(s=>{if(Ge(s.episodes||[]),s.episodes?.length>0){const i=!isNaN(n)&&s.episodes.find(m=>m.episode_number===n)?n:s.episodes[0].episode_number;pe(i)}}).catch(()=>{})},[r,p,u,E]),f(()=>{!r||!p||_||fetch(`/api/tv/episodes/${p}/${u}`).then(e=>e.json()).then(e=>{const n=e.episodes||[];Ge(n),n.length>0&&!n.find(s=>s.episode_number===y)&&pe(n[0].episode_number)}).catch(()=>{})},[u,r,p,_,y]),f(()=>{if(!B||!r||!p)return;fetch(`/api/tv/embed/${O}/${_?"movie":"tv"}/${p}?season=${u}&episode=${y}`).then(n=>n.json()).then(n=>{if(n.url)return Ce(n.url),fetch(`/api/resolve?url=${encodeURIComponent(n.url)}`).then(s=>s.json()).then(s=>{s.finalUrl&&Ce(s.finalUrl)})}).catch(()=>{})},[O,r,p,u,y,_,B]);const Tt=P(async()=>{if(!r||!p||!O||B||r.adult&&!be)return;Le.current.length>0?$(""):(A(!0),$(""),Se([]),Ae(0),Me([]),k([]));try{const n=_?"movie":"tv",s=new URLSearchParams({title:r.title||"",year:r.year||"",season:String(u),episode:String(y),totalSeasons:String(r.number_of_seasons||1),imdbId:r.imdb_id||""});q.length>0&&Q&&s.set("server",Q);const m=await(await fetch(`/api/tv/sources/${O}/${n}/${p}?${s.toString()}`)).json();if(A(!1),!m.valid||!m.sources?.length){$(m.error?`${m.error}`:q.length>0?`No streams from ${Q}. Try another server.`:"No streams available.");return}Se(m.sources),wt("all"),Ae(0),m.referer&&Bt(m.referer);const S=m.audioTracks||[];Me(S),Te(S.length>0?Zt(S):0);const b=m.subtitles||[];if(k(b),b.length>0){const L=Lt(b);de(L),Rt(L)}else de(-1);fetch(`/api/tv/subtitles/${n}/${p}?season=${u}&episode=${y}`).then(L=>L.json()).then(L=>{const ie=Array.isArray(L.subtitles)?L.subtitles:[];ie.length!==0&&k(W=>{const R=[...W,...ie.filter(N=>!W.some(le=>le.url===N.url))];if(W.length===0){const N=Lt(R);de(N),Rt(N)}return R})}).catch(()=>{}),$("")}catch{A(!1),$("Failed to load streams.")}},[r,p,O,u,y,_,B,be,q,Q,Lt,Rt,Zt]),Ft=P(e=>{const n=e.toLowerCase();mt(n);try{localStorage.setItem("movyServer",n)}catch{}$("")},[]),yn=P(e=>{Je(e);try{localStorage.setItem("tvProvider",e)}catch{}},[]);f(()=>{O&&r&&!B&&Tt()},[O,r,Tt,B]),f(()=>{if(!d.current||(Y.current&&(Y.current.destroy(),Y.current=null),B))return;let e=!1;if(re){const b=d.current;return b&&(b.pause(),b.removeAttribute("src"),b.load(),b.src="/av-sync-test.mp4",ot.current||b.play().catch(()=>{})),()=>{e=!0}}const n=he==="all"?X:X.filter(b=>b.type===he),s=n[te]?.url||"";if(!s)return;const i=d.current;if(Yt.current===`${h}:${u}:${y}`&&K.current==null)try{!i.ended&&i.currentTime>1&&(K.current=i.currentTime)}catch{}i.pause(),i.removeAttribute("src"),i.load();const m=`/api/tv/stream-proxy?url=${encodeURIComponent(s)}&referer=${encodeURIComponent($e)}`;n[te]?.type==="hls"?(async()=>{const b=await nr();if(!e)if(b&&b.isSupported()){const g=new b({enableWorker:!0});Y.current=g,g.on(b.Events.ERROR,(W,R)=>{R.fatal&&($(`Stream failed (${R.details}). Try another source or reload.`),A(!1),g.destroy(),Y.current=null)}),g.loadSource(m),g.attachMedia(i);const L=()=>{let W=!1,R=0;try{W=localStorage.getItem("tvSubtitlesEnabled")==="true";const N=parseInt(localStorage.getItem("tvSelectedSubtitle")||"0",10);!isNaN(N)&&N>=0&&(R=N)}catch{}return{enabled:W,index:R}},ie=()=>{if(typeof g.subtitleTrack!="number")return;if(ne.current.length>0){g.subtitleTrack=-1;return}const W=Array.isArray(g.subtitleTracks)?g.subtitleTracks:[];if(W.length===0){g.subtitleTrack=-1;return}const R=L();if(R.enabled){const N=R.index<W.length?R.index:0;g.subtitleTrack=N,de(N)}else g.subtitleTrack=-1};Or(g,b.Events,{getWant:()=>ge.current,onResolve:W=>Te(W)}),g.on(b.Events.MANIFEST_PARSED,()=>{ie(),a.current!=null&&(i.currentTime=a.current,a.current=null),We(),!ot.current&&He.current&&i.play().catch(()=>{})}),g.on(b.Events.SUBTITLE_TRACKS_UPDATED,()=>{ie()}),g.on(b.Events.SUBTITLE_TRACK_SWITCH,(W,R)=>{if(ne.current.length>0){if(R.id!==-1)try{g.subtitleTrack=-1}catch{}return}const N=Array.isArray(g.subtitleTracks)?g.subtitleTracks:[];if(N.length!==0){if(R.id===-1){const le=L();if(le.enabled){const xt=le.index<N.length?le.index:0;g.subtitleTrack=xt;return}}de(R.id)}})}else rr(i)&&(i.src=m,a.current!=null&&(i.currentTime=a.current,a.current=null),We(),!ot.current&&He.current&&i.play().catch(()=>{$("Failed to play stream. Try another source.")}))})():(i.src=m,a.current!=null&&(i.currentTime=a.current,a.current=null),We(),!ot.current&&He.current&&i.play().catch(()=>{$("Failed to play stream. Try another source.")}));const S=()=>{const L=i.error?.code===4?"Video source not supported or not found":"Failed to load video stream";$(`${L}. The source may be invalid or expired. Try switching source or reloading.`),A(!1)};return i.addEventListener("error",S),()=>{e=!0,i.removeEventListener("error",S)}},[X,te,he,O,$e,B,d,re,h,u,y,We]),f(()=>{if(!st||oe||B||re)return;const e=d.current;!e||!e.paused||e.ended||e.readyState<1||(We(),e.play().catch(()=>{}))},[st,oe,B,re,We,d]),f(()=>{const e=Y.current;!e||typeof e.audioTrack!="number"||(e.audioTrack=se)},[se]),f(()=>{const e=Y.current;!e||typeof e.subtitleTrack!="number"||!Array.isArray(e.subtitleTracks)||e.subtitleTracks.length===0||ne.current.length>0||(w>=0?e.subtitleTrack=w:e.subtitleTrack=-1)},[w]),f(()=>{const e=d.current;if(!(!e||B)&&(e.querySelectorAll("track").forEach(n=>n.remove()),ne.current=[],ee.length!==0&&(ee.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 i=`/api/subtitle-proxy?url=${encodeURIComponent(n.url)}&referer=${encodeURIComponent($e)}`;s.src=i,s.addEventListener("load",()=>{const m=ne.current.indexOf(s),S=s.track;S&&m>=0&&(S.mode=m===Xe.current?"showing":"hidden")}),e.appendChild(s),ne.current.push(s)}),ee.length>0)))try{const n=Y.current;n&&typeof n.subtitleTrack=="number"&&n.subtitleTrack!==-1&&(n.subtitleTrack=-1)}catch{}},[ee,$e,B,O,d]),f(()=>{const e=d.current;if(!e||B)return;const n=Y.current;n&&typeof n.subtitleTrack=="number"&&Array.isArray(n.subtitleTracks)&&n.subtitleTracks.length>0&&(n.subtitleTrack=-1);const s=()=>{const S=ne.current;if(S.length>0){S.forEach((g,L)=>{const ie=g.track;ie&&(ie.mode=L===w?"showing":"hidden")});return}const b=Array.from(e.textTracks);b.length!==0&&b.forEach((g,L)=>{g.mode=L===w?"showing":"hidden"})};s();const i=()=>s();e.textTracks.addEventListener("addtrack",i),e.addEventListener("loadedmetadata",s,{once:!0});const m=window.setTimeout(s,600);return()=>{e.textTracks.removeEventListener("addtrack",i),e.removeEventListener("loadedmetadata",s),window.clearTimeout(m)}},[w,ee,B,O,d]),f(()=>{if(!fe)return;const e=d.current,n=ht.current;if(!e||!n)return;const s=()=>{if(n.innerHTML="",Xe.current<0)return;const S=ne.current.map(N=>N.track).find(N=>N&&N.mode==="showing");if(!S)return;const b=et/1e3;let g;if(b>0&&S.cues){const N=e.currentTime-b;g=Array.from(S.cues).filter(le=>le.startTime<=N&&N<=le.endTime)}else g=Array.from(S.activeCues??[]);if(g.length===0)return;const L={fontSize:an(T.state.subtitleFontSize,e.clientHeight||0),position:T.state.subtitlePosition,bgOpacity:T.state.subtitleBgOpacity,bgColor:T.state.subtitleBgColor,textColor:T.state.subtitleTextColor,edge:T.state.subtitleEdge,bold:T.state.subtitleBold},ie=Rn(L),W=Dn(e,L.position),R=Array.from(g);R.forEach((N,le)=>{const xt=String(N.text??"");if(!Vn(xt).trim())return;const zt=document.createElement("div"),Cn=(R.length-1-le)*1.7;zt.style.cssText=`${ie}
|
|
3
|
+
bottom: calc(${W}px + ${Cn}em);`,zt.innerHTML=On(xt),n.appendChild(zt)})},i=()=>s(),m=ne.current.map(S=>S.track).filter(S=>!!S);return m.forEach(S=>S.addEventListener("cuechange",i)),e.addEventListener("timeupdate",i),s(),()=>{m.forEach(S=>S.removeEventListener("cuechange",i)),e.removeEventListener("timeupdate",i),n.innerHTML=""}},[fe,w,ee,et,d,T.state.subtitleFontSize,T.state.subtitlePosition,T.state.subtitleBgOpacity,T.state.subtitleBgColor,T.state.subtitleTextColor,T.state.subtitleEdge,T.state.subtitleBold]);const Ct=()=>{G(null),Se([]),Ce(""),z(-1)},_n=P(e=>{me(e),pe(1),Ue(e,1)},[Ue]),kt=!_&&r?.seasons&&r.seasons.length>1?t("label",{className:c.sidebarSeason,children:[t("span",{children:"Season"}),t("select",{value:u,onChange:e=>_n(parseInt(e.target.value,10)||1),className:c.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,Ke=P(e=>{const n=parseInt(e,10);isNaN(n)||(pe(n),Ue(u,n)),At(!1)},[u,Ue]);f(()=>{if(_)return;const e=n=>{n.target.closest('input, textarea, button, select, a, [role="button"], [contenteditable="true"]')||n.key.toLowerCase()==="n"&&(je!=null?Ke(String(je)):In.error("No next episode available"))};return document.addEventListener("keydown",e),()=>{document.removeEventListener("keydown",e)}},[_,je,Ke]);const Sn=e=>{Te(e);try{const s=Pe[e];s&&localStorage.setItem("tvLastAudio",Wt(s))}catch{}const n=Y.current;n&&n.audioTrack!==void 0&&(n.audioTrack=e)},Tn=e=>{de(e);try{if(e===-1)localStorage.setItem("tvSubtitlesEnabled","false");else{localStorage.setItem("tvSubtitlesEnabled","true"),localStorage.setItem("tvSelectedSubtitle",String(e));const i=ee[e];i&&localStorage.setItem("tvLastSubtitle",Wt(i))}}catch{}const n=d.current,s=Y.current;s&&typeof s.subtitleTrack=="number"&&Array.isArray(s.subtitleTracks)&&s.subtitleTracks.length>0&&(s.subtitleTrack=-1),n&&Array.from(n.textTracks).forEach((i,m)=>{i.mode=m===e?"showing":"hidden"})},lt=P(()=>{if(!r)return;const e=d.current,n=_?"":`S${String(u).padStart(2,"0")}E${String(y).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:ve.current})}).catch(()=>{}),fetch("/api/discord/heartbeat",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sessionId:ve.current})}).catch(()=>{})},[r,_,u,y,d]);f(()=>{if(!r)return;lt();const e=window.setInterval(()=>{const n=d.current;(!n||!n.paused)&<()},15e3);return()=>window.clearInterval(e)},[lt,r,d]),f(()=>{if(!r||B||x||Z||X.length===0)return;const e=d.current;if(!e)return;const n=()=>lt();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,B,x,Z,X,lt,d]),f(()=>{const e=ve.current,n=()=>{const i=JSON.stringify({sessionId:e});navigator.sendBeacon?(navigator.sendBeacon("/api/discord/clear",new Blob([i],{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:i,keepalive:!0}).catch(()=>{})},s=()=>n();return window.addEventListener("pagehide",s),window.addEventListener("beforeunload",s),()=>{window.removeEventListener("pagehide",s),window.removeEventListener("beforeunload",s),n()}},[]);const sn=he==="all"?X:X.filter(e=>e.type===he);return f(()=>{if(!r){document.title="TV & Movies - dango";return}document.title=_?`${r.title} - dango`:`${r.title} - Season ${u} Episode ${y} - dango`},[r,_,u,y]),f(()=>{if(!r||_)return;const e=new URLSearchParams(E),n=e.get("s"),s=e.get("e"),i=String(u),m=String(y);n===i&&s===m||(e.set("type",E.get("type")||"tv"),e.set("s",i),e.set("e",m),z(`${window.location.pathname}?${e.toString()}`,{replace:!0}))},[r,_,u,y,E,z]),t("div",{className:Be.playerPageLayout,children:[t("aside",{className:Be.episodeSidebar,children:r?_?t("div",{className:c.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:c.sidebarPosterMeta,children:[t("strong",{children:r.title}),t("span",{children:r.year})]})]}):t(Fn,{episodes:nn,currentEpisode:String(y),watchedEpisodes:tn,onEpisodeClick:Ke,header:kt}):_?t("div",{className:c.statusMsg,children:[t(I,{name:"spinner",className:c.spinner})," Loading..."]}):t(zn,{variant:"sidebar"})}),t("div",{className:Be.playerMain,children:[r&&t("div",{className:c.playerSection,onContextMenu:e=>e.preventDefault(),style:r.adult&&!be?{filter:"blur(14px)",pointerEvents:"none",userSelect:"none"}:void 0,children:[x&&!B&&t("div",{className:c.statusMsg,children:[t(I,{name:"spinner",className:c.spinner})," Loading stream..."]}),B&&Ye?t("iframe",{src:Ye,className:c.videoIframe,allow:"autoplay; fullscreen",allowFullScreen:!0}):!B&&!x&&sn.length>0?t(Nt,{children:[Z&&t("div",{className:`${c.statusMsg} ${c.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:Z}),t("button",{className:c.retryButton,onClick:Tt,children:"Retry"})]}),q.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:"}),q.map(e=>t("button",{onClick:()=>Ft(e),className:c.retryButton,style:{padding:"4px 8px",fontSize:"0.75rem",textTransform:"capitalize",background:Q===e?"var(--accent)":void 0,color:Q===e?"white":void 0},children:e},e))]})]}),t(Vr,{player:T,title:r.title,episodeLabel:_?void 0:`S${u} E${y}`,audioTracks:Pe,selectedAudioTrack:se,onAudioTrackChange:Sn,subtitles:ee,selectedSubtitle:w,onSubtitleChange:Tn,streams:sn,qualityIdx:te,onQualityChange:Ae,onBack:Ct,movyServers:q,selectedMovyServer:Q,onMovyServerSelect:Ft,isMovySource:q.length>0,videoDelayEnabled:xe,onVideoDelayToggle:e=>{Re(e);try{localStorage.setItem("playerVideoDelayEnabled",String(e))}catch{}},videoDelayMs:ke,onVideoDelayChange:Ie,onCalibrateAvSync:H,children:[t("video",{ref:d,autoPlay:st&&!oe,playsInline:!0,disablePictureInPicture:!0,className:`${c.video} ${fe?c.videoHidden:""}`,onTimeUpdate:pn,onEnded:()=>{re||hn()},onPlay:gn,onPause:fn,onLoadedMetadata:bn,onVolumeChange:T.actions.onVolumeChange,onContextMenu:e=>e.preventDefault(),onError:()=>{$("Video failed to load. Try another server or reload."),A(!1)}}),t("canvas",{ref:pt,className:`${c.delayCanvas} ${fe?c.delayCanvasActive:""}`}),fe&&t("div",{ref:ht,className:c.subtitleOverlay}),t(Hn,{isOpen:Pt,ms:ke,onChange:Ie,onApply:bt,onClose:ft,testClipActive:re,onTestClip:Ze})]})]}):Z&&!B?t("div",{className:`${c.statusMsg} ${c.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:Z}),t("button",{className:c.retryButton,onClick:Tt,children:"Retry"})]}),q.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:"}),q.map(e=>t("button",{onClick:()=>Ft(e),className:c.retryButton,style:{padding:"4px 8px",fontSize:"0.75rem",textTransform:"capitalize",background:Q===e?"var(--accent)":void 0,color:Q===e?"white":void 0},children:e},e))]})]}):null]}),r&&t(Un,{showTheater:!1}),kt&&t("div",{className:c.mobileSeasonRow,children:kt}),r&&t("div",{className:c.providerSelectWrap,children:t("label",{className:c.controlLabel,children:["Source",t("select",{value:O,onChange:e=>yn(e.target.value),className:c.select,disabled:J.length===0,children:ct?t("option",{value:"",children:"Loading…"}):J.length===0?t("option",{value:"",children:"No providers available"}):t(Nt,{children:[C.length>0&&t("optgroup",{label:"Direct HLS",children:C.map(e=>t("option",{value:e.id,children:e.label},e.id))}),ut.length>0&&t("optgroup",{label:"Embeds",children:ut.map(e=>t("option",{value:e.id,children:e.label},e.id))})]})})]})}),r&&t("div",{className:Be.playerInfoContainer,children:[t("div",{className:Be.playerInfoHeader,children:[t("div",{className:Be.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:Be.videoTitleSection,children:[t("div",{className:ue.titleContainer,children:[t("h1",{children:r.title}),t("div",{className:c.meta,children:[t("span",{className:c.year,children:r.year}),r.vote_average!=null&&r.vote_average>0&&t("span",{className:c.rating,children:[t(I,{name:"star",size:12}),Number(r.vote_average).toFixed(1)]}),t("span",{className:`${c.typeBadge} ${c[_?"movie":"tv"]}`,children:_?"Movie":"TV Show"})]}),rn.length>0&&t("div",{className:c.genreRow,children:rn.map(e=>t("span",{className:c.genreChip,children:e},e))}),Ot.length>0&&t("div",{className:c.metaRow,children:Ot.map((e,n)=>t("span",{children:[e,n<Ot.length-1?" · ":""]},`${e}-${n}`))})]}),t("div",{className:ue.controls,children:[t("button",{className:`${ue.watchlistBtn} ${ae?ue.inList:""}`,onClick:Kt,disabled:Mt,type:"button",children:[ae?t(I,{name:"check",size:14}):t(I,{name:"plus",size:14}),ae?"In Watchlist":"Add to Watchlist"]}),!_&&t(Nt,{children:[t("button",{className:`${ue.watchlistBtn}`,onClick:()=>Vt!=null&&Ke(String(Vt)),disabled:Vt==null,type:"button",children:[t(I,{name:"chevron-left",size:14}),"Prev EP"]}),t("button",{className:`${ue.watchlistBtn}`,onClick:()=>je!=null&&Ke(String(je)),disabled:je==null,type:"button",children:["Next EP",t(I,{name:"chevron-right",size:14})]}),un&&t("button",{className:`${ue.watchlistBtn}`,onClick:()=>At(!0),type:"button",children:[t(I,{name:"list-ul",size:14}),"Episodes"]})]})]})]})]}),t("div",{className:ue.descriptionSection,children:[t("h3",{children:"Synopsis"}),t(ar,{text:r.overview,emptyText:"No description available."})]}),t("button",{className:ue.detailsToggleBtn,onClick:()=>cn(!yt),type:"button",children:[yt?t(I,{name:"chevron-up"}):t(I,{name:"chevron-down"}),yt?"Hide Details":"Show Details"]}),yt&&t("div",{className:c.detailGrid,children:[r.first_air_date&&t("div",{className:c.detailItem,children:[t("strong",{children:_?"Release Date":"First Air Date"}),t("span",{children:r.first_air_date})]}),r.last_air_date&&t("div",{className:c.detailItem,children:[t("strong",{children:"Last Air Date"}),t("span",{children:r.last_air_date})]}),r.networks&&r.networks.length>0&&t("div",{className:c.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:c.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:c.detailItem,children:[t("strong",{children:"Episode Runtime"}),t("span",{children:[r.episode_run_time[0]," min"]})]}),r.imdb_id&&t("div",{className:c.detailItem,children:[t("strong",{children:"IMDb"}),t("a",{href:`https://www.imdb.com/title/${r.imdb_id}`,target:"_blank",rel:"noopener noreferrer",className:c.imdbLink,children:"View on IMDb"})]})]})]}),!_&&t(Wn,{isOpen:dn,onClose:()=>At(!1),episodes:nn,currentEpisode:String(y),watchedEpisodes:tn,onEpisodeClick:Ke,header:kt}),r?.adult&&!be&&t(Ut,{isOpen:!0,title:"Content Warning",onClose:Ct,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(qe,{variant:"secondary",onClick:Ct,children:"Go Back"}),t(qe,{onClick:Oe,children:"I'm 18+, Continue"})]})]})}),t(Ut,{isOpen:oe,onClose:Xt,title:"Resume Watching",children:t("div",{style:{padding:"1rem",textAlign:"center"},children:[t("p",{children:["You were at ",t("strong",{children:mn(ze)})]}),t("div",{style:{marginTop:"1rem",display:"flex",gap:"10px",justifyContent:"center"},children:[t(qe,{variant:"secondary",onClick:Xt,children:"Start from Beginning"}),t(qe,{onClick:vn,children:"Resume"})]})]})}),t(Ut,{isOpen:on,onClose:()=>at(!1),title:"Finished!",children:t("div",{style:{padding:"1rem",textAlign:"center"},children:[t(I,{name:"check-circle",size:48,style:{color:"var(--accent-lighter)",marginBottom:"0.5rem"}}),t("p",{style:{fontSize:"1.1rem",fontWeight:600},children:ln}),t("p",{style:{color:"var(--text-secondary)"},children:_?"You finished this movie!":"You finished this season!"}),t("div",{style:{marginTop:"1rem",display:"flex",gap:"10px",justifyContent:"center"},children:[t(qe,{variant:"secondary",onClick:()=>at(!1),children:"Close"}),t(qe,{onClick:()=>{at(!1),Ct()},children:"Back to Details"})]})]})}),!r&&t("div",{className:c.statusMsg,children:[t(I,{name:"spinner",className:c.spinner})," Loading..."]})]})]})};export{Xs as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
._fullscreenFlat_oxcpx_1,._fullscreenFlat_oxcpx_1 ._video_oxcpx_2,._fullscreenFlat_oxcpx_1 ._delayCanvas_oxcpx_3,._fullscreenFlat_oxcpx_1 ._subtitleOverlay_oxcpx_4{border-radius:0}@media(max-width:900px)and (orientation:landscape){._fullscreenFlat_oxcpx_1{border-radius:0}}@container (max-width: 26rem){._timeDisplay_oxcpx_15{display:none}._bottomControls_oxcpx_19{padding:.75rem}._leftControls_oxcpx_23,._rightControls_oxcpx_24{gap:.2rem}._controlBtn_oxcpx_28{padding:5px;min-width:2.125rem;min-height:2.125rem}}._video_oxcpx_2{position:absolute;top:0;left:0;width:100%;height:100%;object-fit:contain;display:block;background:#000;border:none}._controlsOverlay_oxcpx_47{position:absolute;inset:0;opacity:1;transition:opacity .4s cubic-bezier(.4,0,.2,1);z-index:50;pointer-events:none;display:flex;flex-direction:column;justify-content:space-between;background:radial-gradient(circle,transparent 20%,rgba(0,0,0,.4) 100%)}._controlsOverlay_oxcpx_47>*{pointer-events:auto}._controlsOverlay_oxcpx_47._hidden_oxcpx_67{opacity:0;pointer-events:none;cursor:none}._topControls_oxcpx_73{position:absolute;top:0;left:0;right:0;display:flex;align-items:center;gap:var(--space-6);background:linear-gradient(to bottom,rgba(0,0,0,.85) 0%,rgba(0,0,0,.45) 60%,transparent 100%);padding:var(--space-8) var(--space-10);transition:transform .4s cubic-bezier(.2,.8,.2,1);z-index:10;pointer-events:auto}._backBtn_oxcpx_93{background:transparent;border:none;color:#ffffffd9;font-size:1.6rem;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all var(--transition-fast);padding:8px;border-radius:50%}._backBtn_oxcpx_93:hover{background:#0f0f1199;color:#fff;transform:scale(1.1)}._videoTitleInfo_oxcpx_113{display:flex;flex-direction:column;gap:.25rem}._animeTitle_oxcpx_119{font-size:1.4rem;font-weight:800;color:#fff;letter-spacing:-.01em;text-shadow:0 2px 4px rgba(0,0,0,.5)}._episodeLabel_oxcpx_127{font-size:.85rem;font-weight:600;color:#ffffffbf;text-shadow:0 2px 4px rgba(0,0,0,.5)}._speedBoostBadge_oxcpx_134{position:absolute;top:1.5rem;left:50%;transform:translate(-50%);display:flex;align-items:center;gap:.7rem;padding:.65rem 1rem;border:1px solid color-mix(in srgb,var(--accent) 45%,transparent);border-radius:var(--radius-md);background:#121216eb;color:#f5f3ff;font-size:.85rem;font-weight:800;letter-spacing:.06em;z-index:11;pointer-events:none}._speedBoostBadge_oxcpx_134 span{line-height:1}._speedBoostBadge_oxcpx_134 svg{display:block;flex-shrink:0}._bottomControls_oxcpx_19{position:absolute;bottom:0;left:0;right:0;background:linear-gradient(to top,rgba(0,0,0,.85) 0%,rgba(0,0,0,.45) 60%,transparent 100%);padding:clamp(1rem,4cqw,2.5rem) clamp(1rem,4cqw,2.5rem) clamp(.75rem,2.5cqw,1.5rem);z-index:10;pointer-events:auto;transition:transform .4s cubic-bezier(.2,.8,.2,1)}._progressBarContainer_oxcpx_180{width:100%;height:20px;display:flex;align-items:center;cursor:pointer;position:relative;touch-action:pan-y}@media(pointer:coarse){._progressBarContainer_oxcpx_180{height:28px}._progressBarContainer_oxcpx_180 ._progressBar_oxcpx_180{height:6px}._progressBarContainer_oxcpx_180 ._thumb_oxcpx_199{opacity:1}}._progressBar_oxcpx_180{width:100%;height:4px;background:#fff3;border-radius:2px;position:relative;transition:height .15s ease}._progressBarContainer_oxcpx_180:hover ._progressBar_oxcpx_180{height:6px}._bufferedBar_oxcpx_217{position:absolute;top:0;left:0;height:100%;background:#ffffff4d;border-radius:2px;pointer-events:none}._watchedBar_oxcpx_227{position:absolute;top:0;left:0;height:100%;background:var(--accent);border-radius:2px;pointer-events:none}._thumb_oxcpx_199{position:absolute;top:50%;width:12px;height:12px;background:#fff;border-radius:50%;transform:translate(-50%,-50%);box-shadow:0 0 4px #0006;pointer-events:none;opacity:0;transition:opacity .15s ease}._progressBarContainer_oxcpx_180:hover ._thumb_oxcpx_199,._progressBarContainer_oxcpx_180._scrubbing_oxcpx_252 ._thumb_oxcpx_199{opacity:1}._timeBubble_oxcpx_256{position:absolute;bottom:24px;background:#000000d9;color:#fff;padding:4px 8px;border-radius:4px;font-size:.8rem;font-weight:500;transform:translate(-50%);pointer-events:none;white-space:nowrap}._bottomControlsRow_oxcpx_270{display:flex;align-items:center;justify-content:space-between;gap:.75rem;margin-top:8px}._leftControls_oxcpx_23{display:flex;align-items:center;gap:1rem;gap:clamp(.5rem,2.5cqw,1rem);min-width:0}._rightControls_oxcpx_24{display:flex;align-items:center;gap:.75rem;gap:clamp(.5rem,2cqw,.75rem)}._controlBtn_oxcpx_28{background:transparent;border:none;color:#ffffffd9;font-size:1.1rem;cursor:pointer;display:flex;align-items:center;justify-content:center;padding:8px;border-radius:4px;transition:all var(--transition-fast);min-width:2.125rem;min-height:2.125rem;flex:0 0 auto}@media(pointer:coarse){._controlBtn_oxcpx_28{padding:10px;min-width:2.75rem;min-height:2.75rem}}._controlBtn_oxcpx_28:hover{color:#fff;background:#ffffff1a}._controlBtn_oxcpx_28._active_oxcpx_323{color:var(--accent)}._volumeContainer_oxcpx_327{display:flex;align-items:center;position:relative}._volumeSlider_oxcpx_333{width:0;opacity:0;transform:scaleX(0);transform-origin:left;transition:all .3s cubic-bezier(.4,0,.2,1);cursor:pointer;margin-left:8px;-webkit-appearance:none;appearance:none;background:transparent;height:20px}._volumeContainer_oxcpx_327:hover ._volumeSlider_oxcpx_333,._volumeSlider_oxcpx_333:focus{width:80px;opacity:1;transform:scaleX(1)}._volumeSlider_oxcpx_333::-webkit-slider-runnable-track{width:100%;height:4px;background:linear-gradient(to right,var(--accent) 0%,var(--accent) var(--volume-percent, 0%),rgba(255,255,255,.2) var(--volume-percent, 0%),rgba(255,255,255,.2) 100%);border-radius:4px}._volumeSlider_oxcpx_333::-moz-range-track{width:100%;height:4px;background:#fff3;border-radius:4px}._volumeSlider_oxcpx_333::-moz-range-progress{height:4px;background:var(--accent);border-radius:4px}._volumeSlider_oxcpx_333::-webkit-slider-thumb{-webkit-appearance:none;height:12px;width:12px;border-radius:50%;background:#fff;margin-top:-4px;box-shadow:0 0 5px #00000080}._timeDisplay_oxcpx_15{color:#fffc;font-size:.85rem;font-weight:500;font-variant-numeric:tabular-nums;min-width:100px}._settingsPanel_oxcpx_398{position:absolute;bottom:clamp(6rem,15vh,8rem);right:clamp(1rem,3vw,2rem);background:#141418f2;border:1px solid var(--border-secondary);border-radius:var(--radius-md);width:max-content;min-width:12rem;max-width:min(19rem,calc(100vw - 1.5rem));font-size:.85rem;z-index:60;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);box-shadow:0 8px 32px #00000080;display:flex;flex-direction:column;overflow:hidden}._settingsHeader_oxcpx_417{display:flex;align-items:center;padding:.55rem .75rem;border-bottom:1px solid var(--border-secondary);gap:.625rem}._settingsBackBtn_oxcpx_425{background:transparent;border:none;color:#ffffffd9;cursor:pointer;display:flex;align-items:center;justify-content:center;padding:4px;border-radius:4px;transition:all var(--transition-fast)}._settingsBackBtn_oxcpx_425:hover{background:#ffffff1a;color:#fff}._settingsTitle_oxcpx_443{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}._settingsContent_oxcpx_454{overflow-y:auto;padding:.375rem;display:flex;flex-direction:column;gap:.125rem;max-height:min(56vh,22rem)}._currentValue_oxcpx_463{color:var(--text-tertiary);font-size:.8rem;font-weight:500}._settingsLabel_oxcpx_469{padding:var(--space-2) var(--space-4);font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--text-secondary)}._menuItem_oxcpx_478{display:flex;align-items:center;justify-content:space-between;gap:.75rem;width:100%;min-height:2rem;padding:.5rem .75rem;background:transparent;border:none;color:var(--text-primary);font-size:.85rem;cursor:pointer;border-radius:var(--radius-sm);transition:background-color var(--transition-fast);text-align:left;white-space:nowrap}._menuItem_oxcpx_478:hover{background:var(--bg-tertiary)}._menuItem_oxcpx_478._active_oxcpx_323{background:var(--bg-tertiary);color:var(--accent)}._currentValue_oxcpx_463{color:var(--text-secondary);font-size:.85rem}._menuNote_oxcpx_511{padding:.5rem .75rem;font-size:.7rem;line-height:1.5;color:var(--text-tertiary);white-space:normal;overflow-wrap:break-word}._spin_oxcpx_520{animation:_spin_oxcpx_520 1s linear infinite}@keyframes _spin_oxcpx_520{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@media(pointer:coarse){._settingsPanel_oxcpx_398{font-size:.9rem;bottom:calc(env(safe-area-inset-bottom,0px) + 7rem);right:max(.75rem,env(safe-area-inset-right,0px))}._menuItem_oxcpx_478{min-height:2.75rem}._settingsContent_oxcpx_454{max-height:52vh}}@media(max-width:480px){._settingsPanel_oxcpx_398{min-width:9rem;max-width:calc(100vw - 2rem);font-size:.75rem;bottom:calc(env(safe-area-inset-bottom,0px) + 6rem)}._settingsHeader_oxcpx_417{padding:.4rem .625rem}._settingsTitle_oxcpx_443{font-size:.64rem}._menuItem_oxcpx_478{min-height:2.25rem;padding:.45rem .625rem;font-size:.75rem;gap:.5rem}._settingsContent_oxcpx_454{max-height:min(40vh,15rem)}}@media(max-height:500px)and (orientation:landscape){._settingsPanel_oxcpx_398{bottom:7.25rem;right:2rem;min-width:10rem;max-width:min(15rem,calc(100vw - 1.5rem));font-size:.8rem}._menuItem_oxcpx_478{min-height:2.5rem;font-size:.8rem}._settingsContent_oxcpx_454{max-height:50vh;overflow-y:auto}}._page_263ma_1{max-width:1200px;margin:0 auto;padding:1.5rem}._header_263ma_7{margin-bottom:1.5rem}._pageTitle_263ma_11{font-size:1.75rem;font-weight:700;margin:0 0 1rem;display:flex;align-items:center;gap:.5rem;color:var(--text-primary)}._searchForm_263ma_21{display:flex;gap:.5rem;max-width:600px}._searchInput_263ma_27{flex:1;padding:.6rem 1rem;border-radius:8px;border:1px solid var(--border-primary);background:var(--bg-elevated);color:var(--text-primary);font-size:.95rem;outline:none}._searchInput_263ma_27:focus{border-color:var(--accent)}._searchBtn_263ma_42{padding:.6rem 1rem;border-radius:8px;border:none;background:var(--accent);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center}._searchBtn_263ma_42:hover{opacity:.9}._suggestions_263ma_58{display:flex;flex-wrap:wrap;gap:.5rem;margin-bottom:1.5rem}._suggestionPill_263ma_65{padding:.4rem .8rem;border-radius:20px;border:1px solid var(--border-primary);background:var(--bg-elevated);color:var(--text-secondary);cursor:pointer;font-size:.85rem;transition:all .15s ease}._suggestionPill_263ma_65:hover{border-color:var(--accent);color:var(--text-primary)}._statusMsg_263ma_81{padding:1rem;text-align:center;color:var(--text-secondary)}._statusMsg_263ma_81._error_263ma_87{color:#f87171}._statusMsg_263ma_81._textOnly_263ma_91{background:none;padding:.5rem}._spinner_263ma_96{animation:_spin_263ma_96 1s linear infinite;margin-right:.5rem}@keyframes _spin_263ma_96{0%{transform:rotate(0)}to{transform:rotate(360deg)}}._grid_263ma_110{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:1rem}._skeletonCard_263ma_116{border-radius:8px;overflow:hidden}._skeletonThumb_263ma_121{aspect-ratio:2 / 3;background:var(--bg-secondary);border-radius:8px}._skeletonLine_263ma_127{height:12px;background:var(--bg-secondary);border-radius:4px;margin-top:.5rem}._shimmer_263ma_134{background:linear-gradient(90deg,var(--bg-secondary) 25%,var(--bg-elevated) 50%,var(--bg-secondary) 75%);background-size:200% 100%;animation:_shimmer_263ma_134 1.5s infinite}@keyframes _shimmer_263ma_134{0%{background-position:200% 0}to{background-position:-200% 0}}._backBtn_263ma_154{display:inline-flex;align-items:center;gap:.4rem;padding:.4rem .8rem;border-radius:6px;border:1px solid var(--border-primary);background:var(--bg-elevated);color:var(--text-primary);cursor:pointer;font-size:.85rem;margin-bottom:1rem}._backBtn_263ma_154:hover{border-color:var(--accent)}._meta_263ma_172{display:flex;align-items:center;gap:.75rem;margin:.5rem 0;flex-wrap:wrap}._headerActions_263ma_180{display:flex;gap:.5rem;margin:.75rem 0 0;flex-wrap:wrap}._watchlistBtn_263ma_187{display:inline-flex;align-items:center;gap:.4rem;padding:.5rem 1rem;border-radius:6px;border:1px solid var(--border-primary);background:var(--bg-elevated);color:var(--text-primary);cursor:pointer;font-size:.85rem;font-weight:600}._watchlistBtn_263ma_187:hover:not(:disabled){border-color:var(--accent)}._watchlistBtn_263ma_187._active_263ma_205{border-color:var(--color-success);color:var(--color-success)}._watchlistBtn_263ma_187:disabled{opacity:.6;cursor:default}._year_263ma_215{color:var(--text-secondary);font-size:.9rem}._rating_263ma_220{display:inline-flex;align-items:center;gap:4px;color:var(--accent-lighter);font-weight:600;font-size:.9rem}._typeBadge_263ma_229{padding:2px 10px;border-radius:4px;font-size:.75rem;font-weight:600;text-transform:uppercase}._typeBadge_263ma_229._tv_263ma_237{background:color-mix(in srgb,var(--accent) 20%,transparent);color:var(--accent)}._typeBadge_263ma_229._movie_263ma_242{background:color-mix(in srgb,var(--accent-lighter) 20%,transparent);color:var(--accent-lighter)}._typeBadge_263ma_229._tvSeries_263ma_247,._typeBadge_263ma_229._tvMiniSeries_263ma_252{background:color-mix(in srgb,var(--accent) 20%,transparent);color:var(--accent)}._overview_263ma_257{color:var(--text-secondary);line-height:1.6;margin:.5rem 0 0;max-width:800px}._controls_263ma_264{display:flex;flex-wrap:wrap;gap:1rem;margin:1rem 0;align-items:flex-end}._controlLabel_263ma_272{display:flex;flex-direction:column;gap:.3rem;font-size:.8rem;color:var(--text-secondary);text-transform:uppercase;letter-spacing:.05em}._select_263ma_282{padding:.5rem .75rem;border-radius:6px;border:1px solid var(--border-primary);background:var(--bg-elevated);color:var(--text-primary);font-size:.9rem;cursor:pointer;min-width:160px}._playerSection_263ma_293{margin:1.5rem 0;border-radius:0;overflow:hidden;overflow:clip;isolation:isolate;background:#000;position:relative}._video_263ma_297{position:absolute;top:0;left:0;width:100%;height:100%;object-fit:contain;display:block;background:#000;border:none;border-radius:inherit}._videoHidden_263ma_319{opacity:0;pointer-events:none}._delayCanvas_263ma_324{position:absolute;top:0;left:0;width:100%;height:100%;object-fit:contain;opacity:0;pointer-events:none;z-index:2;border-radius:inherit}._delayCanvasActive_263ma_337{opacity:1}._subtitleOverlay_263ma_341{position:absolute;top:0;left:0;width:100%;height:100%;z-index:3;pointer-events:none;overflow:hidden;border-radius:inherit}@media(max-width:900px)and (orientation:landscape){._playerSection_263ma_293{margin:0;border-radius:0}}._videoIframe_263ma_360{width:100%;aspect-ratio:16 / 9;min-height:400px;border:none;background:#000}._retryButton_263ma_368{margin-left:8px;padding:4px 10px;border-radius:4px;border:1px solid var(--border-primary);background:var(--bg-elevated);color:var(--text-primary);cursor:pointer;font-size:.8rem}._retryButton_263ma_368:hover{border-color:var(--accent)}._sidebarSeason_263ma_383{display:flex;flex-direction:column;gap:.4rem;font-size:.75rem;font-weight:700;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.1em;margin-bottom:var(--space-4)}._sidebarSeason_263ma_383 ._select_263ma_282{width:100%}._mobileSeasonRow_263ma_399{display:none}@media(max-width:768px){._mobileSeasonRow_263ma_399{display:block}._mobileSeasonRow_263ma_399 ._sidebarSeason_263ma_383{margin-bottom:0}}._sidebarPosterCard_263ma_413{padding:1rem;display:flex;flex-direction:column;gap:.75rem}._sidebarPosterCard_263ma_413 img{width:100%;border-radius:var(--radius-md);aspect-ratio:2 / 3;object-fit:cover;background:#ffffff0f}._sidebarPosterMeta_263ma_428{display:flex;flex-direction:column;gap:.25rem}._sidebarPosterMeta_263ma_428 strong{color:var(--text-primary);font-size:.95rem;line-height:1.3}._sidebarPosterMeta_263ma_428 span{color:var(--text-secondary);font-size:.85rem}._providerSelectWrap_263ma_445{display:flex;align-items:flex-end;gap:1rem;flex-wrap:wrap;min-width:0}._providerSelectWrap_263ma_445 ._backBtn_263ma_154{margin-bottom:0}._genreRow_263ma_457{display:flex;flex-wrap:wrap;gap:.4rem;margin-top:.6rem}._genreChip_263ma_464{padding:.2rem .7rem;border-radius:20px;border:1px solid var(--glass-border);background:#ffffff0d;color:var(--text-secondary);font-size:.78rem;font-weight:600}._metaRow_263ma_474{display:flex;flex-wrap:wrap;gap:.35rem;margin-top:.6rem;color:var(--text-secondary);font-size:.9rem}._detailGrid_263ma_483{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:.75rem;margin-top:1rem}._detailItem_263ma_490{display:flex;flex-direction:column;gap:.2rem;padding:.75rem 1rem;border-radius:var(--radius-md);border:1px solid var(--glass-border);background:#ffffff08}._detailItem_263ma_490 strong{font-size:.75rem;text-transform:uppercase;letter-spacing:.06em;color:var(--text-tertiary)}._detailItem_263ma_490 span{color:var(--text-primary);font-size:.9rem}._imdbLink_263ma_512{color:var(--accent-light);font-size:.9rem;text-decoration:none}._imdbLink_263ma_512:hover{text-decoration:underline}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
._container_198yg_1{max-width:var(--max-width);margin:0 auto;padding:0;min-height:100vh;background:var(--bg-main);overflow-x:hidden}._heroSection_198yg_11{position:relative;width:100%;padding-bottom:var(--space-12)}._bannerContainer_198yg_17{position:absolute;top:0;left:0;right:0;height:500px;overflow:hidden;z-index:0}._banner_198yg_17{width:100%;height:100%;background-size:cover;background-position:center 20%;filter:brightness(.3) saturate(1.1);transform:scale(1.05);transition:transform var(--transition-slow)}._bannerOverlay_198yg_37{position:absolute;inset:0;background:linear-gradient(to bottom,rgba(5,5,5,.4) 0%,rgba(5,5,5,.7) 40%,var(--bg-main) 100%);box-shadow:inset 0 -100px 100px -20px var(--bg-main)}._heroContent_198yg_49{position:relative;z-index:1;display:grid;grid-template-columns:320px 1fr;gap:var(--space-10);max-width:1200px;margin:0 auto;padding:var(--space-16) var(--space-6) 0;align-items:flex-start}._posterContainer_198yg_62{position:sticky;top:120px;border-radius:var(--radius-lg);overflow:hidden;box-shadow:0 20px 50px #00000080;transform:translateY(0);animation:_floatIn_198yg_1 .8s var(--ease-spring);border:1px solid var(--border-secondary)}._poster_198yg_62{width:100%;display:block;object-fit:cover;aspect-ratio:2 / 3;transition:transform var(--transition-base)}._posterContainer_198yg_62:hover ._poster_198yg_62{transform:scale(1.05)}._infoGlass_198yg_86{background:var(--glass-bg);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);border:1px solid var(--glass-border);border-radius:var(--radius-xl);padding:var(--space-8);box-shadow:var(--glass-shadow);animation:_slideUpIn_198yg_1 .8s var(--ease-smooth);display:flex;flex-direction:column;gap:var(--space-8)}._title_198yg_100{font-size:var(--font-size-2xl);font-weight:800;color:var(--text-primary);margin:0;line-height:1.2;letter-spacing:-.02em}._quickMeta_198yg_110{display:flex;align-items:center;gap:var(--space-5);margin-top:var(--space-2);flex-wrap:wrap}._metaItem_198yg_118{display:flex;align-items:center;gap:var(--space-1);font-size:var(--font-size-sm);color:var(--text-secondary)}._iconStar_198yg_126{color:var(--accent-lighter)}._iconTv_198yg_130{color:var(--accent)}._iconType_198yg_134{color:var(--text-muted)}._genres_198yg_139{display:flex;flex-wrap:wrap;gap:var(--space-2);margin-top:var(--space-2)}._genre_198yg_139{background:var(--bg-tertiary);padding:4px 12px;border-radius:var(--radius-full);font-size:var(--font-size-xs);color:var(--text-secondary);border:1px solid var(--border-primary)}._metaRow_198yg_156{display:flex;align-items:center;gap:var(--space-3);font-size:var(--font-size-sm);color:var(--text-secondary)}._metaValue_198yg_164{color:var(--text-primary)}._metaDivider_198yg_168{color:var(--text-muted)}._synopsisSection_198yg_173{display:flex;flex-direction:column;gap:var(--space-3)}._sectionTitleSmall_198yg_179{font-size:var(--font-size-sm);font-weight:700;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.05em;margin:0}._synopsis_198yg_173{font-size:var(--font-size-base);color:var(--text-secondary);line-height:1.6;margin:0}._actions_198yg_196{display:flex;gap:var(--space-3);flex-wrap:wrap}._watchBtn_198yg_202{flex:1;min-width:180px;height:48px;background-color:var(--accent);color:var(--accent-text);border:none;border-radius:var(--radius-md);font-weight:700;display:flex;align-items:center;justify-content:center;gap:var(--space-2);cursor:pointer;transition:all .2s;font-size:var(--font-size-base);font-family:inherit}._watchBtn_198yg_202:hover{background-color:var(--accent-dark);transform:translateY(-1px)}._watchlistBtn_198yg_226{flex:1;min-width:160px;height:48px;display:flex;align-items:center;justify-content:center;gap:var(--space-3);background:#ffffff0d;color:var(--text-primary);border:1px solid var(--border-secondary);border-radius:var(--radius-md);font-weight:600;cursor:pointer;transition:all var(--transition-base);font-size:var(--font-size-sm);font-family:inherit}._watchlistBtn_198yg_226:hover{background:#ffffff1a;border-color:var(--text-secondary)}._watchlistBtn_198yg_226._active_198yg_250{background:color-mix(in srgb,var(--color-success) 10%,transparent);border-color:var(--color-success);color:var(--color-success)}._seasonPickerLabel_198yg_256{display:flex;flex-direction:column;gap:var(--space-2);font-size:var(--font-size-sm);font-weight:700;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.05em}._seasonSelect_198yg_267{min-width:240px;max-width:100%;height:44px;padding:0 var(--space-4);border-radius:var(--radius-md);border:1px solid var(--border-secondary);background:var(--bg-elevated);color:var(--text-primary);font-size:var(--font-size-base);font-family:inherit;cursor:pointer}._seasonSelect_198yg_267:focus{outline:none;border-color:var(--accent)}._detailsToggleBtn_198yg_286{display:flex;align-items:center;gap:var(--space-2);background:none;border:none;color:var(--text-secondary);cursor:pointer;font-size:var(--font-size-sm);font-weight:600;padding:var(--space-2) 0;font-family:inherit}._detailsToggleBtn_198yg_286:hover{color:var(--accent)}._expandedContent_198yg_304{margin-top:var(--space-4);animation:_slideUpIn_198yg_1 .3s var(--ease-smooth)}._detailGrid_198yg_309{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:var(--space-4)}._detailItem_198yg_315{display:flex;flex-direction:column;gap:var(--space-1)}._detailItem_198yg_315 strong{font-size:var(--font-size-xs);color:var(--text-muted);text-transform:uppercase;letter-spacing:.05em}._detailItem_198yg_315 span{font-size:var(--font-size-sm);color:var(--text-primary)}._imdbLink_198yg_333{color:var(--accent);text-decoration:none}._imdbLink_198yg_333:hover{text-decoration:underline}._heroSkeleton_198yg_343{position:relative}._skeletonBanner_198yg_347{width:100%;height:500px;background:var(--bg-tertiary);animation:_pulse_198yg_1 1.5s ease-in-out infinite}._skeletonContent_198yg_354{position:relative;z-index:1;display:grid;grid-template-columns:320px 1fr;gap:var(--space-10);max-width:1200px;margin:0 auto;padding:var(--space-16) var(--space-6) 0}._skeletonPoster_198yg_365{width:100%;aspect-ratio:2 / 3;background:var(--bg-tertiary);border-radius:var(--radius-lg);animation:_pulse_198yg_1 1.5s ease-in-out infinite}._skeletonInfo_198yg_373{display:flex;flex-direction:column;gap:var(--space-6);padding-top:var(--space-8)}._skeletonTitle_198yg_380{width:60%;height:32px;background:var(--bg-tertiary);border-radius:var(--radius-sm);animation:_pulse_198yg_1 1.5s ease-in-out infinite}._skeletonMeta_198yg_388{width:40%;height:20px;background:var(--bg-tertiary);border-radius:var(--radius-sm);animation:_pulse_198yg_1 1.5s ease-in-out infinite}._skeletonDesc_198yg_396{width:100%;height:80px;background:var(--bg-tertiary);border-radius:var(--radius-sm);animation:_pulse_198yg_1 1.5s ease-in-out infinite}._skeletonActions_198yg_404{width:300px;height:48px;background:var(--bg-tertiary);border-radius:var(--radius-md);animation:_pulse_198yg_1 1.5s ease-in-out infinite}._errorState_198yg_413{display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:60vh;gap:var(--space-4);color:var(--text-secondary);text-align:center}._errorState_198yg_413 h2{margin:0;color:var(--text-primary)}._errorState_198yg_413 p{margin:0}._matureOverlay_198yg_434{position:fixed;inset:0;z-index:100;display:flex;align-items:center;justify-content:center;background:#000c}._matureContent_198yg_444{display:flex;flex-direction:column;align-items:center;gap:var(--space-4);color:var(--text-primary);text-align:center;padding:var(--space-8)}._matureContent_198yg_444 h2{margin:0}._matureContent_198yg_444 p{margin:0;color:var(--text-secondary)}@keyframes _floatIn_198yg_1{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}@keyframes _slideUpIn_198yg_1{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}@keyframes _pulse_198yg_1{0%,to{opacity:.6}50%{opacity:.3}}@media(max-width:900px){._heroContent_198yg_49{grid-template-columns:1fr;padding:var(--space-8) var(--space-4) 0;gap:var(--space-6)}._posterContainer_198yg_62{position:static;max-width:200px;margin:0 auto}._infoGlass_198yg_86{padding:var(--space-6)}._title_198yg_100{font-size:var(--font-size-xl)}._skeletonContent_198yg_354{grid-template-columns:1fr;padding:var(--space-8) var(--space-4) 0}._skeletonPoster_198yg_365{max-width:200px;margin:0 auto}}
|
|
@@ -0,0 +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-IZgh1beL.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-Cwxgy_Bg.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};
|
|
@@ -0,0 +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-Cwxgy_Bg.js";import{p as s,a as S}from"./MediaCard-Be1ST9oj.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};
|
|
@@ -0,0 +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-D37MfTHA.js";import{S as se}from"./SkeletonGrid-CtHKKMLj.js";import{u as le,Q as ie,B as _}from"./index-IZgh1beL.js";import{E as oe}from"./ErrorMessage-z4f4WGgP.js";import{s as t}from"./Search.module-CMEai-B-.js";import"./MediaCard-Be1ST9oj.js";import"./vendor-ui-CUDCvRS_.js";import"./useIsMobile-Dm_b6Ob3.js";import"./TvPopup-YTI7dEbJ.js";import"./useTvLibrary-Cwxgy_Bg.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 $,d as m,h as b,T as V,u as l}from"./vendor-core-8R2fFbyN.js";import{M as F}from"./MediaCard-Be1ST9oj.js";import{L as U}from"./LibraryListPage-CCiee-Ot.js";import{R as x}from"./ResetProgressModal-CR_ovLAu.js";import{T as N}from"./TvPopup-YTI7dEbJ.js";import{e as f}from"./index-IZgh1beL.js";import{k as _,u as K,a as O,b as Q,l as Y,m as q,o as z,p as G,t as R,i as S,T as y}from"./useTvLibrary-Cwxgy_Bg.js";import"./vendor-ui-CUDCvRS_.js";import"./vendor-icons-CDMuNDeL.js";import"./useIsMobile-Dm_b6Ob3.js";import"./SkeletonGrid-CtHKKMLj.js";import"./ErrorMessage-z4f4WGgP.js";import"./Watchlist.module-XGtVQr1d.js";import"./vendor-query-BXRECSI6.js";const Z=["All","Continue Watching",...y],L=24;function ne(){const{filter:d="All"}=$(),[v,T]=m(1),[o,p]=m(null),[g,c]=m(!1);b(()=>{document.title="TV Watchlist - dango"},[]),b(()=>{T(1)},[d]);const t=d==="Continue Watching",r=_(t?"All":d,v,L),i=K(100),h=O(),P=Q(),I=Y(),k=q(),w=z(),C=G(),E=V(()=>t?(i.data?.data??[]).map(e=>{const a=e.currentTime??0,s=e.duration??0,n=e.season??e.lastSeason??1,u=e.episode??e.lastEpisode??1;return{key:e.id,libId:e.id,tmdbId:e.tmdbId,mediaType:e.mediaType,title:e.title,poster:e.poster||"",year:e.year,adult:S({adult:e.adult===1}),status:e.status,badge:`S${n} E${u}`,progressPercent:s>0?a/s*100:0,progressLabel:s>0?`S${n} E${u} · ${f(a)} / ${f(s)}`:`S${n} E${u}`,watchTarget:R(e.mediaType,e.tmdbId,n,u)}}):(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:S({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:R(e.mediaType,e.tmdbId,e.lastSeason??void 0,e.lastEpisode??void 0)})),[t,i.data,r.data]),B=t?i.data?.total??0:r.data?.total??0,W=t?i.isLoading:r.isLoading,A=t?i.error:r.error,M=()=>{o&&(P.mutate({mediaId:o.libId}),g&&h.mutate(o.libId),p(null),c(!1))};return l(U,{headerTitle:"My TV Watchlist",headerSubtitle:"Track and manage your movies and shows",filters:Z,filterBy:d,filterBasePath:"/tv-watchlist",continueFilter:"Continue Watching",statusOptions:[...y],entries:E,total:B,isLoading:W,error:A,page:v,pageSize:L,onPageChange:T,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)=>k.mutate({ids:e,status:a}),onBulkRemove:e=>{t?C.mutate(e):w.mutate(e)},onStatusChange:(e,a)=>I.mutate({id:e,status:a}),onRemoveItem:e=>h.mutate(e),renderCard:e=>l(F,{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:t,metaRow:e.year?l("span",{style:{opacity:.75},children:e.year}):void 0,onRemove:t?()=>p(e):void 0,renderPopup:(a,s)=>l(N,{item:{id:e.tmdbId??0,title:e.title||"",year:e.year||"",type:e.mediaType||"tv",image:e.poster||""},anchorRect:a,onMouseEnter:s.onMouseEnter,onMouseLeave:s.onMouseLeave,onRequestClose:s.close})}),modals:l(x,{isOpen:!!o,itemName:o?.title,progressKind:"watch",listLabel:"my TV watchlist",alsoRemove:g,onAlsoRemoveChange:c,onClose:()=>{p(null),c(!1)},onConfirm:M})})}export{ne as default};
|