@serifpersia/dango 3.5.9 → 3.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -4
- package/client/dist/assets/{AnimeCard-CDeVbWJO.js → AnimeCard-DbrG4Bo-.js} +1 -1
- package/client/dist/assets/AnimeInfo-BivVqWcB.css +1 -0
- package/client/dist/assets/AnimeInfo-CgSQGjef.js +1 -0
- package/client/dist/assets/{AnimeInfoPage-Cc3OcfHY.js → AnimeInfoPage-DSybdvf_.js} +2 -2
- package/client/dist/assets/{Asmr-DZmR_EHb.js → Asmr-DFFV-7y4.js} +1 -1
- package/client/dist/assets/{AsmrResetProgressModal-DBCDlfYq.js → AsmrResetProgressModal-Brdfu_22.js} +1 -1
- package/client/dist/assets/AvSyncCalibrator-DBBUzoHn.js +10 -0
- package/client/dist/assets/AvSyncCalibrator-ZSpMgUid.css +1 -0
- package/client/dist/assets/Home-DeY8zvfI.css +1 -0
- package/client/dist/assets/{Home-BqhPqzWF.js → Home-DjGl-3os.js} +1 -1
- package/client/dist/assets/{Insights-CmbbDZr3.js → Insights-4O52Z1t2.js} +1 -1
- package/client/dist/assets/{LibraryListPage-jLA7gnux.js → LibraryListPage-Z0w_rmHP.js} +1 -1
- package/client/dist/assets/{ListeningList-Cm9zGlLB.js → ListeningList-DjbzDs1E.js} +1 -1
- package/client/dist/assets/{Manga-x4pVT4ZH.js → Manga-BRIDluzF.js} +1 -1
- package/client/dist/assets/{MangaInfoPage-BPSW9UER.js → MangaInfoPage-Q4CjEGJH.js} +1 -1
- package/client/dist/assets/{MangaReadPage-V1iDbCfL.js → MangaReadPage-BbJK5FY6.js} +1 -1
- package/client/dist/assets/{MangaResetProgressModal-Dto3km2X.js → MangaResetProgressModal-BCFPXDF6.js} +1 -1
- package/client/dist/assets/{Mature-B0DoN3tQ.js → Mature-DjQzs66p.js} +1 -1
- package/client/dist/assets/{MediaCard-D6_9HL2Z.js → MediaCard-DedwE5DX.js} +1 -1
- package/client/dist/assets/{Music-1MlUIfdw.js → Music-z2RkiMDf.js} +1 -1
- package/client/dist/assets/{OptionListMenu-BWwktIiH.js → OptionListMenu-CetjZizt.js} +1 -1
- package/client/dist/assets/Player-DCB994_8.css +1 -0
- package/client/dist/assets/{Player-Dgtn--lM.js → Player-DD-9SgWU.js} +6 -6
- package/client/dist/assets/PlayerSettings-BXGe3F5k.css +1 -0
- package/client/dist/assets/{PlayerSettings-CI5hGpEU.js → PlayerSettings-ne_DQSTl.js} +1 -1
- package/client/dist/assets/{QueueOptionsButton-DjcdOJgg.js → QueueOptionsButton-CIKT4YcD.js} +1 -1
- package/client/dist/assets/{QueueRail-B5z_xhzj.js → QueueRail-DPclldS0.js} +1 -1
- package/client/dist/assets/{Radio-BAE-Q-iN.js → Radio-aeqPTMht.js} +1 -1
- package/client/dist/assets/{ReadingList-B97i_hGv.js → ReadingList-p6G7NHtC.js} +1 -1
- package/client/dist/assets/{ResetProgressModal-C7-CvTi-.js → ResetProgressModal-B7UuuL3X.js} +1 -1
- package/client/dist/assets/{Search-CbPFjKeU.js → Search-BzyHVByR.js} +1 -1
- package/client/dist/assets/Settings-DMmtLUsL.js +21 -0
- package/client/dist/assets/{SkeletonGrid-BA_x2PRl.js → SkeletonGrid-B5JXhZO4.js} +1 -1
- package/client/dist/assets/Trackers-tLL1afjB.js +2 -0
- package/client/dist/assets/Tv-Bdruknna.css +1 -0
- package/client/dist/assets/Tv-CluLN4KA.js +4 -0
- package/client/dist/assets/{TvInfo-CxSmzVSL.js → TvInfo-DmrBLjgK.js} +1 -1
- package/client/dist/assets/{TvPopup-S5blnD3l.js → TvPopup-D1mSlOZt.js} +1 -1
- package/client/dist/assets/{TvSearch-B-2sRNbN.js → TvSearch-BGQRUq9E.js} +1 -1
- package/client/dist/assets/{TvWatchlist-MaA-qhQw.js → TvWatchlist-DdLkpeQT.js} +1 -1
- package/client/dist/assets/{Watchlist-yVEi1oVn.js → Watchlist-BObmM6QB.js} +1 -1
- package/client/dist/assets/{hls-CnFtaJwf.js → hls-qCuNYJym.js} +1 -1
- package/client/dist/assets/index-B4AdKbhW.js +178 -0
- package/client/dist/assets/index-D0Haw_Zl.css +1 -0
- package/client/dist/assets/{useAnimeInfoData-BqAd5seW.js → useAnimeInfoData-CSnwUBuU.js} +1 -1
- package/client/dist/assets/{useAsmr-B1vlDm2S.js → useAsmr-BKAaWEXn.js} +1 -1
- package/client/dist/assets/{useAsmrPopup-BNJC4JQo.js → useAsmrPopup-DDLRBLzz.js} +1 -1
- package/client/dist/assets/{useMangaLibrary-CU3bFfuD.js → useMangaLibrary-C6XEMuSr.js} +1 -1
- package/client/dist/assets/{useMangaPopup-LbRnTFzq.js → useMangaPopup-wfCJubPD.js} +1 -1
- package/client/dist/assets/{useProviders-CvKGEjDV.js → useProviders-C7jrBgxf.js} +1 -1
- package/client/dist/assets/{useTv-LsgXHZD4.js → useTv-DM5KtzEc.js} +1 -1
- package/client/dist/assets/{useTvLibrary-c90knUfT.js → useTvLibrary-73NkS_5R.js} +1 -1
- package/client/dist/index.html +2 -2
- package/orchestrator.js +107 -8
- package/package.json +2 -2
- package/server/dist/app-hono.js +13 -8
- package/server/dist/config.js +3 -2
- package/server/dist/hono/auth.js +0 -7
- package/server/dist/trpc/routers/auth.js +16 -0
- package/server/package.json +1 -1
- package/client/dist/assets/AnimeInfo-BFWtHlPC.css +0 -1
- package/client/dist/assets/AnimeInfo-DVpM_cPF.js +0 -1
- package/client/dist/assets/AvSyncCalibrator-Cf5L0Dxf.js +0 -10
- package/client/dist/assets/AvSyncCalibrator-ieaRTs3u.css +0 -1
- package/client/dist/assets/Home-B_q2l74h.css +0 -1
- package/client/dist/assets/Player-DBLl-bj_.css +0 -1
- package/client/dist/assets/PlayerSettings-Bj6SsmQ2.css +0 -1
- package/client/dist/assets/Settings-BbihEcZ2.js +0 -21
- package/client/dist/assets/Trackers-Bperfrcz.js +0 -2
- package/client/dist/assets/Tv-BSGuUz2F.js +0 -4
- package/client/dist/assets/Tv-BlVIanQL.css +0 -1
- package/client/dist/assets/index-Ck-R0JKv.css +0 -1
- package/client/dist/assets/index-DNxWyfmM.js +0 -178
|
@@ -1 +1 @@
|
|
|
1
|
-
import{b as u,c as b,u as g,a as c}from"./vendor-query-BBT5_sHx.js";import{t as p,h as i,z as s}from"./index-
|
|
1
|
+
import{b as u,c as b,u as g,a as c}from"./vendor-query-BBT5_sHx.js";import{t as p,h as i,z as s}from"./index-B4AdKbhW.js";import{T as Q}from"./vendor-core-DfaOB3Rn.js";const v=300*1e3,M={mangadex:"https://mangadex.org/",mangapill:"https://www.mangapill.com/"},f=(e,a)=>`/api/proxy?url=${encodeURIComponent(a)}&referer=${encodeURIComponent(M[e])}`,T=(e,a)=>a&&(e==="mangapill"?f(e,a):a),k=(e,a=!0)=>{const{provider:r,query:n,page:o,sort:t,status:m,type:d,rating:y,mature:l}=e;return u({queryKey:["mangaBrowse",r,n,o,t,m,d,y,l],queryFn:()=>p.manga.search.query({provider:r,q:n.trim()||void 0,page:o,sort:t||void 0,status:m||void 0,type:d||void 0,rating:y||void 0,mature:l?"1":void 0}),staleTime:v,enabled:a&&!!r})},E=(e,a=14)=>{const{provider:r,query:n,sort:o,status:t,type:m,rating:d,mature:y}=e;return b({queryKey:["mangaBrowseInfinite",r,n,o,t,m,d,y,a],queryFn:({pageParam:l=1})=>p.manga.search.query({provider:r,q:n.trim()||void 0,page:l,limit:a,sort:o||void 0,status:t||void 0,type:m||void 0,rating:d||void 0,mature:y?"1":void 0}),initialPageParam:1,getNextPageParam:(l,q)=>l.hasNext?q.length+1:void 0,staleTime:v,enabled:!!r})},O=(e,a,r="safe",n=!1)=>u({queryKey:["mangaDetail",e,a,r,n],queryFn:()=>p.manga.info.query({provider:e||"",id:a||"",rating:r,mature:n?"1":void 0}),enabled:!!e&&!!a,staleTime:v}),$=(e,a,r)=>u({queryKey:["mangaPages",e,a],queryFn:()=>p.manga.pages.query({provider:e||"",id:a||""}),enabled:!!e&&!!a,staleTime:1800*1e3}),B=()=>{const e=i();return u({...e.manga.trending.queryOptions(),staleTime:600*1e3,retry:1})},I=e=>e.contentRating==="erotica"||e.contentRating==="pornographic"||e.type==="doujinshi";function N(e,a){const r=e.titles??{};return a==="englishName"?r.en||e.title:a==="nativeName"&&(r.native||r.romaji||e.altTitle)||e.title}function A(e){return{englishName:e.titles?.en??e.title,nativeName:e.titles?.native??e.titles?.romaji??e.altTitle??void 0}}const h=/^anilist:ch:(\d+)$/;function w(e){if(!e)return null;const a=h.exec(e.trim());if(!a)return null;const r=Number.parseInt(a[1],10);return Number.isFinite(r)?r:null}function x(e,a){const r=String(a),n=e.find(o=>(o.number??"").trim()===r);return n||(e.find(o=>{const t=Number.parseFloat((o.number??"").trim());return Number.isFinite(t)&&t===a})??null)}const _=["Reading","Completed","On-Hold","Dropped","Planned"],L=(e,a)=>`${e.toLowerCase()}:${a}`,D=(e="All",a=1,r=24)=>{const n=i();return u(n.mangaLibrary.list.queryOptions({status:e,page:a,limit:r}))},P=()=>{const e=i();return u({...e.mangaLibrary.ids.queryOptions(),staleTime:1e3*60})},U=e=>{const a=i();return u({...a.mangaLibrary.check.queryOptions({id:e??""}),enabled:!!e,staleTime:1e3*60})},j=e=>{const a=i();return u({...a.mangaLibrary.entry.queryOptions({id:e??""}),enabled:!!e,staleTime:1e3*60})},H=()=>{const e=i(),a=g();return c(e.mangaLibrary.link.mutationOptions({onSuccess:r=>{s.success(r?.progressMigrated?"Linked — chapter progress carried over":"Linked to AniList entry"),a.invalidateQueries(e.mangaLibrary.pathFilter()),a.invalidateQueries({queryKey:["manga-library"]}),a.invalidateQueries({queryKey:["manga-continue-reading"]})},onError:r=>{s.error(`Failed to link: ${r.message}`)}}))},z=(e=24)=>{const a=i();return u(a.mangaProgress.continueReading.queryOptions({limit:e}))},V=e=>{const a=i();return u({...a.mangaProgress.byManga.queryOptions({mangaId:e??""}),enabled:!!e})},S=()=>{const e=i(),a=g();return c(e.mangaLibrary.add.mutationOptions({onSuccess:(r,n)=>{n.silent||s.success("Bookmarked"),a.invalidateQueries(e.mangaLibrary.pathFilter()),a.invalidateQueries({queryKey:["manga-library"]})},onError:r=>{s.error(`Failed to bookmark: ${r.message}`)}}))},F=()=>{const e=i(),a=g();return c(e.mangaLibrary.remove.mutationOptions({onSuccess:()=>{s.success("Bookmark removed"),a.invalidateQueries(e.mangaLibrary.pathFilter()),a.invalidateQueries({queryKey:["manga-library"]}),a.invalidateQueries({queryKey:["manga-continue-reading"]})},onError:r=>{s.error(`Failed to remove: ${r.message}`)}}))},Y=()=>{const e=i(),a=g();return c(e.mangaLibrary.setStatus.mutationOptions({onSuccess:()=>{s.success("Status updated"),a.invalidateQueries(e.mangaLibrary.pathFilter()),a.invalidateQueries({queryKey:["manga-library"]}),a.invalidateQueries({queryKey:["manga-continue-reading"]})},onError:r=>{s.error(`Failed to update status: ${r.message}`)}}))},G=()=>{const e=i(),a=g();return c(e.mangaProgress.save.mutationOptions({onSuccess:(r,n)=>{a.invalidateQueries({queryKey:["manga-progress",n.mangaId]}),a.invalidateQueries({queryKey:["manga-continue-reading"]}),a.invalidateQueries({queryKey:["manga-library"]}),a.invalidateQueries(e.mangaProgress.pathFilter())}}))},J=()=>{const e=i(),a=g();return c(e.mangaProgress.remove.mutationOptions({onSuccess:()=>{s.success("Progress reset"),a.invalidateQueries({queryKey:["manga-progress"]}),a.invalidateQueries({queryKey:["manga-continue-reading"]}),a.invalidateQueries({queryKey:["manga-library"]}),a.invalidateQueries(e.mangaProgress.pathFilter())},onError:r=>{s.error(`Failed to reset progress: ${r.message}`)}}))},W=()=>{const e=i(),a=g();return c(e.mangaLibrary.batchStatus.mutationOptions({onSuccess:r=>{s.success(`Status updated for ${r.updated??0} items`),a.invalidateQueries(e.mangaLibrary.pathFilter()),a.invalidateQueries({queryKey:["manga-library"]}),a.invalidateQueries({queryKey:["manga-continue-reading"]})},onError:r=>{s.error(`Failed to update statuses: ${r.message}`)}}))},X=()=>{const e=i(),a=g();return c(e.mangaLibrary.removeMany.mutationOptions({onSuccess:r=>{const n=r.removed??0;s.success(`Removed ${n} ${n===1?"item":"items"} from reading list`),a.invalidateQueries(e.mangaLibrary.pathFilter()),a.invalidateQueries({queryKey:["manga-library"]}),a.invalidateQueries({queryKey:["manga-continue-reading"]})},onError:r=>{s.error(`Failed to remove: ${r.message}`)}}))},Z=()=>{const e=i(),a=g();return c(e.mangaProgress.removeMany.mutationOptions({onSuccess:r=>{const n=r.removed??0;s.success(`Reset progress for ${n} ${n===1?"item":"items"}`),a.invalidateQueries({queryKey:["manga-progress"]}),a.invalidateQueries({queryKey:["manga-continue-reading"]}),a.invalidateQueries({queryKey:["manga-library"]}),a.invalidateQueries(e.mangaProgress.pathFilter())},onError:r=>{s.error(`Failed to reset progress: ${r.message}`)}}))},ee=()=>{const e=S(),a=F(),{data:r}=P(),n=Q(()=>new Set(r?.ids||[]),[r]);return{toggle:t=>{const m=L(t.provider,t.id);n.has(m)?a.mutate(m):e.mutate({provider:t.provider,mangaId:t.id,title:t.title,cover:t.cover,altTitle:t.altTitle,contentRating:t.contentRating})},bookmarkedIds:n,pending:e.isPending||a.isPending}};export{Z as A,J as B,_ as M,E as a,T as b,A as c,z as d,B as e,k as f,j as g,S as h,I as i,H as j,O as k,U as l,L as m,V as n,F as o,Y as p,w as q,N as r,x as s,$ as t,ee as u,f as v,G as w,D as x,W as y,X as z};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{u as e,S as f,L as m}from"./vendor-core-DfaOB3Rn.js";import{I as l}from"./vendor-icons-DrybRNxP.js";import{k as y,r as T}from"./useMangaLibrary-
|
|
1
|
+
import{u as e,S as f,L as m}from"./vendor-core-DfaOB3Rn.js";import{I as l}from"./vendor-icons-DrybRNxP.js";import{k as y,r as T}from"./useMangaLibrary-C6XEMuSr.js";import{d as I}from"./index-B4AdKbhW.js";import{p as s,a as k}from"./MediaCard-DedwE5DX.js";import{u as P}from"./usePopup-DS9jMzp6.js";const R=({data:i,anchorRect:d,bookmarked:r,onToggleBookmark:p,onMouseEnter:h,onMouseLeave:v,onRequestClose:g})=>{const{data:a,isLoading:N}=y(i.provider,i.mangaId,i.rating||"safe",i.mature||!1),{titlePreference:u}=I(),t=a?.chapters.length??0,c=[a?.status,a?.type].filter(Boolean).join(" · "),o=T({title:i.title,altTitle:a?.altTitle??i.altTitle},u);return e(k,{anchorRect:d,onMouseEnter:h,onMouseLeave:v,onRequestClose:g,children:N?e("div",{className:s.loading,children:[e("div",{className:s.spinner}),e("span",{children:"Fetching details..."})]}):e(f,{children:[e("div",{className:s.header,children:[e("div",{className:s.title,children:o}),a?.altTitle&&a.altTitle!==o&&e("div",{className:s.synopsis,children:["Also known as: ",a.altTitle]})]}),e("div",{className:s.body,children:[e("div",{className:s.metaRow,children:[c&&e("div",{className:s.metaItem,children:[e(l,{name:"book",size:14}),e("span",{children:c})]}),t>0&&e("div",{className:s.metaItem,children:e("span",{children:[t," chapter",t===1?"":"s"]})}),i.progressLabel&&e("div",{className:s.metaItem,children:[e(l,{name:"bookmark",size:12}),e("span",{children:i.progressLabel})]})]}),e("div",{className:s.synopsis,children:a?.description?a.description:"No synopsis available."}),Array.isArray(a?.genres)&&(a?.genres?.length??0)>0&&e("div",{className:s.details,children:e("div",{className:s.genres,children:a.genres.filter(Boolean).slice(0,4).map(n=>e("span",{className:s.genre,children:n},n))})})]}),e("div",{className:s.footer,children:[e("div",{className:s.primaryAction,children:e(m,{to:i.readTarget,className:s.watchBtn,children:[e(l,{name:"book",size:14}),"Read now"]})}),e("div",{className:s.secondaryActions,children:[e("button",{className:`${s.watchlistBtn} ${r?s.active:""}`,onClick:n=>{n.preventDefault(),n.stopPropagation(),p()},children:[r?e(l,{name:"check",size:12}):e(l,{name:"plus",size:12}),e("span",{children:r?"Remove":"Bookmark"})]}),e(m,{to:`/manga/${i.provider}/${encodeURIComponent(i.mangaId)}`,className:s.detailsBtn,children:"Read more"})]})]})]})})},$=()=>P();export{R as M,$ as u};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{T as o}from"./vendor-core-DfaOB3Rn.js";import{b as a}from"./vendor-query-BBT5_sHx.js";import{U as i}from"./index-
|
|
1
|
+
import{T as o}from"./vendor-core-DfaOB3Rn.js";import{b as a}from"./vendor-query-BBT5_sHx.js";import{U as i}from"./index-B4AdKbhW.js";const n=300*1e3;function u(r){return{value:r.id,label:r.label,mature:r.mature,kind:r.kind,sub:r.sub,tier:r.tier,browse:r.browse,facets:r.facets,servers:r.servers}}const d=()=>{const r=a({queryKey:["providers"],queryFn:()=>i("/api/providers"),staleTime:n,retry:1}),e=Array.isArray(r.data)?r.data:null,t=o(()=>e&&e.length>0?e.filter(s=>s.loaded).map(u):[],[e]);return{...r,options:t,isFallback:!e||e.length===0}};export{d as u};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{N as c,u as r,S as d}from"./vendor-core-DfaOB3Rn.js";import{I as v}from"./vendor-icons-DrybRNxP.js";import{M as T}from"./MediaCard-
|
|
1
|
+
import{N as c,u as r,S as d}from"./vendor-core-DfaOB3Rn.js";import{I as v}from"./vendor-icons-DrybRNxP.js";import{M as T}from"./MediaCard-DedwE5DX.js";import{T as g}from"./TvPopup-D1mSlOZt.js";import{c as m,i as f}from"./useTvLibrary-73NkS_5R.js";import{b as i}from"./vendor-query-BBT5_sHx.js";import{h as p}from"./index-B4AdKbhW.js";const _=c(({item:e})=>{const o=e.type==="tv"||e.type==="tvSeries"||e.type==="tvMiniSeries",s=m(e.type,e.id);return r(T,{item:{id:String(e.id),title:e.title,thumbnail:e.image,typeBadge:o?"TV":"Movie",isAdult:f(e)},linkTo:s,hoverIcon:"info",showInfoButton:!0,metaRow:r(d,{children:[e.year&&r("span",{style:{opacity:.75},children:e.year}),e.vote_average!=null&&r("span",{style:{display:"inline-flex",alignItems:"center",gap:3},children:[r(v,{name:"star",size:10}),Number(e.vote_average).toFixed(1)]})]}),renderPopup:(a,t)=>r(g,{item:e,anchorRect:a,onMouseEnter:t.onMouseEnter,onMouseLeave:t.onMouseLeave,onRequestClose:t.close})})}),u=1e3*60*5,b=e=>{const o=p(),{query:s,type:a,genre:t,year:n,sort_by:l,page:y}=e;return i({...o.tv.search.queryOptions({q:s?.trim()||"",type:a||"multi",genre:t||"",year:n&&n!=="ALL"?n:"",sortBy:l||"popularity.desc",page:y||1}),staleTime:u,retry:1})},A=(e="all",o="week",s=1,a=!0)=>{const t=p();return i({...t.tv.trending.queryOptions({mediaType:e,timeWindow:o,page:s}),enabled:a,staleTime:u,retry:1})};export{_ as T,b as a,A as u};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{T as y}from"./vendor-core-DfaOB3Rn.js";import{b as v,u as o,a as n}from"./vendor-query-BBT5_sHx.js";import{h as a,z as i,t as p}from"./index-
|
|
1
|
+
import{T as y}from"./vendor-core-DfaOB3Rn.js";import{b as v,u as o,a as n}from"./vendor-query-BBT5_sHx.js";import{h as a,z as i,t as p}from"./index-B4AdKbhW.js";const d=t=>String(t).toLowerCase()==="movie"?"movie":"tv",m=(t,e)=>`${d(t)}:${e}`,L=(t,e)=>{const r=d(t);return`/tv/${e}?type=${r}`},S=(t,e,r,s)=>{const u=new URLSearchParams;return u.set("type",d(t)),r!==void 0&&u.set("s",String(r)),s!==void 0&&u.set("e",String(s)),`/tv/${e}/watch?${u.toString()}`},F=t=>t.adult===!0||t.adult===1,K=["Watching","Completed","On-Hold","Dropped","Planned"],g=(t,e)=>m(t,e),$=(t="All",e=1,r=24)=>{const s=a();return v(s.tvLibrary.list.queryOptions({status:t,page:e,limit:r}))},h=()=>{const t=a();return v({...t.tvLibrary.ids.queryOptions(),staleTime:1e3*60})},C=t=>{const e=a();return v({...e.tvLibrary.check.queryOptions({id:t||""}),enabled:!!t,staleTime:1e3*60})},w=(t=24)=>{const e=a();return v(e.tvProgress.continueWatching.queryOptions({limit:t}))},O=t=>{const e=a();return v({...e.tvProgress.getByMedia.queryOptions({mediaId:t||""}),enabled:!!t})},f=(t,e,r)=>{const s=a();return v({...s.tvProgress.latest.queryOptions({mediaId:t||"",season:e,episode:r}),enabled:!!t,staleTime:0})},b=()=>{const t=a(),e=o();return n({mutationFn:async r=>{const{silent:s,...u}=r;return p.tvLibrary.add.mutate(u)},onSuccess:(r,s)=>{s.silent||i.success("Added to TV watchlist"),e.invalidateQueries({queryKey:["tv-library"]}),e.invalidateQueries(t.tvLibrary.pathFilter())},onError:r=>{i.error(`Failed to add: ${r.message}`)}})},Q=()=>{const t=a(),e=o();return n(t.tvLibrary.remove.mutationOptions({onSuccess:()=>{i.success("Removed from TV watchlist"),e.invalidateQueries({queryKey:["tv-library"]}),e.invalidateQueries({queryKey:["tv-continue-watching"]}),e.invalidateQueries(t.tvLibrary.pathFilter()),e.invalidateQueries(t.tvProgress.pathFilter())},onError:r=>{i.error(`Failed to remove: ${r.message}`)}}))},k=()=>{const t=a(),e=o();return n(t.tvLibrary.setStatus.mutationOptions({onSuccess:()=>{i.success("Status updated"),e.invalidateQueries({queryKey:["tv-library"]}),e.invalidateQueries({queryKey:["tv-continue-watching"]}),e.invalidateQueries(t.tvLibrary.pathFilter()),e.invalidateQueries(t.tvProgress.pathFilter())},onError:r=>{i.error(`Failed to update status: ${r.message}`)}}))},R=()=>{const t=a(),e=o();return n(t.tvProgress.save.mutationOptions({onSuccess:(r,s)=>{e.invalidateQueries({queryKey:["tv-progress",s.mediaId]}),e.invalidateQueries({queryKey:["tv-continue-watching"]}),e.invalidateQueries({queryKey:["tv-library"]}),e.invalidateQueries(t.tvLibrary.pathFilter()),e.invalidateQueries(t.tvProgress.pathFilter())}}))},B=()=>{const t=a(),e=o();return n(t.tvProgress.remove.mutationOptions({onSuccess:()=>{i.success("Progress reset"),e.invalidateQueries({queryKey:["tv-progress"]}),e.invalidateQueries({queryKey:["tv-continue-watching"]}),e.invalidateQueries({queryKey:["tv-library"]}),e.invalidateQueries(t.tvLibrary.pathFilter()),e.invalidateQueries(t.tvProgress.pathFilter())},onError:r=>{i.error(`Failed to reset progress: ${r.message}`)}}))},E=()=>{const t=a(),e=o();return n(t.tvLibrary.batchStatus.mutationOptions({onSuccess:r=>{i.success(`Status updated for ${r.updated??0} items`),e.invalidateQueries({queryKey:["tv-library"]}),e.invalidateQueries({queryKey:["tv-continue-watching"]}),e.invalidateQueries(t.tvLibrary.pathFilter()),e.invalidateQueries(t.tvProgress.pathFilter())},onError:r=>{i.error(`Failed to update statuses: ${r.message}`)}}))},I=()=>{const t=a(),e=o();return n(t.tvLibrary.removeMany.mutationOptions({onSuccess:r=>{const s=r.removed??0;i.success(`Removed ${s} ${s===1?"item":"items"} from TV watchlist`),e.invalidateQueries({queryKey:["tv-library"]}),e.invalidateQueries({queryKey:["tv-continue-watching"]}),e.invalidateQueries(t.tvLibrary.pathFilter()),e.invalidateQueries(t.tvProgress.pathFilter())},onError:r=>{i.error(`Failed to remove: ${r.message}`)}}))},A=()=>{const t=a(),e=o();return n(t.tvProgress.removeMany.mutationOptions({onSuccess:r=>{const s=r.removed??0;i.success(`Reset progress for ${s} ${s===1?"item":"items"}`),e.invalidateQueries({queryKey:["tv-progress"]}),e.invalidateQueries({queryKey:["tv-continue-watching"]}),e.invalidateQueries({queryKey:["tv-library"]}),e.invalidateQueries(t.tvLibrary.pathFilter()),e.invalidateQueries(t.tvProgress.pathFilter())},onError:r=>{i.error(`Failed to reset progress: ${r.message}`)}}))},M=()=>{const t=b(),e=Q(),{data:r}=h(),s=y(()=>new Set(r?.ids||[]),[r]);return{toggle:c=>{const l=g(c.mediaType,c.tmdbId);s.has(l)?e.mutate(l):t.mutate({...c,poster:c.poster||""})},bookmarkedIds:s,pending:t.isPending||e.isPending}};export{K as T,Q as a,B as b,L as c,m as d,C as e,M as f,R as g,k as h,F as i,f as j,O as k,$ as l,E as m,d as n,I as o,A as p,S as t,w as u};
|
package/client/dist/index.html
CHANGED
|
@@ -33,11 +33,11 @@
|
|
|
33
33
|
background-color: #0c0d12;
|
|
34
34
|
}
|
|
35
35
|
</style>
|
|
36
|
-
<script type="module" crossorigin src="/assets/index-
|
|
36
|
+
<script type="module" crossorigin src="/assets/index-B4AdKbhW.js"></script>
|
|
37
37
|
<link rel="modulepreload" crossorigin href="/assets/vendor-core-DfaOB3Rn.js">
|
|
38
38
|
<link rel="modulepreload" crossorigin href="/assets/vendor-query-BBT5_sHx.js">
|
|
39
39
|
<link rel="modulepreload" crossorigin href="/assets/vendor-icons-DrybRNxP.js">
|
|
40
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
40
|
+
<link rel="stylesheet" crossorigin href="/assets/index-D0Haw_Zl.css">
|
|
41
41
|
</head>
|
|
42
42
|
|
|
43
43
|
<body>
|
package/orchestrator.js
CHANGED
|
@@ -5,6 +5,7 @@ const http = require('http')
|
|
|
5
5
|
const os = require('os')
|
|
6
6
|
const path = require('path')
|
|
7
7
|
const crypto = require('crypto')
|
|
8
|
+
const { parseArgs } = require('util')
|
|
8
9
|
|
|
9
10
|
async function fetchJson(url, timeoutMs) {
|
|
10
11
|
const controller = new AbortController()
|
|
@@ -36,7 +37,38 @@ function detectGlobalInstall() {
|
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
const shutdownToken = crypto.randomBytes(32).toString('hex')
|
|
39
|
-
|
|
40
|
+
let options, mode
|
|
41
|
+
try {
|
|
42
|
+
const { values, positionals } = parseArgs({
|
|
43
|
+
allowPositionals: true,
|
|
44
|
+
options: {
|
|
45
|
+
port: { type: 'string' },
|
|
46
|
+
'dev-port': { type: 'string' },
|
|
47
|
+
'no-update': { type: 'boolean' },
|
|
48
|
+
version: { type: 'boolean', short: 'v' },
|
|
49
|
+
help: { type: 'boolean', short: 'h' },
|
|
50
|
+
},
|
|
51
|
+
})
|
|
52
|
+
options = values
|
|
53
|
+
mode = positionals[0] || 'prod'
|
|
54
|
+
if (positionals.length > 1 || !['dev', 'prod'].includes(mode)) {
|
|
55
|
+
throw new Error('Expected at most one mode: dev or prod')
|
|
56
|
+
}
|
|
57
|
+
for (const [flag, variable] of [
|
|
58
|
+
['port', 'PORT'],
|
|
59
|
+
['dev-port', 'DEV_PORT'],
|
|
60
|
+
]) {
|
|
61
|
+
const value = options[flag]
|
|
62
|
+
if (value === undefined) continue
|
|
63
|
+
if (!/^\d+$/.test(value) || Number(value) < 1 || Number(value) > 65535) {
|
|
64
|
+
throw new Error(`--${flag} must be an integer between 1 and 65535`)
|
|
65
|
+
}
|
|
66
|
+
process.env[variable] = String(Number(value))
|
|
67
|
+
}
|
|
68
|
+
} catch (err) {
|
|
69
|
+
console.error(`dango: ${err.message}`)
|
|
70
|
+
process.exit(1)
|
|
71
|
+
}
|
|
40
72
|
const isWin = os.platform() === 'win32'
|
|
41
73
|
const npmCmd = isWin ? 'npm.cmd' : 'npm'
|
|
42
74
|
|
|
@@ -47,16 +79,20 @@ const colors = {
|
|
|
47
79
|
system: '\x1b[33m',
|
|
48
80
|
}
|
|
49
81
|
|
|
50
|
-
if (
|
|
82
|
+
if (options.version) {
|
|
51
83
|
const pkg = require('./package.json')
|
|
52
84
|
console.log(`dango version ${pkg.version}`)
|
|
53
85
|
process.exit(0)
|
|
54
86
|
}
|
|
55
87
|
|
|
56
|
-
if (
|
|
57
|
-
console.log(
|
|
88
|
+
if (options.help) {
|
|
89
|
+
console.log(
|
|
90
|
+
'Usage: dango [dev|prod] [--port PORT] [--dev-port PORT] [--no-update] [--version] [--help]'
|
|
91
|
+
)
|
|
58
92
|
console.log(' dev Run with hot-reload (server + client)')
|
|
59
93
|
console.log(' prod Run pre-built version (default)')
|
|
94
|
+
console.log(' --port PORT Backend port (overrides PORT; default: 3000)')
|
|
95
|
+
console.log(' --dev-port PORT Development frontend port (overrides DEV_PORT; default: 5173)')
|
|
60
96
|
console.log(' --no-update Skip update checks')
|
|
61
97
|
console.log(' --version, -v Print version and exit')
|
|
62
98
|
console.log(' --help, -h Show this help and exit')
|
|
@@ -104,7 +140,7 @@ const isNewerVersion = (remote, current) => {
|
|
|
104
140
|
}
|
|
105
141
|
|
|
106
142
|
async function checkForUpdates() {
|
|
107
|
-
if (
|
|
143
|
+
if (options['no-update'] || mode === 'dev') return
|
|
108
144
|
|
|
109
145
|
try {
|
|
110
146
|
const isGlobalInstall = detectGlobalInstall()
|
|
@@ -224,6 +260,37 @@ const CLIENT_DIR = path.join(__dirname, 'client')
|
|
|
224
260
|
let syncSpinner = null
|
|
225
261
|
let syncMessage = ''
|
|
226
262
|
let syncDots = 0
|
|
263
|
+
let providerLineActive = false
|
|
264
|
+
let providerPhase = false
|
|
265
|
+
let providerFields = {}
|
|
266
|
+
let pendingProviderSummary = false
|
|
267
|
+
|
|
268
|
+
const ansiPattern = /\x1b\[[0-9;]*m/g
|
|
269
|
+
const readPrettyField = (line) => {
|
|
270
|
+
const match = /^\s+([\w-]+):\s*(.*)$/.exec(line.replace(ansiPattern, ''))
|
|
271
|
+
return match ? [match[1], match[2].trim().replace(/^"|"$/g, '')] : null
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const showProvider = (color, prefix, fields) => {
|
|
275
|
+
process.stdout.write(
|
|
276
|
+
`\r\x1b[K${color}[${prefix}]${colors.reset} ${colors.system}Loading providers${colors.reset} ` +
|
|
277
|
+
`${colors.client}${fields.provider || ''}${fields.version ? ` v${fields.version}` : ''}${colors.reset}`
|
|
278
|
+
)
|
|
279
|
+
providerLineActive = true
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const flushProviderSummary = (color, prefix) => {
|
|
283
|
+
if (providerLineActive) {
|
|
284
|
+
process.stdout.write('\n')
|
|
285
|
+
providerLineActive = false
|
|
286
|
+
}
|
|
287
|
+
if (!pendingProviderSummary) return
|
|
288
|
+
pendingProviderSummary = false
|
|
289
|
+
console.log(
|
|
290
|
+
`${color}[${prefix}]${colors.reset} ${colors.system}Providers ready${colors.reset} ` +
|
|
291
|
+
`${colors.client}${providerFields.count} anime, ${providerFields.mangaCount} manga, ${providerFields.tvCount} tv${colors.reset}`
|
|
292
|
+
)
|
|
293
|
+
}
|
|
227
294
|
|
|
228
295
|
const startSpinner = (msg) => {
|
|
229
296
|
stopSpinner()
|
|
@@ -281,7 +348,7 @@ const formatChildLine = (line) => {
|
|
|
281
348
|
const text =
|
|
282
349
|
`${time ? `[${time}] ` : ''}${levelColor}${levelName}${colors.reset} ${messageColor}${obj.msg}${colors.reset}` +
|
|
283
350
|
(extras.length ? ` (${propertyColor}${extras.join(' ')}${colors.reset})` : '')
|
|
284
|
-
return { text, msg: obj.msg }
|
|
351
|
+
return { text, msg: obj.msg, obj }
|
|
285
352
|
}
|
|
286
353
|
|
|
287
354
|
const log = (prefix, color, data) => {
|
|
@@ -293,9 +360,23 @@ const log = (prefix, color, data) => {
|
|
|
293
360
|
|
|
294
361
|
const display = []
|
|
295
362
|
for (const line of lines) {
|
|
296
|
-
|
|
363
|
+
if (providerPhase) {
|
|
364
|
+
const field = readPrettyField(line)
|
|
365
|
+
if (field) {
|
|
366
|
+
providerFields[field[0]] = field[1]
|
|
367
|
+
if (providerLineActive && field[0] !== 'module') {
|
|
368
|
+
showProvider(color, prefix, providerFields)
|
|
369
|
+
}
|
|
370
|
+
continue
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
const { text, msg, obj } = formatChildLine(line)
|
|
297
375
|
const content = msg !== undefined ? msg : text
|
|
298
376
|
|
|
377
|
+
const boundMatch = content.match(/Server running on http:\/\/localhost:(\d+)/)
|
|
378
|
+
if (boundMatch) boundServerPort = Number(boundMatch[1])
|
|
379
|
+
|
|
299
380
|
if (content.includes('[SERVER_EXIT]')) {
|
|
300
381
|
isShuttingDown = true
|
|
301
382
|
stopSpinner()
|
|
@@ -308,6 +389,23 @@ const log = (prefix, color, data) => {
|
|
|
308
389
|
return
|
|
309
390
|
}
|
|
310
391
|
|
|
392
|
+
if (content.includes('remote provider loaded')) {
|
|
393
|
+
if (pendingProviderSummary) flushProviderSummary(color, prefix)
|
|
394
|
+
providerPhase = true
|
|
395
|
+
providerFields = { ...(obj || {}) }
|
|
396
|
+
showProvider(color, prefix, providerFields)
|
|
397
|
+
continue
|
|
398
|
+
}
|
|
399
|
+
if (content.includes('remote providers refreshed')) {
|
|
400
|
+
providerPhase = true
|
|
401
|
+
Object.assign(providerFields, obj)
|
|
402
|
+
pendingProviderSummary = true
|
|
403
|
+
continue
|
|
404
|
+
}
|
|
405
|
+
flushProviderSummary(color, prefix)
|
|
406
|
+
providerPhase = false
|
|
407
|
+
providerFields = {}
|
|
408
|
+
|
|
311
409
|
if (content.includes('[SYNC_START]')) {
|
|
312
410
|
startSpinner(content.split('[SYNC_START]')[1].trim())
|
|
313
411
|
continue
|
|
@@ -392,6 +490,7 @@ const terminateProcess = (proc, signal = 'SIGTERM') => {
|
|
|
392
490
|
}
|
|
393
491
|
let serverProcess, clientProcess
|
|
394
492
|
let isShuttingDown = false
|
|
493
|
+
let boundServerPort = Number(process.env.PORT) || 3000
|
|
395
494
|
|
|
396
495
|
async function main() {
|
|
397
496
|
console.log(
|
|
@@ -465,7 +564,7 @@ const shutdown = () => {
|
|
|
465
564
|
}, 5000)
|
|
466
565
|
}
|
|
467
566
|
|
|
468
|
-
const serverPort =
|
|
567
|
+
const serverPort = boundServerPort
|
|
469
568
|
const req = http.request(
|
|
470
569
|
{
|
|
471
570
|
hostname: '127.0.0.1',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@serifpersia/dango",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.1",
|
|
4
4
|
"description": "A web application for watching anime.",
|
|
5
5
|
"main": "orchestrator.js",
|
|
6
6
|
"repository": {
|
|
@@ -83,5 +83,5 @@
|
|
|
83
83
|
"allowScripts": {
|
|
84
84
|
"esbuild@0.28.2": true
|
|
85
85
|
},
|
|
86
|
-
"versionDate": "2026-10-
|
|
86
|
+
"versionDate": "2026-10-16T10:34:21.293Z"
|
|
87
87
|
}
|
package/server/dist/app-hono.js
CHANGED
|
@@ -53,6 +53,11 @@ export function getHonoClientIp(c) {
|
|
|
53
53
|
return c.req.header('x-dango-client-ip') ?? undefined;
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
|
+
const NOT_READY_HEADER = 'x-dango-not-ready';
|
|
57
|
+
function notReady(c, body) {
|
|
58
|
+
c.header(NOT_READY_HEADER, '1');
|
|
59
|
+
return typeof body === 'string' ? c.text(body, 503) : c.json(body, 503);
|
|
60
|
+
}
|
|
56
61
|
export async function honoRequestLogger(c, next) {
|
|
57
62
|
const start = process.hrtime.bigint();
|
|
58
63
|
const url = new URL(c.req.url);
|
|
@@ -61,7 +66,7 @@ export async function honoRequestLogger(c, next) {
|
|
|
61
66
|
const ms = Math.round((Number(process.hrtime.bigint() - start) / 1_000_000) * 10) / 10;
|
|
62
67
|
const status = c.res.status;
|
|
63
68
|
const payload = { method: c.req.method, url: loggedUrl, status, ms };
|
|
64
|
-
if (status >= 500) {
|
|
69
|
+
if (status >= 500 && !c.res.headers.get(NOT_READY_HEADER)) {
|
|
65
70
|
logger.warn(payload, 'request failed');
|
|
66
71
|
}
|
|
67
72
|
else if (!loggedUrl.startsWith('/api/proxy')) {
|
|
@@ -208,26 +213,26 @@ export function createHonoApp(getState, getGuardState, getDbs, dbAdmin, provider
|
|
|
208
213
|
app.get('/api/health', (c) => {
|
|
209
214
|
const state = getState();
|
|
210
215
|
if (state.shuttingDown) {
|
|
211
|
-
return c
|
|
216
|
+
return notReady(c, { status: 'shutting-down', ready: false });
|
|
212
217
|
}
|
|
213
218
|
if (!state.dbReady) {
|
|
214
|
-
return c
|
|
219
|
+
return notReady(c, { status: 'starting', ready: false });
|
|
215
220
|
}
|
|
216
221
|
return c.json({ status: 'ok', ready: true });
|
|
217
222
|
});
|
|
218
223
|
app.use(async (c, next) => {
|
|
219
224
|
const guard = getGuardState();
|
|
220
225
|
if (guard.shuttingDown) {
|
|
221
|
-
return c
|
|
226
|
+
return notReady(c, 'Server is shutting down...');
|
|
222
227
|
}
|
|
223
228
|
if (!guard.dbsReady) {
|
|
224
|
-
return c
|
|
229
|
+
return notReady(c, 'Database initializing...');
|
|
225
230
|
}
|
|
226
231
|
if (guard.bootSyncing &&
|
|
227
232
|
c.req.method !== 'GET' &&
|
|
228
233
|
c.req.method !== 'HEAD' &&
|
|
229
234
|
c.req.method !== 'OPTIONS') {
|
|
230
|
-
return c
|
|
235
|
+
return notReady(c, 'Sync in progress...');
|
|
231
236
|
}
|
|
232
237
|
await next();
|
|
233
238
|
});
|
|
@@ -288,7 +293,7 @@ export function createHonoApp(getState, getGuardState, getDbs, dbAdmin, provider
|
|
|
288
293
|
app.get('/api/auth/app-status', (c) => {
|
|
289
294
|
const authed = !hasAppPassword() ||
|
|
290
295
|
validateLanSession(getTokenFromHeaders(c.req.header('authorization'), c.req.header('cookie')));
|
|
291
|
-
return c.json({ hasPassword: hasAppPassword(), isAuthenticated: authed });
|
|
296
|
+
return c.json({ hasPassword: hasAppPassword(), isAuthenticated: authed, port: CONFIG.PORT });
|
|
292
297
|
});
|
|
293
298
|
app.post('/api/auth/app-login', async (c) => {
|
|
294
299
|
const body = (await c.req.json().catch(() => undefined));
|
|
@@ -470,7 +475,7 @@ export function createHonoApp(getState, getGuardState, getDbs, dbAdmin, provider
|
|
|
470
475
|
try {
|
|
471
476
|
const dbs = getDbs();
|
|
472
477
|
if (!dbs.mangaDb || dbs.mangaDb.isClosedCheck()) {
|
|
473
|
-
return c
|
|
478
|
+
return notReady(c, { error: 'Manga database is not ready' });
|
|
474
479
|
}
|
|
475
480
|
let result;
|
|
476
481
|
try {
|
package/server/dist/config.js
CHANGED
|
@@ -117,10 +117,11 @@ migrateFromAniWeb(DATA_ROOT);
|
|
|
117
117
|
dotenv.config({ path: path.join(SERVER_ROOT, '.env') });
|
|
118
118
|
dotenv.config({ path: ENV_PATH, override: true });
|
|
119
119
|
const IS_DEV = process.argv.includes('--dev');
|
|
120
|
-
const PORT = 3000;
|
|
120
|
+
const PORT = Number(process.env.PORT) || 3000;
|
|
121
|
+
const DEV_PORT = Number(process.env.DEV_PORT) || 5173;
|
|
121
122
|
const HOST = process.env.HOST || '0.0.0.0';
|
|
122
123
|
const GOOGLE_REDIRECT_URI = IS_DEV
|
|
123
|
-
?
|
|
124
|
+
? `http://localhost:${DEV_PORT}/api/auth/google/callback`
|
|
124
125
|
: `http://localhost:${PORT}/api/auth/google/callback`;
|
|
125
126
|
export const CONFIG = {
|
|
126
127
|
ROOT: DATA_ROOT,
|
package/server/dist/hono/auth.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import logger from '../logger.js';
|
|
2
2
|
import { googleDriveService } from '../google.js';
|
|
3
|
-
import { CONFIG } from '../config.js';
|
|
4
3
|
import { updateEnvFile } from '../utils/env.utils.js';
|
|
5
4
|
export function registerAuth(app, getDbs, runSync) {
|
|
6
5
|
app.get('/api/auth/google/callback', async (c) => {
|
|
@@ -32,12 +31,6 @@ export function registerAuth(app, getDbs, runSync) {
|
|
|
32
31
|
try {
|
|
33
32
|
if (window.opener && !window.opener.closed) {
|
|
34
33
|
window.opener.postMessage(payload, window.location.origin);
|
|
35
|
-
try {
|
|
36
|
-
window.opener.postMessage(payload, 'http://localhost:${CONFIG.PORT}');
|
|
37
|
-
} catch (e) {}
|
|
38
|
-
try {
|
|
39
|
-
window.opener.postMessage(payload, 'http://127.0.0.1:${CONFIG.PORT}');
|
|
40
|
-
} catch (e) {}
|
|
41
34
|
setTimeout(function () { window.close(); }, 300);
|
|
42
35
|
setTimeout(function () { window.location.href = '/?google_auth=success'; }, 1500);
|
|
43
36
|
} else {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import logger from '../../logger.js';
|
|
2
|
+
import { TRPCError } from '@trpc/server';
|
|
2
3
|
import { googleDriveService } from '../../google.js';
|
|
3
4
|
import { githubSyncService } from '../../github-sync.js';
|
|
4
5
|
import { initSyncProvider, getActiveProvider, runFullSyncSequence } from '../../sync.js';
|
|
@@ -27,6 +28,9 @@ const syncProviderInput = () => defineSchema((value) => ({
|
|
|
27
28
|
const rcloneSaveInput = () => defineSchema((value) => ({
|
|
28
29
|
remote: reqObj(value).remote,
|
|
29
30
|
}));
|
|
31
|
+
const serverPortInput = () => defineSchema((value) => ({
|
|
32
|
+
port: reqObj(value).port,
|
|
33
|
+
}));
|
|
30
34
|
export const authRouter = router({
|
|
31
35
|
configStatus: protectedProcedure.query(async () => {
|
|
32
36
|
const useWorker = !!CONFIG.GOOGLE_AUTH_WORKER_URL;
|
|
@@ -145,6 +149,18 @@ export const authRouter = router({
|
|
|
145
149
|
await runSyncFromCtx(ctx, ctx.db, 'rclone');
|
|
146
150
|
return { success: true };
|
|
147
151
|
}),
|
|
152
|
+
setServerPort: protectedProcedure.input(serverPortInput()).mutation(async ({ input }) => {
|
|
153
|
+
const port = Number(input.port);
|
|
154
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
155
|
+
throw new TRPCError({
|
|
156
|
+
code: 'BAD_REQUEST',
|
|
157
|
+
message: 'Port must be an integer between 1 and 65535',
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
await updateEnvFile({ PORT: String(port) });
|
|
161
|
+
logger.info({ port }, 'Server port saved. Restart required to apply.');
|
|
162
|
+
return { success: true, port };
|
|
163
|
+
}),
|
|
148
164
|
googleAuthUrl: protectedProcedure.query(async () => {
|
|
149
165
|
const url = await googleDriveService.getAuthUrl();
|
|
150
166
|
return { url };
|
package/server/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
._container_1287q_1{max-width:var(--max-width);margin:0 auto;padding:0;min-height:100vh;background:var(--bg-main);overflow-x:hidden}._heroSection_1287q_11{position:relative;width:100%;padding-bottom:var(--space-12)}._bannerContainer_1287q_17{position:absolute;top:0;left:0;right:0;height:500px;overflow:hidden;z-index:0}._banner_1287q_17{width:100%;height:100%;background-size:cover;background-position:center 20%;filter:brightness(.3) saturate(1.1);transform:scale(1.05);transition:transform var(--transition-slow)}._bannerOverlay_1287q_37{position:absolute;inset:0;background:linear-gradient(to bottom,rgba(5,5,5,.4) 0%,rgba(5,5,5,.7) 40%,var(--bg-main) 100%);box-shadow:inset 0 -100px 100px -20px var(--bg-main)}._heroContent_1287q_49{position:relative;z-index:1;display:grid;grid-template-columns:320px 1fr;gap:var(--space-10);max-width:1200px;margin:0 auto;padding:var(--space-16) var(--space-6) 0;align-items:flex-start}._posterContainer_1287q_62{position:sticky;top:120px;border-radius:var(--radius-lg);overflow:hidden;box-shadow:0 20px 50px #00000080;transform:translateY(0);animation:_floatIn_1287q_1 .8s var(--ease-spring);border:1px solid var(--border-secondary)}._poster_1287q_62{width:100%;display:block;object-fit:cover;aspect-ratio:2 / 3;transition:transform var(--transition-base)}._posterContainer_1287q_62:hover ._poster_1287q_62{transform:scale(1.05)}._infoGlass_1287q_86{background:var(--glass-bg);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);border:1px solid var(--glass-border);border-radius:var(--radius-xl);padding:var(--space-8);box-shadow:var(--glass-shadow);animation:_slideUpIn_1287q_1 .8s var(--ease-smooth);display:flex;flex-direction:column;gap:var(--space-8)}._title_1287q_100{font-size:clamp(1.5rem,4vw,2.5rem);font-weight:800;color:var(--text-primary);line-height:1.1;margin:0 0 var(--space-4);letter-spacing:-.02em}._quickMeta_1287q_109{display:flex;flex-wrap:wrap;gap:var(--space-6);align-items:center;margin-bottom:var(--space-2)}._metaItem_1287q_117{display:flex;align-items:center;gap:var(--space-2);color:var(--text-secondary);font-size:var(--font-size-sm);font-weight:500}._iconStar_1287q_126{color:var(--accent-lighter)}._iconTv_1287q_129{color:var(--accent)}._iconType_1287q_132{color:var(--color-success)}._iconClock_1287q_135{color:#60a5fa}._genres_1287q_139{display:flex;flex-wrap:wrap;gap:var(--space-2);margin-top:var(--space-4)}._genre_1287q_139{background:#ffffff0d;padding:.4rem 1rem;border-radius:var(--radius-full);font-size:var(--font-size-sm);color:var(--text-secondary);border:1px solid var(--border-primary);transition:all var(--transition-fast);font-weight:500}._genre_1287q_139:hover{background:var(--accent);border-color:var(--accent);color:var(--accent-text);transform:translateY(-2px)}._synopsisSection_1287q_165{border-top:1px solid var(--border-primary);padding-top:var(--space-6)}._sectionTitleSmall_1287q_170{font-size:var(--font-size-sm);text-transform:uppercase;letter-spacing:.1em;color:var(--text-tertiary);margin-bottom:var(--space-3)}._description_1287q_178{font-size:var(--font-size-base);color:var(--text-secondary);line-height:1.7;max-width:800px}._actions_1287q_186{display:flex;gap:var(--space-4);margin-top:auto}._watchBtn_1287q_192{display:inline-flex;align-items:center;gap:var(--space-3);background:linear-gradient(135deg,var(--accent) 0%,var(--accent-dark) 100%);color:var(--accent-text);padding:.8rem 1.8rem;border-radius:var(--radius-md);font-weight:600;font-size:var(--font-size-sm);border:none;cursor:pointer;transition:all var(--transition-base);box-shadow:0 4px 15px var(--accent-glow)}._watchBtn_1287q_192:hover{transform:translateY(-2px);box-shadow:0 8px 25px var(--accent-glow);opacity:.95}._watchlistBtn_1287q_214{display:inline-flex;align-items:center;gap:var(--space-3);background:#ffffff0d;color:var(--text-primary);border:1px solid var(--border-secondary);padding:.8rem 1.8rem;border-radius:var(--radius-md);font-weight:600;font-size:var(--font-size-sm);cursor:pointer;transition:all var(--transition-base)}._watchlistBtn_1287q_214:hover{background:#ffffff1a;border-color:var(--text-secondary)}._watchlistBtn_1287q_214._active_1287q_234{background:color-mix(in srgb,var(--color-success) 10%,transparent);border-color:var(--color-success);color:var(--color-success)}._detailsSection_1287q_241{max-width:1200px;margin:0 auto var(--space-16);padding:0 var(--space-6)}._detailsToggleBtn_1287q_247{display:flex;align-items:center;justify-content:center;gap:var(--space-3);width:100%;padding:var(--space-4);background:var(--bg-secondary);color:var(--text-secondary);border:1px solid var(--border-primary);border-radius:var(--radius-lg);font-weight:600;cursor:pointer;transition:all var(--transition-base);margin-bottom:var(--space-6)}._detailsToggleBtn_1287q_247:hover{background:var(--bg-tertiary);color:var(--text-primary);border-color:var(--border-secondary)}._expandedContent_1287q_270{animation:_fadeIn_1287q_1 .5s var(--ease-smooth)}._detailsGridContainer_1287q_274{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:var(--space-6);padding:var(--space-8);background:var(--bg-secondary);border-radius:var(--radius-xl);border:1px solid var(--border-primary)}._detailItem_1287q_284{display:flex;flex-direction:column;gap:var(--space-1)}._detailItem_1287q_284 strong{font-size:.7rem;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.1em}._detailItem_1287q_284 span{font-size:var(--font-size-sm);color:var(--text-primary);font-weight:500}._airingValue_1287q_303{color:var(--accent-light)!important}._loadingDetails_1287q_308{display:flex;flex-direction:column;align-items:center;gap:var(--space-4);padding:var(--space-12);color:var(--text-tertiary)}._spinner_1287q_317{width:30px;height:30px;border:3px solid rgba(255,255,255,.1);border-top-color:var(--accent);border-radius:50%;animation:_spin_1287q_317 .8s linear infinite}@keyframes _spin_1287q_317{to{transform:rotate(360deg)}}._heroSkeleton_1287q_332{width:100%}._skeletonBanner_1287q_336,._skeletonPoster_1287q_337,._skeletonTitle_1287q_338,._skeletonMeta_1287q_339,._skeletonDesc_1287q_340,._skeletonActions_1287q_341{position:relative;overflow:hidden;background:var(--bg-tertiary)}._skeletonBanner_1287q_336:after,._skeletonPoster_1287q_337:after,._skeletonTitle_1287q_338:after,._skeletonMeta_1287q_339:after,._skeletonDesc_1287q_340:after,._skeletonActions_1287q_341:after{content:"";position:absolute;inset:0;transform:translate(-100%);background-image:linear-gradient(90deg,#fff0 0,#ffffff0d 20%,#ffffff1f 60%,#fff0);animation:_skeleton-wave_1287q_1 1.8s infinite ease-in-out}._skeletonBanner_1287q_336{height:400px}._skeletonContent_1287q_374{max-width:1200px;margin:-100px auto 0;padding:0 var(--space-6);display:grid;grid-template-columns:320px 1fr;gap:var(--space-10)}._skeletonPoster_1287q_337{height:480px;border-radius:var(--radius-lg)}._skeletonInfo_1287q_388{background:var(--bg-secondary);border-radius:var(--radius-xl);padding:var(--space-8);display:flex;flex-direction:column;gap:var(--space-6)}._skeletonTitle_1287q_338{height:40px;width:60%;border-radius:var(--radius-sm)}._skeletonMeta_1287q_339{height:24px;width:40%;border-radius:var(--radius-sm)}._skeletonDesc_1287q_340{height:160px;width:100%;border-radius:var(--radius-sm)}._skeletonActions_1287q_341{height:50px;width:50%;border-radius:var(--radius-sm)}@keyframes _floatIn_1287q_1{0%{opacity:0;transform:translateY(30px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes _slideUpIn_1287q_1{0%{opacity:0;transform:translateY(50px)}to{opacity:1;transform:translateY(0)}}@keyframes _fadeIn_1287q_1{0%{opacity:0}to{opacity:1}}@media(max-width:1024px){._heroContent_1287q_49{grid-template-columns:1fr;padding-top:var(--space-12)}._posterContainer_1287q_62{width:220px;margin:0 auto;position:relative;top:0}._infoGlass_1287q_86{margin-top:-40px;padding-top:var(--space-12);text-align:center}._quickMeta_1287q_109,._genres_1287q_139{justify-content:center}._actions_1287q_186{flex-direction:column}._watchBtn_1287q_192,._watchlistBtn_1287q_214{width:100%;justify-content:center}._skeletonContent_1287q_374{grid-template-columns:1fr}._skeletonPoster_1287q_337{width:220px;height:330px;margin:0 auto}}@media(max-width:768px){._heroSection_1287q_11{padding-bottom:var(--space-8)}._heroContent_1287q_49{grid-template-columns:1fr;gap:var(--space-6);padding:var(--space-12) var(--space-4) 0}._posterContainer_1287q_62{position:relative;top:0;max-width:240px;margin:0 auto;margin-bottom:var(--space-4);animation:none}._infoGlass_1287q_86{padding:var(--space-6);animation:none}}@media(max-width:480px){._infoGlass_1287q_86{padding:var(--space-6);animation:none}._title_1287q_100{font-size:1.5rem}._quickMeta_1287q_109{gap:var(--space-3)}._metaItem_1287q_117 span{font-size:.75rem}}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{o as C,a as I,d as S,h as p,T,u as e}from"./vendor-core-DfaOB3Rn.js";import{I as s}from"./vendor-icons-DrybRNxP.js";import{u as b}from"./useAnimeInfoData-BqAd5seW.js";import{d as B,e as w,f as d,s as M,M as x,B as u}from"./index-DNxWyfmM.js";import{A}from"./AnimeMetaDetails-BogOi_bM.js";import{S as D}from"./SynopsisText-B3Sa5pRv.js";import{Q as G}from"./QueueOptionsButton-DjcdOJgg.js";import"./vendor-query-BBT5_sHx.js";import"./useIsMobile-Dvx1uJ82.js";import"./vendor-ui-3qrARCPr.js";const P="_container_1287q_1",W="_heroSection_1287q_11",O="_bannerContainer_1287q_17",$="_banner_1287q_17",U="_bannerOverlay_1287q_37",j="_heroContent_1287q_49",z="_posterContainer_1287q_62",V="_floatIn_1287q_1",Q="_poster_1287q_62",E="_infoGlass_1287q_86",H="_slideUpIn_1287q_1",F="_title_1287q_100",J="_quickMeta_1287q_109",K="_metaItem_1287q_117",L="_iconStar_1287q_126",R="_iconTv_1287q_129",X="_iconType_1287q_132",Y="_iconClock_1287q_135",Z="_genres_1287q_139",ee="_genre_1287q_139",ne="_synopsisSection_1287q_165",te="_sectionTitleSmall_1287q_170",se="_description_1287q_178",ae="_actions_1287q_186",ie="_watchBtn_1287q_192",oe="_watchlistBtn_1287q_214",le="_active_1287q_234",ce="_detailsSection_1287q_241",re="_detailsToggleBtn_1287q_247",de="_expandedContent_1287q_270",_e="_fadeIn_1287q_1",me="_detailsGridContainer_1287q_274",he="_detailItem_1287q_284",pe="_airingValue_1287q_303",ue="_loadingDetails_1287q_308",ve="_spinner_1287q_317",ge="_spin_1287q_317",ke="_heroSkeleton_1287q_332",qe="_skeletonBanner_1287q_336",fe="_skeletonPoster_1287q_337",Ne="_skeletonTitle_1287q_338",ye="_skeletonMeta_1287q_339",Ce="_skeletonDesc_1287q_340",Ie="_skeletonActions_1287q_341",Se="_skeletonContent_1287q_374",Te="_skeletonInfo_1287q_388",n={container:P,heroSection:W,bannerContainer:O,banner:$,bannerOverlay:U,heroContent:j,posterContainer:z,floatIn:V,poster:Q,infoGlass:E,slideUpIn:H,title:F,quickMeta:J,metaItem:K,iconStar:L,iconTv:R,iconType:X,iconClock:Y,genres:Z,genre:ee,synopsisSection:ne,sectionTitleSmall:te,description:se,actions:ae,watchBtn:ie,watchlistBtn:oe,active:le,detailsSection:ce,detailsToggleBtn:re,expandedContent:de,fadeIn:_e,detailsGridContainer:me,detailItem:he,airingValue:pe,loadingDetails:ue,spinner:ve,spin:ge,heroSkeleton:ke,skeletonBanner:qe,skeletonPoster:fe,skeletonTitle:Ne,skeletonMeta:ye,skeletonDesc:Ce,skeletonActions:Ie,"skeleton-wave":"_skeleton-wave_1287q_1",skeletonContent:Se,skeletonInfo:Te};function Oe(){const{id:a}=C(),i=I(),{titlePreference:l}=B(),[o,v]=S(!1),{showMeta:t,loadingMeta:g,toggleWatchlist:k,inWatchlist:c}=b(a),{hasConsent:q,grant:f}=w();p(()=>{a&&t?.id&&t.id!==a&&i(`/anime/${t.id}`,{replace:!0})},[a,t,i]),p(()=>{document.title=t?.name?`${t.name} - dango`:"Anime - dango"},[t?.name]);const N=()=>t?.name?l==="name"?t.name:l==="nativeName"?t.names?.native||t.name:l==="englishName"&&t.names?.english||t.name:"",y=()=>{a&&i(`/watch/${a}`)},_=T(()=>t?.bannerImage?d(t.bannerImage):t?.thumbnail?d(t.thumbnail,1200,450):"",[t?.bannerImage,t?.thumbnail]);if(g||!t?.name)return e("div",{className:n.container,children:e("div",{className:n.heroSkeleton,children:[e("div",{className:n.skeletonBanner}),e("div",{className:n.skeletonContent,children:[e("div",{className:n.skeletonPoster}),e("div",{className:n.skeletonInfo,children:[e("div",{className:n.skeletonTitle}),e("div",{className:n.skeletonMeta}),e("div",{className:n.skeletonDesc}),e("div",{className:n.skeletonActions})]})]})]})});const m=t.isAdult===!0&&!q;return e("div",{className:n.container,style:m?{filter:"blur(14px)",pointerEvents:"none",userSelect:"none"}:void 0,children:[e("div",{className:n.heroSection,children:[e("div",{className:n.bannerContainer,children:[e("div",{className:n.banner,style:_?{backgroundImage:`url(${_})`}:void 0}),e("div",{className:n.bannerOverlay})]}),e("div",{className:n.heroContent,children:[e("div",{className:n.posterContainer,children:e("img",{src:d(t.thumbnail||"",320,480),alt:t.name,className:n.poster,decoding:"async"})}),e("div",{className:n.infoGlass,children:[e("div",{className:n.topInfo,children:[e("h1",{className:n.title,children:N()}),e("div",{className:n.quickMeta,children:[t.score&&e("div",{className:n.metaItem,children:[e(s,{name:"star",className:n.iconStar}),e("span",{children:t.score})]}),t.status&&e("div",{className:n.metaItem,children:[e(s,{name:"tv",className:n.iconTv}),e("span",{children:t.status})]}),t.type&&e("div",{className:n.metaItem,children:[e(s,{name:"layer-group",className:n.iconType}),e("span",{children:t.type})]})]}),Array.isArray(t.genres)&&t.genres.length>0&&e("div",{className:n.genres,children:t.genres.filter(Boolean).slice(0,5).map(r=>{const h=typeof r=="string"?r:r?.name;return e("span",{className:n.genre,children:h},h)})})]}),e("div",{className:n.synopsisSection,children:[e("h2",{className:n.sectionTitleSmall,children:"Synopsis"}),e(D,{text:M(t.description),emptyText:"No description available."})]}),e("div",{className:n.actions,children:[e("button",{className:n.watchBtn,onClick:y,children:[e(s,{name:"play",size:14}),"Start Watching"]}),e("button",{className:`${n.watchlistBtn} ${c?n.active:""}`,onClick:k,children:[c?e(s,{name:"check",size:14}):e(s,{name:"plus",size:14}),c?"In Watchlist":"Add to Watchlist"]}),e(G,{showId:a,showName:t.name||t.names?.romaji,showThumbnail:t.thumbnail,nativeName:t.names?.native,englishName:t.names?.english,showType:t.type,className:n.watchlistBtn,activeClassName:n.active})]})]})]})]}),e("div",{className:n.detailsSection,children:[e("button",{className:n.detailsToggleBtn,onClick:()=>{v(!o)},children:[o?e(s,{name:"chevron-up"}):e(s,{name:"chevron-down"}),o?"Hide Details":"Show Details"]}),o&&e("div",{className:n.expandedContent,children:e(A,{showMeta:t,styles:n})})]}),m&&e(x,{isOpen:!0,title:"Content Warning",onClose:()=>i("/"),children:e("div",{style:{padding:"1rem",textAlign:"center"},children:[e("p",{children:"This title contains mature content intended for adult audiences."}),e("p",{children:["By proceeding, you confirm that you are ",e("strong",{children:"18 years of age or older"})," (or the age of majority in your jurisdiction) and wish to view this content."]}),e("div",{style:{marginTop:"1rem",display:"flex",gap:"10px",justifyContent:"center"},children:[e(u,{variant:"secondary",onClick:()=>i("/"),children:"Go Back"}),e(u,{onClick:f,children:"I'm 18+, Continue"})]})]})})]})}export{Oe as default};
|