`).join("")).join(""),this.art.emit("subtitleAfterUpdate",this.activeCues))}async switch(d,g={}){let{i18n:y,notice:x,option:f}=this.art,v={...f.subtitle,...g,url:d},w=await this.init(v);return g.name&&(x.show=`${y.get("Switch Subtitle")}: ${g.name}`),w}createTrack(d,g){let{template:y,proxy:x,option:f}=this.art,{$video:v,$track:w}=y,j=(0,n.createElement)("track");j.default=!0,j.kind=d,j.src=g,j.label=f.subtitle.name||"Artplayer",j.track.mode="hidden",j.onload=()=>{this.art.emit("subtitleLoad",this.cues,this.option)},this.art.events.remove(this.destroyEvent),w.onload=null,(0,n.remove)(w),(0,n.append)(v,j),y.$track=j,this.destroyEvent=x(this.textTrack,"cuechange",()=>this.update())}async init(d){let{notice:g,template:{$subtitle:y}}=this.art;return this.textTrack?((0,u.default)(d,i.default.subtitle),d.url?(this.option=d,this.style(d.style),fetch(d.url).then(x=>x.arrayBuffer()).then(x=>{let f=new TextDecoder(d.encoding).decode(x);switch(d.type||(0,n.getExt)(d.url)){case"srt":{let v=(0,n.srtToVtt)(f),w=d.onVttLoad(v);return(0,n.vttToBlob)(w)}case"ass":{let v=(0,n.assToVtt)(f),w=d.onVttLoad(v);return(0,n.vttToBlob)(w)}case"vtt":{let v=d.onVttLoad(f);return(0,n.vttToBlob)(v)}default:return d.url}}).then(x=>(y.innerHTML="",this.url===x||(URL.revokeObjectURL(this.url),this.createTrack("metadata",x)),x)).catch(x=>{throw y.innerHTML="",g.show=x,x})):void 0):null}}o.default=c},{"option-validator":"g7VGh","./scheme":"biLjm","./utils":"aBlEo","./utils/component":"idCEj","@parcel/transformer-js/src/esmodule-helpers.js":"loqXi"}],fwOA1:[function(a,h,o,m){a("@parcel/transformer-js/src/esmodule-helpers.js").defineInteropFlag(o);var e=a("../package.json"),t=a("./utils");class u{constructor(i){this.art=i;let{option:n,constructor:s}=i;n.container instanceof Element?this.$container=n.container:(this.$container=(0,t.query)(n.container),(0,t.errorHandle)(this.$container,`No container element found by ${n.container}`)),(0,t.errorHandle)((0,t.supportsFlex)(),"The current browser does not support flex layout");let l=this.$container.tagName.toLowerCase();(0,t.errorHandle)(l==="div",`Unsupported container element type, only support 'div' but got '${l}'`),(0,t.errorHandle)(s.instances.every(c=>c.template.$container!==this.$container),"Cannot mount multiple instances on the same dom element"),this.query=this.query.bind(this),this.$container.dataset.artId=i.id,this.init()}static get html(){return`
Player version:
${e.version}
Video url:
Video volume:
Video time:
Video duration:
Video resolution:
x
[x]
`}query(i){return(0,t.query)(i,this.$container)}init(){let{option:i}=this.art;if(i.useSSR||(this.$container.innerHTML=u.html),this.$player=this.query(".art-video-player"),this.$video=this.query(".art-video"),this.$track=this.query("track"),this.$poster=this.query(".art-poster"),this.$subtitle=this.query(".art-subtitle"),this.$danmuku=this.query(".art-danmuku"),this.$bottom=this.query(".art-bottom"),this.$progress=this.query(".art-progress"),this.$controls=this.query(".art-controls"),this.$controlsLeft=this.query(".art-controls-left"),this.$controlsCenter=this.query(".art-controls-center"),this.$controlsRight=this.query(".art-controls-right"),this.$layer=this.query(".art-layers"),this.$loading=this.query(".art-loading"),this.$notice=this.query(".art-notice"),this.$noticeInner=this.query(".art-notice-inner"),this.$mask=this.query(".art-mask"),this.$state=this.query(".art-state"),this.$setting=this.query(".art-settings"),this.$info=this.query(".art-info"),this.$infoPanel=this.query(".art-info-panel"),this.$infoClose=this.query(".art-info-close"),this.$contextmenu=this.query(".art-contextmenus"),i.proxy){let n=i.proxy.call(this.art,this.art);(0,t.errorHandle)(n instanceof HTMLVideoElement||n instanceof HTMLCanvasElement,"Function 'option.proxy' needs to return 'HTMLVideoElement' or 'HTMLCanvasElement'"),(0,t.replaceElement)(n,this.$video),n.className="art-video",this.$video=n}i.backdrop&&(0,t.addClass)(this.$player,"art-backdrop"),t.isMobile&&(0,t.addClass)(this.$player,"art-mobile")}destroy(i){i?this.$container.innerHTML="":(0,t.addClass)(this.$player,"art-destroy")}}o.default=u},{"../package.json":"lh3R5","./utils":"aBlEo","@parcel/transformer-js/src/esmodule-helpers.js":"loqXi"}],"4NM7P":[function(a,h,o,m){a("@parcel/transformer-js/src/esmodule-helpers.js").defineInteropFlag(o),o.default=class{on(e,t,u){let r=this.e||(this.e={});return(r[e]||(r[e]=[])).push({fn:t,ctx:u}),this}once(e,t,u){let r=this;function i(...n){r.off(e,i),t.apply(u,n)}return i._=t,this.on(e,i,u)}emit(e,...t){let u=((this.e||(this.e={}))[e]||[]).slice();for(let r=0;rc.destroy()),c.on(Hls.Events.ERROR,(p,d)=>{if(d.fatal)switch(d.type){case Hls.ErrorTypes.NETWORK_ERROR:console.warn("HLS network error, trying to recover..."),c.startLoad();break;case Hls.ErrorTypes.MEDIA_ERROR:console.warn("HLS media error, trying to recover..."),c.recoverMediaError();break;default:console.error("Fatal HLS error");break}})}else n.canPlayType("application/vnd.apple.mpegurl")&&(n.src=s)}},settings:[{html:"Speed",selector:[{html:"0.5x",value:.5},{html:"0.75x",value:.75},{html:"Normal",value:1,default:!0},{html:"1.25x",value:1.25},{html:"1.5x",value:1.5},{html:"2x",value:2}],onSelect(i){return N&&(N.playbackRate=i.value),i.html}}],icons:{loading:'',state:''},cssVar:{"--art-theme":"#f5c518","--art-background-color":"#0f0f0f","--art-progress-color":"#f5c518","--art-control-background-color":"rgba(0, 0, 0, 0.8)","--art-control-height":"48px","--art-bottom-gap":"12px"}};return u.length>0&&(r.quality=u.map((i,n)=>({default:n===0,html:i,url:o}))),N=new Pt(r),N.on("ready",()=>{console.log("Player ready"),N.video&&(N.video.preload="auto")}),N.on("video:waiting",()=>{console.log("Buffering...")}),N.on("video:canplay",()=>{console.log("Can play")}),N.on("error",i=>{console.error("Player error:",i)}),N}function Ot(){N&&(N.destroy(),N=null)}const _t=4e3;function Vt(a,h="info"){const o=document.getElementById("toastContainer");if(!o)return;const m=document.createElement("div");m.className=`toast toast--${h}`,m.innerHTML=`
-
- ${zt(a)}
- `,o.appendChild(m),setTimeout(()=>{m.style.animation="slideIn 0.3s ease reverse",setTimeout(()=>m.remove(),300)},_t)}function Ht(a){switch(a){case"success":return'';case"error":return'';default:return''}}function zt(a){if(!a)return"";const h=document.createElement("div");return h.textContent=a,h.innerHTML}export{Dt as a,Ot as d,Nt as i,Vt as s};
diff --git a/backend/static/assets/keyboard-nav-CZ5sEhKF.js b/backend/static/assets/keyboard-nav-CZ5sEhKF.js
new file mode 100644
index 0000000..65bc152
--- /dev/null
+++ b/backend/static/assets/keyboard-nav-CZ5sEhKF.js
@@ -0,0 +1,47 @@
+(function(){const u=document.createElement("link").relList;if(u&&u.supports&&u.supports("modulepreload"))return;for(const e of document.querySelectorAll('link[rel="modulepreload"]'))h(e);new MutationObserver(e=>{for(const t of e)if(t.type==="childList")for(const c of t.addedNodes)c.tagName==="LINK"&&c.rel==="modulepreload"&&h(c)}).observe(document,{childList:!0,subtree:!0});function o(e){const t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin==="use-credentials"?t.credentials="include":e.crossOrigin==="anonymous"?t.credentials="omit":t.credentials="same-origin",t}function h(e){if(e.ep)return;e.ep=!0;const t=o(e);fetch(e.href,t)}})();const _=window.location.origin.includes("localhost")||window.location.origin.includes("127.0.0.1")?"/api":"https://nf.khoavo.myds.me/api",Yt=[121,111,117,114,45,115,117,112,101,114,45,115,101,99,114,101,116,45,107,101,121,45,99,104,97,110,103,101,45,116,104,105,115],Gt=String.fromCharCode(...Yt);class Zt{async signRequest(u,o="GET"){const h=Math.floor(Date.now()/1e3).toString(),e=u.startsWith("/api")?u:`/api${u}`,t=`${h}${e}${o.toUpperCase()}`,c=new TextEncoder,r=c.encode(Gt),i=c.encode(t),n=await crypto.subtle.importKey("raw",r,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),l=await crypto.subtle.sign("HMAC",n,i);return{"X-Signature":Array.from(new Uint8Array(l)).map(f=>f.toString(16).padStart(2,"0")).join(""),"X-Timestamp":h}}getProxyUrl(u,o=200){return u?`${_}/images/proxy?url=${encodeURIComponent(u)}&width=${o}`:""}async extractVideo(u,o=null){const e=await this.signRequest("/api/extract","POST"),t=await fetch(`${_}/extract`,{method:"POST",headers:{"Content-Type":"application/json",...e},body:JSON.stringify({url:u,quality:o})});if(!t.ok){const c=await t.json();throw new Error(c.detail||"Extraction failed")}return t.json()}async updateHeaders(u={},o,h="GET"){const e=await this.signRequest(o,h);return{...u,headers:{...u.headers,...e}}}async getQualities(u){const h=await this.signRequest("/api/qualities","GET"),e=await fetch(`${_}/qualities?url=${encodeURIComponent(u)}`,{headers:h});if(!e.ok)throw new Error("Failed to get qualities");return(await e.json()).qualities}async listVideos({skip:u=0,limit:o=50,category:h=null}={}){let e=`${_}/videos?skip=${u}&limit=${o}`;h&&h!=="all"&&(e+=`&category=${encodeURIComponent(h)}`);const c=await this.signRequest("/api/videos","GET"),r=await fetch(e,{headers:c});if(!r.ok)throw new Error("Failed to fetch videos");return r.json()}async addVideo(u){const h=await this.signRequest("/api/videos","POST"),e=await fetch(`${_}/videos`,{method:"POST",headers:{"Content-Type":"application/json",...h},body:JSON.stringify(u)});if(!e.ok){const t=await e.json();throw new Error(t.detail||"Failed to add video")}return e.json()}async deleteVideo(u){const o=`/api/videos/${u}`,h=await this.signRequest(o,"DELETE");if(!(await fetch(`${_}/videos/${u}`,{method:"DELETE",headers:h})).ok)throw new Error("Failed to delete video")}async searchVideos(u,o=20){const h=`${_}/search?q=${encodeURIComponent(u)}&limit=${o}`,t=await this.signRequest("/api/search","GET"),c=await fetch(h,{headers:t});if(!c.ok)throw new Error("Search failed");return c.json()}async health(){return(await fetch(`${_}/health`)).json()}async getRophimCatalog({category:u=null,country:o=null,genre:h=null,page:e=1,limit:t=24,sort:c="modified"}={}){let r=`${_}/rophim/catalog?page=${e}&limit=${t}&sort=${c}`;u&&(r+=`&category=${encodeURIComponent(u)}`),o&&(r+=`&country=${encodeURIComponent(o)}`),h&&(r+=`&genre=${encodeURIComponent(h)}`);const n=await this.signRequest("/api/rophim/catalog","GET"),l=await fetch(r,{headers:n});if(!l.ok)throw new Error("Failed to fetch RoPhim catalog");return l.json()}async getCuratedSections(){const o=await this.signRequest("/api/rophim/home/curated","GET"),h=await fetch(`${_}/rophim/home/curated`,{headers:o});if(!h.ok)throw new Error("Failed to fetch curated sections");return h.json()}async searchRophim(u,o=20){const h=`${_}/rophim/search?q=${encodeURIComponent(u)}&limit=${o}`,t=await this.signRequest("/api/rophim/search","GET"),c=await fetch(h,{headers:t});if(!c.ok)throw new Error("RoPhim search failed");return c.json()}async getHomeSections(u=2,o="home"){const e=await this.signRequest("/api/rophim/home/sections","GET"),t=await fetch(`${_}/rophim/home/sections?page=${u}&view=${o}`,{headers:e});if(!t.ok)throw new Error("Failed to fetch home sections");return t.json()}async getRophimMovie(u){const o=`/api/rophim/movie/${encodeURIComponent(u)}`,h=await this.signRequest(o,"GET"),e=await fetch(`${_}/rophim/movie/${encodeURIComponent(u)}`,{headers:h});if(!e.ok)throw new Error("Failed to fetch movie details");return e.json()}async getRophimStream(u,o=1){const h=`/api/rophim/stream/${encodeURIComponent(u)}`,e=await this.signRequest(h,"GET"),t=await fetch(`${_}/rophim/stream/${encodeURIComponent(u)}?episode=${o}`,{headers:e});if(!t.ok)throw new Error("Failed to get stream");return t.json()}async getRophimStreamByUrl(u,o="",h=1,e=0){const c=await this.signRequest("/api/rophim/stream","POST"),r=await fetch(`${_}/rophim/stream`,{method:"POST",headers:{"Content-Type":"application/json",...c},body:JSON.stringify({source_url:u,slug:o||"",episode:h,server:e})});if(!r.ok){const i=await r.json();throw new Error(i.detail||"Failed to get stream")}return r.json()}async discoverCategories(){const o=await this.signRequest("/api/rophim/categories/discover","GET"),h=await fetch(`${_}/rophim/categories/discover`,{headers:o});if(!h.ok)throw new Error("Failed to discover categories");return h.json()}async getMoviesByCategory(u,o=1,h=24){const t=await this.signRequest("/api/rophim/category","GET"),c=await fetch(`${_}/rophim/category?slug=${encodeURIComponent(u)}&page=${o}&limit=${h}`,{headers:t});if(!c.ok)throw new Error("Failed to fetch category");return c.json()}async getHotMovies(u=24){const h=await this.signRequest("/api/rophim/categories/hot","GET"),e=await fetch(`${_}/rophim/categories/hot?limit=${u}`,{headers:h});if(!e.ok)throw new Error("Failed to fetch hot movies");return e.json()}async getNewReleases(u=24){const h=await this.signRequest("/api/rophim/categories/new-releases","GET"),e=await fetch(`${_}/rophim/categories/new-releases?limit=${u}`,{headers:h});if(!e.ok)throw new Error("Failed to fetch new releases");return e.json()}async getTop10(){const o=await this.signRequest("/api/rophim/categories/top10","GET"),h=await fetch(`${_}/rophim/categories/top10`,{headers:o});if(!h.ok)throw new Error("Failed to fetch top 10");return h.json()}async getCinemaReleases(u=24){const h=await this.signRequest("/api/rophim/categories/cinema","GET"),e=await fetch(`${_}/rophim/categories/cinema?limit=${u}`,{headers:h});if(!e.ok)throw new Error("Failed to fetch cinema releases");return e.json()}}const Kt=new Zt;let yt=null;const Jt=300,Et=document.getElementById("searchModal"),St=document.getElementById("searchBackdrop"),Z=document.getElementById("searchInput"),Tt=document.getElementById("closeSearch"),pt=document.getElementById("searchLoading"),ft=document.getElementById("searchGrid");document.querySelector('[data-view="search"]');function bt(){Et.classList.add("active"),setTimeout(()=>Z.focus(),100)}function wt(){Et.classList.remove("active"),Z.value="",ft.innerHTML="",pt.style.display="none"}async function xt(a){if(!a||a.trim().length<2){ft.innerHTML="",pt.style.display="none";return}pt.style.display="flex";try{const u=await Kt.searchRophim(a);pt.style.display="none",u&&u.movies&&u.movies.length>0?ft.innerHTML=u.movies.map(o=>`
+
`).join("")).join(""),this.art.emit("subtitleAfterUpdate",this.activeCues))}async switch(p,g={}){let{i18n:v,notice:x,option:m}=this.art,y={...m.subtitle,...g,url:p},j=await this.init(y);return g.name&&(x.show=`${v.get("Switch Subtitle")}: ${g.name}`),j}createTrack(p,g){let{template:v,proxy:x,option:m}=this.art,{$video:y,$track:j}=v,k=(0,n.createElement)("track");k.default=!0,k.kind=p,k.src=g,k.label=m.subtitle.name||"Artplayer",k.track.mode="hidden",k.onload=()=>{this.art.emit("subtitleLoad",this.cues,this.option)},this.art.events.remove(this.destroyEvent),j.onload=null,(0,n.remove)(j),(0,n.append)(y,k),v.$track=k,this.destroyEvent=x(this.textTrack,"cuechange",()=>this.update())}async init(p){let{notice:g,template:{$subtitle:v}}=this.art;return this.textTrack?((0,c.default)(p,i.default.subtitle),p.url?(this.option=p,this.style(p.style),fetch(p.url).then(x=>x.arrayBuffer()).then(x=>{let m=new TextDecoder(p.encoding).decode(x);switch(p.type||(0,n.getExt)(p.url)){case"srt":{let y=(0,n.srtToVtt)(m),j=p.onVttLoad(y);return(0,n.vttToBlob)(j)}case"ass":{let y=(0,n.assToVtt)(m),j=p.onVttLoad(y);return(0,n.vttToBlob)(j)}case"vtt":{let y=p.onVttLoad(m);return(0,n.vttToBlob)(y)}default:return p.url}}).then(x=>(v.innerHTML="",this.url===x||(URL.revokeObjectURL(this.url),this.createTrack("metadata",x)),x)).catch(x=>{throw v.innerHTML="",g.show=x,x})):void 0):null}}o.default=d},{"option-validator":"g7VGh","./scheme":"biLjm","./utils":"aBlEo","./utils/component":"idCEj","@parcel/transformer-js/src/esmodule-helpers.js":"loqXi"}],fwOA1:[function(a,u,o,h){a("@parcel/transformer-js/src/esmodule-helpers.js").defineInteropFlag(o);var e=a("../package.json"),t=a("./utils");class c{constructor(i){this.art=i;let{option:n,constructor:l}=i;n.container instanceof Element?this.$container=n.container:(this.$container=(0,t.query)(n.container),(0,t.errorHandle)(this.$container,`No container element found by ${n.container}`)),(0,t.errorHandle)((0,t.supportsFlex)(),"The current browser does not support flex layout");let s=this.$container.tagName.toLowerCase();(0,t.errorHandle)(s==="div",`Unsupported container element type, only support 'div' but got '${s}'`),(0,t.errorHandle)(l.instances.every(d=>d.template.$container!==this.$container),"Cannot mount multiple instances on the same dom element"),this.query=this.query.bind(this),this.$container.dataset.artId=i.id,this.init()}static get html(){return`
Player version:
${e.version}
Video url:
Video volume:
Video time:
Video duration:
Video resolution:
x
[x]
`}query(i){return(0,t.query)(i,this.$container)}init(){let{option:i}=this.art;if(i.useSSR||(this.$container.innerHTML=c.html),this.$player=this.query(".art-video-player"),this.$video=this.query(".art-video"),this.$track=this.query("track"),this.$poster=this.query(".art-poster"),this.$subtitle=this.query(".art-subtitle"),this.$danmuku=this.query(".art-danmuku"),this.$bottom=this.query(".art-bottom"),this.$progress=this.query(".art-progress"),this.$controls=this.query(".art-controls"),this.$controlsLeft=this.query(".art-controls-left"),this.$controlsCenter=this.query(".art-controls-center"),this.$controlsRight=this.query(".art-controls-right"),this.$layer=this.query(".art-layers"),this.$loading=this.query(".art-loading"),this.$notice=this.query(".art-notice"),this.$noticeInner=this.query(".art-notice-inner"),this.$mask=this.query(".art-mask"),this.$state=this.query(".art-state"),this.$setting=this.query(".art-settings"),this.$info=this.query(".art-info"),this.$infoPanel=this.query(".art-info-panel"),this.$infoClose=this.query(".art-info-close"),this.$contextmenu=this.query(".art-contextmenus"),i.proxy){let n=i.proxy.call(this.art,this.art);(0,t.errorHandle)(n instanceof HTMLVideoElement||n instanceof HTMLCanvasElement,"Function 'option.proxy' needs to return 'HTMLVideoElement' or 'HTMLCanvasElement'"),(0,t.replaceElement)(n,this.$video),n.className="art-video",this.$video=n}i.backdrop&&(0,t.addClass)(this.$player,"art-backdrop"),t.isMobile&&(0,t.addClass)(this.$player,"art-mobile")}destroy(i){i?this.$container.innerHTML="":(0,t.addClass)(this.$player,"art-destroy")}}o.default=c},{"../package.json":"lh3R5","./utils":"aBlEo","@parcel/transformer-js/src/esmodule-helpers.js":"loqXi"}],"4NM7P":[function(a,u,o,h){a("@parcel/transformer-js/src/esmodule-helpers.js").defineInteropFlag(o),o.default=class{on(e,t,c){let r=this.e||(this.e={});return(r[e]||(r[e]=[])).push({fn:t,ctx:c}),this}once(e,t,c){let r=this;function i(...n){r.off(e,i),t.apply(c,n)}return i._=t,this.on(e,i,c)}emit(e,...t){let c=((this.e||(this.e={}))[e]||[]).slice();for(let r=0;rd.destroy()),d.on(Hls.Events.ERROR,(f,p)=>{if(p.fatal)switch(p.type){case Hls.ErrorTypes.NETWORK_ERROR:console.warn("HLS network error, trying to recover..."),d.startLoad();break;case Hls.ErrorTypes.MEDIA_ERROR:console.warn("HLS media error, trying to recover..."),d.recoverMediaError();break;default:console.error("Fatal HLS error");break}})}else n.canPlayType("application/vnd.apple.mpegurl")&&(n.src=l)}},settings:[{html:"Speed",selector:[{html:"0.5x",value:.5},{html:"0.75x",value:.75},{html:"Normal",value:1,default:!0},{html:"1.25x",value:1.25},{html:"1.5x",value:1.5},{html:"2x",value:2}],onSelect(i){return V&&(V.playbackRate=i.value),i.html}}],icons:{loading:'',state:''},cssVar:{"--art-theme":"#f5c518","--art-background-color":"#0f0f0f","--art-progress-color":"#f5c518","--art-control-background-color":"rgba(0, 0, 0, 0.8)","--art-control-height":"48px","--art-bottom-gap":"12px"}};return c.length>0&&(r.quality=c.map((i,n)=>({default:n===0,html:i,url:o}))),V=new Qt(r),V.on("ready",()=>{console.log("Player ready"),V.video&&(V.video.preload="auto")}),V.on("video:waiting",()=>{console.log("Buffering...")}),V.on("video:canplay",()=>{console.log("Can play")}),V.on("error",i=>{console.error("Player error:",i)}),V}function te(){V&&(V.destroy(),V=null)}const ee=4e3;function ye(a,u="info"){const o=document.getElementById("toastContainer");if(!o)return;const h=document.createElement("div");h.className=`toast toast--${u}`,h.innerHTML=`
+
+ ${ae(a)}
+ `,o.appendChild(h),setTimeout(()=>{h.style.animation="slideIn 0.3s ease reverse",setTimeout(()=>h.remove(),300)},ee)}function re(a){switch(a){case"success":return'';case"error":return'';default:return''}}function ae(a){if(!a)return"";const u=document.createElement("div");return u.textContent=a,u.innerHTML}const oe="modulepreload",ie=function(a){return"/"+a},Ct={},ne=function(u,o,h){let e=Promise.resolve();if(o&&o.length>0){document.getElementsByTagName("link");const c=document.querySelector("meta[property=csp-nonce]"),r=(c==null?void 0:c.nonce)||(c==null?void 0:c.getAttribute("nonce"));e=Promise.allSettled(o.map(i=>{if(i=ie(i),i in Ct)return;Ct[i]=!0;const n=i.endsWith(".css"),l=n?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${i}"]${l}`))return;const s=document.createElement("link");if(s.rel=n?"stylesheet":oe,n||(s.as="script"),s.crossOrigin="",s.href=i,r&&s.setAttribute("nonce",r),document.head.appendChild(s),n)return new Promise((d,f)=>{s.addEventListener("load",d),s.addEventListener("error",()=>f(new Error(`Unable to preload CSS for ${i}`)))})}))}function t(c){const r=new Event("vite:preloadError",{cancelable:!0});if(r.payload=c,window.dispatchEvent(r),!r.defaultPrevented)throw c}return e.then(c=>{for(const r of c||[])r.status==="rejected"&&t(r.reason);return u().catch(t)})};/*! Capacitor: https://capacitorjs.com/ - MIT License */var rt;(function(a){a.Unimplemented="UNIMPLEMENTED",a.Unavailable="UNAVAILABLE"})(rt||(rt={}));class jt extends Error{constructor(u,o,h){super(u),this.message=u,this.code=o,this.data=h}}const se=a=>{var u,o;return a!=null&&a.androidBridge?"android":!((o=(u=a==null?void 0:a.webkit)===null||u===void 0?void 0:u.messageHandlers)===null||o===void 0)&&o.bridge?"ios":"web"},le=a=>{const u=a.CapacitorCustomPlatform||null,o=a.Capacitor||{},h=o.Plugins=o.Plugins||{},e=()=>u!==null?u.name:se(a),t=()=>e()!=="web",c=s=>{const d=n.get(s);return!!(d!=null&&d.platforms.has(e())||r(s))},r=s=>{var d;return(d=o.PluginHeaders)===null||d===void 0?void 0:d.find(f=>f.name===s)},i=s=>a.console.error(s),n=new Map,l=(s,d={})=>{const f=n.get(s);if(f)return console.warn(`Capacitor plugin "${s}" already registered. Cannot register plugins twice.`),f.proxy;const p=e(),g=r(s);let v;const x=async()=>(!v&&p in d?v=typeof d[p]=="function"?v=await d[p]():v=d[p]:u!==null&&!v&&"web"in d&&(v=typeof d.web=="function"?v=await d.web():v=d.web),v),m=(E,C)=>{var I,L;if(g){const R=g==null?void 0:g.methods.find(w=>C===w.name);if(R)return R.rtype==="promise"?w=>o.nativePromise(s,C.toString(),w):(w,b)=>o.nativeCallback(s,C.toString(),w,b);if(E)return(I=E[C])===null||I===void 0?void 0:I.bind(E)}else{if(E)return(L=E[C])===null||L===void 0?void 0:L.bind(E);throw new jt(`"${s}" plugin is not implemented on ${p}`,rt.Unimplemented)}},y=E=>{let C;const I=(...L)=>{const R=x().then(w=>{const b=m(w,E);if(b){const T=b(...L);return C=T==null?void 0:T.remove,T}else throw new jt(`"${s}.${E}()" is not implemented on ${p}`,rt.Unimplemented)});return E==="addListener"&&(R.remove=async()=>C()),R};return I.toString=()=>`${E.toString()}() { [capacitor code] }`,Object.defineProperty(I,"name",{value:E,writable:!1,configurable:!1}),I},j=y("addListener"),k=y("removeListener"),$=(E,C)=>{const I=j({eventName:E},C),L=async()=>{const w=await I;k({eventName:E,callbackId:w},C)},R=new Promise(w=>I.then(()=>w({remove:L})));return R.remove=async()=>{console.warn("Using addListener() without 'await' is deprecated."),await L()},R},S=new Proxy({},{get(E,C){switch(C){case"$$typeof":return;case"toJSON":return()=>({});case"addListener":return g?$:j;case"removeListener":return k;default:return y(C)}}});return h[s]=S,n.set(s,{name:s,proxy:S,platforms:new Set([...Object.keys(d),...g?[p]:[]])}),S};return o.convertFileSrc||(o.convertFileSrc=s=>s),o.getPlatform=e,o.handleError=i,o.isNativePlatform=t,o.isPluginAvailable=c,o.registerPlugin=l,o.Exception=jt,o.DEBUG=!!o.DEBUG,o.isLoggingEnabled=!!o.isLoggingEnabled,o},ce=a=>a.Capacitor=le(a),kt=ce(typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{}),gt=kt.registerPlugin;class $t{constructor(){this.listeners={},this.retainedEventArguments={},this.windowListeners={}}addListener(u,o){let h=!1;this.listeners[u]||(this.listeners[u]=[],h=!0),this.listeners[u].push(o);const t=this.windowListeners[u];t&&!t.registered&&this.addWindowListener(t),h&&this.sendRetainedArgumentsForEvent(u);const c=async()=>this.removeListener(u,o);return Promise.resolve({remove:c})}async removeAllListeners(){this.listeners={};for(const u in this.windowListeners)this.removeWindowListener(this.windowListeners[u]);this.windowListeners={}}notifyListeners(u,o,h){const e=this.listeners[u];if(!e){if(h){let t=this.retainedEventArguments[u];t||(t=[]),t.push(o),this.retainedEventArguments[u]=t}return}e.forEach(t=>t(o))}hasListeners(u){var o;return!!(!((o=this.listeners[u])===null||o===void 0)&&o.length)}registerWindowListener(u,o){this.windowListeners[o]={registered:!1,windowEventName:u,pluginEventName:o,handler:h=>{this.notifyListeners(o,h)}}}unimplemented(u="not implemented"){return new kt.Exception(u,rt.Unimplemented)}unavailable(u="not available"){return new kt.Exception(u,rt.Unavailable)}async removeListener(u,o){const h=this.listeners[u];if(!h)return;const e=h.indexOf(o);this.listeners[u].splice(e,1),this.listeners[u].length||this.removeWindowListener(this.windowListeners[u])}addWindowListener(u){window.addEventListener(u.windowEventName,u.handler),u.registered=!0}removeWindowListener(u){u&&(window.removeEventListener(u.windowEventName,u.handler),u.registered=!1)}sendRetainedArgumentsForEvent(u){const o=this.retainedEventArguments[u];o&&(delete this.retainedEventArguments[u],o.forEach(h=>{this.notifyListeners(u,h)}))}}const Mt=a=>encodeURIComponent(a).replace(/%(2[346B]|5E|60|7C)/g,decodeURIComponent).replace(/[()]/g,escape),Lt=a=>a.replace(/(%[\dA-F]{2})+/gi,decodeURIComponent);class ue extends $t{async getCookies(){const u=document.cookie,o={};return u.split(";").forEach(h=>{if(h.length<=0)return;let[e,t]=h.replace(/=/,"CAP_COOKIE").split("CAP_COOKIE");e=Lt(e).trim(),t=Lt(t).trim(),o[e]=t}),o}async setCookie(u){try{const o=Mt(u.key),h=Mt(u.value),e=`; expires=${(u.expires||"").replace("expires=","")}`,t=(u.path||"/").replace("path=",""),c=u.url!=null&&u.url.length>0?`domain=${u.url}`:"";document.cookie=`${o}=${h||""}${e}; path=${t}; ${c};`}catch(o){return Promise.reject(o)}}async deleteCookie(u){try{document.cookie=`${u.key}=; Max-Age=0`}catch(o){return Promise.reject(o)}}async clearCookies(){try{const u=document.cookie.split(";")||[];for(const o of u)document.cookie=o.replace(/^ +/,"").replace(/=.*/,`=;expires=${new Date().toUTCString()};path=/`)}catch(u){return Promise.reject(u)}}async clearAllCookies(){try{await this.clearCookies()}catch(u){return Promise.reject(u)}}}gt("CapacitorCookies",{web:()=>new ue});const de=async a=>new Promise((u,o)=>{const h=new FileReader;h.onload=()=>{const e=h.result;u(e.indexOf(",")>=0?e.split(",")[1]:e)},h.onerror=e=>o(e),h.readAsDataURL(a)}),pe=(a={})=>{const u=Object.keys(a);return Object.keys(a).map(e=>e.toLocaleLowerCase()).reduce((e,t,c)=>(e[t]=a[u[c]],e),{})},fe=(a,u=!0)=>a?Object.entries(a).reduce((h,e)=>{const[t,c]=e;let r,i;return Array.isArray(c)?(i="",c.forEach(n=>{r=u?encodeURIComponent(n):n,i+=`${t}=${r}&`}),i.slice(0,-1)):(r=u?encodeURIComponent(c):c,i=`${t}=${r}`),`${h}&${i}`},"").substr(1):null,he=(a,u={})=>{const o=Object.assign({method:a.method||"GET",headers:a.headers},u),e=pe(a.headers)["content-type"]||"";if(typeof a.data=="string")o.body=a.data;else if(e.includes("application/x-www-form-urlencoded")){const t=new URLSearchParams;for(const[c,r]of Object.entries(a.data||{}))t.set(c,r);o.body=t.toString()}else if(e.includes("multipart/form-data")||a.data instanceof FormData){const t=new FormData;if(a.data instanceof FormData)a.data.forEach((r,i)=>{t.append(i,r)});else for(const r of Object.keys(a.data))t.append(r,a.data[r]);o.body=t;const c=new Headers(o.headers);c.delete("content-type"),o.headers=c}else(e.includes("application/json")||typeof a.data=="object")&&(o.body=JSON.stringify(a.data));return o};class me extends $t{async request(u){const o=he(u,u.webFetchExtra),h=fe(u.params,u.shouldEncodeUrlParams),e=h?`${u.url}?${h}`:u.url,t=await fetch(e,o),c=t.headers.get("content-type")||"";let{responseType:r="text"}=t.ok?u:{};c.includes("application/json")&&(r="json");let i,n;switch(r){case"arraybuffer":case"blob":n=await t.blob(),i=await de(n);break;case"json":i=await t.json();break;case"document":case"text":default:i=await t.text()}const l={};return t.headers.forEach((s,d)=>{l[d]=s}),{data:i,headers:l,status:t.status,url:t.url}}async get(u){return this.request(Object.assign(Object.assign({},u),{method:"GET"}))}async post(u){return this.request(Object.assign(Object.assign({},u),{method:"POST"}))}async put(u){return this.request(Object.assign(Object.assign({},u),{method:"PUT"}))}async patch(u){return this.request(Object.assign(Object.assign({},u),{method:"PATCH"}))}async delete(u){return this.request(Object.assign(Object.assign({},u),{method:"DELETE"}))}}gt("CapacitorHttp",{web:()=>new me});var Rt;(function(a){a.Dark="DARK",a.Light="LIGHT",a.Default="DEFAULT"})(Rt||(Rt={}));var Ft;(function(a){a.StatusBar="StatusBar",a.NavigationBar="NavigationBar"})(Ft||(Ft={}));class ge extends $t{async setStyle(){this.unavailable("not available for web")}async setAnimation(){this.unavailable("not available for web")}async show(){this.unavailable("not available for web")}async hide(){this.unavailable("not available for web")}}gt("SystemBars",{web:()=>new ge});var mt;(function(a){a.Heavy="HEAVY",a.Medium="MEDIUM",a.Light="LIGHT"})(mt||(mt={}));var At;(function(a){a.Success="SUCCESS",a.Warning="WARNING",a.Error="ERROR"})(At||(At={}));const qt=gt("Haptics",{web:()=>ne(()=>import("./web-Bp6c6Vk9.js"),[]).then(a=>new a.HapticsWeb)}),be=async()=>{try{await qt.impact({style:mt.Light})}catch{}},we=async()=>{try{await qt.impact({style:mt.Medium})}catch{}};class xe{constructor(){this.currentFocus=null,this.isEnabled=!1,this.selectors=[".video-card",".hero__btn",".slider-btn","#topSearchBtn",".nav-item",".category-card",".tab-btn",".episode-row",".recommendation-card"]}init(){this.isEnabled=!0,document.addEventListener("keydown",this.handleKey.bind(this)),document.addEventListener("mousemove",this.handleMouseMove.bind(this))}handleMouseMove(){this.currentFocus&&(this.currentFocus.blur(),this.currentFocus.classList.remove("keyboard-focused"),this.currentFocus=null)}handleKey(u){if(["ArrowUp","ArrowDown","ArrowLeft","ArrowRight"].includes(u.key)){if(u.preventDefault(),!this.currentFocus){this.focusFirstVisible();return}let o=null;switch(u.key){case"ArrowRight":o=this.moveHorizontal(1);break;case"ArrowLeft":o=this.moveHorizontal(-1);break;case"ArrowUp":o=this.moveVertical(-1);break;case"ArrowDown":o=this.moveVertical(1);break}o&&this.setFocus(o)}else u.key==="Enter"&&this.currentFocus&&this.currentFocus.click()}focusFirstVisible(){const u=document.querySelectorAll(".video-card");u.length>0&&this.setFocus(u[0])}setFocus(u){this.currentFocus&&this.currentFocus.classList.remove("keyboard-focused"),this.currentFocus=u,u.classList.add("keyboard-focused"),u.focus({preventScroll:!0}),u.scrollIntoView({behavior:"smooth",block:"center",inline:"center"})}moveHorizontal(u){if(!this.currentFocus)return null;const o=Array.from(document.querySelectorAll(this.selectors.join(","))),h=o.indexOf(this.currentFocus);if(h===-1)return null;const e=h+u;if(e>=0&&et.height*.5,c}return null}moveVertical(u){if(!this.currentFocus)return null;const o=this.currentFocus.getBoundingClientRect(),h=o.left+o.width/2,t=Array.from(document.querySelectorAll(this.selectors.join(","))).filter(i=>{if(i===this.currentFocus)return!1;const n=i.getBoundingClientRect();return u===1?n.top>=o.bottom-o.height*.2:n.bottom<=o.top+o.height*.2});if(t.length===0)return null;let c=null,r=1/0;return t.forEach(i=>{const n=i.getBoundingClientRect(),l=n.left+n.width/2;n.top+n.height/2;const s=Math.abs(n.top-o.top),d=Math.abs(l-h),f=Math.sqrt(Math.pow(s,2)+Math.pow(d,2));fthis.getCachedImage(d)))}}createCachedImage(e,r="",i=""){const s=document.createElement("img");return s.alt=r,s.className=i,s.loading="lazy",s.decoding="async",s.src='data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 450"%3E%3Crect fill="%23222"%3E%3C/rect%3E%3C/svg%3E',e&&this.getCachedImage(e).then(d=>{s.src=d}),s}async _cleanupCache(e){try{const r=await e.keys();if(r.length>te){const i=Math.floor(r.length*.2);for(let s=0;sd)return!0}return!1}function se(t){var s;const e=(t.quality||"").toLowerCase(),r=((s=t.episodes)==null?void 0:s.length)||0,i=(t.category||t.type||"").toLowerCase();return e.includes("trailer")||i.includes("trailer")?"trailer":r>1||i.includes("series")||i.includes("phim-bo")||e.includes("tập")||e.includes("ep")?"series":i.includes("hoathinh")||i.includes("animation")||i.includes("anime")?"animation":"movie"}function oe(t){var s;const e=t.quality||"";if(e.match(/(?:tập\s*)?(\d+)(?:\s*\/\s*(\d+))?/i))return e;const i=((s=t.episodes)==null?void 0:s.length)||0;return i>1?`${i} Tập`:null}function ne(t,e,r){var I;const i=document.createElement("div");i.className="video-card",i.dataset.videoId=t.id;const s=t.thumbnail||"",d=t.year||new Date().getFullYear(),m=ie(t),a=se(t),o=oe(t);let u=t.quality||"HD";u=u.replace(/(?:tập\s*)?\d+(?:\s*\/\s*\d+)?/gi,"").trim()||"HD",u.length>6&&(u="HD");const n=parseFloat(t.rating||0),c=n>=7,g=Math.round(n*10);let h="";n>0&&(h=`
-
- `,u.addEventListener("click",()=>w(a)),s.appendChild(u)})}catch(m){console.error("Failed to load my list content",m)}const d=document.querySelectorAll(".mylist-chip");d.forEach(m=>{m.addEventListener("click",async()=>{const a=m.dataset.filter,o=m.dataset.category;if(!a||!o)return;d.forEach(c=>{c.classList.remove("active","bg-white"),c.classList.add("bg-surface-dark");const g=c.querySelector("p");g&&(g.classList.remove("font-bold","text-black"),g.classList.add("font-medium","text-gray-200"))}),m.classList.add("active","bg-white"),m.classList.remove("bg-surface-dark");const u=m.querySelector("p");u&&(u.classList.add("font-bold","text-black"),u.classList.remove("font-medium","text-gray-200"));const n=document.getElementById("mylistGrid");if(n){n.innerHTML='
+ `,u.addEventListener("click",()=>k(r)),i.appendChild(u)})}catch(m){console.error("Failed to load my list content",m)}const c=document.querySelectorAll(".mylist-chip");c.forEach(m=>{m.addEventListener("click",async()=>{const r=m.dataset.filter,s=m.dataset.category;if(!r||!s)return;c.forEach(h=>{h.classList.remove("active","bg-white"),h.classList.add("bg-surface-dark");const d=h.querySelector("p");d&&(d.classList.remove("font-bold","text-black"),d.classList.add("font-medium","text-gray-200"))}),m.classList.add("active","bg-white"),m.classList.remove("bg-surface-dark");const u=m.querySelector("p");u&&(u.classList.add("font-bold","text-black"),u.classList.remove("font-medium","text-gray-200"));const l=document.getElementById("mylistGrid");if(l){l.innerHTML='