@serifpersia/dango 3.3.9 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. package/README.md +1 -1
  2. package/client/dist/assets/{AnimeCard-URCiiy5W.js → AnimeCard-CJy1SXH3.js} +1 -1
  3. package/client/dist/assets/{AnimeInfo-e3z3er9t.js → AnimeInfo-BoXlVvZ-.js} +1 -1
  4. package/client/dist/assets/{AnimeInfoPage-B7Djlmy_.js → AnimeInfoPage-BxbA_7AV.js} +2 -2
  5. package/client/dist/assets/Asmr--Zc8G9zv.js +2 -0
  6. package/client/dist/assets/AsmrResetProgressModal-CKYm-8cp.js +1 -0
  7. package/client/dist/assets/AvSyncCalibrator-3yjZS7s6.js +10 -0
  8. package/client/dist/assets/Home-rrhOGQcg.js +1 -0
  9. package/client/dist/assets/Insights-Bay90Yeg.js +1 -0
  10. package/client/dist/assets/{LibraryListPage-B0qWqhb_.js → LibraryListPage-HzuDavbb.js} +1 -1
  11. package/client/dist/assets/{ListeningList-CSqD8j1C.js → ListeningList-DYcQnnsG.js} +1 -1
  12. package/client/dist/assets/{Manga-Cg2YuObF.js → Manga-D8CT9aO0.js} +1 -1
  13. package/client/dist/assets/{MangaInfoPage-DcArhEsy.js → MangaInfoPage-DGK6CYp1.js} +1 -1
  14. package/client/dist/assets/MangaReadPage-B9XoDKF9.js +1 -0
  15. package/client/dist/assets/{MangaResetProgressModal-D_yT3d1v.js → MangaResetProgressModal-QjZyIAjl.js} +1 -1
  16. package/client/dist/assets/Mature-CHt_-Hz5.js +1 -0
  17. package/client/dist/assets/MediaCard-B5584Cq9.js +1 -0
  18. package/client/dist/assets/Music-HeLrEZ2d.js +1 -0
  19. package/client/dist/assets/OptionListMenu-CJ90CdwI.js +1 -0
  20. package/client/dist/assets/Player-BYtEax_z.js +56 -0
  21. package/client/dist/assets/PlayerSettings-4-cUAY4B.js +1 -0
  22. package/client/dist/assets/QueueOptionsButton-Ba0dg_82.js +1 -0
  23. package/client/dist/assets/{QueueRail-B7f1-e6i.js → QueueRail-O7f4RqjB.js} +1 -1
  24. package/client/dist/assets/Radio-DPZxQnyD.js +1 -0
  25. package/client/dist/assets/{ReadingList-BaIem8H1.js → ReadingList-n6rr8ygy.js} +1 -1
  26. package/client/dist/assets/{ResetProgressModal-DES5Y-Fl.js → ResetProgressModal-CcStlbhP.js} +1 -1
  27. package/client/dist/assets/Search-C2wrWOdy.js +1 -0
  28. package/client/dist/assets/Settings-CluUYs8U.js +21 -0
  29. package/client/dist/assets/{SkeletonGrid-BxfgjP4i.js → SkeletonGrid-CLEPY9nP.js} +1 -1
  30. package/client/dist/assets/Trackers-CTGPxs0V.js +2 -0
  31. package/client/dist/assets/Tv-BwHlDdi8.js +4 -0
  32. package/client/dist/assets/Tv-ZEA45gXK.css +1 -0
  33. package/client/dist/assets/TvInfo-CXnrLekr.js +1 -0
  34. package/client/dist/assets/TvPopup-BekfiNcX.js +1 -0
  35. package/client/dist/assets/{TvSearch-BWDwWnHe.js → TvSearch-DuqR-z3v.js} +1 -1
  36. package/client/dist/assets/{TvWatchlist-D3n5_4MI.js → TvWatchlist-CBvgFrA0.js} +1 -1
  37. package/client/dist/assets/Watchlist-mj8mTOam.js +1 -0
  38. package/client/dist/assets/{hls-BO_L1WoN.js → hls-Boje3IOE.js} +1 -1
  39. package/client/dist/assets/index-BXwhFWB_.js +178 -0
  40. package/client/dist/assets/useAnimeInfoData-DJ7A4B4T.js +1 -0
  41. package/client/dist/assets/useAsmr-DIwIsJXF.js +1 -0
  42. package/client/dist/assets/{useAsmrPopup-D_o9-QlR.js → useAsmrPopup-e4zNN9ig.js} +1 -1
  43. package/client/dist/assets/useMangaLibrary-C9Lci5N4.js +1 -0
  44. package/client/dist/assets/{useMangaPopup-TFzkC-tG.js → useMangaPopup-B8nnpvyi.js} +1 -1
  45. package/client/dist/assets/useProviders-B5Qr4I1y.js +1 -0
  46. package/client/dist/assets/useTv-Dm8MCYlL.js +1 -0
  47. package/client/dist/assets/useTvLibrary-B7jEk2Q7.js +1 -0
  48. package/client/dist/assets/{vendor-query-BXRECSI6.js → vendor-query-BUTye89G.js} +1 -1
  49. package/client/dist/index.html +2 -2
  50. package/orchestrator.js +1 -2
  51. package/package.json +2 -6
  52. package/server/dist/app-auth.js +9 -29
  53. package/server/dist/app-hono.js +621 -0
  54. package/server/dist/config.js +0 -1
  55. package/server/dist/db/drizzle.js +32 -0
  56. package/server/dist/db/schema-anime.js +64 -0
  57. package/server/dist/db/schema-asmr.js +25 -0
  58. package/server/dist/db/schema-manga.js +31 -0
  59. package/server/dist/db/schema-tv.js +33 -0
  60. package/server/dist/db.js +75 -4
  61. package/server/dist/discord-gateway.js +1 -1
  62. package/server/dist/google.js +0 -7
  63. package/server/dist/hono/asmr.js +1 -0
  64. package/server/dist/hono/auth.js +56 -0
  65. package/server/dist/hono/music.js +419 -0
  66. package/server/dist/{controllers/proxy.controller.js → hono/proxy.js} +390 -394
  67. package/server/dist/hono/tv.js +197 -0
  68. package/server/dist/hono/watchlist.js +733 -0
  69. package/server/dist/lib/anilist.js +3 -3
  70. package/server/dist/lib/insights.js +185 -0
  71. package/server/dist/lib/ipc.js +1 -2
  72. package/server/dist/lib/kitsu.js +1 -28
  73. package/server/dist/lib/mal-import.js +291 -0
  74. package/server/dist/lib/migration.js +20 -34
  75. package/server/dist/lib/offline-db.js +36 -36
  76. package/server/dist/lib/tracker/manga-sync.service.js +21 -21
  77. package/server/dist/lib/tracker/sync.service.js +20 -20
  78. package/server/dist/lib/translate.js +79 -0
  79. package/server/dist/lib/ytmusic.js +0 -2
  80. package/server/dist/providers/title-matching.js +0 -1
  81. package/server/dist/repositories/asmr.repository.js +90 -87
  82. package/server/dist/repositories/insights.repository.js +24 -13
  83. package/server/dist/repositories/library.repository.js +33 -93
  84. package/server/dist/repositories/manga.repository.js +108 -116
  85. package/server/dist/repositories/notifications.repository.js +50 -31
  86. package/server/dist/repositories/queue.repository.js +36 -25
  87. package/server/dist/repositories/settings.repository.js +18 -8
  88. package/server/dist/repositories/shows-meta.repository.js +54 -41
  89. package/server/dist/repositories/temp-show-ids.repository.js +43 -31
  90. package/server/dist/repositories/tv.repository.js +98 -115
  91. package/server/dist/repositories/watched-episodes.repository.js +52 -20
  92. package/server/dist/repositories/watchlist.repository.js +36 -48
  93. package/server/dist/server.js +59 -151
  94. package/server/dist/sync.js +41 -4
  95. package/server/dist/trpc/context.js +7 -0
  96. package/server/dist/trpc/errors.js +21 -0
  97. package/server/dist/trpc/index.js +19 -0
  98. package/server/dist/trpc/router.js +49 -0
  99. package/server/dist/trpc/routers/asmr-library.js +122 -0
  100. package/server/dist/trpc/routers/asmr-progress.js +133 -0
  101. package/server/dist/trpc/routers/asmr.js +87 -0
  102. package/server/dist/trpc/routers/auth.js +247 -0
  103. package/server/dist/trpc/routers/continue-watching.js +83 -0
  104. package/server/dist/trpc/routers/data.js +1039 -0
  105. package/server/dist/trpc/routers/discord.js +288 -0
  106. package/server/dist/trpc/routers/discovery.js +15 -0
  107. package/server/dist/trpc/routers/insights.js +45 -0
  108. package/server/dist/trpc/routers/manga-library.js +280 -0
  109. package/server/dist/trpc/routers/manga-progress.js +181 -0
  110. package/server/dist/trpc/routers/manga.js +201 -0
  111. package/server/dist/{controllers/music.controller.js → trpc/routers/music.js} +155 -288
  112. package/server/dist/trpc/routers/notifications.js +80 -0
  113. package/server/dist/trpc/routers/progress.js +15 -0
  114. package/server/dist/trpc/routers/queue.js +95 -0
  115. package/server/dist/{routes/radio.routes.js → trpc/routers/radio.js} +30 -23
  116. package/server/dist/trpc/routers/settings.js +105 -0
  117. package/server/dist/trpc/routers/tracker.js +219 -0
  118. package/server/dist/trpc/routers/tv-library.js +145 -0
  119. package/server/dist/trpc/routers/tv-progress.js +171 -0
  120. package/server/dist/trpc/routers/tv.js +565 -0
  121. package/server/dist/trpc/routers/watchlist.js +564 -0
  122. package/server/dist/trpc/validation.js +159 -0
  123. package/server/dist/utils/security.utils.js +0 -18
  124. package/server/package.json +5 -10
  125. package/client/dist/assets/Asmr-C28TfSvX.js +0 -2
  126. package/client/dist/assets/AsmrResetProgressModal-6Xh71AgR.js +0 -1
  127. package/client/dist/assets/AvSyncCalibrator-BwCtRW0P.js +0 -10
  128. package/client/dist/assets/Home-BJdbHYja.js +0 -1
  129. package/client/dist/assets/Insights-CjRy42YE.js +0 -1
  130. package/client/dist/assets/MangaReadPage-YCETZRte.js +0 -1
  131. package/client/dist/assets/Mature-BGxRWkV5.js +0 -1
  132. package/client/dist/assets/MediaCard-CAzoxsRS.js +0 -1
  133. package/client/dist/assets/Music-Cgo-yQ7E.js +0 -1
  134. package/client/dist/assets/OptionListMenu--Owe9Jle.js +0 -1
  135. package/client/dist/assets/Player-yRXG2BrP.js +0 -56
  136. package/client/dist/assets/PlayerSettings-DrZLa0CC.js +0 -1
  137. package/client/dist/assets/QueueOptionsButton-BVZyPyKf.js +0 -1
  138. package/client/dist/assets/Radio-BFjxlzuF.js +0 -1
  139. package/client/dist/assets/Search-BOBo0Ogh.js +0 -1
  140. package/client/dist/assets/Settings-DOvNQ0gX.js +0 -21
  141. package/client/dist/assets/Trackers-DZ9KqOWv.js +0 -2
  142. package/client/dist/assets/Tv-5mATEU4p.js +0 -4
  143. package/client/dist/assets/Tv-C2SWcVzN.css +0 -1
  144. package/client/dist/assets/TvInfo-CF-5C5Fs.js +0 -1
  145. package/client/dist/assets/TvPopup-Dfqifj3s.js +0 -1
  146. package/client/dist/assets/Watchlist-B8MHNsAU.js +0 -1
  147. package/client/dist/assets/index-D2RkUJIN.js +0 -178
  148. package/client/dist/assets/useAnimeInfoData-BWShDHqE.js +0 -1
  149. package/client/dist/assets/useAsmr-FyfD9G7b.js +0 -1
  150. package/client/dist/assets/useMangaLibrary-BJU5x8Vz.js +0 -1
  151. package/client/dist/assets/useProviders-DDRxa8vl.js +0 -1
  152. package/client/dist/assets/useTv-Bh6WmNnZ.js +0 -1
  153. package/client/dist/assets/useTvLibrary-_Pqm8re1.js +0 -1
  154. package/server/dist/controllers/asmr-library.controller.js +0 -288
  155. package/server/dist/controllers/auth.controller.js +0 -225
  156. package/server/dist/controllers/data.controller.js +0 -767
  157. package/server/dist/controllers/insights.controller.js +0 -203
  158. package/server/dist/controllers/manga-library.controller.js +0 -350
  159. package/server/dist/controllers/settings.controller.js +0 -609
  160. package/server/dist/controllers/tv-library.controller.js +0 -314
  161. package/server/dist/controllers/watchlist.controller.js +0 -1069
  162. package/server/dist/request-logger.js +0 -16
  163. package/server/dist/routes/asmr-library.routes.js +0 -23
  164. package/server/dist/routes/asmr.routes.js +0 -81
  165. package/server/dist/routes/auth.routes.js +0 -25
  166. package/server/dist/routes/data.routes.js +0 -47
  167. package/server/dist/routes/discord-gateway.routes.js +0 -51
  168. package/server/dist/routes/insights.routes.js +0 -35
  169. package/server/dist/routes/lan-auth.routes.js +0 -46
  170. package/server/dist/routes/manga-library.routes.js +0 -25
  171. package/server/dist/routes/manga.routes.js +0 -141
  172. package/server/dist/routes/music.routes.js +0 -20
  173. package/server/dist/routes/providers.routes.js +0 -17
  174. package/server/dist/routes/proxy.routes.js +0 -12
  175. package/server/dist/routes/settings.routes.js +0 -24
  176. package/server/dist/routes/tracker.routes.js +0 -287
  177. package/server/dist/routes/translate.routes.js +0 -88
  178. package/server/dist/routes/tv-library.routes.js +0 -23
  179. package/server/dist/routes/tv.routes.js +0 -629
  180. package/server/dist/routes/watchlist.routes.js +0 -341
@@ -1 +1 @@
1
- import{g as s,u as n,a as Y}from"./vendor-core-8R2fFbyN.js";import{I as P}from"./vendor-icons-CDMuNDeL.js";import{d as L,f as z}from"./index-D2RkUJIN.js";const F="_section_1pwqc_1",O="_header_1pwqc_10",j="_headerToggle_1pwqc_20",G="_headerActions_1pwqc_34",J="_title_1pwqc_40",K="_badge_1pwqc_50",V="_clearBtn_1pwqc_65",W="_nextBtn_1pwqc_83",Z="_list_1pwqc_101",ee="_item_1pwqc_114",ne="_active_1pwqc_134",te="_dragging_1pwqc_142",re="_dragHandle_1pwqc_149",ce="_thumbnail_1pwqc_167",ae="_meta_1pwqc_175",oe="_name_1pwqc_182",se="_episode_1pwqc_204",ie="_iconBtn_1pwqc_210",r={section:F,header:O,headerToggle:j,headerActions:G,title:J,badge:K,clearBtn:V,nextBtn:W,list:Z,item:ee,active:ne,dragging:te,dragHandle:re,thumbnail:ce,meta:ae,name:oe,episode:se,iconBtn:ie},le=({item:c,isActive:T,index:m,onRemove:D,onTouchPointerDown:v,onTouchPointerMove:x,onTouchPointerUp:q,onTouchPointerCancel:I,shouldIgnoreClick:_,onDragStart:B,onDragEnter:f,onDragEnd:o,isDragging:w})=>{const a=Y(),{titlePreference:i}=L(),l=c[i]||c.name||"Unknown show";return n("div",{"data-queue-index":m,className:`${r.item} ${T?r.active:""} ${w?r.dragging:""}`,draggable:!0,onDragStart:B,onDragEnter:f,onDragOver:u=>u.preventDefault(),onDragEnd:o,onPointerDown:u=>v(m,u),onPointerMove:x,onPointerUp:q,onPointerCancel:I,children:[n("button",{className:r.dragHandle,type:"button","aria-label":"Drag queue item",children:n(P,{name:"bars"})}),n("img",{className:r.thumbnail,src:z(c.thumbnail||"",72,96),alt:l,loading:"lazy",decoding:"async",onError:u=>{u.currentTarget.src="/placeholder.svg"}}),n("div",{className:r.meta,children:[n("button",{className:r.name,type:"button",onClick:()=>{_()||a(`/watch/${c.showId}/${c.episodeNumber}`)},children:l}),n("div",{className:r.episode,children:["Episode ",c.episodeNumber]})]}),n("button",{className:r.iconBtn,type:"button",onClick:()=>{_()||D(c)},"aria-label":`Remove ${l} episode ${c.episodeNumber} from queue`,children:n(P,{name:"times"})})]})},he=({title:c="Queue",eyebrow:T,items:m,currentShowId:D,currentEpisode:v,onRemove:x,onReorder:q,onNextQueue:I,onClear:_,showClearAll:B=!1,defaultExpanded:f=!0})=>{const[o,w]=s.useState([]),[a,i]=s.useState(null),[l,u]=s.useState(f),b=s.useRef(null),N=s.useRef(null),d=s.useRef(null),p=s.useRef(!1),R=s.useRef(!1);s.useEffect(()=>{w(m)},[m]),s.useEffect(()=>{u(f)},[f]);const E=e=>{i(e)},$=e=>{if(a===null||a===e)return;const t=[...o],h=t[a];t.splice(a,1),t.splice(e,0,h),i(e),w(t)},k=()=>{a!==null&&q(o.map(e=>({id:e.id,showId:e.showId,episodeNumber:e.episodeNumber}))),i(null)},C=(e=!1)=>{d.current!==null&&(window.clearTimeout(d.current),d.current=null),e&&p.current&&(q(o.map(t=>({id:t.id,showId:t.showId,episodeNumber:t.episodeNumber}))),R.current=!0,window.setTimeout(()=>{R.current=!1},0)),b.current=null,N.current=null,p.current=!1,i(null)},A=(e,t)=>{if(t.pointerType==="mouse")return;const h=t.currentTarget,g=t.pointerId;b.current=t.pointerId,N.current={x:t.clientX,y:t.clientY},d.current!==null&&window.clearTimeout(d.current),d.current=window.setTimeout(()=>{p.current=!0,i(e);try{h.setPointerCapture(g)}catch{}},220)},Q=e=>{if(e.pointerType==="mouse"||b.current!==e.pointerId)return;if(!p.current&&N.current){const H=Math.abs(e.clientX-N.current.x),X=Math.abs(e.clientY-N.current.y);(H>8||X>8)&&C(!1);return}if(!p.current)return;e.preventDefault();const h=document.elementFromPoint(e.clientX,e.clientY)?.closest?.("[data-queue-index]"),g=h?Number(h.dataset.queueIndex):NaN;if(Number.isNaN(g)||a===null||g===a)return;const y=[...o],U=y[a];y.splice(a,1),y.splice(g,0,U),i(g),w(y)},S=e=>{e.pointerType!=="mouse"&&b.current===e.pointerId&&C(p.current)},M=e=>{e.pointerType!=="mouse"&&b.current===e.pointerId&&C(!1)};return o.length===0?null:n("section",{className:r.section,children:[n("div",{className:r.header,children:[n("button",{className:r.headerToggle,type:"button",onClick:()=>u(e=>!e),"aria-expanded":l,"aria-label":l?`Collapse ${c}`:`Expand ${c}`,children:[n("span",{className:r.title,children:[n("span",{className:"title-stack",children:[T&&n("div",{className:"section-eyebrow",children:T}),n("span",{children:c})]}),n("span",{className:r.badge,children:o.length})]}),l?n(P,{name:"chevron-up"}):n(P,{name:"chevron-down"})]}),B&&_&&n("div",{className:r.headerActions,children:[I&&o.length>1&&n("button",{className:r.nextBtn,type:"button",onClick:I,children:"Next"}),n("button",{className:r.clearBtn,type:"button",onClick:_,children:"Clear All"})]})]}),l&&n("div",{className:r.list,children:o.map((e,t)=>n(le,{item:e,isActive:e.showId===D&&e.episodeNumber===v,index:t,onRemove:x,onTouchPointerDown:A,onTouchPointerMove:Q,onTouchPointerUp:S,onTouchPointerCancel:M,shouldIgnoreClick:()=>R.current,onDragStart:()=>E(t),onDragEnter:()=>$(t),onDragEnd:k,isDragging:a===t},e.id))})]})};export{he as Q,r as s};
1
+ import{g as s,u as n,a as Y}from"./vendor-core-8R2fFbyN.js";import{I as P}from"./vendor-icons-CDMuNDeL.js";import{d as L,f as z}from"./index-BXwhFWB_.js";const F="_section_1pwqc_1",O="_header_1pwqc_10",j="_headerToggle_1pwqc_20",G="_headerActions_1pwqc_34",J="_title_1pwqc_40",K="_badge_1pwqc_50",V="_clearBtn_1pwqc_65",W="_nextBtn_1pwqc_83",Z="_list_1pwqc_101",ee="_item_1pwqc_114",ne="_active_1pwqc_134",te="_dragging_1pwqc_142",re="_dragHandle_1pwqc_149",ce="_thumbnail_1pwqc_167",ae="_meta_1pwqc_175",oe="_name_1pwqc_182",se="_episode_1pwqc_204",ie="_iconBtn_1pwqc_210",r={section:F,header:O,headerToggle:j,headerActions:G,title:J,badge:K,clearBtn:V,nextBtn:W,list:Z,item:ee,active:ne,dragging:te,dragHandle:re,thumbnail:ce,meta:ae,name:oe,episode:se,iconBtn:ie},le=({item:c,isActive:T,index:m,onRemove:D,onTouchPointerDown:v,onTouchPointerMove:x,onTouchPointerUp:q,onTouchPointerCancel:I,shouldIgnoreClick:_,onDragStart:B,onDragEnter:f,onDragEnd:o,isDragging:w})=>{const a=Y(),{titlePreference:i}=L(),l=c[i]||c.name||"Unknown show";return n("div",{"data-queue-index":m,className:`${r.item} ${T?r.active:""} ${w?r.dragging:""}`,draggable:!0,onDragStart:B,onDragEnter:f,onDragOver:u=>u.preventDefault(),onDragEnd:o,onPointerDown:u=>v(m,u),onPointerMove:x,onPointerUp:q,onPointerCancel:I,children:[n("button",{className:r.dragHandle,type:"button","aria-label":"Drag queue item",children:n(P,{name:"bars"})}),n("img",{className:r.thumbnail,src:z(c.thumbnail||"",72,96),alt:l,loading:"lazy",decoding:"async",onError:u=>{u.currentTarget.src="/placeholder.svg"}}),n("div",{className:r.meta,children:[n("button",{className:r.name,type:"button",onClick:()=>{_()||a(`/watch/${c.showId}/${c.episodeNumber}`)},children:l}),n("div",{className:r.episode,children:["Episode ",c.episodeNumber]})]}),n("button",{className:r.iconBtn,type:"button",onClick:()=>{_()||D(c)},"aria-label":`Remove ${l} episode ${c.episodeNumber} from queue`,children:n(P,{name:"times"})})]})},he=({title:c="Queue",eyebrow:T,items:m,currentShowId:D,currentEpisode:v,onRemove:x,onReorder:q,onNextQueue:I,onClear:_,showClearAll:B=!1,defaultExpanded:f=!0})=>{const[o,w]=s.useState([]),[a,i]=s.useState(null),[l,u]=s.useState(f),b=s.useRef(null),N=s.useRef(null),d=s.useRef(null),p=s.useRef(!1),R=s.useRef(!1);s.useEffect(()=>{w(m)},[m]),s.useEffect(()=>{u(f)},[f]);const E=e=>{i(e)},$=e=>{if(a===null||a===e)return;const t=[...o],h=t[a];t.splice(a,1),t.splice(e,0,h),i(e),w(t)},k=()=>{a!==null&&q(o.map(e=>({id:e.id,showId:e.showId,episodeNumber:e.episodeNumber}))),i(null)},C=(e=!1)=>{d.current!==null&&(window.clearTimeout(d.current),d.current=null),e&&p.current&&(q(o.map(t=>({id:t.id,showId:t.showId,episodeNumber:t.episodeNumber}))),R.current=!0,window.setTimeout(()=>{R.current=!1},0)),b.current=null,N.current=null,p.current=!1,i(null)},A=(e,t)=>{if(t.pointerType==="mouse")return;const h=t.currentTarget,g=t.pointerId;b.current=t.pointerId,N.current={x:t.clientX,y:t.clientY},d.current!==null&&window.clearTimeout(d.current),d.current=window.setTimeout(()=>{p.current=!0,i(e);try{h.setPointerCapture(g)}catch{}},220)},Q=e=>{if(e.pointerType==="mouse"||b.current!==e.pointerId)return;if(!p.current&&N.current){const H=Math.abs(e.clientX-N.current.x),X=Math.abs(e.clientY-N.current.y);(H>8||X>8)&&C(!1);return}if(!p.current)return;e.preventDefault();const h=document.elementFromPoint(e.clientX,e.clientY)?.closest?.("[data-queue-index]"),g=h?Number(h.dataset.queueIndex):NaN;if(Number.isNaN(g)||a===null||g===a)return;const y=[...o],U=y[a];y.splice(a,1),y.splice(g,0,U),i(g),w(y)},S=e=>{e.pointerType!=="mouse"&&b.current===e.pointerId&&C(p.current)},M=e=>{e.pointerType!=="mouse"&&b.current===e.pointerId&&C(!1)};return o.length===0?null:n("section",{className:r.section,children:[n("div",{className:r.header,children:[n("button",{className:r.headerToggle,type:"button",onClick:()=>u(e=>!e),"aria-expanded":l,"aria-label":l?`Collapse ${c}`:`Expand ${c}`,children:[n("span",{className:r.title,children:[n("span",{className:"title-stack",children:[T&&n("div",{className:"section-eyebrow",children:T}),n("span",{children:c})]}),n("span",{className:r.badge,children:o.length})]}),l?n(P,{name:"chevron-up"}):n(P,{name:"chevron-down"})]}),B&&_&&n("div",{className:r.headerActions,children:[I&&o.length>1&&n("button",{className:r.nextBtn,type:"button",onClick:I,children:"Next"}),n("button",{className:r.clearBtn,type:"button",onClick:_,children:"Clear All"})]})]}),l&&n("div",{className:r.list,children:o.map((e,t)=>n(le,{item:e,isActive:e.showId===D&&e.episodeNumber===v,index:t,onRemove:x,onTouchPointerDown:A,onTouchPointerMove:Q,onTouchPointerUp:S,onTouchPointerCancel:M,shouldIgnoreClick:()=>R.current,onDragStart:()=>E(t),onDragEnter:()=>$(t),onDragEnd:k,isDragging:a===t},e.id))})]})};export{he as Q,r as s};
@@ -0,0 +1 @@
1
+ import{d as h,A as j,h as y,g as se,u as e,S as T,$ as _,T as K}from"./vendor-core-8R2fFbyN.js";import{I as o}from"./vendor-icons-CDMuNDeL.js";import{b as Z}from"./vendor-query-BUTye89G.js";import{g as x,t as G}from"./index-BXwhFWB_.js";import{a}from"./Asmr.module-ChUXDZKx.js";import{r as i}from"./Radio.module-DGSZLpKM.js";const ee=300*1e3,re="https://cdn.listen.moe/covers/";function V(n){return n?n.startsWith("http")?n:`${re}${n}`:null}function le(n){return n?V(n.albums[0]?.image)||V(n.artists[0]?.image)||V(n.sources[0]?.image):null}function H(n){return n?n.artists.map(s=>s.nameRomaji||s.name).join(", "):""}const oe=()=>{const n=x();return Z({...n.radio.stations.queryOptions(),staleTime:ee})},ie=n=>{const s=x();return Z({...s.radio.search.queryOptions({q:n}),enabled:n.trim().length>0,staleTime:ee})},X={song:null,lastPlayed:[],listeners:0,startTime:null},ce=n=>{const[s,p]=h(X),[l,c]=h(!1),d=j(null);return y(()=>{if(p(X),c(!1),!n)return;let m=null,f=!1;try{m=new WebSocket(n)}catch{return}return m.onopen=()=>{f||c(!0)},m.onmessage=v=>{try{const u=JSON.parse(v.data);if(u.op===0){const b=u.d?.heartbeat||35e3;d.current&&window.clearInterval(d.current),d.current=window.setInterval(()=>{m&&m.readyState===WebSocket.OPEN&&m.send(JSON.stringify({op:9}))},b)}else u.op===1&&p({song:u.d?.song||null,lastPlayed:u.d?.lastPlayed||[],listeners:u.d?.listeners||0,startTime:u.d?.startTime||null})}catch{}},m.onclose=()=>{f||c(!1)},()=>{f=!0,d.current&&window.clearInterval(d.current),d.current=null,m&&m.close()}},[n]),{nowPlaying:s,connected:l}};function Y(n){if(!n)return"";const s=Math.max(0,Math.floor((Date.now()-new Date(n).getTime())/1e3)),p=Math.floor(s/60),l=s%60;return`${p}:${String(l).padStart(2,"0")}`}const de=({station:n,nowPlaying:s,connected:p,expanded:l,onStationStep:c,onExpandedChange:d,onClose:m})=>{const f=j(null),[v,u]=h(!1),[b,F]=h(!0),[S,I]=h(!1),[L,k]=h(!0),[M,P]=h(""),[N,A]=h(()=>{const t=parseFloat(localStorage.getItem("radioVolume")||"");return Number.isFinite(t)?t:1}),r=j(""),g=j(N);g.current=N,r.current||(r.current=typeof crypto<"u"&&"randomUUID"in crypto?crypto.randomUUID():`radio-${Date.now()}-${Math.random().toString(36).slice(2)}`);const w=s.song,C=le(w)||n.favicon||null,[R,q]=h(!1);y(()=>{q(!1)},[C]);const E=R?null:C,U=!!E,B=w?`${H(w)} — ${w.title}`:n.name;y(()=>{const t=f.current;if(t)return u(!1),t.src=n.streamUrl,t.load(),t.volume=g.current,t.play().catch(()=>u(!1)),()=>{t.removeAttribute("src")}},[n.id,n.streamUrl]),y(()=>{const t=f.current;t&&(t.volume=N)},[N]),y(()=>{if(l)return document.body.classList.add("asmr-player-open"),()=>document.body.classList.remove("asmr-player-open")},[l]),y(()=>{l&&k(!0)},[l]);const te=t=>t?Math.max(0,Math.floor((Date.now()-new Date(t).getTime())/1e3)):0,O=se.useCallback(t=>{n&&(G.discord.radioPresence.mutate({title:B,stationLabel:n.name,isPlaying:t,thumbnail:E||"",currentTime:te(s.startTime),sessionId:r.current}).catch(()=>{}),G.discord.heartbeat.mutate({sessionId:r.current}).catch(()=>{}))},[n,B,E,s.startTime]);y(()=>{O(v)},[O,v,n.id,B,l]),y(()=>{if(!v)return;const t=window.setInterval(()=>O(!0),15e3);return()=>window.clearInterval(t)},[v,O]),y(()=>{const t=r.current,$=()=>{if(!t)return;const Q=JSON.stringify({sessionId:t});navigator.sendBeacon?(navigator.sendBeacon("/api/discord/clear",new Blob([Q],{type:"application/json"})),navigator.sendBeacon("/api/discord/heartbeat",new Blob([JSON.stringify({sessionId:t,bye:!0})],{type:"application/json"}))):(fetch("/api/discord/clear",{method:"POST",headers:{"Content-Type":"application/json"},body:Q,keepalive:!0}).catch(()=>{}),fetch("/api/discord/heartbeat",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sessionId:t,bye:!0}),keepalive:!0}).catch(()=>{}))},D=()=>$(),W=()=>{document.visibilityState==="hidden"&&$()};return window.addEventListener("pagehide",D),window.addEventListener("beforeunload",D),document.addEventListener("visibilitychange",W),()=>{window.removeEventListener("pagehide",D),window.removeEventListener("beforeunload",D),document.removeEventListener("visibilitychange",W),$()}},[]),y(()=>{if(!s.startTime){P("");return}P(Y(s.startTime));const t=window.setInterval(()=>P(Y(s.startTime)),1e3);return()=>window.clearInterval(t)},[s.startTime,s.song?.id]),y(()=>{if(!l)return;const t=$=>{$.key==="Escape"&&(S?I(!1):d(!1))};return window.addEventListener("keydown",t),()=>window.removeEventListener("keydown",t)},[l,S,d]);const ae=()=>{const t=f.current;t&&(t.paused?(t.load(),t.play().catch(()=>{})):t.pause())},ne=e(T,{children:[e("div",{className:a.playerButtons,children:[e("button",{className:a.playerBtn,onClick:()=>c(-1),"aria-label":"Previous station",children:e(o,{name:"step-backward"})}),e("button",{className:`${a.playerBtn} ${a.playBtn}`,onClick:ae,"aria-label":v?"Pause":"Play",children:v?e(o,{name:"pause"}):e(o,{name:"play"})}),e("button",{className:a.playerBtn,onClick:()=>c(1),"aria-label":"Next station",children:e(o,{name:"step-forward"})})]}),e("div",{className:a.seekRow,children:[e("span",{className:i.liveBadge,children:[e(o,{name:"broadcast-tower",size:10})," LIVE"]}),M&&e("span",{className:a.timeLabel,children:M}),p&&s.listeners>0&&e("span",{className:a.timeLabel,children:[s.listeners," listening"]}),!p&&n.source==="listen.moe"&&e("span",{className:a.timeLabel,children:"connecting…"})]})]}),z=e(T,{children:[e("button",{className:`${a.playerBtn} ${a.playerToggle}`,onClick:()=>d(!l),"aria-label":l?"Minimize player":"Expand player",title:l?"Minimize to browse":"Expand",children:l?e(o,{name:"chevron-down"}):e(o,{name:"chevron-up"})}),e("div",{className:a.playerInfo,children:[e("p",{className:a.playerTitle,title:B,children:B}),e("p",{className:a.playerTrack,children:n.name})]}),e("div",{className:a.playerControls,children:ne}),e("div",{className:a.playerRight,children:[N===0?e(o,{name:"volume-mute",className:a.volumeIcon}):N<.5?e(o,{name:"volume-down",className:a.volumeIcon}):e(o,{name:"volume-up",className:a.volumeIcon}),e("input",{className:a.volumeBar,type:"range",min:0,max:1,step:.01,value:N,onChange:t=>{const $=parseFloat(t.target.value);A($),localStorage.setItem("radioVolume",String($))},style:{"--volume-percent":`${N*100}%`},"aria-label":"Volume"})]}),e("div",{className:a.playerActions,children:[l&&U&&e("button",{className:a.playerBtn,onClick:()=>F(t=>!t),"aria-label":b?"Hide art":"Show art",title:b?"Hide art":"Show art",children:b?e(o,{name:"eye-slash"}):e(o,{name:"image"})}),l&&s.lastPlayed.length>0&&e("button",{className:`${a.playerBtn} ${S?a.playerBtnActive:""}`,onClick:()=>I(t=>!t),"aria-label":S?"Hide history":"Show history",title:"Recently played",children:e(o,{name:"list-ol"})}),e("button",{className:a.playerBtn,onClick:m,"aria-label":"Close player",children:e(o,{name:"times"})})]})]}),J=e("audio",{ref:f,preload:"none",onPlay:()=>u(!0),onPause:()=>u(!1)});return l?_(e(T,{children:[J,e("div",{className:`${a.npOverlay} ${L?"":a.npOverlayControlsHidden}`,children:[e("div",{className:`${a.npStage} ${!b||!U?a.npStageBlank:""}`,onClick:()=>k(t=>!t),children:b&&U&&E&&e("div",{className:i.coverWrap,children:e("img",{src:E,alt:B,loading:"lazy",decoding:"async",draggable:!1,className:i.cover,onError:()=>q(!0)})})}),e("div",{className:`${a.playerBar} ${a.playerBarDocked} ${L?"":a.playerBarDockedHidden}`,onClick:t=>t.stopPropagation(),children:[z,S&&e(T,{children:[e("div",{className:a.npBackdrop,onClick:()=>I(!1)}),e("div",{className:a.chapterPanel,children:s.lastPlayed.map(t=>e("div",{className:a.chapterRow,children:e("span",{className:a.chapterRowLabel,title:`${H(t)} — ${t.title}`,children:[H(t)," — ",t.title]})},t.id))})]})]})]})]}),document.body):_(e(T,{children:[J,e("div",{className:a.playerBar,children:z})]}),document.body)},ve=()=>{y(()=>{document.title="Radio - dango"},[]);const[n,s]=h(""),[p,l]=h(""),[c,d]=h(null),[m,f]=h(!0),{data:v,isLoading:u}=oe(),{data:b,isLoading:F}=ie(p),S=K(()=>v?.stations||[],[v]),I=K(()=>b?.stations||[],[b]),L=p?I:S,{nowPlaying:k,connected:M}=ce(c?.gateway),P=r=>{d(r),f(!0)},N=r=>{const g=L.length>0?L:S;if(g.length===0||!c)return;const w=g.findIndex(R=>R.id===c.id),C=g[(w<0?0:w+r+g.length)%g.length];d(C)},A=r=>{const g=c?.id===r.id,w=g&&k.song?`${H(k.song)} — ${k.song.title}`:null,C=[r.codec,r.bitrate?`${r.bitrate}k`:"",r.tags].filter(Boolean).join(" · ");return e("button",{className:`${i.stationRow} ${g?i.stationRowActive:""}`,onClick:()=>P(r),children:[r.favicon?e("img",{src:r.favicon,alt:"",className:i.stationThumb,loading:"lazy",decoding:"async",onError:R=>{R.target.style.display="none"}}):e("span",{className:i.stationThumbPlaceholder,children:e(o,{name:"broadcast-tower"})}),e("span",{className:i.stationMeta,children:[e("span",{className:i.stationName,children:r.name}),C&&e("span",{className:i.stationSub,children:C})]}),w&&e("span",{className:i.stationNowPlaying,children:w})]},r.id)};return e("div",{className:`${a.page} ${c?a.pageWithPlayer:""}`,children:[e("div",{className:a.header,children:[e("h1",{className:a.pageTitle,children:[e(o,{name:"broadcast-tower"})," Radio"]}),e("form",{className:a.searchForm,onSubmit:r=>{r.preventDefault(),l(n)},children:[e("input",{className:a.searchInput,value:n,onChange:r=>s(r.target.value),placeholder:"Search stations (anime, j-pop, k-pop…)","aria-label":"Search radio stations"}),e("button",{className:a.searchBtn,type:"submit","aria-label":"Search",children:e(o,{name:"search"})})]})]}),p?e(T,{children:[e("h2",{className:i.sectionTitle,children:["Results for “",p,"”"]}),F?e("p",{className:a.statusMsg,children:"Searching…"}):I.length===0?e("p",{className:a.statusMsg,children:"No stations found."}):e("div",{className:i.stationList,children:I.map(A)})]}):e(T,{children:[e("h2",{className:i.sectionTitle,children:"Featured"}),u?e("p",{className:a.statusMsg,children:"Loading…"}):e("div",{className:i.stationList,children:S.map(A)})]}),c&&e(de,{station:c,nowPlaying:k,connected:M,expanded:m,onStationStep:N,onExpandedChange:f,onClose:()=>d(null)})]})};export{ve as default};
@@ -1 +1 @@
1
- import{n as U,d as v,h as b,T as w,u as i,S as E}from"./vendor-core-8R2fFbyN.js";import{M as x}from"./MediaCard-CAzoxsRS.js";import{L as F}from"./LibraryListPage-B0qWqhb_.js";import{u as _,M as z}from"./useMangaPopup-TFzkC-tG.js";import{M as D}from"./MangaResetProgressModal-D_yT3d1v.js";import{x as G,d as O,o as Q,p as Y,u as q,y as H,z as K,A as V,M as h,m as Z,i as j,b as J,c as W}from"./useMangaLibrary-BJU5x8Vz.js";import"./vendor-ui-CUDCvRS_.js";import"./vendor-icons-CDMuNDeL.js";import"./index-D2RkUJIN.js";import"./vendor-query-BXRECSI6.js";import"./useIsMobile-Dm_b6Ob3.js";import"./SkeletonGrid-BxfgjP4i.js";import"./ErrorMessage-z4f4WGgP.js";import"./Watchlist.module-XGtVQr1d.js";import"./ResetProgressModal-DES5Y-Fl.js";const X=["All","Continue Reading",...h],R=24,y=e=>({provider:e.provider,mangaId:e.mangaId,title:e.title,altTitle:e.altTitle,cover:e.cover,contentRating:e.contentRating,readTarget:e.detailTarget,progressLabel:e.progressLabel});function va(){const{filter:e="All"}=U(),[g,p]=v(1),[d,u]=v(null);b(()=>{document.title="Reading List - dango"},[]),b(()=>{p(1)},[e]);const r=e==="Continue Reading",n=G(r?"All":e,g,R),s=O(100),I=Q(),T=Y(),{toggle:L,bookmarkedIds:C}=q(),{popup:t,openPopup:k,scheduleClose:c,cancelClose:m,closePopup:M}=_(),f=H(),P=K(),B=V(),S=w(()=>r?(s.data?.data??[]).map(a=>{const o=a.page??0,l=a.pageCount??0;return{key:a.id,libId:a.id,provider:a.provider,mangaId:a.mangaId,title:a.title,altTitle:a.altTitle,cover:a.cover||"",status:a.status,contentRating:a.contentRating||void 0,chapterLabel:a.chapterNumber?`Ch. ${a.chapterNumber}`:void 0,progressPercent:l>0?o/l*100:0,progressLabel:a.chapterNumber&&l>0?`Ch. ${a.chapterNumber} · p. ${o}/${l}`:void 0,detailTarget:a.chapterId&&a.provider&&a.mangaId?`/manga/${a.provider}/${encodeURIComponent(a.mangaId)}/read?chapter=${encodeURIComponent(a.chapterId)}`:`/manga/${a.provider}/${encodeURIComponent(a.mangaId)}`}}):(n.data?.data??[]).map(a=>({key:a.id,libId:a.id,provider:a.provider,mangaId:a.mangaId,title:a.title,altTitle:a.altTitle,cover:a.cover||"",status:a.status,contentRating:a.contentRating||void 0,chapterLabel:a.lastChapterNumber?`Ch. ${a.lastChapterNumber}`:void 0,progressPercent:void 0,progressLabel:void 0,detailTarget:`/manga/${a.provider}/${encodeURIComponent(a.mangaId)}`})),[r,s.data,n.data]),A=r?s.data?.total??0:n.data?.total??0,$=r?s.isLoading:n.isLoading,N=r?s.error:n.error;return i(F,{headerTitle:"My Reading List",headerSubtitle:"Track and manage your manga collection",filters:X,filterBy:e,filterBasePath:"/reading-list",continueFilter:"Continue Reading",statusOptions:[...h],entries:S,total:A,isLoading:$,error:N,page:g,pageSize:R,onPageChange:p,emptyTitle:"Your reading list is looking a bit lonely",emptyFilteredText:"No titles match this filter.",emptyAllText:"Let's find something to read!",browseLabel:"Browse Manga",browseTarget:"/manga",removeListLabel:"Remove from Reading List",listNoun:"reading list",skipConfirmKey:"mangaSkipRemoveConfirmation",onBulkStatus:(a,o)=>f.mutate({ids:a,status:o}),onBulkRemove:a=>{r?B.mutate(a):P.mutate(a)},onStatusChange:(a,o)=>T.mutate({id:a,status:o}),onRemoveItem:a=>I.mutate(a),renderCard:a=>i(x,{item:{id:a.libId,title:a.title,...W({title:a.title,altTitle:a.altTitle}),thumbnail:J(a.provider,a.cover),chapterBadge:a.chapterLabel??null,isAdult:j(a)},linkTo:a.detailTarget,hoverIcon:"book",progress:a.progressPercent!==void 0&&a.progressLabel?{percent:a.progressPercent,label:a.progressLabel}:void 0,showProgress:r,display:{elements:{poster:{typeBadge:!1,chapterBadge:!0,adultBadge:!0},info:{title:!0,mobileBadges:!0,progress:!0,meta:!1}}},onRemove:r?()=>u(a):void 0,onOpenDetails:o=>k(o,y(a)),onPopupHoverIntent:o=>o?m():c(),rawThumbnail:!0}),modals:i(E,{children:[t&&t.data.provider&&i(z,{data:t.data,anchorRect:t.rect,bookmarked:C.has(Z(t.data.provider,t.data.mangaId)),onToggleBookmark:()=>L({id:t.data.mangaId,provider:t.data.provider,title:t.data.title,cover:t.data.cover,altTitle:t.data.altTitle??void 0,contentRating:t.data.contentRating}),onMouseEnter:m,onMouseLeave:c,onRequestClose:M}),i(D,{mangaId:d?d.libId:null,title:d?.title,onClose:()=>u(null)})]})})}export{va as default};
1
+ import{n as U,d as v,h as b,T as w,u as i,S as E}from"./vendor-core-8R2fFbyN.js";import{M as x}from"./MediaCard-B5584Cq9.js";import{L as F}from"./LibraryListPage-HzuDavbb.js";import{u as _,M as z}from"./useMangaPopup-B8nnpvyi.js";import{M as D}from"./MangaResetProgressModal-QjZyIAjl.js";import{x as G,d as O,o as Q,p as Y,u as q,y as H,z as K,A as V,M as h,m as Z,i as j,b as J,c as W}from"./useMangaLibrary-C9Lci5N4.js";import"./vendor-ui-CUDCvRS_.js";import"./vendor-icons-CDMuNDeL.js";import"./index-BXwhFWB_.js";import"./vendor-query-BUTye89G.js";import"./useIsMobile-Dm_b6Ob3.js";import"./SkeletonGrid-CLEPY9nP.js";import"./ErrorMessage-z4f4WGgP.js";import"./Watchlist.module-XGtVQr1d.js";import"./ResetProgressModal-CcStlbhP.js";const X=["All","Continue Reading",...h],R=24,y=e=>({provider:e.provider,mangaId:e.mangaId,title:e.title,altTitle:e.altTitle,cover:e.cover,contentRating:e.contentRating,readTarget:e.detailTarget,progressLabel:e.progressLabel});function va(){const{filter:e="All"}=U(),[g,p]=v(1),[d,u]=v(null);b(()=>{document.title="Reading List - dango"},[]),b(()=>{p(1)},[e]);const r=e==="Continue Reading",n=G(r?"All":e,g,R),s=O(100),I=Q(),T=Y(),{toggle:L,bookmarkedIds:C}=q(),{popup:t,openPopup:k,scheduleClose:c,cancelClose:m,closePopup:M}=_(),f=H(),P=K(),B=V(),S=w(()=>r?(s.data?.data??[]).map(a=>{const o=a.page??0,l=a.pageCount??0;return{key:a.id,libId:a.id,provider:a.provider,mangaId:a.mangaId,title:a.title,altTitle:a.altTitle,cover:a.cover||"",status:a.status,contentRating:a.contentRating||void 0,chapterLabel:a.chapterNumber?`Ch. ${a.chapterNumber}`:void 0,progressPercent:l>0?o/l*100:0,progressLabel:a.chapterNumber&&l>0?`Ch. ${a.chapterNumber} · p. ${o}/${l}`:void 0,detailTarget:a.chapterId&&a.provider&&a.mangaId?`/manga/${a.provider}/${encodeURIComponent(a.mangaId)}/read?chapter=${encodeURIComponent(a.chapterId)}`:`/manga/${a.provider}/${encodeURIComponent(a.mangaId)}`}}):(n.data?.data??[]).map(a=>({key:a.id,libId:a.id,provider:a.provider,mangaId:a.mangaId,title:a.title,altTitle:a.altTitle,cover:a.cover||"",status:a.status,contentRating:a.contentRating||void 0,chapterLabel:a.lastChapterNumber?`Ch. ${a.lastChapterNumber}`:void 0,progressPercent:void 0,progressLabel:void 0,detailTarget:`/manga/${a.provider}/${encodeURIComponent(a.mangaId)}`})),[r,s.data,n.data]),A=r?s.data?.total??0:n.data?.total??0,$=r?s.isLoading:n.isLoading,N=r?s.error:n.error;return i(F,{headerTitle:"My Reading List",headerSubtitle:"Track and manage your manga collection",filters:X,filterBy:e,filterBasePath:"/reading-list",continueFilter:"Continue Reading",statusOptions:[...h],entries:S,total:A,isLoading:$,error:N,page:g,pageSize:R,onPageChange:p,emptyTitle:"Your reading list is looking a bit lonely",emptyFilteredText:"No titles match this filter.",emptyAllText:"Let's find something to read!",browseLabel:"Browse Manga",browseTarget:"/manga",removeListLabel:"Remove from Reading List",listNoun:"reading list",skipConfirmKey:"mangaSkipRemoveConfirmation",onBulkStatus:(a,o)=>f.mutate({ids:a,status:o}),onBulkRemove:a=>{r?B.mutate(a):P.mutate(a)},onStatusChange:(a,o)=>T.mutate({id:a,status:o}),onRemoveItem:a=>I.mutate(a),renderCard:a=>i(x,{item:{id:a.libId,title:a.title,...W({title:a.title,altTitle:a.altTitle}),thumbnail:J(a.provider,a.cover),chapterBadge:a.chapterLabel??null,isAdult:j(a)},linkTo:a.detailTarget,hoverIcon:"book",progress:a.progressPercent!==void 0&&a.progressLabel?{percent:a.progressPercent,label:a.progressLabel}:void 0,showProgress:r,display:{elements:{poster:{typeBadge:!1,chapterBadge:!0,adultBadge:!0},info:{title:!0,mobileBadges:!0,progress:!0,meta:!1}}},onRemove:r?()=>u(a):void 0,onOpenDetails:o=>k(o,y(a)),onPopupHoverIntent:o=>o?m():c(),rawThumbnail:!0}),modals:i(E,{children:[t&&t.data.provider&&i(z,{data:t.data,anchorRect:t.rect,bookmarked:C.has(Z(t.data.provider,t.data.mangaId)),onToggleBookmark:()=>L({id:t.data.mangaId,provider:t.data.provider,title:t.data.title,cover:t.data.cover,altTitle:t.data.altTitle??void 0,contentRating:t.data.contentRating}),onMouseEnter:m,onMouseLeave:c,onRequestClose:M}),i(D,{mangaId:d?d.libId:null,title:d?.title,onClose:()=>u(null)})]})})}export{va as default};
@@ -1 +1 @@
1
- import{u as e}from"./vendor-core-8R2fFbyN.js";import{M as r,B as n}from"./index-D2RkUJIN.js";const p=({isOpen:t,itemName:c,progressKind:i,listLabel:s,alsoRemove:a,onAlsoRemoveChange:d,onClose:o,onConfirm:l})=>e(r,{isOpen:t,onClose:o,title:"Reset Progress",children:[e(r.Body,{children:[e("p",{children:["Are you sure you want to remove your ",i,' progress for "',c,'"?']}),e("label",{children:[e("input",{type:"checkbox",checked:a,onChange:h=>d(h.target.checked)}),"Also remove from ",s]})]}),e(r.Actions,{children:[e(n,{variant:"secondary",onClick:o,children:"No"}),e(n,{variant:"danger",onClick:l,children:"Yes"})]})]});export{p as R};
1
+ import{u as e}from"./vendor-core-8R2fFbyN.js";import{M as r,B as n}from"./index-BXwhFWB_.js";const p=({isOpen:t,itemName:c,progressKind:i,listLabel:s,alsoRemove:a,onAlsoRemoveChange:d,onClose:o,onConfirm:l})=>e(r,{isOpen:t,onClose:o,title:"Reset Progress",children:[e(r.Body,{children:[e("p",{children:["Are you sure you want to remove your ",i,' progress for "',c,'"?']}),e("label",{children:[e("input",{type:"checkbox",checked:a,onChange:h=>d(h.target.checked)}),"Also remove from ",s]})]}),e(r.Actions,{children:[e(n,{variant:"secondary",onClick:o,children:"No"}),e(n,{variant:"danger",onClick:l,children:"Yes"})]})]});export{p as R};
@@ -0,0 +1 @@
1
+ import{h as O,o as me,a as ge,d as o,A as ve,g as fe,u as a}from"./vendor-core-8R2fFbyN.js";import{I as L}from"./vendor-icons-CDMuNDeL.js";import{P as ee,S as Le}from"./SkeletonGrid-CLEPY9nP.js";import{A as Ae}from"./AnimeCard-CJy1SXH3.js";import{t as be,u as ye,r as Se,Q as ae,B as w,R as Ne}from"./index-BXwhFWB_.js";import{E as Ce}from"./ErrorMessage-z4f4WGgP.js";import{s as t}from"./Search.module-CMEai-B-.js";import"./useAnimeInfoData-DJ7A4B4T.js";import"./vendor-query-BUTye89G.js";import"./QueueOptionsButton-Ba0dg_82.js";import"./vendor-ui-CUDCvRS_.js";import"./MediaCard-B5584Cq9.js";import"./useIsMobile-Dm_b6Ob3.js";const Te=[{value:"ALL",label:"All Types"},{value:"TV",label:"TV Series"},{value:"Movie",label:"Movie"},{value:"OVA",label:"OVA"},{value:"ONA",label:"ONA"},{value:"TV_SHORT",label:"TV Short"},{value:"SPECIAL",label:"Special"},{value:"ADULT",label:"Mature"}],Ee=[{value:"ALL",label:"All Seasons"},{value:"Winter",label:"Winter"},{value:"Spring",label:"Spring"},{value:"Summer",label:"Summer"},{value:"Fall",label:"Fall"}],Ie=[{value:"ALL",label:"All Countries"},{value:"JP",label:"Japan"},{value:"CN",label:"China"}],De=[{value:"POPULARITY_DESC",label:"Popularity"},{value:"TRENDING_DESC",label:"Trending"},{value:"SCORE_DESC",label:"Score"},{value:"START_DATE_DESC",label:"Newest"},{value:"START_DATE_ASC",label:"Oldest"},{value:"EPISODES_DESC",label:"Most Episodes"},{value:"FAVOURITES_DESC",label:"Favourites"}],Pe=[{value:"RELEASING",label:"Currently Airing"},{value:"FINISHED",label:"Finished"},{value:"NOT_YET_RELEASED",label:"Not Yet Released"},{value:"CANCELLED",label:"Cancelled"},{value:"HIATUS",label:"Hiatus"}];function Ve(){O(()=>{document.title="Search - dango"},[]);const[r,te]=me(),le=ge(),[h,k]=o(r.get("query")||""),[p,_]=o(parseInt(r.get("page")||"1")),[u,A]=o(r.get("type")||"ALL"),[m,b]=o(r.get("season")||"ALL"),[g,y]=o(r.get("year")||"ALL"),[B,E]=o(r.get("country")||"ALL"),[G,ne]=o(r.get("provider")||"anilist"),[Y,I]=o(r.get("sortBy")||"POPULARITY_DESC"),[U,D]=o(r.get("status")||""),[S,re]=o(!1),[se,F]=o(null);O(()=>{let e=!1;return be.data.anilistStatus.query().then(n=>{e||F(n.available)}).catch(()=>{e||F(!0)}),()=>{e=!0}},[]);const{lowEndMode:ie}=ye(),P=ve(null),{data:oe}=Se(),M=oe?.genres||[],[v,N]=o(()=>{const e={},n=r.get("genres")?.split(",").map(l=>l.trim()).filter(Boolean)||[],s=r.get("excludeGenres")?.split(",").map(l=>l.trim()).filter(Boolean)||[];return n.forEach(l=>l&&(e[l]="include")),s.forEach(l=>l&&(e[l]="exclude")),e}),$=new URLSearchParams(r);$.delete("page");const V=$.toString(),{data:f=[],isLoading:C,isError:ce,error:ue}=ae(V,p,14),{data:j}=ae(V,p+1,14),[x,de]=o(!1),T=fe.useMemo(()=>G==="anilist"&&u==="ADULT"||x?f:f.filter(e=>!(e.isAdult||e.rating==="R+"||e.rating==="Rx"||e.rating?.includes("17+"))),[f,x,G,u]);O(()=>{k(r.get("query")||""),A(r.get("type")||"ALL"),b(r.get("season")||"ALL"),y(r.get("year")||"ALL"),E(r.get("country")||"ALL"),ne(r.get("provider")||"anilist"),I(r.get("sortBy")||"POPULARITY_DESC"),D(r.get("status")||""),_(parseInt(r.get("page")||"1"));const e={},n=r.get("genres")?.split(",").map(l=>l.trim()).filter(Boolean)||[],s=r.get("excludeGenres")?.split(",").map(l=>l.trim()).filter(Boolean)||[];n.forEach(l=>l&&(e[l]="include")),s.forEach(l=>l&&(e[l]="exclude")),N(e)},[r]);const c=(e=1,n={})=>{Ne();const s=n.type??u,l=n.status??U,q=n.season??m,H=n.year??g,J=n.country??B,K=n.sort??Y,Q=n.genreState??v,pe=n.showMature??x,i=new URLSearchParams;h.trim()&&i.set("query",h.trim()),s!=="ALL"&&i.set("type",s),l&&i.set("status",l),q!=="ALL"&&i.set("season",q),H!=="ALL"&&i.set("year",H),J!=="ALL"&&i.set("country",J),K!=="POPULARITY_DESC"&&i.set("sortBy",K);const X=Object.entries(Q).filter(([,d])=>d==="include").map(([d])=>d),Z=Object.entries(Q).filter(([,d])=>d==="exclude").map(([d])=>d);X.length>0&&i.set("genres",X.join(",")),Z.length>0&&i.set("excludeGenres",Z.join(",")),s!=="ADULT"&&!pe&&i.set("adult","false"),i.set("provider","anilist"),e>1&&i.set("page",e.toString()),te(i),e!==p&&_(e)},W=e=>{if(c(e),P.current){const n=P.current.getBoundingClientRect().top+window.scrollY-100;window.scrollTo({top:n,behavior:"smooth"})}},R=new Date().getFullYear(),he=[{value:"ALL",label:"All Years"},...Array.from({length:R-1980+1},(e,n)=>({value:String(R-n),label:String(R-n)}))],z=f.length>=14&&j&&j.length>0;return a("div",{className:"page-container",children:[a("div",{className:t.header,children:[a("h1",{className:t.pageTitle,children:"Search Anime"}),a("p",{className:t.pageSubtitle,children:"Search through thousands of titles and discover your next favorite"})]}),a("div",{className:t.filterContainer,children:[a("div",{className:t.searchBarWrapper,children:[a("div",{className:t.inputIconWrapper,children:[a(L,{name:"search",className:t.searchIcon}),a("input",{type:"text","data-virtual-keyboard":"true",className:t.searchInput,placeholder:"Search by title, character, or studio...",value:h,onInput:e=>k(e.currentTarget.value),onKeyDown:e=>e.key==="Enter"&&c()})]}),a("div",{className:t.searchActions,children:[a(w,{onClick:()=>c(),className:t.searchBtn,children:"Search"}),a("button",{className:`${t.filterToggleBtn} ${S?t.active:""}`,onClick:()=>re(!S),children:[a(L,{name:"filter",size:14}),a("span",{children:"Filters"}),S?a(L,{name:"chevron-up",size:12}):a(L,{name:"chevron-down",size:12})]})]})]}),a("div",{className:`${t.advancedFilters} ${S?t.show:""}`,children:[a("div",{className:t.filterDivider}),a("div",{className:t.filterGrid,children:[a("div",{className:t.filterItem,children:[a("label",{children:"Type"}),a("select",{value:u,onChange:e=>{if(e.currentTarget.value==="ADULT"){le("/mature?provider=mal");return}A(e.currentTarget.value)},children:Te.map(e=>a("option",{value:e.value,children:e.label},e.value))})]}),a("div",{className:t.filterItem,children:[a("label",{children:"Status"}),a("select",{value:U,onChange:e=>D(e.currentTarget.value),children:[a("option",{value:"",children:"All Status"}),Pe.map(e=>a("option",{value:e.value,children:e.label},e.value))]})]}),a("div",{className:t.filterItem,children:[a("label",{children:"Season"}),a("select",{value:m,onChange:e=>b(e.currentTarget.value),children:Ee.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:g,onChange:e=>y(e.currentTarget.value),children:he.map(e=>a("option",{value:e.value,children:e.label},e.value))})]}),a("div",{className:t.filterItem,children:[a("label",{children:["Country",se===!1&&a("span",{style:{display:"block",fontSize:"0.75rem",color:"var(--text-muted)",fontWeight:400},children:"AniList only — ignored by fallback providers"})]}),a("select",{value:B,onChange:e=>E(e.currentTarget.value),children:Ie.map(e=>a("option",{value:e.value,children:e.label},e.value))})]}),a("div",{className:t.filterItem,children:[a("label",{children:"Sort By"}),a("select",{value:Y,onChange:e=>I(e.currentTarget.value),children:De.map(e=>a("option",{value:e.value,children:e.label},e.value))})]})]}),M.length>0&&a("div",{className:t.genreSection,children:[a("label",{className:t.genreLabel,children:"Genres"}),a("div",{className:t.genreContainer,children:M.map(e=>a("button",{className:`${t.genreButton} ${t[v[e]||""]}`,onClick:()=>{N(n=>{const s=n[e],l={...n};return s==="include"?l[e]="exclude":s==="exclude"?delete l[e]:l[e]="include",l})},children:e},e))})]}),a("div",{className:t.filterActions,children:[a(w,{variant:"secondary",onClick:()=>{N({}),A("ALL"),b("ALL"),y("ALL"),E("ALL"),I("POPULARITY_DESC"),D(""),de(!1),c(1,{type:"ALL",status:"",season:"ALL",year:"ALL",country:"ALL",sort:"POPULARITY_DESC",genreState:{},showMature:!1})},children:"Reset All"}),a(w,{onClick:()=>c(),className:t.applyBtn,children:"Apply Filters"})]})]})]}),ce&&a(Ce,{message:ue?.message||"Error"}),(u!=="ALL"||m!=="ALL"||g!=="ALL"||Object.keys(v).length>0)&&a("div",{style:{display:"flex",flexWrap:"wrap",gap:"8px",alignItems:"center",marginBottom:"1.5rem"},children:[a("span",{style:{fontSize:"0.8rem",color:"var(--text-muted)",fontWeight:600},children:"Active Filters:"}),u!=="ALL"&&a("span",{className:"badge badge-secondary",style:{display:"inline-flex",alignItems:"center",gap:"6px"},children:["Type: ",u,a("button",{onClick:e=>{e.stopPropagation(),e.preventDefault(),A("ALL"),c(1,{type:"ALL"})},style:{background:"none",border:"none",color:"inherit",cursor:"pointer"},children:"✕"})]}),m!=="ALL"&&a("span",{className:"badge badge-secondary",style:{display:"inline-flex",alignItems:"center",gap:"6px"},children:["Season: ",m,a("button",{onClick:e=>{e.stopPropagation(),e.preventDefault(),b("ALL"),c(1,{season:"ALL"})},style:{background:"none",border:"none",color:"inherit",cursor:"pointer"},children:"✕"})]}),g!=="ALL"&&a("span",{className:"badge badge-secondary",style:{display:"inline-flex",alignItems:"center",gap:"6px"},children:["Year: ",g,a("button",{onClick:e=>{e.stopPropagation(),e.preventDefault(),y("ALL"),c(1,{year:"ALL"})},style:{background:"none",border:"none",color:"inherit",cursor:"pointer"},children:"✕"})]}),Object.entries(v).map(([e,n])=>a("span",{className:`badge ${n==="include"?"badge-primary":"badge-danger"}`,style:{display:"inline-flex",alignItems:"center",gap:"6px"},children:[n==="include"?`+ ${e}`:`- ${e}`,a("button",{onClick:s=>{s.stopPropagation(),s.preventDefault();const l={...v};delete l[e],N(l),c(1,{genreState:l})},style:{background:"none",border:"none",color:"inherit",cursor:"pointer"},children:"✕"})]},e))]}),a("div",{className:t.resultsHeader,ref:P,children:[a("h2",{className:t.resultsTitle,children:h?`Search Results for "${h}"`:"Discover Anime"}),T.length>0&&a(ee,{page:p,canGoNext:z,onChange:W,isLoading:C})]}),a("div",{className:`${t.resultsGrid} ${ie?t.lowEnd:""}`,children:C?a(Le,{}):T.map(e=>a(Ae,{anime:e},e._id))}),!C&&T.length===0&&a("div",{className:t.noResults,children:[a(L,{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(ee,{page:p,canGoNext:z,onChange:W,isLoading:C,variant:"labeled"})})]})}export{Ve as default};
@@ -0,0 +1,21 @@
1
+ import{d as s,A as V,h as O,u as e,q as ae,S as te,T as De,o as Ie,a as Le,g as me,_ as xe}from"./vendor-core-8R2fFbyN.js";import{d as Pe,t as _,B as I,M as K,i as we,g as Ae,T as H,z as pe,E as oe,F as Oe,G as Ue,u as Me,H as Ee,x as ye,y as $e,I as Ge,J as Ke,V as Fe,K as He,L as Be,N as ze}from"./index-BXwhFWB_.js";import{u as ue}from"./vendor-query-BUTye89G.js";import{I as W}from"./vendor-icons-CDMuNDeL.js";const ce={"title-preference-container":"_title-preference-container_sdqgs_1","toggle-button":"_toggle-button_sdqgs_21","toggle-label":"_toggle-label_sdqgs_51"},le=["name","nativeName","englishName"],de={name:"Default (Romaji)",nativeName:"Native",englishName:"English"},qe=()=>{const{titlePreference:t,setTitlePreference:r,loading:i}=Pe(),[c,h]=s(de[t]),[d,k]=s(!1),m=V(null);O(()=>{i||h(de[t])},[t,i]);const a=async()=>{if(d)return;k(!0);const f=(le.indexOf(t)+1)%le.length,p=le[f],l=de[p];m.current&&(m.current.style.transform="translateX(-100%)",m.current.style.opacity="0"),setTimeout(async()=>{h(l),r(p),m.current&&(m.current.style.transition="none",m.current.style.transform="translateX(100%)",m.current.style.opacity="0",m.current.offsetWidth,m.current.style.transition="transform 0.3s ease-out, opacity 0.3s ease-out",m.current.style.transform="translateX(0)",m.current.style.opacity="1");try{await _.settings.set.mutate({key:"titlePreference",value:p})}catch(T){console.error("Error saving title preference:",T)}finally{k(!1)}},300)};return i?e("p",{children:"Loading title preference..."}):e("div",{className:ce["title-preference-container"],children:[e("h4",{children:"Anime Title Display Preference"}),e("button",{onClick:a,className:ce["toggle-button"],disabled:d,children:e("span",{ref:m,className:ce["toggle-label"],children:c})})]})},je="_settingsHeader_14a5d_1",We="_pageTitle_14a5d_6",Ve="_pageSubtitle_14a5d_14",Ye="_settingsLayout_14a5d_20",Qe="_sidebar_14a5d_27",Je="_sidebarIndicator_14a5d_35",Xe="_sidebarItem_14a5d_50",Ze="_active_14a5d_72",et="_mainContent_14a5d_80",tt="_tabContent_14a5d_85",at="_sectionCard_14a5d_103",nt="_settingItem_14a5d_127",rt="_settingRow_14a5d_132",st="_controls_14a5d_145",it="_status_14a5d_151",g={settingsHeader:je,pageTitle:We,pageSubtitle:Ve,settingsLayout:Ye,sidebar:Qe,sidebarIndicator:Je,sidebarItem:Xe,active:Ze,mainContent:et,tabContent:tt,sectionCard:at,settingItem:nt,settingRow:rt,controls:st,status:it},ot="_sectionCard_wt900_12",ct="_title_wt900_22",lt="_signIn_wt900_29",dt="_userInfo_wt900_36",ut="_warning_wt900_58",ht="_formGroup_wt900_65",gt="_label_wt900_69",mt="_inputWrapper_wt900_79",pt="_input_wt900_79",yt="_select_wt900_103",ft="_actions_wt900_140",wt="_hr_wt900_148",y={sectionCard:ot,title:ct,signIn:lt,userInfo:dt,warning:ut,formGroup:ht,label:gt,inputWrapper:mt,input:pt,select:yt,actions:ft,hr:wt},vt=()=>{const[t,r]=s(!0),[i,c]=s(!1),[h,d]=s(!1),[k,m]=s(null),[a,u]=s({status:"idle"}),[f,p]=s(!1),[l,T]=s(""),[w,S]=s(!1),D=V(null),[L,x]=s({show:!1,message:"",type:"info"}),U=()=>{D.current&&(window.clearInterval(D.current),D.current=null)},C=ae(N=>{d(N.authenticated),m(N.user||N.device.user||null),u(N.device),p(!!N.hasCustomClientId)},[]),R=ae(async()=>{const N=await _.auth.githubStatus.query();C(N)},[C]),E=async()=>{try{const N=await _.auth.githubPoll.query();u(N),N.status==="success"?(U(),await R(),x({show:!0,message:"GitHub authentication complete. Sync has been initialized.",type:"success"})):N.status==="error"&&(U(),x({show:!0,message:N.error||"GitHub authentication failed.",type:"error"}))}catch{U(),x({show:!0,message:"Failed to poll GitHub authentication status.",type:"error"})}},v=(N=5)=>{U(),D.current=window.setInterval(E,Math.max(N,5)*1e3)};O(()=>(R().catch(()=>{x({show:!0,message:"Failed to load GitHub sync status.",type:"error"})}).finally(()=>r(!1)),U),[R]);const b=async()=>{c(!0);try{const N=await _.auth.githubStart.mutate();u(N),v(N.verification?.interval)}catch(N){x({show:!0,message:N instanceof Error?N.message:"Failed to start GitHub authentication.",type:"error"})}finally{c(!1)}},A=async()=>{try{await _.auth.githubLogout.mutate(),d(!1),m(null),u({status:"idle"}),x({show:!0,message:"Signed out of GitHub sync.",type:"success"})}catch{x({show:!0,message:"Failed to sign out of GitHub.",type:"error"})}},M=async()=>{S(!0);try{await _.auth.saveGithubAuth.mutate({clientId:l}),T(""),await R(),x({show:!0,message:"Custom GitHub auth saved.",type:"success"})}catch{x({show:!0,message:"Failed to save override.",type:"error"})}finally{S(!1)}},z=async()=>{S(!0);try{await _.auth.saveGithubAuth.mutate({clientId:""}),T(""),await R(),x({show:!0,message:"Custom auth cleared. Using dango defaults.",type:"success"})}catch{x({show:!0,message:"Failed to clear override.",type:"error"})}finally{S(!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."}),h&&k?e("div",{className:y.userInfo,children:[e("p",{children:["Signed in as: ",e("strong",{children:k.name||k.login})]}),e(I,{variant:"danger",onClick:A,children:"Sign Out"})]}):e("div",{className:y.signIn,children:e(I,{onClick:b,disabled:i||a.status==="pending",children:i||a.status==="pending"?"Waiting for GitHub...":"Sign in with GitHub"})}),a.status==="pending"&&a.verification&&e(te,{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:a.verification.verification_uri,readOnly:!0}),e(I,{onClick:()=>{const N=a.verification?.verification_uri;N&&/^https?:\/\//i.test(N)&&window.open(N,"_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:a.verification.user_code,readOnly:!0})]})]}),a.status==="error"&&e("p",{className:y.warning,children:a.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 ",f?"(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:l,onChange:N=>T(N.currentTarget.value),placeholder:"Your GitHub OAuth app ID"})]}),e("div",{className:y.actions,children:[e(I,{onClick:M,disabled:w,children:"Save override"}),e(I,{variant:"secondary",onClick:z,disabled:w,children:"Use dango defaults"})]})]}),e(K,{isOpen:L.show,onClose:()=>x(N=>({...N,show:!1})),width:"sm",children:[e(K.Body,{children:e("p",{children:L.message})}),e(K.Actions,{children:e(I,{onClick:()=>x(N=>({...N,show:!1})),children:"OK"})})]})]})},bt=()=>{const[t,r]=s(!0),[i,c]=s(null),[h,d]=s(!1),[k,m]=s(!1),[a,u]=s(""),[f,p]=s(""),[l,T]=s(""),[w,S]=s(!1),[D,L]=s({show:!1,message:"",type:"info"}),x=async()=>{try{const b=await _.auth.user.query();c(b?.email?b:null)}catch{c(null)}},U=async()=>{try{const[b,A]=await Promise.all([_.auth.configStatus.query(),_.auth.googleAuth.query()]);d(!!b.hasConfig),m(!!(A.hasCustomWorkerUrl||A.hasCustomClientId||A.hasClientSecret))}catch(b){console.error("Failed to fetch config status",b)}};O(()=>{(async()=>{r(!0),await Promise.all([x(),U()]);try{new URLSearchParams(window.location.search).get("google_auth")==="success"&&(await x(),window.history.replaceState(null,"",window.location.pathname))}catch{}r(!1)})();const A=M=>{M.origin===window.location.origin&&typeof M.data=="object"&&M.data!==null&&M.data.type==="GOOGLE_AUTH_SUCCESS"&&(c(M.data.user),window.location.reload())};return window.addEventListener("message",A),()=>window.removeEventListener("message",A)},[]);const C=async()=>{try{const b=await _.auth.googleLogin.mutate();if(b.authenticated){window.location.reload();return}if(b.url){if(typeof window.DangoBridge<"u"){window.location.href=b.url;return}const M=600,z=700,N=window.innerWidth/2-M/2,ne=window.innerHeight/2-z/2;window.open(b.url,"GoogleAuth",`width=${M},height=${z},top=${ne},left=${N}`)}else throw new Error("Auth URL not available")}catch{L({show:!0,message:"Authentication failed. Ensure server is configured correctly.",type:"error"})}},R=async()=>{try{await _.auth.logout.mutate(),c(null),L({show:!0,message:"Successfully signed out.",type:"success"}),window.location.reload()}catch(b){console.error("Sign out failed",b),L({show:!0,message:"Failed to sign out.",type:"error"})}},E=async()=>{S(!0);try{await _.auth.saveGoogleAuth.mutate({workerUrl:a,clientId:f,clientSecret:l}),u(""),p(""),T(""),await U(),L({show:!0,message:"Custom auth saved. Restart may be required.",type:"success"})}catch{L({show:!0,message:"Failed to save override.",type:"error"})}finally{S(!1)}},v=async()=>{S(!0);try{await _.auth.saveGoogleAuth.mutate({workerUrl:"",clientId:"",clientSecret:""}),u(""),p(""),T(""),await U(),L({show:!0,message:"Custom auth cleared. Using dango defaults.",type:"success"})}catch{L({show:!0,message:"Failed to clear override.",type:"error"})}finally{S(!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"}),i?e("div",{className:y.userInfo,children:[e("p",{children:["Signed in as: ",e("strong",{children:i.name})," (",i.email,")"]}),e(I,{variant:"danger",onClick:R,children:"Sign Out"})]}):e("div",{className:y.signIn,children:[e("p",{children:"Sign in with your Google account to enable synchronization features."}),e(I,{onClick:C,disabled:!h,children:"Sign in with Google"}),!h&&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 ",k?"(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:a,onChange:b=>u(b.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:f,onChange:b=>p(b.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:l,onChange:b=>T(b.currentTarget.value),placeholder:"Your Google OAuth secret"})]}),e("div",{className:y.actions,children:[e(I,{onClick:E,disabled:w,children:"Save override"}),e(I,{variant:"secondary",onClick:v,disabled:w,children:"Use dango defaults"})]})]}),e(K,{isOpen:D.show,onClose:()=>L(b=>({...b,show:!1})),width:"sm",children:[e(K.Body,{children:e("p",{children:D.message})}),e(K.Actions,{children:e(I,{onClick:()=>L(b=>({...b,show:!1})),children:"OK"})})]})]})},_t="_sectionCard_1pqo4_1",kt="_settingItem_1pqo4_26",St="_settingRow_1pqo4_31",Ct="_modalOverlay_1pqo4_38",Nt="_modal_1pqo4_38",Tt="_modalActions_1pqo4_73",Rt="_modalSecondary_1pqo4_79",Dt="_modalPrimary_1pqo4_89",G={sectionCard:_t,settingItem:kt,settingRow:St,modalOverlay:Ct,modal:Nt,modalActions:Tt,modalSecondary:Rt,modalPrimary:Dt},It={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"]]}},Lt=(t,r)=>{if(t==null)return r;const i=String(t);return i==="true"||i==="1"?!0:i==="false"||i==="0"?!1:r},fe=(t,r,i)=>{const[c,h]=s(r),[d,k]=s(!1),m=ue();return O(()=>{(async()=>{try{const f=await _.settings.getByKey.query({key:t});h(Lt(f.value,r))}catch(f){console.error("Failed to fetch setting",f)}})()},[t,r]),{value:c,setValue:h,isUpdating:d,toggle:async()=>{if(d)return;k(!0);const u=!c;h(u);try{await _.settings.set.mutate({key:t,value:u});for(const f of i)m.invalidateQueries({queryKey:f})}catch(f){console.error("Error saving setting:",f),h(!u)}finally{k(!1)}}}},xt=()=>{const{contentType:t}=we(),r=It[t],[i,c]=s(!1),[h,d]=s(!0),[k,m]=s(!1),a=fe(r.ignoreKey,!0,r.invalidateKeys),u=fe(r.listOnlyKey,!1,r.invalidateKeys),[f,p]=s(null),[l,T]=s(!1),w=ue(),S=Ae();O(()=>{d(!0),(async()=>{try{const R=await _.settings.getByKey.query({key:r.skipKey});String(R.value)==="true"||String(R.value)==="1"?c(!0):c(!1)}catch(R){console.error("Failed to fetch setting",R)}finally{d(!1)}})()},[r.skipKey]);const D=async()=>{if(k)return;m(!0);const C=!i;c(C);try{await _.settings.set.mutate({key:r.skipKey,value:C})}catch(R){console.error("Error saving setting:",R),c(!C)}finally{m(!1)}},L=async()=>{if(!a.isUpdating){if(a.value)try{let C;if(t==="anime"?C=(await _.continueWatching.adultCount.query()).count:t==="manga"?C=(await _.mangaProgress.adultCount.query()).count:t==="asmr"?C=(await _.asmrProgress.adultCount.query()).count:C=(await _.tvProgress.adultCount.query()).count,typeof C=="number"&&C>0){p(C);return}}catch(C){console.error("Failed to fetch adult count",C)}a.toggle()}},x=()=>{p(null),a.toggle()},U=async()=>{if(!l){T(!0);try{let C;t==="anime"?C=(await _.continueWatching.purgeAdult.mutate()).removed:t==="manga"?C=(await _.mangaProgress.purgeAdult.mutate()).removed:t==="asmr"?C=(await _.asmrProgress.purgeAdult.mutate()).removed:C=(await _.tvProgress.purgeAdult.mutate()).removed,pe.success(r.purgeDoneText(C??0));for(const R of r.invalidateKeys)w.invalidateQueries({queryKey:R});t==="anime"&&w.invalidateQueries(S.continueWatching.pathFilter()),t==="manga"&&w.invalidateQueries(S.mangaProgress.pathFilter()),t==="asmr"&&w.invalidateQueries(S.asmrProgress.pathFilter()),t==="tv"&&w.invalidateQueries(S.tvProgress.pathFilter())}catch(C){console.error("Failed to purge adult entries",C),pe.error("Failed to remove adult entries")}finally{T(!1),p(null)}a.toggle()}};return h?e("div",{children:"Loading settings..."}):e("div",{className:G.sectionCard,children:[e("h3",{children:r.heading}),e("p",{children:r.blurb}),e("div",{className:G.settingItem,children:e("div",{className:G.settingRow,children:[e("label",{htmlFor:"skip-confirmation-toggle",children:r.skipLabel}),e(H,{isChecked:i,onChange:D,id:"skip-confirmation-toggle",disabled:k})]})}),e("div",{className:G.settingItem,children:e("div",{className:G.settingRow,children:[e("label",{htmlFor:"ignore-adult-toggle",children:r.ignoreLabel}),e(H,{isChecked:a.value,onChange:L,id:"ignore-adult-toggle",disabled:a.isUpdating})]})}),e("div",{className:G.settingItem,children:e("div",{className:G.settingRow,children:[e("label",{htmlFor:"cw-watchlist-only-toggle",children:r.listOnlyLabel}),e(H,{isChecked:u.value,onChange:u.toggle,id:"cw-watchlist-only-toggle",disabled:u.isUpdating})]})}),f!==null&&e("div",{className:G.modalOverlay,onClick:()=>p(null),children:e("div",{className:G.modal,onClick:C=>C.stopPropagation(),children:[e("h4",{children:"Show adult entries?"}),e("p",{children:[f," adult ",f===1?"entry":"entries"," not in your"," ",r.listNoun," ",f===1?"is":"are"," currently hidden from"," ",r.continueNoun,". You can purge ",f===1?"it":"them"," from the database instead of showing ",f===1?"it":"them","."]}),e("div",{className:G.modalActions,children:[e("button",{type:"button",className:G.modalSecondary,onClick:x,disabled:l,children:"Show them"}),e("button",{type:"button",className:G.modalPrimary,onClick:U,disabled:l,children:l?"Purging...":`Purge ${f}`})]})]})})]})},Pt="_sectionCard_jkggs_1",At="_statsGrid_jkggs_26",Ot="_statCard_jkggs_33",Ut="_statLabel_jkggs_43",Mt="_statValue_jkggs_51",Et="_statMeta_jkggs_57",$t="_statusBanner_jkggs_63",Gt="_statusSuccess_jkggs_74",Kt="_statusUpdating_jkggs_80",Ft="_statusError_jkggs_86",Ht="_sha_jkggs_92",Bt="_settingItem_jkggs_99",zt="_settingRow_jkggs_104",qt="_settingTitle_jkggs_111",jt="_settingSubtitle_jkggs_117",Wt="_actionsRow_jkggs_124",P={sectionCard:Pt,statsGrid:At,statCard:Ot,statLabel:Ut,statValue:Mt,statMeta:Et,statusBanner:$t,statusSuccess:Gt,statusUpdating:Kt,statusError:Ft,sha:Ht,settingItem:Bt,settingRow:zt,settingTitle:qt,settingSubtitle:jt,actionsRow:Wt},Vt=()=>{const[t,r]=s(null),[i,c]=s(!0),[h,d]=s(!1),[k,m]=s(!1),a=V(null),u=async()=>{try{const w=await _.settings.offlineDbInfo.query();return r(w),w}catch(w){console.error("Failed to fetch offline DB info:",w)}finally{c(!1)}return null};O(()=>(u(),()=>{a.current&&window.clearInterval(a.current)}),[]),O(()=>{t?.isRefreshing?a.current||(a.current=window.setInterval(async()=>{const w=await u();w&&!w.isRefreshing&&a.current&&(window.clearInterval(a.current),a.current=null)},2e3)):a.current&&(window.clearInterval(a.current),a.current=null)},[t?.isRefreshing]);const f=async()=>{if(!t||h)return;const w=!t.autoUpdateEnabled;d(!0),r({...t,autoUpdateEnabled:w});try{await _.settings.setOfflineDbAutoUpdate.mutate({enabled:w})}catch(S){console.error("Failed to update auto update setting:",S),r({...t,autoUpdateEnabled:!w})}finally{d(!1)}},p=async()=>{if(!(t?.isRefreshing||k)){m(!0);try{await _.settings.triggerOfflineDbUpdate.mutate(),r(w=>w?{...w,isRefreshing:!0,lastStatus:"updating",lastMessage:"Downloading database..."}:null)}catch(w){console.error("Failed to trigger offline DB update:",w)}finally{m(!1)}}},l=w=>{if(!w)return"Never";try{return new Date(w).toLocaleString(void 0,{dateStyle:"medium",timeStyle:"short"})}catch{return w}},T=t?.isRefreshing||k;return e("div",{className:P.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:P.statsGrid,children:[e("div",{className:P.statCard,children:[e("span",{className:P.statLabel,children:"MAL Mapped"}),e("span",{className:P.statValue,children:i?"—":(t?.totalMalMapped??0).toLocaleString()})]}),e("div",{className:P.statCard,children:[e("span",{className:P.statLabel,children:"Release"}),e("span",{className:P.statMeta,children:i?"—":t?.releaseTag??"Never"})]}),e("div",{className:P.statCard,children:[e("span",{className:P.statLabel,children:"Last Checked"}),e("span",{className:P.statMeta,children:i?"—":l(t?.lastCheckedAt??null)})]}),e("div",{className:P.statCard,children:[e("span",{className:P.statLabel,children:"Last Updated"}),e("span",{className:P.statMeta,children:i?"—":l(t?.lastUpdatedAt??null)})]})]}),t?.lastMessage&&e("div",{className:`${P.statusBanner} ${t.lastStatus==="failed"?P.statusError:t.lastStatus==="updating"?P.statusUpdating:P.statusSuccess}`,children:[e("span",{children:t.lastMessage}),t.contentSha256&&e("span",{className:P.sha,children:["sha:",t.contentSha256.slice(0,12)]})]}),e("div",{className:P.settingItem,children:e("div",{className:P.settingRow,children:[e("div",{children:[e("span",{className:P.settingTitle,children:"Weekly Automatic Updates (Saturdays)"}),e("div",{className:P.settingSubtitle,children:"Download and index new database releases in the background. Catches up on startup if the server was offline."})]}),e(H,{id:"offline-db-auto-update-toggle",isChecked:t?t.autoUpdateEnabled:!0,onChange:f,disabled:i||h})]})}),e("div",{className:P.actionsRow,children:e(I,{onClick:p,disabled:i||T,children:T?"Updating Database...":"Update Offline Database Now"})})]})},Yt="_sectionCard_1g4qx_1",Qt="_dangerCard_1g4qx_26",Jt="_status_1g4qx_34",Xt="_warningText_1g4qx_40",Zt="_ackLabel_1g4qx_44",ee={sectionCard:Yt,dangerCard:Qt,status:Jt,warningText:Xt,ackLabel:Zt},ea=()=>{const t=ue(),[r,i]=s(!1),[c,h]=s(!1),[d,k]=s(!1),[m,a]=s(""),u=()=>{h(!1),a(""),i(!0)},f=()=>{d||(i(!1),h(!1))},p=async()=>{if(!(!c||d)){k(!0),a("");try{const l=await fetch("/api/database/clear",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({confirm:!0})}),T=await l.json();if(!l.ok)throw new Error(T.error||"Failed to clear database");const w=T.deleted,S=T.deletedManga,D=T.deletedTv,L=T.deletedAsmr,x=Object.values(w).reduce((E,v)=>E+(v||0),0)+Object.values(S??{}).reduce((E,v)=>E+(v||0),0)+Object.values(D??{}).reduce((E,v)=>E+(v||0),0)+Object.values(L??{}).reduce((E,v)=>E+(v||0),0),U=(S?.manga_library??0)+(S?.manga_progress??0),C=(D?.tv_library??0)+(D?.tv_progress??0),R=(L?.asmr_library??0)+(L?.asmr_progress??0);a(`Library cleared — ${w.watchlist??0} watchlist entries, ${U} manga rows, ${C} TV rows, ${R} ASMR rows and ${x} 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"]}),i(!1)}catch(l){a(l.message)}finally{k(!1),h(!1)}}};return e("div",{className:`${ee.sectionCard} ${ee.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(I,{variant:"danger",onClick:u,children:"Clear Library Data"}),m&&e("p",{className:ee.status,children:m}),e(K,{isOpen:r,onClose:f,title:"Clear library data?",width:"sm",children:[e(K.Body,{children:[e("p",{className:ee.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:ee.ackLabel,children:[e("input",{type:"checkbox",checked:c,onChange:l=>h(l.target.checked),disabled:d}),e("span",{children:"I understand this permanently deletes my library"})]})]}),e(K.Actions,{children:[e(I,{variant:"secondary",onClick:f,disabled:d,children:"Cancel"}),e(I,{variant:"danger",onClick:p,disabled:!c||d,children:d?"Clearing...":"Yes, delete everything"})]})]})]})},ta=()=>{const[t,r]=s(""),[i,c]=s([]),[h,d]=s(null),[k,m]=s(!0),[a,u]=s({show:!1,message:"",type:"info"}),f=async()=>{try{m(!0);const T=await(await fetch("/api/auth/settings/rclone")).json();r(T.remote||""),c(T.availableRemotes||[]),d(T.activeRemote||null)}catch(l){console.error("Failed to fetch Rclone settings",l)}finally{m(!1)}};O(()=>{f()},[]);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"}),f();else throw new Error("Failed to save")}catch{u({show:!0,message:"Failed to save Rclone configuration.",type:"error"})}};return k?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."}),h?e("div",{className:y.userInfo,children:e("p",{children:["Current Active Remote: ",e("strong",{children:h})]})}):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:l=>r(l.target.value),children:[e("option",{value:"",children:"(Disabled / None)"}),i.map(l=>e("option",{value:l,children:l},l)),t&&!i.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(I,{onClick:p,children:"Save Rclone Settings"})}),e(K,{isOpen:a.show,onClose:()=>u(l=>({...l,show:!1})),width:"sm",children:[e(K.Body,{children:e("p",{children:a.message})}),e(K.Actions,{children:e(I,{onClick:()=>u(l=>({...l,show:!1})),children:"OK"})})]})]})},aa=()=>{const[t,r]=s(null),[i,c]=s(!0),h=async()=>{try{const u=await(await fetch("/api/auth/settings/sync")).json();r(u)}catch(a){console.error("Failed to fetch sync settings",a)}finally{c(!1)}};O(()=>{h()},[]);const d=async a=>{const u=a.target.value;try{const f=await fetch("/api/auth/settings/sync",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({provider:u})});if(f.ok){const p=await f.json();r(l=>l?{...l,activeProvider:p.activeProvider}:null),await h(),oe.success(`Sync provider updated to ${u==="default"?"Default Order":u}`)}else oe.error("Failed to update sync provider")}catch{oe.error("Error updating sync provider")}};if(i||!t)return null;const k=[{value:"default",label:"Default (Priority Based)"}];t.authenticatedProviders.github&&k.push({value:"github",label:"GitHub"}),t.authenticatedProviders.google&&k.push({value:"google",label:"Google Drive"}),t.authenticatedProviders.rclone&&k.push({value:"rclone",label:"Rclone"}),k.push({value:"none",label:"None (Local Only)"});const m=a=>a==="none"?"Local Only (No Sync)":a==="google"?"Google Drive":a==="github"?"GitHub":a==="rclone"?"Rclone":a;return e("div",{className:g.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:m(t.actualActiveProvider)})]}),e("div",{className:g.settingRow,children:[e("label",{htmlFor:"sync-provider-select",children:"Selected Preference"}),e("select",{id:"sync-provider-select",value:t.activeProvider,onChange:d,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:k.map(a=>e("option",{value:a.value,children:a.label},a.value))})]})]})};function na(){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 ra=()=>{const t=De(na,[]);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:c=>{c.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(W,{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(I,{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.`})]})},sa="_sectionCard_1ag4p_1",ia="_settingItem_1ag4p_25",oa="_field_1ag4p_30",ca="_input_1ag4p_43",la="_actions_1ag4p_63",da="_status_1ag4p_69",B={sectionCard:sa,settingItem:ia,field:oa,input:ca,actions:la,status:da},ua=()=>{const[t,r]=s(!1),[i,c]=s(""),[h,d]=s(""),[k,m]=s(!0),[a,u]=s(!1),[f,p]=s("");O(()=>{(async()=>{try{const L=await(await fetch("/api/auth/app-status")).json();r(L.hasPassword)}catch{console.error("Failed to fetch LAN auth status")}finally{m(!1)}})()},[]);const l=async()=>{if(p(""),i!==h){p("Passwords do not match");return}if(i.length<4){p("Password must be at least 4 characters");return}u(!0);try{const S=await fetch("/api/auth/app-setup",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({password:i})}),D=await S.json();if(!S.ok){p(D.error||"Failed to update password");return}r(D.hasPassword),c(""),d(""),p(D.hasPassword?"Password set successfully":"Password removed")}catch{p("Network error")}finally{u(!1)}},T=async()=>{u(!0);try{const S=await fetch("/api/auth/app-setup",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({password:""})}),D=await S.json();if(!S.ok){p(D.error||"Failed to remove password");return}r(!1),c(""),d(""),p("Password removed")}catch{p("Network error")}finally{u(!1)}},w=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 k?e("div",{className:B.sectionCard,children:e("p",{children:"Loading..."})}):e("div",{className:B.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:B.settingItem,children:[e("div",{className:B.field,children:[e("label",{htmlFor:"lan-password",children:"New Password"}),e("input",{id:"lan-password",type:"password",value:i,onChange:S=>c(S.target.value),placeholder:t?"Leave empty to keep current password":"Enter a password...",className:B.input})]}),e("div",{className:B.field,children:[e("label",{htmlFor:"lan-confirm-password",children:"Confirm Password"}),e("input",{id:"lan-confirm-password",type:"password",value:h,onChange:S=>d(S.target.value),placeholder:"Confirm password...",className:B.input})]}),e("div",{className:B.actions,children:[e(I,{variant:"primary",onClick:l,loading:a,disabled:a,children:t?"Update Password":"Set Password"}),t&&e(I,{variant:"danger",onClick:w,loading:a,disabled:a,children:"Logout"}),t&&e(I,{variant:"secondary",onClick:T,loading:a,disabled:a,children:"Remove Password"})]}),f&&e("p",{className:B.status,children:f})]})]})},ha=()=>{const{theme:t,setTheme:r,loading:i}=Oe();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:Ue.map(c=>{const h=t===c.id;return e("button",{role:"radio","aria-checked":h,disabled:i,onClick:()=>r(c.id),style:{display:"flex",gap:"0.6rem",alignItems:"center",textAlign:"left",padding:"0.65rem 0.75rem",borderRadius:"10px",cursor:"pointer",background:h?"var(--accent-subtle)":"var(--bg-tertiary)",border:h?"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:c.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:c.label}),e("span",{style:{display:"block",fontSize:"0.75rem",color:"var(--text-secondary)",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"},children:c.blurb})]})]},c.id)})})]})},ga="_card_13wyw_1",ma="_cardHeader_13wyw_9",pa="_discordBadge_13wyw_16",ya="_cardTitle_13wyw_27",fa="_cardSub_13wyw_34",wa="_description_13wyw_40",va="_divider_13wyw_47",ba="_statsRow_13wyw_54",_a="_statBox_13wyw_61",ka="_statValue_13wyw_71",Sa="_statLabel_13wyw_78",Ca="_rolePreview_13wyw_86",Na="_badge_13wyw_93",Ta="_badgeRank_13wyw_100",Ra="_badgeDere_13wyw_106",Da="_progressSection_13wyw_112",Ia="_progressLabel_13wyw_116",La="_progressTrack_13wyw_124",xa="_progressFill_13wyw_132",Pa="_tierList_13wyw_139",Aa="_dereSection_13wyw_147",Oa="_sectionHeading_13wyw_152",Ua="_dereGrid_13wyw_161",Ma="_dereCard_13wyw_167",Ea="_dereCardActive_13wyw_178",$a="_dereName_13wyw_184",Ga="_dereGenre_13wyw_194",Ka="_actions_13wyw_199",Fa="_btnPrimary_13wyw_205",Ha="_btnSecondary_13wyw_234",Ba="_statusMsg_13wyw_257",za="_statusSuccess_13wyw_264",qa="_statusError_13wyw_270",ja="_statusInfo_13wyw_276",Wa="_userRow_13wyw_283",Va="_avatar_13wyw_294",Ya="_avatarPlaceholder_13wyw_302",Qa="_userName_13wyw_314",Ja="_userId_13wyw_320",Xa="_notice_13wyw_325",Za="_shareList_13wyw_332",en="_btnUnlink_13wyw_340",o={card:ga,cardHeader:ma,discordBadge:pa,cardTitle:ya,cardSub:fa,description:wa,divider:va,statsRow:ba,statBox:_a,statValue:ka,statLabel:Sa,rolePreview:Ca,badge:Na,badgeRank:Ta,badgeDere:Ra,progressSection:Da,progressLabel:Ia,progressTrack:La,progressFill:xa,tierList:Pa,dereSection:Aa,sectionHeading:Oa,dereGrid:Ua,dereCard:Ma,dereCardActive:Ea,dereName:$a,dereGenre:Ga,actions:Ka,btnPrimary:Fa,btnSecondary:Ha,statusMsg:Ba,statusSuccess:za,statusError:qa,statusInfo:ja,userRow:Wa,avatar:Va,avatarPlaceholder:Ya,userName:Qa,userId:Ja,notice:Xa,shareList:Za,btnUnlink:en},q=[{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}],ve={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 tn(t){return ve[(t||"").toLowerCase().trim()]||"Tsundere"}function an(t){const r=new Set;for(const i of t){const c=ve[i.toLowerCase().trim()];c&&r.add(c)}return[...r]}const nn=[{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 rn(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 sn(t){const r=[...q].reverse().findIndex(u=>t>=u.hours),i=r===-1?0:q.length-1-r,c=q[i].label,h=i<q.length-1?q[i+1]:null;if(!h)return{pct:100,current:c,next:"MAX",nextHours:0};const d=q[i].hours,k=q.length-1,m=(t-d)/(h.hours-d);return{pct:Math.min(100,(i+m)/k*100),current:c,next:h.label,nextHours:h.hours-t}}const se="dango_discord_user";function on({workerUrl:t}){const[r,i]=s(()=>{try{const v=localStorage.getItem(se);if(v)return JSON.parse(v)}catch{}try{const b=new URLSearchParams(window.location.search).get("discord_user");if(b)return JSON.parse(b)}catch{}return null}),[c,h]=s(null),[d,k]=s(!1),[m,a]=s(null),[u,f]=s(()=>!r);O(()=>{const v=new URLSearchParams(window.location.search),b=v.get("discord_user");if(b){try{const A=JSON.parse(b);A&&A.id&&(i(A),f(!1),localStorage.setItem(se,JSON.stringify(A)),_.insights.setDiscordUser.mutate({user:A}).catch(()=>{}))}catch{}v.delete("discord_user"),window.history.replaceState(null,"",window.location.pathname+(v.toString()?`?${v.toString()}`:""))}},[]);const p=ae(async()=>{if(r){f(!1);return}try{const v=await _.insights.discordUser.query();v.user&&(i(v.user),localStorage.setItem(se,JSON.stringify(v.user)))}catch{}finally{f(!1)}},[r]),l=ae(async()=>{try{const v=await _.insights.discordSyncStats.query();h(v)}catch{}},[]);O(()=>{p(),l()},[p,l]);const T=()=>{localStorage.removeItem(se),i(null),a(null),_.insights.setDiscordUser.mutate({user:null}).catch(()=>{})},w=async()=>{if(!(!r||!c)){k(!0),a(null);try{const v=await _.insights.discordSyncNow.mutate();v.success?a({type:"success",text:`✅ ${v.message}`}):a({type:"error",text:`❌ ${v.error||v.message||"Sync failed"}`})}catch{a({type:"error",text:"❌ Network error — check your connection"})}finally{k(!1)}}},S=c?Math.round(c.totalSeconds/3600):0,D=rn(S),L=c?tn(c.topGenre):"—",x=c?.dere||(c?.genres?an(c.genres):[L]),{pct:U,next:C,nextHours:R}=sn(S),E=r?.avatar?`https://cdn.discordapp.com/avatars/${r.id}/${r.avatar}.${r.avatar.startsWith("a_")?"gif":"png"}?size=80`:null;return e(te,{children:[e("div",{className:o.card,children:[e("div",{className:o.cardHeader,children:[e("div",{className:o.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:o.cardTitle,children:"Discord Account"}),e("p",{className:o.cardSub,children:"Link your Discord to earn community roles"})]})]}),u?e("p",{className:o.notice,children:"Loading…"}):r?e(te,{children:[e("div",{className:o.userRow,children:[E?e("img",{className:o.avatar,src:E,alt:r.username}):e("div",{className:o.avatarPlaceholder,children:"👤"}),e("div",{children:[e("p",{className:o.userName,children:r.username}),e("p",{className:o.userId,children:["ID: ",r.id]})]}),e("button",{className:o.btnUnlink,onClick:T,title:"Disconnect your Discord account",children:"Disconnect"})]}),e("p",{className:o.notice,children:"The following data is shared with the Dango community service to assign roles:"}),e("ul",{className:o.shareList,children:[e("li",{children:"Total watch time (hours)"}),e("li",{children:"Top 3 watched genres"}),e("li",{children:"Discord user ID + username"})]})]}):e(te,{children:[e("p",{className:o.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:o.actions,children:[e("button",{className:o.btnPrimary,onClick:()=>{const v=encodeURIComponent(window.location.origin+"/settings?tab=community"),b=`${t}/auth/login?return_to=${v}`;window.location.href=b},children:"Login with Discord"}),e("a",{className:o.btnSecondary,href:"https://discord.gg/2FTSPXCsvn",target:"_blank",rel:"noopener noreferrer",children:"Join Server"})]})]})]}),e("div",{className:o.card,children:[e("div",{className:o.cardHeader,children:e("div",{children:[e("p",{className:o.cardTitle,children:"Your Roles"}),e("p",{className:o.cardSub,children:"Based on your current Dango watch history"})]})}),c?e(te,{children:[e("div",{className:o.statsRow,children:[e("div",{className:o.statBox,children:[e("span",{className:o.statValue,children:[S,"h"]}),e("span",{className:o.statLabel,children:"Watch Time"})]}),e("div",{className:o.statBox,children:[e("span",{className:o.statValue,children:c.topGenre||"—"}),e("span",{className:o.statLabel,children:"Top Genre"})]})]}),e("div",{className:o.rolePreview,children:[e("span",{className:`${o.badge} ${o.badgeRank}`,children:D}),e("span",{className:`${o.badge} ${o.badgeDere}`,children:L})]}),e("div",{className:o.progressSection,children:[e("div",{className:o.progressLabel,children:[e("span",{children:["Progress to ",C]}),e("span",{children:C==="MAX"?"MAX":`${R}h remaining`})]}),e("div",{className:o.progressTrack,children:e("div",{className:o.progressFill,style:{width:`${U}%`}})}),e("div",{className:o.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:o.dereSection,children:[e("p",{className:o.sectionHeading,children:"Personality Archetypes"}),e("div",{className:o.dereGrid,children:nn.map(v=>{const b=x.includes(v.name);return e("div",{className:`${o.dereCard} ${b?o.dereCardActive:""}`,children:[e("span",{className:o.dereName,children:v.name}),e("span",{className:o.dereGenre,children:v.genres})]},v.name)})})]}),e("hr",{className:o.divider}),e("div",{className:o.actions,children:[e("button",{className:o.btnPrimary,onClick:w,disabled:!r||d,id:"discord-roles-sync-btn",children:d?"Syncing…":"Sync Roles"}),!r&&e("span",{style:{fontSize:"0.78rem",color:"var(--text-tertiary)",alignSelf:"center"},children:"Login first to sync"})]}),m&&e("p",{className:`${o.statusMsg} ${m.type==="success"?o.statusSuccess:m.type==="error"?o.statusError:o.statusInfo}`,children:m.text})]}):e("p",{className:o.notice,children:"No watch data yet — start watching to earn roles!"})]}),e("div",{className:o.card,children:[e("div",{className:o.cardHeader,children:e("div",{children:[e("p",{className:o.cardTitle,children:"Dango Discord Server"}),e("p",{className:o.cardSub,children:"Community, announcements and support"})]})}),e("div",{className:o.actions,children:e("a",{className:o.btnPrimary,href:"https://discord.gg/2FTSPXCsvn",target:"_blank",rel:"noopener noreferrer",children:"Join the Server"})})]})]})}function cn({variant:t="info",children:r,className:i=""}){return e("div",{className:`alert alert-${t} ${i}`,children:r})}const ln={anime:"Watchlist",manga:"Reading List",tv:"TV Watchlist",asmr:"Listening List"},mn=()=>{const[t,r]=Ie(),i=Le(),{contentType:c}=we(),h=t.get("tab"),[d,k]=s(h&&["general","sync","watchlist","database","community"].includes(h)?h:"general"),[m,a]=s(""),u=V(null),f=V(null),p=V(new Map),[l,T]=s({top:0,height:0,left:0,width:0}),{lowEndMode:w,setLowEndMode:S}=Me(),[D,L]=s(""),[x,U]=s(localStorage.getItem("telemetry_enabled")!=="false"),[C,R]=s(localStorage.getItem("installation_id")||"");O(()=>{_.settings.installationId.query().then(n=>{n.id&&(R(n.id),localStorage.setItem("installation_id",n.id))}).catch(()=>{})},[]),O(()=>{_.discord.rolesConfig.query().then(n=>{n.workerUrl&&L(n.workerUrl)}).catch(()=>{})},[]);const[E,v]=s(Ee),[b,A]=s(!0),{data:M}=ye("discordRPCEnabled"),z=$e(),[N,ne]=s(!0),{data:Y}=ye("discordRPCHideMature"),[he,re]=s(""),[Q,ie]=s(null);O(()=>{_.discord.gatewayStatus.query().then(n=>{ie(n),n.masked&&n.masked!=="none"&&re(n.masked)}).catch(()=>{})},[]),O(()=>{M!==void 0&&A(M==="true"||M===!0||M===null)},[M]),O(()=>{Y!==void 0&&ne(Y==="true"||Y===!0||Y===null)},[Y]);const be=n=>{A(n),z.mutate({key:"discordRPCEnabled",value:String(n)})},_e=n=>{ne(n),z.mutate({key:"discordRPCHideMature",value:String(n)})},ke=n=>{U(n),localStorage.setItem("telemetry_enabled",String(n)),n?Be():ze()},Se=n=>{v(n),localStorage.setItem(Fe,String(n)),window.dispatchEvent(new CustomEvent(He))};me.useEffect(()=>{document.title="Settings - dango"},[]),me.useEffect(()=>{const n=t.get("tab");n&&["general","sync","watchlist","database","community"].includes(n)&&k(n)},[t]);const J=n=>{k(n),r(n==="general"?{}:{tab:n})},X=ae(()=>{const n=p.current.get(d),$=f.current;if(n&&$){const j=$.getBoundingClientRect(),F=n.getBoundingClientRect(),Z=window.matchMedia("(max-width: 900px)").matches;T(Z?{top:F.top-j.top,height:F.height,left:F.left-j.left,width:F.width}:{top:F.top-j.top,height:F.height,left:0,width:0})}},[d]);xe(()=>{X()},[d,X]),O(()=>{const n=()=>X();window.addEventListener("resize",n);let $=!1;return document.fonts?.ready&&document.fonts.ready.then(()=>{$||X()}),()=>{$=!0,window.removeEventListener("resize",n)}},[d,X]);const Ce=()=>{a("Exporting databases...");const n=window.DangoBridge;if(n?.downloadFile){n.downloadFile("/api/backup-db","dango-backup.json"),setTimeout(()=>{a("Databases exported successfully!")},1500);return}const $=document.createElement("a");$.href="/api/backup-db",$.download="dango-backup.json",document.body.appendChild($),$.click(),$.remove(),setTimeout(()=>{a("Databases exported successfully!")},1500)},Ne=async n=>{const $=n.target.files?.[0];if(!$)return;a("Importing databases...");const j=new FormData;j.append("dbfile",$);try{const F=await fetch("/api/restore-db",{method:"POST",body:j}),Z=await F.json();if(F.ok){const ge=Array.isArray(Z.restored)?Z.restored.join(", "):null;a(ge?`Databases imported successfully (${ge})!`:"Database imported successfully!"),setTimeout(()=>window.location.reload(),2e3)}else a(`Import failed: ${Z.error}`)}catch{a("Import failed: An unexpected error occurred.")}finally{n.target.value=""}},Te=()=>{u.current?.click()},Re=()=>{switch(d){case"general":return e("div",{className:g.tabContent,children:e("div",{className:g.sectionCard,children:[e("h3",{children:"Appearance & Preferences"}),e("p",{children:"Configure how titles are displayed and other general preferences."}),e("div",{className:g.settingItem,children:e(qe,{})}),e("div",{className:g.settingItem,style:{marginTop:"1.5rem"},children:e(ha,{})}),e("div",{className:g.settingItem,style:{marginTop:"1.5rem"},children:e("div",{className:g.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(H,{isChecked:w,onChange:n=>S(n.target.checked),id:"low-end-mode"})]})}),e("div",{className:g.settingItem,style:{marginTop:"1.5rem"},children:e("div",{className:g.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(H,{isChecked:E,onChange:n=>Se(n.target.checked),id:"virtual-keyboard-enabled"})]})}),e("div",{className:g.settingItem,style:{marginTop:"1.5rem"},children:e("div",{className:g.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(H,{isChecked:b,onChange:n=>be(n.target.checked),id:"discord-rpc-enabled"})]})}),e("div",{style:{marginTop:"2rem"},children:e(ua,{})}),b&&e("div",{className:g.settingItem,style:{marginTop:"1rem"},children:e("div",{className:g.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(H,{isChecked:N,onChange:n=>_e(n.target.checked),id:"discord-hide-mature"})]})}),e("div",{className:g.settingItem,style:{marginTop:"1.5rem",background:"var(--bg-tertiary)",padding:"1rem",borderRadius:"8px",border:"1px solid var(--border-color)"},children:[e("div",{className:g.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(cn,{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:he,onChange:n=>re(n.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(I,{variant:"primary",size:"sm",onClick:async()=>{try{const n=await _.discord.gatewaySave.mutate({token:he});ie({hasToken:!0,masked:n.masked,enabled:!0}),re(n.masked)}catch(n){alert(n instanceof Error?n.message:"Failed to save token")}},children:"Save"}),e(I,{variant:"secondary",size:"sm",onClick:async()=>{await _.discord.gatewayRemove.mutate().catch(()=>{}),re(""),ie({hasToken:!1,masked:null,enabled:!1})},children:"Remove"})]}),Q&&e("p",{style:{marginTop:"0.5rem",fontSize:"0.8rem",color:Q.hasToken?"green":"var(--text-secondary)"},children:["Status:"," ",Q.hasToken?`Token saved (${Q.masked})`:"No token saved",Q.enabled?" - Gateway active":""]}),e(ra,{})]}),e("div",{className:g.settingItem,style:{marginTop:"1.5rem"},children:[e("div",{className:g.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(H,{isChecked:x,onChange:n=>ke(n.target.checked),id:"telemetry-enabled"})]}),x&&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:"})," ",C||"Loading..."]}),e("p",{style:{margin:"0"},children:[e("strong",{children:"Version:"})," ",Ge.version]}),e("p",{style:{margin:"0"},children:[e("strong",{children:"Browser:"})," ",Ke()]}),e("p",{style:{margin:"0"},children:[e("strong",{children:"Timezone:"})," ",Intl.DateTimeFormat().resolvedOptions().timeZone]})]})]}),e("div",{style:{marginTop:"1rem"},children:e(I,{variant:"secondary",size:"sm",onClick:()=>i("/map"),children:"View User Map"})})]}),localStorage.getItem("agreedToViewMature")==="true"&&e("div",{className:g.settingItem,style:{marginTop:"1.5rem"},children:e("div",{className:g.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(H,{isChecked:!0,onChange:n=>{n.target.checked||(localStorage.removeItem("agreedToViewMature"),window.location.reload())},id:"mature-content-enabled"})]})})]})});case"sync":return e("div",{className:g.tabContent,children:[e(aa,{}),e(vt,{}),e(bt,{}),e(ta,{})]});case"watchlist":return e("div",{className:g.tabContent,children:e(xt,{})});case"database":return e("div",{className:g.tabContent,children:[e("div",{className:g.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:g.controls,children:[e(I,{onClick:Ce,children:"Backup Database"}),e(I,{variant:"secondary",onClick:Te,children:"Restore Database"})]}),e("input",{type:"file",ref:u,onChange:Ne,style:{position:"absolute",width:1,height:1,opacity:0,overflow:"hidden"},accept:".json,.db,application/octet-stream"}),m&&e("p",{className:g.status,children:m})]}),e(Vt,{}),e(ea,{})]});case"community":return e("div",{className:g.tabContent,children:D?e(on,{workerUrl:D}):e("div",{className:g.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:g.settingsHeader,children:[e("h1",{className:g.pageTitle,children:"Settings"}),e("p",{className:g.pageSubtitle,children:"Manage your preferences and data synchronization"})]}),e("div",{className:g.settingsLayout,children:[e("aside",{className:g.sidebar,ref:f,children:[e("div",{className:g.sidebarIndicator,style:{top:l.top,height:l.height,left:l.left,...l.width?{width:l.width}:{}}}),e("button",{ref:n=>{n&&p.current.set("general",n)},className:`${g.sidebarItem} ${d==="general"?g.active:""}`,onClick:()=>J("general"),children:[e(W,{name:"cog"})," ",e("span",{children:"General"})]}),e("button",{ref:n=>{n&&p.current.set("sync",n)},className:`${g.sidebarItem} ${d==="sync"?g.active:""}`,onClick:()=>J("sync"),children:[e(W,{name:"cloud"})," ",e("span",{children:"Synchronization"})]}),e("button",{ref:n=>{n&&p.current.set("watchlist",n)},className:`${g.sidebarItem} ${d==="watchlist"?g.active:""}`,onClick:()=>J("watchlist"),children:[e(W,{name:"list"})," ",e("span",{children:ln[c]})]}),e("button",{ref:n=>{n&&p.current.set("database",n)},className:`${g.sidebarItem} ${d==="database"?g.active:""}`,onClick:()=>J("database"),children:[e(W,{name:"database"})," ",e("span",{children:"Database"})]}),D&&e("button",{ref:n=>{n&&p.current.set("community",n)},className:`${g.sidebarItem} ${d==="community"?g.active:""}`,onClick:()=>J("community"),children:[e(W,{name:"discord"})," ",e("span",{children:"Community"})]})]}),e("main",{className:g.mainContent,children:e("div",{className:g.tabContent,children:Re()},d)})]})]})};export{mn as default};
@@ -1 +1 @@
1
- import{d as _,A as v,h as E,T as R,u as e,g as A}from"./vendor-core-8R2fFbyN.js";import{I as P}from"./vendor-icons-CDMuNDeL.js";import{u as L}from"./index-D2RkUJIN.js";const x="_pagination_zelsc_1",M="_pageBtn_zelsc_7",S="_pageInfo_zelsc_38",G="_pagePicker_zelsc_48",F="_dropdown_zelsc_52",K="_flipDown_zelsc_68",T="_jumpRow_zelsc_73",W="_jumpInput_zelsc_79",q="_jumpGo_zelsc_90",J="_optionList_zelsc_105",O="_optionBtn_zelsc_113",H="_current_zelsc_132",s={pagination:x,pageBtn:M,pageInfo:S,pagePicker:G,dropdown:F,flipDown:K,jumpRow:T,jumpInput:W,jumpGo:q,optionList:J,optionBtn:O,current:H},cn=({page:t,totalPages:d,canGoNext:m,onChange:p,isLoading:f=!1,variant:g="compact"})=>{const[l,u]=_(!1),[b,h]=_(""),[k,N]=_(0),[$,z]=_(!1),w=v(null),y=v(null),j=v(null);E(()=>{if(!l)return;const n=o=>{w.current&&!w.current.contains(o.target)&&u(!1)},r=o=>{o.key==="Escape"&&u(!1)};return document.addEventListener("pointerdown",n),document.addEventListener("keydown",r),()=>{document.removeEventListener("pointerdown",n),document.removeEventListener("keydown",r)}},[l]),E(()=>{if(!l)return;N(0),z(!1);const n=requestAnimationFrame(()=>{const r=j.current?.getBoundingClientRect(),o=y.current?.getBoundingClientRect();if(!r)return;let c=0;r.right>window.innerWidth-8?c=window.innerWidth-8-r.right:r.left<8&&(c=8-r.left),N(Math.round(c)),o&&o.top<r.height+24&&z(!0)});return()=>cancelAnimationFrame(n)},[l]);const i=d,C=R(()=>{if(i!==void 0){if(i<=100)return Array.from({length:i},(o,c)=>c+1);const r=new Set([1,i]);for(let o=t-10;o<=t+10;o++)o>=1&&o<=i&&r.add(o);return[...r].sort((o,c)=>o-c)}const n=m?t+1:t;return Array.from({length:n},(r,o)=>o+1)},[i,t,m]),B=n=>{const r=i!==void 0?Math.min(Math.max(1,n),i):Math.max(1,n);u(!1),h(""),r!==t&&p(r)},D=()=>{const n=parseInt(b,10);Number.isNaN(n)||B(n)},I=f||(i!==void 0?t>=i:!m);return e("div",{className:s.pagination,ref:w,children:[e("button",{className:s.pageBtn,onClick:()=>p(t-1),disabled:t<=1||f,"aria-label":"Previous page",children:[e(P,{name:"chevron-left",size:14}),g==="labeled"&&e("span",{children:"Previous"})]}),e("div",{className:s.pagePicker,ref:y,children:[e("button",{className:s.pageBtn,onClick:()=>{h(""),u(n=>!n)},disabled:f,"aria-label":"Jump to page","aria-expanded":l,children:e("span",{className:s.pageInfo,children:["Page ",e("strong",{children:t}),i!==void 0&&` of ${i}`]})}),l&&e("div",{ref:j,className:`${s.dropdown} ${$?s.flipDown:""}`,style:k!==0?{marginLeft:k}:void 0,children:[e("div",{className:s.jumpRow,children:[e("input",{className:s.jumpInput,type:"number",inputMode:"numeric",min:1,max:i,value:b,placeholder:"Page #",onChange:n=>h(n.currentTarget.value),onKeyDown:n=>{n.key==="Enter"&&D()}}),e("button",{className:s.jumpGo,onClick:D,children:"Go"})]}),e("div",{className:s.optionList,children:C.map(n=>e("button",{className:`${s.optionBtn} ${n===t?s.current:""}`,onClick:()=>B(n),disabled:n===t,children:n},n))})]})]}),e("button",{className:s.pageBtn,onClick:()=>p(t+1),disabled:I,"aria-label":"Next page",children:[g==="labeled"&&e("span",{children:"Next"}),e(P,{name:"chevron-right",size:14})]})]})},Q="_skeletonCard_1b0hr_1",U="_poster_1b0hr_11",V="_line_1b0hr_20",X="_info_1b0hr_38",Y="_short_1b0hr_54",Z="_horizontal_1b0hr_60",nn="_vertical_1b0hr_78",en="_lowEnd_1b0hr_97",a={skeletonCard:Q,poster:U,line:V,"skeleton-wave":"_skeleton-wave_1b0hr_1",info:X,short:Y,horizontal:Z,vertical:nn,lowEnd:en},tn=({layout:t="vertical"})=>{const{lowEndMode:d}=L();return e("div",{className:`${a.skeletonCard} ${a[t]} ${d?a.lowEnd:""}`,children:[e("div",{className:a.poster}),e("div",{className:a.info,children:[e("div",{className:a.line}),e("div",{className:`${a.line} ${a.short}`})]})]})},on=({count:t=14,layout:d="vertical"})=>e("div",{className:"grid-container",children:Array.from({length:t}).map((m,p)=>e(tn,{layout:d},p))}),ln=A.memo(on);export{tn as A,cn as P,ln as S};
1
+ import{d as _,A as v,h as E,T as R,u as e,g as A}from"./vendor-core-8R2fFbyN.js";import{I as P}from"./vendor-icons-CDMuNDeL.js";import{u as L}from"./index-BXwhFWB_.js";const x="_pagination_zelsc_1",M="_pageBtn_zelsc_7",S="_pageInfo_zelsc_38",G="_pagePicker_zelsc_48",F="_dropdown_zelsc_52",K="_flipDown_zelsc_68",T="_jumpRow_zelsc_73",W="_jumpInput_zelsc_79",q="_jumpGo_zelsc_90",J="_optionList_zelsc_105",O="_optionBtn_zelsc_113",H="_current_zelsc_132",s={pagination:x,pageBtn:M,pageInfo:S,pagePicker:G,dropdown:F,flipDown:K,jumpRow:T,jumpInput:W,jumpGo:q,optionList:J,optionBtn:O,current:H},cn=({page:t,totalPages:d,canGoNext:m,onChange:p,isLoading:f=!1,variant:g="compact"})=>{const[l,u]=_(!1),[b,h]=_(""),[k,N]=_(0),[$,z]=_(!1),w=v(null),y=v(null),j=v(null);E(()=>{if(!l)return;const n=o=>{w.current&&!w.current.contains(o.target)&&u(!1)},r=o=>{o.key==="Escape"&&u(!1)};return document.addEventListener("pointerdown",n),document.addEventListener("keydown",r),()=>{document.removeEventListener("pointerdown",n),document.removeEventListener("keydown",r)}},[l]),E(()=>{if(!l)return;N(0),z(!1);const n=requestAnimationFrame(()=>{const r=j.current?.getBoundingClientRect(),o=y.current?.getBoundingClientRect();if(!r)return;let c=0;r.right>window.innerWidth-8?c=window.innerWidth-8-r.right:r.left<8&&(c=8-r.left),N(Math.round(c)),o&&o.top<r.height+24&&z(!0)});return()=>cancelAnimationFrame(n)},[l]);const i=d,C=R(()=>{if(i!==void 0){if(i<=100)return Array.from({length:i},(o,c)=>c+1);const r=new Set([1,i]);for(let o=t-10;o<=t+10;o++)o>=1&&o<=i&&r.add(o);return[...r].sort((o,c)=>o-c)}const n=m?t+1:t;return Array.from({length:n},(r,o)=>o+1)},[i,t,m]),B=n=>{const r=i!==void 0?Math.min(Math.max(1,n),i):Math.max(1,n);u(!1),h(""),r!==t&&p(r)},D=()=>{const n=parseInt(b,10);Number.isNaN(n)||B(n)},I=f||(i!==void 0?t>=i:!m);return e("div",{className:s.pagination,ref:w,children:[e("button",{className:s.pageBtn,onClick:()=>p(t-1),disabled:t<=1||f,"aria-label":"Previous page",children:[e(P,{name:"chevron-left",size:14}),g==="labeled"&&e("span",{children:"Previous"})]}),e("div",{className:s.pagePicker,ref:y,children:[e("button",{className:s.pageBtn,onClick:()=>{h(""),u(n=>!n)},disabled:f,"aria-label":"Jump to page","aria-expanded":l,children:e("span",{className:s.pageInfo,children:["Page ",e("strong",{children:t}),i!==void 0&&` of ${i}`]})}),l&&e("div",{ref:j,className:`${s.dropdown} ${$?s.flipDown:""}`,style:k!==0?{marginLeft:k}:void 0,children:[e("div",{className:s.jumpRow,children:[e("input",{className:s.jumpInput,type:"number",inputMode:"numeric",min:1,max:i,value:b,placeholder:"Page #",onChange:n=>h(n.currentTarget.value),onKeyDown:n=>{n.key==="Enter"&&D()}}),e("button",{className:s.jumpGo,onClick:D,children:"Go"})]}),e("div",{className:s.optionList,children:C.map(n=>e("button",{className:`${s.optionBtn} ${n===t?s.current:""}`,onClick:()=>B(n),disabled:n===t,children:n},n))})]})]}),e("button",{className:s.pageBtn,onClick:()=>p(t+1),disabled:I,"aria-label":"Next page",children:[g==="labeled"&&e("span",{children:"Next"}),e(P,{name:"chevron-right",size:14})]})]})},Q="_skeletonCard_1b0hr_1",U="_poster_1b0hr_11",V="_line_1b0hr_20",X="_info_1b0hr_38",Y="_short_1b0hr_54",Z="_horizontal_1b0hr_60",nn="_vertical_1b0hr_78",en="_lowEnd_1b0hr_97",a={skeletonCard:Q,poster:U,line:V,"skeleton-wave":"_skeleton-wave_1b0hr_1",info:X,short:Y,horizontal:Z,vertical:nn,lowEnd:en},tn=({layout:t="vertical"})=>{const{lowEndMode:d}=L();return e("div",{className:`${a.skeletonCard} ${a[t]} ${d?a.lowEnd:""}`,children:[e("div",{className:a.poster}),e("div",{className:a.info,children:[e("div",{className:a.line}),e("div",{className:`${a.line} ${a.short}`})]})]})},on=({count:t=14,layout:d="vertical"})=>e("div",{className:"grid-container",children:Array.from({length:t}).map((m,p)=>e(tn,{layout:d},p))}),ln=A.memo(on);export{tn as A,cn as P,ln as S};
@@ -0,0 +1,2 @@
1
+ import{d as s,h as Ke,g as Be,A as De,q as $e,u as e,S as d}from"./vendor-core-8R2fFbyN.js";import{u as Ue,b as Fe,a as I}from"./vendor-query-BUTye89G.js";import{z as i,t as h,Y as nn,i as an,B as le}from"./index-BXwhFWB_.js";import{I as l}from"./vendor-icons-CDMuNDeL.js";function tn(){const R=Ue(),[J,k]=s(!1);return Ke(()=>{const t=new URLSearchParams(window.location.search),b=t.get("anilist");if(b){const m=t.get("user"),_=t.get("reason");window.history.replaceState(null,"",window.location.pathname),b==="success"?(i.success(m?`Connected to AniList as ${decodeURIComponent(m)}`:"Connected to AniList"),R.invalidateQueries({queryKey:["trackerStatus"]})):i.error(_?decodeURIComponent(_):"AniList authentication failed");return}const j=new URLSearchParams(window.location.hash.substring(1)),y=j.get("access_token"),x=t.get("code");if(!y&&!x){const m=j.get("error");m&&(i.error(`AniList error: ${m}`),window.history.replaceState(null,"",window.location.pathname));return}const g=window.location.origin+window.location.pathname;window.history.replaceState(null,"",window.location.pathname),k(!0),i("Connecting to AniList..."),h.tracker.anilistAuth.mutate(y?{token:y}:{code:x,redirectUri:g}).then(async m=>{const _=m.user;i.success(`Connected to AniList as ${_?.name??"AniList user"}`),R.invalidateQueries({queryKey:["trackerStatus"]})}).catch(m=>{i.error(m instanceof Error?m.message:"Failed to authenticate with AniList")}).finally(()=>{k(!1)})},[R]),J}const sn="_header_j1lbh_1",rn="_fadeIn_j1lbh_1",ln="_pageTitle_j1lbh_6",on="_pageSubtitle_j1lbh_14",cn="_importCard_j1lbh_20",dn="_slideUpIn_j1lbh_1",mn="_cardHeader_j1lbh_37",pn="_uploadArea_j1lbh_55",hn="_fileInputWrapper_j1lbh_59",un="_fileInput_j1lbh_59",gn="_fileDisplay_j1lbh_87",yn="_fileIcon_j1lbh_95",bn="_fileName_j1lbh_100",_n="_browseButton_j1lbh_109",fn="_optionsArea_j1lbh_120",Nn="_checkboxLabel_j1lbh_128",kn="_checkbox_j1lbh_128",vn="_checkboxCustom_j1lbh_141",wn="_optionText_j1lbh_169",In="_optionTitle_j1lbh_175",xn="_optionDesc_j1lbh_181",Mn="_actions_j1lbh_187",Cn="_importBtn_j1lbh_195",Ln="_cancelBtn_j1lbh_201",Sn="_statusMessage_j1lbh_215",Tn="_success_j1lbh_225",An="_error_j1lbh_231",jn="_progressSection_j1lbh_237",Pn="_progressBar_j1lbh_242",En="_progressFill_j1lbh_250",Bn="_progressInfo_j1lbh_257",Dn="_progressCount_j1lbh_264",$n="_progressTitle_j1lbh_271",Fn="_sourceBadge_j1lbh_289",qn="_anilist_j1lbh_301",Kn="_kitsu_j1lbh_307",Un="_offline_j1lbh_313",Rn="_skipped_j1lbh_319",Qn="_cardTitleRow_j1lbh_324",On="_anilistIcon_j1lbh_334",Gn="_malIcon_j1lbh_340",Hn="_badgeOnline_j1lbh_346",Wn="_badgeOffline_j1lbh_358",zn="_connectedProfile_j1lbh_370",Xn="_avatar_j1lbh_379",Yn="_connectedInfo_j1lbh_386",Jn="_connectedName_j1lbh_394",Vn="_connectedHint_j1lbh_400",Zn="_loginPrompt_j1lbh_405",ea="_loginSection_j1lbh_413",na="_fieldLabel_j1lbh_419",aa="_helpText_j1lbh_438",ta="_loginText_j1lbh_455",sa="_primaryBtn_j1lbh_464",ia="_secondaryBtn_j1lbh_465",ra="_syncBtn_j1lbh_466",la="_divider_j1lbh_518",oa="_actionSection_j1lbh_524",ca="_inputGroup_j1lbh_538",da="_input_j1lbh_538",ma="_syncSummary_j1lbh_559",pa="_syncErrors_j1lbh_565",ha="_spin_j1lbh_569",ua="_radioGroup_j1lbh_598",ga="_radioLabel_j1lbh_604",ya="_syncHint_j1lbh_642",ba="_importLoading_j1lbh_649",n={header:sn,fadeIn:rn,pageTitle:ln,pageSubtitle:on,importCard:cn,slideUpIn:dn,cardHeader:mn,uploadArea:pn,fileInputWrapper:hn,fileInput:un,fileDisplay:gn,fileIcon:yn,fileName:bn,browseButton:_n,optionsArea:fn,checkboxLabel:Nn,checkbox:kn,checkboxCustom:vn,optionText:wn,optionTitle:In,optionDesc:xn,actions:Mn,importBtn:Cn,cancelBtn:Ln,statusMessage:Sn,success:Tn,error:An,progressSection:jn,progressBar:Pn,progressFill:En,progressInfo:Bn,progressCount:Dn,progressTitle:$n,sourceBadge:Fn,anilist:qn,kitsu:Kn,offline:Un,skipped:Rn,cardTitleRow:Qn,anilistIcon:On,malIcon:Gn,badgeOnline:Hn,badgeOffline:Wn,connectedProfile:zn,avatar:Xn,connectedInfo:Yn,connectedName:Jn,connectedHint:Vn,loginPrompt:Zn,loginSection:ea,fieldLabel:na,helpText:aa,loginText:ta,primaryBtn:sa,secondaryBtn:ia,syncBtn:ra,divider:la,actionSection:oa,inputGroup:ca,input:da,syncSummary:ma,syncErrors:pa,spin:ha,radioGroup:ua,radioLabel:ga,syncHint:ya,importLoading:ba},oe="tracker_anilist_client_id",qe="49887".trim(),va=()=>{const{setIsOpen:R}=nn(),{contentType:J}=an(),k=J==="manga",t=Ue();Be.useEffect(()=>{document.title="Trackers - dango"},[]);const[b,j]=s(""),[y,x]=s("username"),[g,m]=s(null),[_,ce]=s(""),[M,de]=s(!1),Re=tn(),{data:me,isLoading:pe}=Fe({queryKey:["trackerStatus"],queryFn:async()=>await h.tracker.status.query()}),{data:C}=Fe({queryKey:["anilistClientId"],queryFn:async()=>(await h.settings.getByKey.query({key:oe})).value||""}),he=De(!1);Be.useEffect(()=>{he.current||C!==void 0&&(C&&ce(C),he.current=!0)},[C]);const v=me?.anilist?.connected??!1;Ke(()=>{v&&x("sync")},[v]);const Q=me?.anilist?.user??null,V=!!qe,Qe=(C||"").trim(),Oe=async()=>{const a=_.trim(),r=a||qe;if(!r){i.error("Enter your AniList client ID first");return}const N=async(A,se)=>{await h.settings.set.mutate({key:A,value:se})};try{a?a!==C&&await N(oe,a):V&&Qe&&await N(oe,""),t.invalidateQueries({queryKey:["anilistClientId"]})}catch(A){i.error(A.message);return}const o=window.location.origin+window.location.pathname,q=encodeURIComponent(o);window.location.href=`https://anilist.co/api/v2/oauth/authorize?client_id=${encodeURIComponent(r)}&response_type=token&state=${q}`},ue=I({mutationFn:async()=>h.tracker.anilistDisconnect.mutate(),onSuccess:()=>{t.invalidateQueries({queryKey:["trackerStatus"]}),i.success("Disconnected from AniList")},onError:a=>i.error(a.message)}),O=I({mutationFn:async()=>(await h.tracker.sync.mutate({provider:"anilist"})).summary,onSuccess:a=>{t.invalidateQueries({queryKey:["watchlist"]}),t.invalidateQueries({queryKey:["allContinueWatching"]}),m(a),i.success(`Sync complete — pushed ${a.pushed}, pulled ${a.pulled}, merged ${a.merged}, unchanged ${a.unchanged}`,{duration:6e3})},onError:a=>i.error(a.message)}),[P,ge]=s(""),[G,ye]=s("sync"),[Z,be]=s("two-way"),[c,Ge]=s(null),H=I({mutationFn:async()=>(await h.tracker.mangaSync.mutate({direction:Z})).summary,onSuccess:a=>{t.invalidateQueries({queryKey:["manga-library"]}),t.invalidateQueries({queryKey:["manga-library-ids"]}),t.invalidateQueries({queryKey:["manga-continue-reading"]}),Ge(a);const r=(a.warnings?.length??0)>0?`, ${a.warnings.length} warning(s)`:"";i.success(`Manga sync complete — pushed ${a.pushed}, pulled ${a.pulled}, merged ${a.merged}, unchanged ${a.unchanged}${r}`,{duration:6e3})},onError:a=>i.error(a.message)}),L=I({mutationFn:async()=>{if(!P.trim())throw new Error("Please enter a username");return(await h.tracker.mangaImport.mutate({username:P.trim(),erase:M})).count},onSuccess:a=>{t.invalidateQueries({queryKey:["manga-library"]}),t.invalidateQueries({queryKey:["manga-library-ids"]}),t.invalidateQueries({queryKey:["manga-continue-reading"]}),i.success(`Imported ${a} manga entries from AniList`),ge("")},onError:a=>i.error(a.message)}),[E,_e]=s(""),[W,fe]=s("username"),[ee,Ne]=s(null),[z,ke]=s(!1),[ve,ne]=s(""),[we,He]=s(""),f=I({mutationFn:async()=>{if(!E.trim())throw new Error("Please enter a MAL username");const a=await h.tracker.mangaMalImport.mutate({username:E.trim(),erase:M});return{imported:a.imported??0,skipped:a.skipped??0}},onSuccess:({imported:a,skipped:r})=>{t.invalidateQueries({queryKey:["manga-library"]}),t.invalidateQueries({queryKey:["manga-library-ids"]}),t.invalidateQueries({queryKey:["manga-continue-reading"]}),i.success(`Imported ${a} manga entries from MAL${r>0?`, skipped ${r}`:""}`),_e("")},onError:a=>i.error(a.message)}),We=$e(async()=>{const a=document.getElementById("malMangaFile");if(!a.files||a.files.length===0){ne("Please select a file first.");return}ke(!0),ne(""),Ne(null);try{const r=new FormData;r.append("xmlfile",a.files[0]),r.append("erase",String(M));const N=await fetch("/api/import/mal-xml-manga",{method:"POST",body:r}),o=await N.json().catch(()=>({}));if(!N.ok)throw new Error(o.error||"Import failed");Ne({imported:o.imported??0,skipped:o.skipped??0}),t.invalidateQueries({queryKey:["manga-library"]}),t.invalidateQueries({queryKey:["manga-library-ids"]}),t.invalidateQueries({queryKey:["manga-continue-reading"]})}catch(r){ne(r.message)}finally{ke(!1)}},[M,t]),S=I({mutationFn:async()=>{if(!b.trim())throw new Error("Please enter a username");return(await h.tracker.anilistImport.mutate({username:b.trim(),erase:w})).count},onSuccess:a=>{t.invalidateQueries({queryKey:["watchlist"]}),t.invalidateQueries({queryKey:["allContinueWatching"]}),i.success(`Imported ${a} anime entries from AniList`),j("")},onError:a=>i.error(a.message)}),[B,Ie]=s(""),u=I({mutationFn:async a=>{if(!B.trim())throw new Error("Please enter a MAL username");return(await h.tracker.malImport.mutate({username:B.trim(),erase:a.erase,useOfflineDb:a.useOfflineDb,skipFallback:a.skipFallback})).count},onSuccess:a=>{t.invalidateQueries({queryKey:["watchlist"]}),t.invalidateQueries({queryKey:["allContinueWatching"]}),i.success(`Imported ${a} anime entries from MAL`),Ie("")},onError:a=>i.error(a.message)}),[w,xe]=s(!1),[D,ze]=s(!0),[$,Xe]=s(!1),[Me,Ce]=s(""),[T,Le]=s(!1),[p,Se]=s(null),[ae,Te]=s(null),[Ae,X]=s(""),te=De(null),Ye=a=>{a.target.files&&a.target.files.length>0?Ce(a.target.files[0].name):Ce("")},Je=$e(async()=>{const a=document.getElementById("malFile");if(!a.files||a.files.length===0){X("Please select a file first.");return}const r=a.files[0];Le(!0),Se(null),Te(null),X("");const N=new AbortController;te.current=N;try{const o=new FormData;o.append("xmlfile",r),o.append("erase",String(w)),o.append("useOfflineDb",String(D)),o.append("skipFallback",String($));const q=await fetch("/api/import/mal-xml",{method:"POST",body:o,signal:N.signal});if(!q.ok){const re=await q.text();let K="Failed to import";try{K=JSON.parse(re).error||K}catch{}throw new Error(K)}const A=q.body?.getReader();if(!A)throw new Error("No response stream");const se=new TextDecoder;let ie="",Y="";for(;;){const{done:re,value:K}=await A.read();if(re)break;ie+=se.decode(K,{stream:!0});const Pe=ie.split(`
2
+ `);ie=Pe.pop()||"";for(const U of Pe)if(U.startsWith("event: "))Y=U.slice(7).trim();else if(U.startsWith("data: ")){const en=U.slice(6);try{const Ee=JSON.parse(en);Y==="progress"?Se(Ee):Y==="complete"&&Te(Ee)}catch{}}else U===""&&(Y="")}t.invalidateQueries({queryKey:["watchlist"]})}catch(o){o instanceof DOMException&&o.name==="AbortError"?X("Import cancelled."):X(o.message)}finally{Le(!1),te.current=null}},[w,D,$,t]),Ve=()=>{te.current?.abort(),h.settings.malImportCancel.mutate().catch(()=>{})},Ze=p?Math.round(p.current/p.total*100):0,[F,je]=s("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 and manga reading lists with tracking services"})]}),e("div",{style:{marginBottom:"16px",padding:"10px 14px",borderRadius:"8px",fontSize:"0.85rem",background:"color-mix(in srgb, var(--color-warning) 8%, transparent)",border:"1px solid color-mix(in srgb, var(--color-warning) 25%, transparent)",color:"var(--text-secondary)"},children:"⚠ Syncing writes directly to your AniList entries, and dango may not always handle anime/manga lists correctly — always keep a backup of your lists before syncing."}),!k&&e(d,{children:e("div",{className:n.importCard,children:[e("div",{className:n.cardHeader,children:e("div",{className:n.cardTitleRow,children:[e(l,{name:"anilist",className:n.anilistIcon}),e("h3",{children:"AniList"}),pe?null:v?e("span",{className:n.badgeOnline,children:"Connected"}):e("span",{className:n.badgeOffline,children:"Not connected"})]})}),v&&Q?e("div",{className:n.connectedProfile,children:[Q.avatar&&e("img",{src:Q.avatar,alt:"Avatar",className:n.avatar,loading:"lazy",decoding:"async"}),e("div",{className:n.connectedInfo,children:[e("span",{className:n.connectedName,children:Q.name}),e("span",{className:n.connectedHint,children:"2-way sync is ready"})]}),e("button",{className:n.secondaryBtn,onClick:()=>ue.mutate(),disabled:ue.isPending,children:[e(l,{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.",Re&&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(l,{name:"external-link-alt",size:9})]})]}),e("div",{className:n.inputGroup,children:[e("input",{type:"text",placeholder:"Client ID",value:_,onChange:a=>ce(a.target.value),className:n.input}),e("button",{className:n.primaryBtn,onClick:Oe,disabled:!(_.trim()||V),children:[e(l,{name:"external-link-alt"})," Connect"]})]}),e("p",{className:n.helpText,children:V?e(d,{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(d,{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."]})})]}),v&&e(d,{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:y==="username",onChange:()=>x("username")}),e("span",{children:"Quick Import"})]}),e("label",{className:n.radioLabel,children:[e("input",{type:"radio",name:"anilistMode",value:"sync",checked:y==="sync",onChange:()=>x("sync")}),e("span",{children:"Two-way Sync"})]})]}),y==="username"?e("div",{className:n.inputGroup,children:e("input",{type:"text",placeholder:"Enter AniList username",value:b,onChange:a=>j(a.target.value),className:n.input,disabled:S.isPending,onKeyDown:a=>{a.key==="Enter"&&b.trim()&&S.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."}),y==="username"&&e("div",{className:n.optionsArea,children:e("label",{className:n.checkboxLabel,children:[e("input",{type:"checkbox",checked:w,onChange:a=>xe(a.target.checked),className:n.checkbox,disabled:S.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."})]})]})}),y==="username"?e("button",{className:n.syncBtn,onClick:()=>S.mutate(),disabled:!b.trim()||S.isPending,children:[e(l,{name:"download"}),S.isPending?"Importing...":"Start Import"]}):e(d,{children:[e("button",{className:n.syncBtn,onClick:()=>O.mutate(),disabled:O.isPending,children:[e(l,{name:"sync-alt",className:O.isPending?n.spin:""}),O.isPending?"Syncing...":"Start Sync"]}),g&&e("div",{className:n.syncSummary,children:["Pushed: ",g.pushed," · Pulled: ",g.pulled," · Merged:"," ",g.merged," · Unchanged: ",g.unchanged,g.errors.length>0&&e("span",{className:n.syncErrors,children:[" ","· ",g.errors.length," error",g.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."]})]})]})}),k&&e(d,{children:e("div",{className:n.importCard,children:[e("div",{className:n.cardHeader,children:e("div",{className:n.cardTitleRow,children:[e(l,{name:"anilist",className:n.anilistIcon}),e("h3",{children:"AniList Manga"}),pe?null:v?e("span",{className:n.badgeOnline,children:"Connected"}):e("span",{className:n.badgeOffline,children:"Not connected"})]})}),v?e(d,{children:[e("div",{className:n.radioGroup,children:[e("label",{className:n.radioLabel,children:[e("input",{type:"radio",name:"mangaMode",value:"username",checked:G==="username",onChange:()=>ye("username")}),e("span",{children:"Quick Import"})]}),e("label",{className:n.radioLabel,children:[e("input",{type:"radio",name:"mangaMode",value:"sync",checked:G==="sync",onChange:()=>ye("sync")}),e("span",{children:"Two-way Sync"})]})]}),G==="username"?e(d,{children:[e("div",{className:n.inputGroup,children:e("input",{type:"text",placeholder:"Enter AniList username",value:P,onChange:a=>ge(a.target.value),className:n.input,disabled:L.isPending,onKeyDown:a=>{a.key==="Enter"&&P.trim()&&L.mutate()}})}),e("div",{className:n.optionsArea,children:e("label",{className:n.checkboxLabel,children:[e("input",{type:"checkbox",checked:M,onChange:a=>de(a.target.checked),className:n.checkbox,disabled:L.isPending}),e("span",{className:n.checkboxCustom}),e("div",{className:n.optionText,children:[e("span",{className:n.optionTitle,children:"Replace AniList-linked manga"}),e("span",{className:n.optionDesc,children:"Clears previously imported (anilist:) entries before importing. Your provider bookmarks are never touched."})]})]})})]}):e(d,{children:[e("p",{className:n.syncHint,children:"Merges chapter progress non-destructively: pushes manga and chapters you read on dango to AniList, and pulls anything you updated on AniList into dango. Local titles are linked only on exact title matches, and bookmarks with no chapters read are never pushed."}),e("div",{className:n.radioGroup,children:[e("label",{className:n.radioLabel,children:[e("input",{type:"radio",name:"mangaDirection",value:"two-way",checked:Z==="two-way",onChange:()=>be("two-way")}),e("span",{children:"Two-way"})]}),e("label",{className:n.radioLabel,children:[e("input",{type:"radio",name:"mangaDirection",value:"pull-only",checked:Z==="pull-only",onChange:()=>be("pull-only")}),e("span",{children:"Pull only (never writes to AniList)"})]})]})]}),G==="username"?e("button",{className:n.syncBtn,onClick:()=>L.mutate(),disabled:!P.trim()||L.isPending,children:[e(l,{name:"download"}),L.isPending?"Importing...":"Start Import"]}):e(d,{children:[e("button",{className:n.syncBtn,onClick:()=>H.mutate(),disabled:H.isPending,children:[e(l,{name:"sync-alt",className:H.isPending?n.spin:""}),H.isPending?"Syncing...":"Start Manga Sync"]}),c&&e(d,{children:[e("div",{className:n.syncSummary,children:["Pushed: ",c.pushed," · Pulled: ",c.pulled," · Merged: ",c.merged," · Unchanged:"," ",c.unchanged,(c.skipped??0)>0&&e("span",{children:[" · Skipped: ",c.skipped]}),c.errors.length>0&&e("span",{className:n.syncErrors,children:[" ","· ",c.errors.length," error",c.errors.length>1?"s":""]})]}),(c.warnings?.length??0)>0&&e("div",{className:n.syncErrors,style:{marginTop:"8px"},children:[(c.warnings??[]).slice(0,5).map((a,r)=>e("div",{children:["⚠ ",a]},r)),(c.warnings?.length??0)>5&&e("div",{children:["+",(c.warnings?.length??0)-5," more warning(s)"]})]})]})]}),e("p",{style:{fontSize:"0.75rem",color:"var(--text-tertiary)",marginTop:"8px"},children:["AniList ",e("code",{children:"Rereading (REPEATING)"})," is not tracked — entries with this status are ignored."]})]}):e("p",{className:n.loginText,children:"Connect your AniList account above to sync your manga reading list."})]})}),!k&&e(d,{children:e("div",{className:n.importCard,children:[e("div",{className:n.cardHeader,children:e("div",{className:n.cardTitleRow,children:[e(l,{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:F==="username",onChange:()=>je("username")}),e("span",{children:"Username"})]}),e("label",{className:n.radioLabel,children:[e("input",{type:"radio",name:"malMode",value:"xml",checked:F==="xml",onChange:()=>je("xml")}),e("span",{children:"XML File"})]})]}),F==="username"?e(d,{children:[e("div",{className:n.inputGroup,children:e("input",{type:"text",placeholder:"Enter MAL username",value:B,onChange:a=>Ie(a.target.value),className:n.input,disabled:u.isPending,onKeyDown:a=>{a.key==="Enter"&&B.trim()&&u.mutate({erase:w,useOfflineDb:D,skipFallback:$})}})}),u.isPending&&e("div",{className:n.importLoading,children:[e(l,{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:Ye,disabled:T}),e("div",{className:n.fileDisplay,children:[e(l,{name:"file-alt",className:n.fileIcon}),e("span",{className:n.fileName,children:Me||"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:w,onChange:a=>xe(a.target.checked),className:n.checkbox,disabled:T||u.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:D,onChange:a=>ze(a.target.checked),className:n.checkbox,disabled:T||u.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:$,onChange:a=>Xe(a.target.checked),className:n.checkbox,disabled:T||u.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."})]})]})]}),F==="username"?e("button",{className:n.syncBtn,onClick:()=>u.mutate({erase:w,useOfflineDb:D,skipFallback:$}),disabled:!B.trim()||u.isPending,children:[e(l,{name:"download"}),u.isPending?"Importing...":"Start Import"]}):e("div",{className:n.actions,children:T?e(le,{onClick:Ve,className:n.cancelBtn,children:"Cancel Import"}):e(le,{onClick:Je,className:n.importBtn,disabled:!Me,children:[e(l,{name:"upload"})," Start Import"]})}),F==="username"&&u.isError&&e("div",{className:`${n.statusMessage} ${n.error}`,children:u.error.message}),T&&p&&e("div",{className:n.progressSection,children:[e("div",{className:n.progressBar,children:e("div",{className:n.progressFill,style:{width:`${Ze}%`}})}),e("div",{className:n.progressInfo,children:[e("span",{className:n.progressCount,children:[p.current," / ",p.total]}),e("span",{className:n.progressTitle,children:p.found?e(d,{children:[p.matchedTitle,e("span",{className:`${n.sourceBadge} ${n[p.source||"anilist"]}`,children:p.source==="kitsu"?"Kitsu":p.source==="offline"?"Offline DB":"AniList"})]}):e("span",{className:n.skipped,children:["Skipped: ",p.title]})})]})]}),ae&&e("div",{className:`${n.statusMessage} ${n.success}`,children:["Import complete! Imported: ",ae.imported,", Skipped: ",ae.skipped,"."]}),Ae&&e("div",{className:`${n.statusMessage} ${n.error}`,children:Ae})]})}),k&&e("div",{className:n.importCard,children:[e("div",{className:n.cardHeader,children:e("div",{className:n.cardTitleRow,children:[e(l,{name:"myanimelist",className:n.malIcon}),e("h3",{children:"MyAnimeList Manga"})]})}),e("div",{className:n.radioGroup,children:[e("label",{className:n.radioLabel,children:[e("input",{type:"radio",name:"malMangaMode",value:"username",checked:W==="username",onChange:()=>fe("username")}),e("span",{children:"Username"})]}),e("label",{className:n.radioLabel,children:[e("input",{type:"radio",name:"malMangaMode",value:"xml",checked:W==="xml",onChange:()=>fe("xml")}),e("span",{children:"XML File"})]})]}),W==="username"?e("div",{className:n.inputGroup,children:e("input",{type:"text",placeholder:"Enter MAL username",value:E,onChange:a=>_e(a.target.value),className:n.input,disabled:f.isPending,onKeyDown:a=>{a.key==="Enter"&&E.trim()&&f.mutate()}})}):e("div",{className:n.uploadArea,children:e("div",{className:n.fileInputWrapper,children:[e("input",{type:"file",id:"malMangaFile",accept:".xml,application/xml",className:n.fileInput,onChange:a=>He(a.target.files?.[0]?.name??""),disabled:z}),e("div",{className:n.fileDisplay,children:[e(l,{name:"file-alt",className:n.fileIcon}),e("span",{className:n.fileName,children:we||"Choose XML file..."})]}),e("label",{htmlFor:"malMangaFile",className:n.browseButton,children:"Browse"})]})}),e("div",{className:n.optionsArea,children:e("label",{className:n.checkboxLabel,children:[e("input",{type:"checkbox",checked:M,onChange:a=>de(a.target.checked),className:n.checkbox,disabled:f.isPending||z}),e("span",{className:n.checkboxCustom}),e("div",{className:n.optionText,children:[e("span",{className:n.optionTitle,children:"Replace AniList-linked manga"}),e("span",{className:n.optionDesc,children:"Clears previously imported (anilist:) entries before importing. Your provider bookmarks are never touched."})]})]})}),W==="username"?e("button",{className:n.syncBtn,onClick:()=>f.mutate(),disabled:!E.trim()||f.isPending,children:[e(l,{name:"download"}),f.isPending?"Importing...":"Start Import"]}):e("div",{className:n.actions,children:e(le,{onClick:We,className:n.importBtn,disabled:z||!we,children:[e(l,{name:"upload"})," ",z?"Importing...":"Start Import"]})}),f.isError&&e("div",{className:`${n.statusMessage} ${n.error}`,children:f.error.message}),ve&&e("div",{className:`${n.statusMessage} ${n.error}`,children:ve}),ee&&e("div",{className:`${n.statusMessage} ${n.success}`,children:["Import complete! Imported: ",ee.imported,", Skipped:"," ",ee.skipped,"."]}),e("p",{style:{fontSize:"0.75rem",color:"var(--text-tertiary)",marginTop:"8px"},children:"MAL manga is matched to AniList by MAL ID with a title fallback. Unmatched titles are skipped. Imports land as AniList-linked entries alongside your provider bookmarks."})]})]})};export{va as default};
@@ -0,0 +1,4 @@
1
+ import{d as b,A as x,h as S,u as t,S as Ae,n as Wr,o as zr,a as Hr,T as Ce,q as C}from"./vendor-core-8R2fFbyN.js";import{u as Ur}from"./vendor-query-BUTye89G.js";import{e as Pn,t as tt,z as qr,M as mn,B as Te}from"./index-BXwhFWB_.js";import{I as D}from"./vendor-icons-CDMuNDeL.js";import{M as Kr,t as mr,f as Dn,d as jr,C as Yr,S as Qr,U as Gr,a as Jr,p as On,u as Xr,b as Zr,c as es,l as ts,q as ns,i as Ln,v as rs,w as ss,x as dr,s as Rn,e as as,g as os,h as is,r as ls,j as nt,k as cs,E as ds,A as us,P as ms,m as ye,o as hs}from"./AvSyncCalibrator-3yjZS7s6.js";import{O as pn,S as ps,a as gs,A as fs}from"./OptionListMenu-CJ90CdwI.js";import{u as vs}from"./useMatureConsent-CT7-KfzG.js";import{u as bs}from"./useProviders-B5Qr4I1y.js";import{d as ys,g as Ss,h as _s,f as Cs,e as Ts,j as ks,k as xs}from"./useTvLibrary-B7jEk2Q7.js";import{l as Es,c as Ns}from"./hls-Boje3IOE.js";import{u as ws}from"./useIsMobile-Dm_b6Ob3.js";import{S as Is}from"./SynopsisText-BcpwT5iw.js";const Bs="_fullscreenFlat_11xhe_1",Ms="_timeDisplay_11xhe_15",As="_bottomControls_11xhe_19",Ps="_leftControls_11xhe_23",Ls="_rightControls_11xhe_24",Rs="_controlBtn_11xhe_28",$s="_controlsOverlay_11xhe_47",Ds="_hidden_11xhe_67",Os="_topControls_11xhe_73",Vs="_backBtn_11xhe_93",Fs="_videoTitleInfo_11xhe_113",Ws="_animeTitle_11xhe_119",zs="_episodeLabel_11xhe_127",Hs="_speedBoostBadge_11xhe_134",Us="_progressBarContainer_11xhe_180",qs="_progressBar_11xhe_180",Ks="_thumb_11xhe_199",js="_bufferedBar_11xhe_217",Ys="_watchedBar_11xhe_227",Qs="_scrubbing_11xhe_252",Gs="_timeBubble_11xhe_256",Js="_bottomControlsRow_11xhe_270",Xs="_nextEpisodeBtn_11xhe_293",Zs="_active_11xhe_346",ea="_settingsPanel_11xhe_421",ta="_settingsHeader_11xhe_440",na="_settingsBackBtn_11xhe_448",ra="_settingsTitle_11xhe_466",sa="_settingsContent_11xhe_477",aa="_currentValue_11xhe_486",oa="_menuItem_11xhe_501",ia="_menuNote_11xhe_534",la="_loadingOverlay_11xhe_547",ca="_loadingDots_11xhe_558",da="_dot_11xhe_563",ua="_bufferingOverlay_11xhe_592",ma="_bufferingSpinner_11xhe_601",a={fullscreenFlat:Bs,timeDisplay:Ms,bottomControls:As,leftControls:Ps,rightControls:Ls,controlBtn:Rs,controlsOverlay:$s,hidden:Ds,topControls:Os,backBtn:Vs,videoTitleInfo:Fs,animeTitle:Ws,episodeLabel:zs,speedBoostBadge:Hs,progressBarContainer:Us,progressBar:qs,thumb:Ks,bufferedBar:js,watchedBar:Ys,scrubbing:Qs,timeBubble:Gs,bottomControlsRow:Js,nextEpisodeBtn:Xs,active:Zs,settingsPanel:ea,settingsHeader:ta,settingsBackBtn:na,settingsTitle:ra,settingsContent:sa,currentValue:aa,menuItem:oa,menuNote:ia,loadingOverlay:la,loadingDots:ca,dot:da,bufferingOverlay:ua,bufferingSpinner:ma},hn=-1e4,$n=1e4,ur=500,ha=({classes:u,delayMs:w,onDelayChange:J})=>{const[U,F]=b(null),O=U??w,r=x(J);r.current=J;const L=x(w);L.current=w;const ae=x(null);ae.current=U,S(()=>{F(null)},[w]),S(()=>()=>{const q=ae.current;q!==null&&q!==L.current&&r.current(q)},[]);const he=q=>{L.current=q,ae.current=null,r.current(q),F(null)},i=q=>{const re=ae.current??L.current,Ve=Math.max(hn,Math.min($n,re+q));he(Ve)};return t(Ae,{children:[t("div",{style:{display:"flex",gap:6,padding:"0.5rem 0.75rem 0.25rem"},children:[t("button",{type:"button",className:u.item,onClick:()=>i(-ur),"aria-label":"Show subtitles 0.5 seconds earlier",style:{flex:1,justifyContent:"center"},children:t("span",{children:"-0.5s"})}),t("button",{type:"button",className:u.item,onClick:()=>i(ur),"aria-label":"Show subtitles 0.5 seconds later",style:{flex:1,justifyContent:"center"},children:t("span",{children:"+0.5s"})}),t("button",{type:"button",className:u.item,onClick:()=>he(0),disabled:O===0,"aria-label":"Reset subtitle timing",style:{flex:1,justifyContent:"center"},children:t("span",{children:"Reset"})})]}),t(Kr,{label:"Subtitle timing",display:mr(O),min:hn,max:$n,step:100,value:O,percent:(O-hn)/($n-hn)*100,onChange:q=>{const re=Math.round(q);ae.current=re,F(re)},onCommit:()=>{const q=ae.current;q!==null&&he(q)}}),t("div",{className:u.note,children:"Positive delays subtitles (show later). Negative shows them earlier. 0.0s is default."})]})},pa=({classes:u,tracks:w,selected:J,onChange:U})=>t(pn,{classes:u,options:w.map((F,O)=>({key:String(O),label:F.label||F.language,selected:O===J})),onSelect:F=>U(Number(F))}),ga=({player:u,title:w,episodeLabel:J,audioTracks:U,selectedAudioTrack:F,onAudioTrackChange:O,subtitles:r,selectedSubtitle:L,onSubtitleChange:ae,streams:he,qualityIdx:i,onQualityChange:q,onBack:re,children:Ve,movyServers:f=[],selectedMovyServer:Se="atlanta",onMovyServerSelect:$,isMovySource:Dt=!1,videoDelayEnabled:oe=!1,onVideoDelayToggle:Fe,videoDelayMs:Ct=0,onVideoDelayChange:Tt,onCalibrateAvSync:Ot,subtitleDelayMs:Vt=0,onSubtitleDelayChange:gn,showNextEpisodeButton:Ft=!1,onNextEpisode:ie,isLoading:We=!1})=>{const{state:T,refs:rt,actions:M}=u,K=rt.videoRef,{subtitleFontSize:j,subtitlePosition:Pe,subtitleBgOpacity:st,subtitleBgColor:ke,subtitleTextColor:ze,subtitleEdge:pe,subtitleBold:He}=T,[y,Q]=b(null),Le=x(null),[Wt,at]=b(0);S(()=>{const l=K.current;if(!l)return;const c=()=>at(l.clientHeight||0);c();const te=new ResizeObserver(c);return te.observe(l),()=>te.disconnect()},[K,he]);const ge=(l,c)=>{try{localStorage.setItem(l,String(c))}catch{}},ot=(l,c)=>{switch(l){case"fontSize":typeof c=="number"&&(M.setSubtitleFontSize(c),ge("subtitleFontSize",c));break;case"position":typeof c=="number"&&(M.setSubtitlePosition(c),ge("subtitlePosition",c));break;case"bgOpacity":typeof c=="number"&&(M.setSubtitleBgOpacity(c),ge("subtitleBgOpacity",c));break;case"bgColor":typeof c=="string"&&(M.setSubtitleBgColor(c),ge("subtitleBgColor",c));break;case"textColor":typeof c=="string"&&(M.setSubtitleTextColor(c),ge("subtitleTextColor",c));break;case"edge":(c==="shadow"||c==="outline"||c==="none")&&(M.setSubtitleEdge(c),ge("subtitleEdge",c));break;case"bold":typeof c=="boolean"&&(M.setSubtitleBold(c),ge("subtitleBold",c));break}};S(()=>{const l="tv-player-subtitle-style";let c=document.getElementById(l);c||(c=document.createElement("style"),c.id=l,document.head.appendChild(c));const te={fontSize:j,position:Pe,bgOpacity:st,bgColor:ke,textColor:ze,edge:pe,bold:He},Z=K.current,Et=Dn(j,Wt||Z?.clientHeight||720);if(c.textContent=jr({...te,fontSize:Et}),Z){const Be=()=>{const E=Number(Pe);return isNaN(E)?0:Math.max(0,Math.min(100,E))},Nt=(E,I)=>{try{const ee=E;ee.snapToLines=!1,ee.line=I}catch{}},wt=()=>{const E=Et*16,I=Z.videoHeight||Z.clientHeight||720,ee=Z.videoWidth||Z.clientWidth||1280;return{step:E*1.3/I*100,chars:Math.max(20,Math.floor(ee/(E*.55)))}},Yt=E=>{const I=Math.max(0,Math.min(100,100-Be())),ee=Array.from(E.activeCues??[]);if(ee.length<=1){ee.forEach(fe=>Nt(fe,I));return}const{step:mt,chars:ht}=wt();let Jt=I;for(let fe=ee.length-1;fe>=0;fe--){const pt=String(ee[fe].text??"").replace(/<[^>]*>/g,"").split(`
2
+ `).reduce((Xt,gt)=>Xt+Math.max(1,Math.ceil(gt.length/ht)),0),R=Jt-pt*mt;Nt(ee[fe],Math.max(0,R)),Jt=R-mt*.4}},It=()=>{const E=Math.max(0,Math.min(100,100-Be()));Array.from(Z.textTracks).forEach(I=>{I.cues&&(Array.from(I.cues).forEach(ee=>Nt(ee,E)),I.mode==="showing"&&Yt(I))})};It();const dt=E=>{const I=E.target;I.mode==="showing"&&Yt(I)},Qt=()=>{Array.from(Z.textTracks).forEach(E=>{E.removeEventListener("cuechange",dt),E.addEventListener("cuechange",dt)}),It()};Array.from(Z.textTracks).forEach(E=>{E.addEventListener("cuechange",dt)}),Z.textTracks.addEventListener("addtrack",Qt);const Gt=Array.from(Z.querySelectorAll("track")),ut=()=>It();return Gt.forEach(E=>E.addEventListener("load",ut)),()=>{Array.from(Z.textTracks).forEach(E=>{E.removeEventListener("cuechange",dt)}),Z.textTracks.removeEventListener("addtrack",Qt),Gt.forEach(E=>E.removeEventListener("load",ut))}}},[j,Pe,st,ke,ze,pe,He,L,r,K,Wt]);const fn=l=>{const c=K.current;!c||isNaN(T.duration)||T.duration===0||(c.currentTime=l*T.duration)},kt=()=>{K.current&&(M.setIsScrubbing(!0),M.wasPlayingBeforeScrub.current=!K.current.paused,K.current.pause())},Ue=l=>{const c=K.current;c&&T.duration&&(c.currentTime=l*T.duration)},X=()=>{M.setIsScrubbing(!1),M.wasPlayingBeforeScrub.current&&K.current?.play().catch(()=>{})},zt=l=>{const c=K.current;c&&(c.volume=l,c.muted=l===0,localStorage.setItem("playerVolume",l.toString()))},xt=()=>{M.toggleMute()},A=r.length>0,W=L>=0,Ht=()=>{Q("main"),M.setShowControls(!0)},Ut=()=>{if(W){ae(-1);return}let l=null;try{l=localStorage.getItem("tvLastSubtitle")}catch{}ae(On(r,{lastKey:l,enabled:!0}))},it=()=>{Q(null)},vn=()=>t(Ae,{children:[he.length>1&&t("button",{className:a.menuItem,onClick:()=>Q("quality"),children:[t("span",{children:"Quality"}),t("span",{className:a.currentValue,children:he[i]?.quality||"Auto"})]}),Dt&&f.length>0&&t("button",{className:a.menuItem,onClick:()=>Q("server"),children:[t("span",{style:{display:"flex",alignItems:"center",gap:6},children:[t(D,{name:"server",size:12})," Movy Server"]}),t("span",{className:a.currentValue,style:{textTransform:"capitalize"},children:Se})]}),A&&t("button",{className:a.menuItem,onClick:()=>Q("subtitles"),children:[t("span",{children:"Subtitles"}),t("span",{className:a.currentValue,children:W?r[L]?.label||r[L]?.language:"Off"})]}),A&&t("button",{className:a.menuItem,onClick:()=>Q("subtitle-style"),children:[t("span",{children:"Subtitle Style"}),t("span",{className:a.currentValue,children:[j.toFixed(1),"x · ",Pe]})]}),A&&t("button",{className:a.menuItem,onClick:()=>Q("subtitle-timing"),children:[t("span",{children:"Subtitle Timing"}),t("span",{className:a.currentValue,children:mr(Vt)})]}),U.length>0&&t("button",{className:a.menuItem,onClick:()=>Q("audio"),children:[t("span",{children:"Audio Track"}),t("span",{className:a.currentValue,children:U[F]?.label||U[F]?.language})]}),t("button",{className:a.menuItem,onClick:()=>Q("av-sync"),children:[t("span",{children:"A/V Sync"}),t("span",{className:a.currentValue,children:oe?`${Ct}ms`:"Off"})]})]}),_=()=>t(pn,{classes:{item:a.menuItem,active:a.active},options:he.map((l,c)=>({key:String(c),label:l.quality,selected:c===i})),onSelect:l=>q(Number(l))}),d=()=>t(pn,{classes:{item:a.menuItem,active:a.active},options:[{key:"off",label:"Off",selected:!W},...r.map((l,c)=>({key:String(c),label:l.label||l.language,selected:c===L}))],onSelect:l=>ae(l==="off"?-1:Number(l))}),le=()=>t(gs,{classes:{item:a.menuItem,active:a.active},values:{fontSize:j,position:Pe,bgOpacity:st,bgColor:ke,textColor:ze,edge:pe,bold:He},onChange:ot}),ce=()=>t(ha,{classes:{item:a.menuItem,active:a.active,note:a.menuNote},delayMs:Vt,onDelayChange:l=>gn?.(l)}),qt=()=>t(pa,{classes:{item:a.menuItem,active:a.active},tracks:U,selected:F,onChange:O}),Kt=()=>t(pn,{classes:{item:a.menuItem,active:a.active},options:f.map(l=>({key:l,label:t("span",{style:{textTransform:"capitalize"},children:l}),selected:Se===l})),onSelect:l=>$?.(l)}),qe=()=>t(fs,{classes:{item:a.menuItem,active:a.active,note:a.menuNote},enabled:oe,delayMs:Ct,onToggle:l=>Fe?.(l),onDelayChange:l=>Tt?.(l),onCalibrate:()=>{Q(null),Ot?.()}}),jt=T.isMuted?t(D,{name:"volume-mute"}):T.volume<.5?t(D,{name:"volume-down"}):t(D,{name:"volume-up"}),Ke=t("div",{className:`${a.controlsOverlay} ${!T.showControls&&!y?a.hidden:""}`,"data-speed-boost-ignore":"true",style:{pointerEvents:"none",background:"none"},children:t("div",{className:a.topControls,onClick:l=>l.stopPropagation(),children:[t("button",{className:a.backBtn,onClick:re,title:"Back","aria-label":"Back",children:t(D,{name:"chevron-left"})}),t("div",{className:a.videoTitleInfo,children:[t("span",{className:a.animeTitle,children:w}),J&&t("span",{className:a.episodeLabel,children:J})]})]})}),lt=!We&&!T.isBuffering&&T.duration>0?t(Yr,{isPlaying:T.isPlaying,onTogglePlay:M.togglePlay,onSkipBack:()=>M.seek(-10),onSkipForward:()=>M.seek(10)}):null,bn=t("div",{className:`${a.controlsOverlay} ${!T.showControls&&!y?a.hidden:""}`,"data-speed-boost-ignore":"true",style:{pointerEvents:"none",background:"none",justifyContent:"flex-end"},children:t("div",{className:a.bottomControls,onClick:l=>l.stopPropagation(),children:[t(Qr,{classes:{container:a.progressBarContainer,scrubbing:a.scrubbing,timeBubble:a.timeBubble,bar:a.progressBar,buffered:a.bufferedBar,watched:a.watchedBar,thumb:a.thumb},videoRef:K,duration:T.duration,formatTime:Pn,isScrubbing:T.isScrubbing,buffered:"full",onSeek:fn,onScrubStart:kt,onScrubMove:Ue,onScrubEnd:X,timeLabelRef:Le}),t("div",{className:a.bottomControlsRow,children:[t("div",{className:a.leftControls,children:[t("button",{className:a.controlBtn,onClick:M.togglePlay,"aria-label":T.isPlaying?"Pause":"Play",children:T.isPlaying?t(D,{name:"pause"}):t(D,{name:"play"})}),t(Gr,{muted:T.isMuted,volume:T.volume,volumeIcon:jt,buttonClassName:a.controlBtn,onToggleMute:xt,onVolumeChange:zt,onExpandedChange:l=>M.setShowVolumeSlider(l)}),t("span",{className:a.timeDisplay,ref:Le,children:[Pn(0)," / ",Pn(T.duration)]})]}),t("div",{className:a.rightControls,children:[Ft&&t("button",{className:a.nextEpisodeBtn,onClick:ie,title:"Play next episode",children:"Next EP"}),A&&t("button",{className:`${a.controlBtn} ${W?a.active:""}`,onClick:Ut,"aria-label":W?"Turn subtitles off":"Turn subtitles on",children:t(D,{name:"closed-captioning"})}),t("button",{className:`${a.controlBtn} ${y?a.active:""}`,onClick:()=>y?it():Ht(),"aria-label":"Settings",children:t(D,{name:"cog"})}),t("button",{className:a.controlBtn,onClick:M.toggleFullscreen,"aria-label":T.isFullscreen?"Exit Fullscreen":"Fullscreen",children:T.isFullscreen?t(D,{name:"compress"}):t(D,{name:"expand"})})]})]})]})}),ct=y?t("div",{"data-speed-boost-ignore":"true",onClick:l=>l.stopPropagation(),children:t(ps,{classes:{panel:a.settingsPanel,header:a.settingsHeader,backBtn:a.settingsBackBtn,title:a.settingsTitle,content:a.settingsContent},title:y==="main"?"Settings":y==="subtitle-style"?"Subtitle Style":y==="subtitle-timing"?"Subtitle Timing":y==="audio"?"Audio Track":y==="server"?"Movy Server":y==="av-sync"?"A/V Sync":y.charAt(0).toUpperCase()+y.slice(1),onBack:()=>y==="main"?it():Q("main"),children:[y==="main"&&vn(),y==="quality"&&_(),y==="subtitles"&&d(),y==="subtitle-style"&&le(),y==="subtitle-timing"&&ce(),y==="audio"&&qt(),y==="server"&&Kt(),y==="av-sync"&&qe()]})}):null,_e=t(Ae,{children:[We&&t("div",{className:a.loadingOverlay,"aria-hidden":"true",children:t("div",{className:a.loadingDots,children:[t("div",{className:a.dot}),t("div",{className:a.dot}),t("div",{className:a.dot})]})}),T.isBuffering&&!We&&t("div",{className:a.bufferingOverlay,"aria-hidden":"true",children:t("div",{className:a.bufferingSpinner})}),T.isSpeedBoostActive&&t("div",{className:a.speedBoostBadge,"aria-hidden":"true",children:[t("span",{children:"2x"}),t(D,{name:"forward",size:12})]})]});return t(Jr,{player:u,topBar:Ke,centerControls:lt,bottomBar:!We&&!T.isBuffering&&T.duration>0?bn:null,settingsPanel:ct,overlays:_e,isInteracting:!!y,className:T.isFullscreen?a.fullscreenFlat:"",children:Ve})};function fa(u,w,J){const U=()=>{const O=Array.isArray(u.audioTracks)?u.audioTracks.length:0,r=J.getWant(),L=O>0?Math.min(Math.max(0,r),O-1):r;u.audioTrack=L,L!==r&&J.onResolve(L)},F=(O,r)=>{const L=J.getWant(),ae=Array.isArray(u.audioTracks)?u.audioTracks.length:0;if(r.id!==L&&L>=0&&L<ae){u.audioTrack!==L&&(u.audioTrack=L);return}J.onResolve(r.id)};return u.on(w.MANIFEST_PARSED,U),u.on(w.AUDIO_TRACK_SWITCHED,F),()=>{u.off(w.MANIFEST_PARSED,U),u.off(w.AUDIO_TRACK_SWITCHED,F)}}const va="_page_263ma_1",ba="_header_263ma_7",ya="_pageTitle_263ma_11",Sa="_searchForm_263ma_21",_a="_searchInput_263ma_27",Ca="_searchBtn_263ma_42",Ta="_suggestions_263ma_58",ka="_suggestionPill_263ma_65",xa="_statusMsg_263ma_81",Ea="_error_263ma_87",Na="_textOnly_263ma_91",wa="_spinner_263ma_96",Ia="_spin_263ma_96",Ba="_grid_263ma_110",Ma="_skeletonCard_263ma_116",Aa="_skeletonThumb_263ma_121",Pa="_skeletonLine_263ma_127",La="_shimmer_263ma_134",Ra="_backBtn_263ma_154",$a="_meta_263ma_172",Da="_headerActions_263ma_180",Oa="_watchlistBtn_263ma_187",Va="_active_263ma_205",Fa="_year_263ma_215",Wa="_rating_263ma_220",za="_typeBadge_263ma_229",Ha="_tv_263ma_237",Ua="_movie_263ma_242",qa="_tvSeries_263ma_247",Ka="_tvMiniSeries_263ma_252",ja="_overview_263ma_257",Ya="_controls_263ma_264",Qa="_controlLabel_263ma_272",Ga="_select_263ma_282",Ja="_playerSection_263ma_293",Xa="_video_263ma_297",Za="_videoHidden_263ma_319",eo="_delayCanvas_263ma_324",to="_delayCanvasActive_263ma_337",no="_subtitleOverlay_263ma_341",ro="_videoIframe_263ma_360",so="_retryButton_263ma_368",ao="_sidebarSeason_263ma_383",oo="_mobileSeasonRow_263ma_399",io="_sidebarPosterCard_263ma_413",lo="_sidebarPosterMeta_263ma_428",co="_providerSelectWrap_263ma_445",uo="_genreRow_263ma_457",mo="_genreChip_263ma_464",ho="_metaRow_263ma_474",po="_detailGrid_263ma_483",go="_detailItem_263ma_490",fo="_imdbLink_263ma_512",p={page:va,header:ba,pageTitle:ya,searchForm:Sa,searchInput:_a,searchBtn:Ca,suggestions:Ta,suggestionPill:ka,statusMsg:xa,error:Ea,textOnly:Na,spinner:wa,spin:Ia,grid:Ba,skeletonCard:Ma,skeletonThumb:Aa,skeletonLine:Pa,shimmer:La,backBtn:Ra,meta:$a,headerActions:Da,watchlistBtn:Oa,active:Va,year:Fa,rating:Wa,typeBadge:za,tv:Ha,movie:Ua,tvSeries:qa,tvMiniSeries:Ka,overview:ja,controls:Ya,controlLabel:Qa,select:Ga,playerSection:Ja,video:Xa,videoHidden:Za,delayCanvas:eo,delayCanvasActive:to,subtitleOverlay:no,videoIframe:ro,retryButton:so,sidebarSeason:ao,mobileSeasonRow:oo,sidebarPosterCard:io,sidebarPosterMeta:lo,providerSelectWrap:co,genreRow:uo,genreChip:mo,metaRow:ho,detailGrid:po,detailItem:go,imdbLink:fo},vo=[],Mo=()=>{const{id:u}=Wr(),[w]=zr(),J=x(w);J.current=w;const U=Hr(),F=Ur(),O=w.get("type"),[r,L]=b(null),[ae,he]=b(!1),[i,q]=b(()=>parseInt(w.get("s")||"1",10)||1),[re,Ve]=b([]),[f,Se]=b(()=>parseInt(w.get("e")||"1",10)||1),[$,Dt]=b(()=>{try{return localStorage.getItem("tvProvider")||""}catch{return""}}),[oe,Fe]=b([]),[Ct,Tt]=b(""),{options:Ot,isFallback:Vt,isLoading:gn}=bs(),Ft=Ce(()=>Ot.filter(e=>(e.kind??"tv")==="tv").map(e=>({id:e.value,label:e.label,tier:e.tier==="embed"?"embed":"direct",servers:e.servers})),[Ot]),ie=Vt||Ft.length===0?vo:Ft,We=ie.filter(e=>e.tier==="direct"),T=ie.filter(e=>e.tier==="embed"),[rt,M]=b(!1),[K,j]=b(""),[Pe,st]=b([]),[ke,ze]=b(0),[pe,He]=b([]),[y,Q]=b(-1),[Le,Wt]=b("all"),[at,ge]=b(0),[ot,fn]=b(""),[kt,Ue]=b(""),[X,zt]=b(()=>{try{return localStorage.getItem("movyServer")||""}catch{return""}}),xt=Ce(()=>ie.find(e=>e.id===$),[ie,$]),A=xt?.tier==="embed",W=Ce(()=>xt?.servers??[],[xt]),Ht=x([]);S(()=>{Ht.current=oe},[oe]);const Ut=x(ke);S(()=>{Ut.current=ke},[ke]);const it=x(y);S(()=>{it.current=y},[y]);const vn=Ce(()=>[],[]),_=Xr({skipIntervals:vn}),d=_.refs.videoRef,le=x(null),ce=x([]),qt=x(null),Kt=x(null),[qe,jt]=b(()=>{try{const e=Number(localStorage.getItem("playerVideoDelayMs"));if(Number.isFinite(e)&&e>=0&&e<=500)return Math.round(e)}catch{}return 180}),[Ke,lt]=b(()=>{try{return localStorage.getItem("playerVideoDelayEnabled")==="true"}catch{return!1}}),[bn,ct]=b(!1),[_e,l]=b(!1),c=x(null),te=x(null),Z=(e,n)=>{try{localStorage.setItem("playerVideoDelayMs",String(e)),localStorage.setItem("playerVideoDelayEnabled",String(n))}catch{}},Et=e=>{const n=Math.max(0,Math.min(500,Math.round(e)));jt(n);try{localStorage.setItem("playerVideoDelayMs",String(n))}catch{}},[Be,Nt]=b(()=>{try{const e=Number(localStorage.getItem("tvSubtitleDelayMs"));if(Number.isFinite(e)&&e>=-1e4&&e<=1e4)return Math.round(e)}catch{}return 0}),wt=x(Be);wt.current=Be;const Yt=C(e=>{const n=Math.max(-1e4,Math.min(1e4,Math.round(e)));if(wt.current!==n){wt.current=n,Nt(n);try{localStorage.setItem("tvSubtitleDelayMs",String(n))}catch{}}},[]),It=()=>{c.current={enabled:Ke,ms:qe},lt(!0);try{localStorage.setItem("playerVideoDelayEnabled","true")}catch{}ct(!0)},dt=()=>{const e=c.current;c.current=null,e&&(jt(e.ms),lt(e.enabled),Z(e.ms,e.enabled)),l(!1),ct(!1)},Qt=()=>{c.current=null,lt(!0),Z(qe,!0),l(!1),ct(!1)},Gt=()=>{if(_e){l(!1);return}const e=d.current;e&&!isNaN(e.currentTime)&&(te.current=e.currentTime),l(!0)},ut=Ke?qe:0;Zr({videoRef:d,canvasRef:qt,delayMs:ut,enabled:Ke});const E=Ke,I=E||Be!==0,ee=x(I);ee.current=I;const mt=C(()=>{if(!ee.current)return;const e=d.current;e&&Array.from(e.textTracks).forEach(n=>{n.mode!=="hidden"&&(n.mode="hidden")})},[d]),{hasConsent:ht,grant:Jt}=vs(),fe=x("");fe.current||(fe.current=`tv-${Date.now()}-${Math.random().toString(36).slice(2)}`);const h=O==="movie",pt=u?ys(O||"tv",u):"",R=pt,Xt=Ss(),gt=_s(),{toggle:Vn,bookmarkedIds:hr,pending:pr}=Cs(),{data:Fn}=Ts(r?pt:void 0),Zt=Fn?!!Fn.inLibrary:pt?hr.has(pt):!1,gr=C(()=>{!r||!u||Vn({tmdbId:Number(u),mediaType:O||"tv",title:r.title,poster:r.poster,year:r.year,adult:r.adult})},[r,u,O,Vn]),{data:je,isFetched:Wn,isPending:zn}=ks(R||void 0,i,f),en=Ce(()=>re.map(e=>e.episode_number).sort((e,n)=>e-n),[re]),Ye=en.indexOf(f),yn=Ye>0?en[Ye-1]:null,N=Ye>=0&&Ye<en.length-1?en[Ye+1]:null,tn=Ce(()=>(r?.seasons??[]).map(e=>e.season_number).filter(e=>Number.isFinite(e)).sort((e,n)=>e-n),[r]),ve=Ce(()=>{if(h||N!=null)return null;const e=tn.indexOf(i);return e>=0&&e<tn.length-1?tn[e+1]:(r?.number_of_seasons??0)>i?i+1:null},[h,N,tn,i,r?.number_of_seasons]),Hn=je?.currentTime??0,Un=je?.duration??0,Sn=je?.completed===!0||je?.completed===1||Ln(Hn,Un),[xe,Me]=b(!1),Ee=x(!1),_n=x(null),Bt=x(null);S(()=>{Ee.current=!1,Bt.current=null,Me(!1)},[R,i,f]);const[Ne,nn]=b(!1),[ft,qn]=b(0),[Qe,Kn]=b(!1),[Re,Ge]=b(!1),[fr,Cn]=b(!1),[vr,jn]=b(""),[rn,br]=b(!1),[yr,Tn]=b(!1);es(_,(oe.length>0||kt!=="")&&!Ne&&!xe&&!Re);const Sr=ws(),[vt,_r]=b(ts),Cr=C(e=>{_r(e),ns(e)},[]),de=x(!1),Je=x(null),kn=x(0),Yn=x(!1),Qn=x(0),ne=x(null),Mt=x(""),Tr=dr(Hn,Un),At=!de.current&&!Ee.current&&(Ne||xe||Re||Sn||Tr),bt=x(At);bt.current=At;const yt=x(!1);S(()=>{yt.current=Qe},[Qe]);const kr=e=>{const n=Math.floor(e/3600),s=Math.floor(e%3600/60),o=Math.floor(e%60);return n>0?`${n}:${String(s).padStart(2,"0")}:${String(o).padStart(2,"0")}`:`${s}:${String(o).padStart(2,"0")}`},$e=C((e,n)=>{if(!R||!n||n<30)return;const s=Ln(e,n),o=s?n:e;Math.abs(o-kn.current)<10&&!s||(kn.current=o,Xt.mutate({mediaId:R,season:i,episode:f,currentTime:Math.floor(o),duration:Math.floor(n),completed:s,title:r?.title??null,poster:r?.poster??null,backdrop:r?.backdrop??null,year:r?.year??null,overview:r?.overview??null,tmdbId:r?.id??null,mediaType:O||"tv",adult:r?.adult?1:0}))},[R,i,f,Xt,r,O]),we=C((e,n)=>{l(!1),ct(!1);const s=new URLSearchParams(w);s.set("type",w.get("type")||"tv"),s.set("s",String(e)),s.set("e",String(n)),U(`${window.location.pathname}?${s.toString()}`)},[w,U]),Pt=C(()=>{const e=d.current;if(!e||h||N==null){Cn(!1);return}const n=e.duration||0,s=e.currentTime||0;Cn(n>0&&s/n>=.8)},[h,N,d]),sn=C((e,n)=>["tv-sources",$,h?"movie":"tv",u,e,n,X],[$,h,u,X]),an=C(async(e,n)=>{if(!r||!u||!$)return{valid:!1,sources:[]};const s=h?"movie":"tv",o=await tt.tv.sources.query({provider:$,type:s,tmdbId:String(u),season:e,episode:n,title:r.title||"",year:r.year||"",totalSeasons:String(r.number_of_seasons||1),imdbId:r.imdb_id||"",...W.length>0&&X?{server:X}:{}});return{valid:"valid"in o?o.valid:!1,error:"error"in o?o.error:void 0,sources:o.sources,referer:"referer"in o?o.referer:void 0,audioTracks:o.audioTracks,subtitles:"subtitles"in o?o.subtitles:void 0}},[r,u,$,h,W,X]),Gn=C(()=>{if(h||!r||!u||!$||A||N==null)return;const e=sn(i,N);F.getQueryState(e)?.status!=="success"&&F.prefetchQuery({queryKey:e,queryFn:()=>an(i,N),staleTime:300*1e3,gcTime:1800*1e3})},[h,r,u,$,A,N,i,F,sn,an]),xr=C(()=>{if(_e)return;Pt();const e=d.current;!e||e.paused||e.ended||(e.duration>0&&e.duration-e.currentTime<=60&&Gn(),Je.current&&clearTimeout(Je.current),Je.current=setTimeout(()=>{$e(e.currentTime,e.duration||0)},5e3))},[$e,d,_e,Pt,Gn]),Er=C(()=>{const e=d.current;if(!e||!r)return;Je.current&&clearTimeout(Je.current),$e(e.currentTime,e.duration||0),Yn.current=!0;const n=rs({seekInduced:Date.now()-Qn.current<ss,autoplayEnabled:vt,hasNext:!h&&N!=null,isFinal:h||N==null});n==="advance"&&N!=null?(Se(N),we(i,N)):n==="prompt-next"?(Ee.current=!1,de.current=!0,Me(!0)):n==="prompt-complete"&&(jn(h?r.title:`${r.title} — Season ${i}`),Ge(!0),Ee.current=!0,de.current=!0)},[h,r,i,N,vt,$e,we,d]),Nr=C(()=>{Yn.current=!1,_.actions.onPlay()},[_.actions]),wr=C(()=>{_.actions.onPause();const e=d.current;e&&!e.ended&&$e(e.currentTime,e.duration||0)},[_.actions,$e,d]),Ir=C(()=>{_.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(ne.current!=null&&ne.current>0){try{e.currentTime=ne.current}catch{}ne.current=null}Pt()}},[_.actions,d,Pt]),St=C(()=>{const e=d.current;if(e&&ne.current!=null&&ne.current>0){try{e.currentTime=ne.current}catch{}ne.current=null}},[d]),Br=C(()=>{ft>0&&(ne.current=ft);const e=d.current;if(e&&ft>0){try{e.currentTime=ft,ne.current=null}catch{}e.play().catch(()=>{})}nn(!1),de.current=!0},[ft,d]),Jn=C(()=>{ne.current=null;const e=d.current;e&&(e.currentTime=0,e.play().catch(()=>{})),nn(!1),de.current=!0},[d]),Mr=C(()=>{Ee.current=!0,Me(!1),de.current=!0},[]),Ar=C(()=>{Ee.current=!0,Me(!1),de.current=!0,ne.current=null;const e=d.current;if(e){try{e.currentTime=0}catch{}e.play().catch(()=>{})}},[d]),Xn=C(()=>{N!=null&&(Ee.current=!0,Me(!1),de.current=!0,Se(N),we(i,N))},[N,i,we]),Zn=C(()=>{ve!=null&&(Ee.current=!0,Me(!1),Ge(!1),de.current=!0,q(ve),Se(1),we(ve,1))},[ve,we]),Pr=C(async()=>{if(R)try{await gt.mutateAsync({id:R,status:"Completed"}),Ge(!1),Me(!1),U("/")}catch{}},[R,gt,U]);S(()=>{de.current=!1,_n.current=null,nn(!1),Cn(!1),qn(0),Kn(!1),yt.current=!1,ne.current=null,Mt.current=`${R}:${i}:${f}`,kn.current=0},[R,i,f]),S(()=>{Wn&&(Kn(!0),yt.current=!0)},[Wn,R,i,f]),S(()=>{if(!je||de.current)return;const e=`${R}:${i}:${f}`;if(_n.current===e)return;_n.current=e;const n=je,s=n.currentTime??0,o=n.duration??0;dr(s,o)&&(qn(s),nn(!0))},[je,R,i,f]),S(()=>{if(!Qe||de.current||Ee.current||Ne||Re||xe)return;const e=`${R}:${i}:${f}`;if(Bt.current!==e){if(!Sn){zn||(Bt.current=e);return}if(h){Bt.current=e,Me(!0);return}if(!(!r||Ye<0||re.length===0)){if(Bt.current=e,N==null&&ve==null){r&&re.length>0&&(jn(`${r.title} — Season ${i}`),Ge(!0),Ee.current=!0,de.current=!0);return}Me(!0)}}},[Qe,Sn,zn,Ne,Re,xe,h,N,ve,r,Ye,re.length,R,i,f]),S(()=>{(Ne||xe)&&d.current&&d.current.pause()},[Ne,xe,d]),S(()=>{const e=d.current;return()=>{Je.current&&clearTimeout(Je.current),e&&!e.ended&&$e(e.currentTime,e.duration||0)}},[$e,d]);const xn=C(e=>{let n=null,s=!0;try{n=localStorage.getItem("tvLastSubtitle"),s=localStorage.getItem("tvSubtitlesEnabled")!=="false"}catch{}return On(e,{lastKey:n,enabled:s})},[]),En=C(e=>{if(!(e<0))try{localStorage.setItem("tvSubtitlesEnabled","true"),localStorage.setItem("tvSelectedSubtitle",String(e))}catch{}},[]),er=C(e=>{if(e.length===0)return 0;let n=null;try{n=localStorage.getItem("tvLastAudio")}catch{}if(n){const s=e.findIndex(g=>Rn(g)===n);if(s>=0)return s;const o=n.indexOf("|||"),m=o>=0?n.slice(0,o):n,P=o>=0?n.slice(o+3):n,v=e.findIndex(g=>g.language===m||g.label===P);if(v>=0)return v}return On(e,{lastKey:null,enabled:!0})},[]),{data:tr}=xs(R||void 0),nr=Ce(()=>(tr?.progress??[]).filter(n=>n.season===i&&(n.completed===!0||n.completed===1||Ln(n.currentTime,n.duration))).map(n=>String(n.episode)),[tr,i]),rr=Ce(()=>re.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})),[re]),sr=Ce(()=>(r?.genres??[]).map(e=>e.name).slice(0,5),[r]),Nn=Ce(()=>[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]);S(()=>{if(ie.length!==0&&!ie.some(e=>e.id===$)){const e=ie.find(n=>n.tier==="direct")?.id??ie[0].id;Dt(e);try{localStorage.setItem("tvProvider",e)}catch{}}},[ie,$]),S(()=>{if(W.length!==0&&!W.includes(X)){zt(W[0]);try{localStorage.setItem("movyServer",W[0])}catch{}}},[W,X]),S(()=>{if(!u){L(null),Fe([]),Tt(""),j(""),Ue("");return}const e=Number(u),n=O||"tv";he(!0),L(null),Fe([]),Tt(""),j(""),Ue("");const s=parseInt(J.current.get("s")||"",10),o=parseInt(J.current.get("e")||"",10);q(isNaN(s)?1:s),Se(isNaN(o)?1:o),ge(0),tt.tv.details.query({type:n,id:String(e)}).then(m=>{const P={id:m.id,title:m.title||"",overview:m.overview||"",vote_average:m.vote_average,year:m.year,poster:m.poster,backdrop:m.backdrop,imdb_id:m.imdb_id||void 0,adult:m.adult,seasons:m.seasons,number_of_seasons:m.number_of_seasons};L(P),he(!1),P.seasons&&P.seasons.length>0&&isNaN(s)&&q(P.seasons[0].season_number)}).catch(()=>{he(!1)})},[u,O]),S(()=>{if(!r||!u)return;if(!(r.seasons!==void 0||r.number_of_seasons!==void 0)){Ve([]);return}const n=parseInt(w.get("e")||"",10);tt.tv.episodes.query({id:String(u),season:String(i)}).then(s=>{const o=(s.episodes||[]).map(m=>({episode_number:m.episode_number,name:m.name||"",vote_average:m.vote_average,overview:m.overview||"",still_path:m.still_path||""}));if(Ve(o),o.length>0){const m=!isNaN(n)&&o.find(P=>P.episode_number===n)?n:o[0].episode_number;Se(m)}}).catch(()=>{})},[r,u,i,w]),S(()=>{!r||!u||h||tt.tv.episodes.query({id:String(u),season:String(i)}).then(e=>{const n=(e.episodes||[]).map(s=>({episode_number:s.episode_number,name:s.name||"",vote_average:s.vote_average,overview:s.overview||"",still_path:s.still_path||""}));Ve(n),n.length>0&&!n.find(s=>s.episode_number===f)&&Se(n[0].episode_number)}).catch(()=>{})},[i,r,u,h,f]),S(()=>{if(!A||!r||!u)return;fetch(`/api/tv/embed/${$}/${h?"movie":"tv"}/${u}?season=${i}&episode=${f}`).then(n=>n.json()).then(n=>{if(n.url)return Ue(n.url),fetch(`/api/resolve?url=${encodeURIComponent(n.url)}`).then(s=>s.json()).then(s=>{s.finalUrl&&Ue(s.finalUrl)})}).catch(()=>{})},[$,r,u,i,f,h,A]);const on=C(async()=>{if(!r||!u||!$||A||r.adult&&!ht)return;const e=`${R}:${i}:${f}`;Ht.current.length>0?j(""):(M(!0),j(""),Fe([]),ge(0),st([]),He([]));try{const s=await F.fetchQuery({queryKey:sn(i,f),queryFn:()=>an(i,f),staleTime:3e5,gcTime:18e5});if(Mt.current!==e)return;if(M(!1),!s.valid||!s.sources?.length){j(s.error?`${s.error}`:W.length>0?`No streams from ${X}. Try another server.`:"No streams available.");return}Fe(s.sources),Tt(e),Wt("all"),ge(0),s.referer&&fn(s.referer);const o=s.audioTracks||[];st(o),ze(o.length>0?er(o):0);const m=s.subtitles||[];if(He(m),m.length>0){const g=xn(m);Q(g),En(g)}else Q(-1);const P=h?"movie":"tv",v=u;tt.tv.subtitles.query({type:P,tmdbId:String(v),season:String(i),episode:String(f)}).then(g=>{if(Mt.current!==e)return;const se=Array.isArray(g.subtitles)?g.subtitles:[];se.length!==0&&He(be=>{const V=[...be,...se.filter(B=>!be.some(k=>k.url===B.url))];if(be.length===0){const B=xn(V);Q(B),En(B)}return V})}).catch(()=>{}),j("")}catch{if(Mt.current!==e)return;M(!1),j("Failed to load streams.")}},[r,u,$,i,f,h,A,ht,W,X,xn,En,er,R,F,sn,an]),wn=C(e=>{const n=e.toLowerCase();zt(n);try{localStorage.setItem("movyServer",n)}catch{}j("")},[]),Lr=C(e=>{Dt(e);try{localStorage.setItem("tvProvider",e)}catch{}},[]);S(()=>{$&&r&&!A&&on()},[$,r,on,A]),S(()=>{if(!d.current||(le.current&&(le.current.destroy(),le.current=null),A))return;let e=!1;if(_e){const v=d.current;return v&&(v.pause(),v.removeAttribute("src"),v.load(),v.src="/av-sync-test.mp4",bt.current||v.play().catch(()=>{})),()=>{e=!0}}const n=Le==="all"?oe:oe.filter(v=>v.type===Le),s=Ct===`${R}:${i}:${f}`&&n[at]?.url||"";if(!s){try{d.current?.pause()}catch{}return}const o=d.current;if(Mt.current===`${R}:${i}:${f}`&&ne.current==null&&!bt.current)try{!o.ended&&o.currentTime>1&&(ne.current=o.currentTime)}catch{}o.pause(),o.removeAttribute("src"),o.load(),_.actions.resetMediaState();const m=`/api/tv/stream-proxy?url=${encodeURIComponent(s)}&referer=${encodeURIComponent(ot)}`;n[at]?.type==="hls"?(async()=>{const v=await Es();if(!e)if(v&&v.isSupported()){const g=new v({enableWorker:!0});le.current=g,g.on(v.Events.ERROR,(V,B)=>{B.fatal&&(j(`Stream failed (${B.details}). Try another source or reload.`),M(!1),g.destroy(),le.current=null)}),g.loadSource(m),g.attachMedia(o);const se=()=>{let V=!1,B=0;try{V=localStorage.getItem("tvSubtitlesEnabled")==="true";const k=parseInt(localStorage.getItem("tvSelectedSubtitle")||"0",10);!isNaN(k)&&k>=0&&(B=k)}catch{}return{enabled:V,index:B}},be=()=>{if(typeof g.subtitleTrack!="number")return;if(ce.current.length>0){g.subtitleTrack=-1;return}const V=Array.isArray(g.subtitleTracks)?g.subtitleTracks:[];if(V.length===0){g.subtitleTrack=-1;return}const B=se();if(B.enabled){const k=B.index<V.length?B.index:0;g.subtitleTrack=k,Q(k),mt()}else g.subtitleTrack=-1};fa(g,v.Events,{getWant:()=>Ut.current,onResolve:V=>ze(V)}),g.on(v.Events.MANIFEST_PARSED,()=>{be(),te.current!=null&&(o.currentTime=te.current,te.current=null),St(),!bt.current&&yt.current&&o.play().catch(()=>{})}),g.on(v.Events.SUBTITLE_TRACKS_UPDATED,()=>{be()}),g.on(v.Events.SUBTITLE_TRACK_SWITCH,(V,B)=>{if(ce.current.length>0){if(B.id!==-1)try{g.subtitleTrack=-1}catch{}return}const k=Array.isArray(g.subtitleTracks)?g.subtitleTracks:[];if(k.length!==0){if(B.id===-1){const Y=se();if(Y.enabled){const G=Y.index<k.length?Y.index:0;g.subtitleTrack=G;return}}Q(B.id),mt()}})}else Ns(o)&&(o.src=m,te.current!=null&&(o.currentTime=te.current,te.current=null),St(),!bt.current&&yt.current&&o.play().catch(()=>{j("Failed to play stream. Try another source.")}))})():(o.src=m,te.current!=null&&(o.currentTime=te.current,te.current=null),St(),!bt.current&&yt.current&&o.play().catch(()=>{j("Failed to play stream. Try another source.")}));const P=()=>{const se=o.error?.code===4?"Video source not supported or not found":"Failed to load video stream";j(`${se}. The source may be invalid or expired. Try switching source or reloading.`),M(!1)};return o.addEventListener("error",P),()=>{e=!0,o.removeEventListener("error",P)}},[oe,Ct,at,Le,$,ot,A,d,_e,R,i,f,St,mt,_.actions]),S(()=>{if(!Qe||Ne||xe||Re||At||A||_e)return;const e=d.current;!e||!e.paused||e.ended||e.readyState<1||(St(),e.play().catch(()=>{}))},[Qe,Ne,xe,Re,At,A,_e,St,d]),S(()=>{const e=le.current;!e||typeof e.audioTrack!="number"||(e.audioTrack=ke)},[ke]),S(()=>{const e=le.current;!e||typeof e.subtitleTrack!="number"||!Array.isArray(e.subtitleTracks)||e.subtitleTracks.length===0||ce.current.length>0||(y>=0?e.subtitleTrack=y:e.subtitleTrack=-1)},[y]),S(()=>{const e=d.current;if(!(!e||A)&&(e.querySelectorAll("track").forEach(n=>n.remove()),ce.current=[],pe.length!==0&&(pe.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 o=`/api/subtitle-proxy?url=${encodeURIComponent(n.url)}&referer=${encodeURIComponent(ot)}`;s.src=o,s.addEventListener("load",()=>{const m=ce.current.indexOf(s),P=s.track;if(P&&m>=0){const v=m===it.current;P.mode=v&&!ee.current?"showing":"hidden"}}),e.appendChild(s),ce.current.push(s)}),pe.length>0)))try{const n=le.current;n&&typeof n.subtitleTrack=="number"&&n.subtitleTrack!==-1&&(n.subtitleTrack=-1)}catch{}},[pe,ot,A,$,d]),S(()=>{const e=d.current;if(!e||A)return;const n=le.current;ce.current.length>0&&n&&typeof n.subtitleTrack=="number"&&Array.isArray(n.subtitleTracks)&&n.subtitleTracks.length>0&&(n.subtitleTrack=-1);const s=()=>{const P=Dn(_.state.subtitleFontSize,e.clientHeight||720),v=Math.max(0,Math.min(100,100-_.state.subtitlePosition)),g=()=>{const k=P*16,Y=e.videoHeight||e.clientHeight||720,G=e.videoWidth||e.clientWidth||1280;return{step:k*1.3/Y*100,chars:Math.max(20,Math.floor(G/(k*.55)))}},se=(k,Y)=>{const G=k;G.snapToLines=!1,G.line=Y},be=k=>{if(!k.cues)return;Array.from(k.cues).forEach(ue=>se(ue,v));const Y=Array.from(k.activeCues??[]);if(Y.length<=1){Y.forEach(ue=>se(ue,v));return}const{step:G,chars:z}=g();let Xe=v;for(let ue=Y.length-1;ue>=0;ue--){const De=String(Y[ue].text??"").replace(/<[^>]*>/g,"").split(`
3
+ `).reduce((dn,Rt)=>dn+Math.max(1,Math.ceil(Rt.length/z)),0);Xe=Math.max(0,Xe-De*G),se(Y[ue],Xe),Xe-=G*.4}},V=ce.current;if(V.length>0){V.forEach((k,Y)=>{const G=k.track;if(!G)return;const z=Y===y;G.mode=z&&!I?"showing":"hidden",z&&!I&&be(G)});return}const B=Array.from(e.textTracks);B.length!==0&&B.forEach((k,Y)=>{const G=Y===y;k.mode=G&&!I?"showing":"hidden",G&&!I&&be(k)})};s();const o=()=>s();e.textTracks.addEventListener("addtrack",o),e.addEventListener("loadedmetadata",s,{once:!0});const m=window.setTimeout(s,600);return()=>{e.textTracks.removeEventListener("addtrack",o),e.removeEventListener("loadedmetadata",s),window.clearTimeout(m)}},[y,pe,A,$,d,I,_.state.subtitleFontSize,_.state.subtitlePosition]),S(()=>{if(!I)return;const e=d.current,n=Kt.current;if(!e||!n)return;const s=Be/1e3,o=ut/1e3,m=new Set;let P=[],v=-1,g=-1,se=-1,be=-1,V=0,B=0,k=!1;const Y=()=>{const H=it.current;if(H<0)return null;const Oe=ce.current;return Oe.length>0?Oe[H]?.track??null:Array.from(e.textTracks)[H]??null},G=(H,Oe)=>{const me=H.cues;if(!me||me.length===0)return Array.from(H.activeCues??[]);let Ze=0,et=me.length;for(;Ze<et;){const Ie=Ze+et>>>1;me[Ie].endTime+s<Oe?Ze=Ie+1:et=Ie}const $t=[];for(let Ie=Ze;Ie<me.length;Ie++){const un=me[Ie];if(un.startTime+s>Oe)break;un.endTime+s>=Oe&&$t.push(un)}return $t},z=()=>{const H=Y(),Oe=e.currentTime-o,me=H?G(H,Oe):[],Ze=e.clientWidth,et=e.clientHeight,$t=e.videoWidth,Ie=e.videoHeight;if(me.length===P.length&&me.every((Bn,Mn)=>Bn===P[Mn])&&Ze===v&&et===g&&$t===se&&Ie===be||(P=me,v=Ze,g=et,se=$t,be=Ie,n.textContent="",me.length===0))return;const lr={fontSize:Dn(_.state.subtitleFontSize,et),position:_.state.subtitlePosition,bgOpacity:_.state.subtitleBgOpacity,bgColor:_.state.subtitleBgColor,textColor:_.state.subtitleTextColor,edge:_.state.subtitleEdge,bold:_.state.subtitleBold},Or=as(lr),Vr=os(e,lr.position);me.forEach((Bn,Mn)=>{const cr=String(Bn.text??"");if(!is(cr).trim())return;const An=document.createElement("div"),Fr=(me.length-1-Mn)*1.7;An.style.cssText=`${Or}
4
+ bottom: calc(${Vr}px + ${Fr}em);`,An.innerHTML=ls(cr),n.appendChild(An)})},Xe=()=>{Array.from(e.textTracks).forEach(H=>{m.has(H)||(m.add(H),H.addEventListener("cuechange",z))})},ue=()=>{Xe(),z()},In=()=>{if(k||B)return;const H=()=>{B=0,!(k||e.paused||e.ended)&&(z(),In())};B=window.requestAnimationFrame(H)},De=e,dn=()=>{V=0,z(),!k&&De.requestVideoFrameCallback&&(V=De.requestVideoFrameCallback(dn))},Rt=()=>{z(),De.requestVideoFrameCallback?V||(V=De.requestVideoFrameCallback(dn)):In()};Xe(),e.textTracks.addEventListener("addtrack",ue),e.textTracks.addEventListener("removetrack",ue),e.addEventListener("timeupdate",z),e.addEventListener("seeked",z),e.addEventListener("loadedmetadata",z),e.addEventListener("play",Rt);const or=Array.from(e.querySelectorAll("track"));or.forEach(H=>H.addEventListener("load",z));const ir=typeof ResizeObserver>"u"?null:new ResizeObserver(()=>z());return ir?.observe(e),z(),Rt(),()=>{k=!0,m.forEach(H=>H.removeEventListener("cuechange",z)),e.textTracks.removeEventListener("addtrack",ue),e.textTracks.removeEventListener("removetrack",ue),e.removeEventListener("timeupdate",z),e.removeEventListener("seeked",z),e.removeEventListener("loadedmetadata",z),e.removeEventListener("play",Rt),or.forEach(H=>H.removeEventListener("load",z)),ir?.disconnect(),B&&window.cancelAnimationFrame(B),V&&De.cancelVideoFrameCallback&&De.cancelVideoFrameCallback(V),n.textContent=""}},[I,Be,y,pe,ut,d,_.state.subtitleFontSize,_.state.subtitlePosition,_.state.subtitleBgOpacity,_.state.subtitleBgColor,_.state.subtitleTextColor,_.state.subtitleEdge,_.state.subtitleBold]);const ln=()=>{L(null),Fe([]),Ue(""),U(-1)},Rr=C(e=>{q(e),Se(1),we(e,1)},[we]),cn=!h&&r?.seasons&&r.seasons.length>1?t("label",{className:p.sidebarSeason,children:[t("span",{children:"Season"}),t("select",{value:i,onChange:e=>Rr(parseInt(e.target.value,10)||1),className:p.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,_t=C(e=>{const n=parseInt(e,10);if(!isNaN(n)){try{d.current?.pause()}catch{}Se(n),we(i,n)}Tn(!1)},[i,we,d]);S(()=>{if(h)return;const e=n=>{n.target.closest('input, textarea, button, select, a, [role="button"], [contenteditable="true"]')||n.key.toLowerCase()==="n"&&(N!=null?_t(String(N)):qr.error("No next episode available"))};return document.addEventListener("keydown",e),()=>{document.removeEventListener("keydown",e)}},[h,N,_t]);const $r=e=>{ze(e);try{const s=Pe[e];s&&localStorage.setItem("tvLastAudio",Rn(s))}catch{}const n=le.current;n&&n.audioTrack!==void 0&&(n.audioTrack=e)},Dr=e=>{Q(e);try{if(e===-1)localStorage.setItem("tvSubtitlesEnabled","false");else{localStorage.setItem("tvSubtitlesEnabled","true"),localStorage.setItem("tvSelectedSubtitle",String(e));const m=pe[e];m&&localStorage.setItem("tvLastSubtitle",Rn(m))}}catch{}const n=d.current,s=le.current;if(s&&typeof s.subtitleTrack=="number"&&Array.isArray(s.subtitleTracks)&&s.subtitleTracks.length>0&&(s.subtitleTrack=ce.current.length>0||e<0?-1:e),!n)return;const o=ce.current;if(o.length>0){o.forEach((m,P)=>{const v=m.track;if(!v)return;const g=P===e;v.mode=g&&!I?"showing":"hidden"});return}Array.from(n.textTracks).forEach((m,P)=>{const v=P===e;m.mode=v&&!I?"showing":"hidden"})},Lt=C(()=>{if(!r)return;const e=d.current,n=h?"":`S${String(i).padStart(2,"0")}E${String(f).padStart(2,"0")}`;tt.discord.tvPresence.mutate({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:fe.current}).catch(()=>{}),tt.discord.heartbeat.mutate({sessionId:fe.current}).catch(()=>{})},[r,h,i,f,d]);S(()=>{if(!r)return;Lt();const e=window.setInterval(()=>{const n=d.current;(!n||!n.paused)&&Lt()},15e3);return()=>window.clearInterval(e)},[Lt,r,d]),S(()=>{if(!r||A||rt||K||oe.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,A,rt,K,oe,Lt,d]),S(()=>{const e=fe.current,n=()=>{const o=JSON.stringify({sessionId:e});navigator.sendBeacon?(navigator.sendBeacon("/api/discord/clear",new Blob([o],{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:o,keepalive:!0}).catch(()=>{})},s=()=>n();return window.addEventListener("pagehide",s),window.addEventListener("beforeunload",s),()=>{window.removeEventListener("pagehide",s),window.removeEventListener("beforeunload",s),n()}},[]);const ar=Le==="all"?oe:oe.filter(e=>e.type===Le);return S(()=>{if(!r){document.title="TV & Movies - dango";return}document.title=h?`${r.title} - dango`:`${r.title} - Season ${i} Episode ${f} - dango`},[r,h,i,f]),S(()=>{if(!r||h)return;const e=new URLSearchParams(w),n=e.get("s"),s=e.get("e"),o=String(i),m=String(f);n===o&&s===m||(e.set("type",w.get("type")||"tv"),e.set("s",o),e.set("e",m),U(`${window.location.pathname}?${e.toString()}`,{replace:!0}))},[r,h,i,f,w,U]),t("div",{className:nt.playerPageLayout,children:[t("aside",{className:nt.episodeSidebar,children:r?h?t("div",{className:p.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:p.sidebarPosterMeta,children:[t("strong",{children:r.title}),t("span",{children:r.year})]})]}):t(cs,{episodes:rr,currentEpisode:String(f),watchedEpisodes:nr,onEpisodeClick:_t,header:cn}):h?t("div",{className:p.statusMsg,children:[t(D,{name:"spinner",className:p.spinner})," Loading..."]}):t(ds,{variant:"sidebar"})}),t("div",{className:nt.playerMain,children:[r&&t("div",{className:p.playerSection,onContextMenu:e=>e.preventDefault(),style:r.adult&&!ht?{filter:"blur(14px)",pointerEvents:"none",userSelect:"none"}:void 0,children:A&&kt?t("iframe",{src:kt,className:p.videoIframe,allow:"autoplay; fullscreen",allowFullScreen:!0}):!A&&(ar.length>0||rt)?t(Ae,{children:[K&&t("div",{className:`${p.statusMsg} ${p.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:K}),t("button",{className:p.retryButton,onClick:on,children:"Retry"})]}),W.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:"}),W.map(e=>t("button",{onClick:()=>wn(e),className:p.retryButton,style:{padding:"4px 8px",fontSize:"0.75rem",textTransform:"capitalize",background:X===e?"var(--accent)":void 0,color:X===e?"white":void 0},children:e},e))]})]}),t(ga,{player:_,title:r.title,episodeLabel:h?void 0:`S${i} E${f}`,audioTracks:Pe,selectedAudioTrack:ke,onAudioTrackChange:$r,subtitles:pe,selectedSubtitle:y,onSubtitleChange:Dr,streams:ar,qualityIdx:at,onQualityChange:ge,onBack:ln,movyServers:W,selectedMovyServer:X,onMovyServerSelect:wn,isMovySource:W.length>0,videoDelayEnabled:Ke,onVideoDelayToggle:e=>{lt(e);try{localStorage.setItem("playerVideoDelayEnabled",String(e))}catch{}},videoDelayMs:qe,onVideoDelayChange:Et,onCalibrateAvSync:It,subtitleDelayMs:Be,onSubtitleDelayChange:Yt,showNextEpisodeButton:fr&&!Ne&&!xe&&!Re,onNextEpisode:Xn,isLoading:rt,children:[t("video",{ref:d,autoPlay:Qe&&!At,playsInline:!0,disablePictureInPicture:!0,className:`${p.video} ${E?p.videoHidden:""}`,onTimeUpdate:xr,onEnded:()=>{_e||Er()},onPlay:Nr,onPause:wr,onSeeked:()=>{Qn.current=Date.now(),Pt()},onLoadedMetadata:Ir,onVolumeChange:_.actions.onVolumeChange,onWaiting:_.actions.onWaiting,onPlaying:_.actions.onPlaying,onContextMenu:e=>e.preventDefault(),onError:()=>{j("Video failed to load. Try another server or reload."),M(!1)}}),t("canvas",{ref:qt,className:`${p.delayCanvas} ${E?p.delayCanvasActive:""}`}),I&&t("div",{ref:Kt,className:p.subtitleOverlay}),t(us,{isOpen:bn,ms:qe,onChange:Et,onApply:Qt,onClose:dt,testClipActive:_e,onTestClip:Gt})]})]}):K&&!A?t("div",{className:`${p.statusMsg} ${p.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:K}),t("button",{className:p.retryButton,onClick:on,children:"Retry"})]}),W.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:"}),W.map(e=>t("button",{onClick:()=>wn(e),className:p.retryButton,style:{padding:"4px 8px",fontSize:"0.75rem",textTransform:"capitalize",background:X===e?"var(--accent)":void 0,color:X===e?"white":void 0},children:e},e))]})]}):null}),r&&t(ms,{showTheater:!1}),cn&&t("div",{className:p.mobileSeasonRow,children:cn}),r&&t("div",{className:p.providerSelectWrap,children:t("label",{className:p.controlLabel,children:["Source",t("select",{value:$,onChange:e=>Lr(e.target.value),className:p.select,disabled:ie.length===0,children:gn?t("option",{value:"",children:"Loading…"}):ie.length===0?t("option",{value:"",children:"No providers available"}):t(Ae,{children:[We.length>0&&t("optgroup",{label:"Direct HLS",children:We.map(e=>t("option",{value:e.id,children:e.label},e.id))}),T.length>0&&t("optgroup",{label:"Embeds",children:T.map(e=>t("option",{value:e.id,children:e.label},e.id))})]})})]})}),r&&t("div",{className:nt.playerInfoContainer,children:[t("div",{className:nt.playerInfoHeader,children:[t("div",{className:nt.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:nt.videoTitleSection,children:[t("div",{className:ye.titleContainer,children:[t("h1",{children:r.title}),t("div",{className:p.meta,children:[t("span",{className:p.year,children:r.year}),r.vote_average!=null&&r.vote_average>0&&t("span",{className:p.rating,children:[t(D,{name:"star",size:12}),Number(r.vote_average).toFixed(1)]}),t("span",{className:`${p.typeBadge} ${p[h?"movie":"tv"]}`,children:h?"Movie":"TV Show"})]}),sr.length>0&&t("div",{className:p.genreRow,children:sr.map(e=>t("span",{className:p.genreChip,children:e},e))}),Nn.length>0&&t("div",{className:p.metaRow,children:Nn.map((e,n)=>t("span",{children:[e,n<Nn.length-1?" · ":""]},`${e}-${n}`))})]}),t("div",{className:ye.controls,children:[t("button",{className:`${ye.watchlistBtn} ${Zt?ye.inList:""}`,onClick:gr,disabled:pr,type:"button",children:[Zt?t(D,{name:"check",size:14}):t(D,{name:"plus",size:14}),Zt?"In Watchlist":"Add to Watchlist"]}),!h&&t(Ae,{children:[t("button",{className:`${ye.watchlistBtn}`,onClick:()=>yn!=null&&_t(String(yn)),disabled:yn==null,type:"button",children:[t(D,{name:"chevron-left",size:14}),"Prev EP"]}),t("button",{className:`${ye.watchlistBtn}`,onClick:()=>N!=null&&_t(String(N)),disabled:N==null,type:"button",children:["Next EP",t(D,{name:"chevron-right",size:14})]}),!h&&t("button",{className:`${ye.watchlistBtn} ${ye.modeToggleBtn} ${vt?ye.modeToggleActive:""}`,onClick:()=>Cr(!vt),type:"button","aria-pressed":vt,children:vt?"AUTOPLAY: ON":"AUTOPLAY: OFF"}),Sr&&t("button",{className:`${ye.watchlistBtn}`,onClick:()=>Tn(!0),type:"button",children:[t(D,{name:"list-ul",size:14}),"Episodes"]})]})]})]})]}),t("div",{className:ye.descriptionSection,children:[t("h3",{children:"Synopsis"}),t(Is,{text:r.overview,emptyText:"No description available."})]}),t("button",{className:ye.detailsToggleBtn,onClick:()=>br(!rn),type:"button",children:[rn?t(D,{name:"chevron-up"}):t(D,{name:"chevron-down"}),rn?"Hide Details":"Show Details"]}),rn&&t("div",{className:p.detailGrid,children:[r.first_air_date&&t("div",{className:p.detailItem,children:[t("strong",{children:h?"Release Date":"First Air Date"}),t("span",{children:r.first_air_date})]}),r.last_air_date&&t("div",{className:p.detailItem,children:[t("strong",{children:"Last Air Date"}),t("span",{children:r.last_air_date})]}),r.networks&&r.networks.length>0&&t("div",{className:p.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:p.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:p.detailItem,children:[t("strong",{children:"Episode Runtime"}),t("span",{children:[r.episode_run_time[0]," min"]})]}),r.imdb_id&&t("div",{className:p.detailItem,children:[t("strong",{children:"IMDb"}),t("a",{href:`https://www.imdb.com/title/${r.imdb_id}`,target:"_blank",rel:"noopener noreferrer",className:p.imdbLink,children:"View on IMDb"})]})]})]}),!h&&t(hs,{isOpen:yr,onClose:()=>Tn(!1),episodes:rr,currentEpisode:String(f),watchedEpisodes:nr,onEpisodeClick:_t,header:cn}),r?.adult&&!ht&&t(mn,{isOpen:!0,title:"Content Warning",onClose:ln,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(Te,{variant:"secondary",onClick:ln,children:"Go Back"}),t(Te,{onClick:Jt,children:"I'm 18+, Continue"})]})]})}),t(mn,{isOpen:Ne,onClose:Jn,title:"Resume Watching",children:t("div",{style:{padding:"1rem",textAlign:"center"},children:[t("p",{children:["You were at ",t("strong",{children:kr(ft)})]}),t("div",{style:{marginTop:"1rem",display:"flex",gap:"10px",justifyContent:"center"},children:[t(Te,{variant:"secondary",onClick:Jn,children:"Start from Beginning"}),t(Te,{onClick:Br,children:"Resume"})]})]})}),t(mn,{isOpen:xe,onClose:Mr,title:h?"Movie Completed":"Episode Completed",children:t("div",{style:{padding:"1rem",textAlign:"center"},children:[t("p",{children:h?t(Ae,{children:"You've already watched this movie."}):t(Ae,{children:["You've already watched"," ",t("strong",{children:["Season ",i," Episode ",f]}),". Would you like to continue?"]})}),t("div",{style:{marginTop:"1rem",display:"flex",gap:"10px",justifyContent:"center",flexWrap:"wrap"},children:[t(Te,{variant:"secondary",onClick:Ar,children:"Replay"}),N!=null?t(Te,{onClick:Xn,children:["Watch EP ",N]}):ve!=null?t(Te,{onClick:Zn,children:["Start Season ",ve]}):null]})]})}),t(mn,{isOpen:Re,onClose:()=>Ge(!1),title:h?"Movie Completed!":ve!=null?"Season Complete!":"Show Completed!",children:t("div",{style:{padding:"1rem",textAlign:"center"},children:[t(D,{name:"check-circle",size:48,style:{color:"var(--accent-lighter)",marginBottom:"0.5rem"}}),t("p",{style:{fontSize:"1.1rem",fontWeight:600},children:vr}),t("p",{style:{color:"var(--text-secondary)"},children:h?"You finished this movie!":ve!=null?`You finished Season ${i}.`:"Congratulations! You finished all available episodes."}),t("div",{style:{marginTop:"1rem",display:"flex",gap:"10px",justifyContent:"center",flexWrap:"wrap"},children:[t(Te,{variant:"secondary",onClick:()=>Ge(!1),children:"Close"}),ve!=null?t(Te,{onClick:Zn,children:["Start Season ",ve]}):t(Ae,{children:[t(Te,{onClick:()=>{Ge(!1),ln()},children:"Back to Details"}),Zt&&t(Te,{onClick:Pr,disabled:gt.isPending,children:gt.isPending?"Saving...":"Move to Completed"})]})]})]})}),!r&&t("div",{className:p.statusMsg,children:[t(D,{name:"spinner",className:p.spinner})," Loading..."]})]})]})};export{Mo as default};