@serifpersia/dango 3.5.0 → 3.5.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 +1 -15
- package/client/dist/assets/{AnimeCard-CpMObnqU.js → AnimeCard-B2ErWl4t.js} +1 -1
- package/client/dist/assets/{AnimeInfo-DkDW8o1k.js → AnimeInfo-Dfd4zWTx.js} +1 -1
- package/client/dist/assets/AnimeInfoPage-_DAHOnnx.js +2 -0
- package/client/dist/assets/{Asmr-B08Aimrk.js → Asmr-CppKRwf3.js} +2 -2
- package/client/dist/assets/{AsmrResetProgressModal-CZMbyJZz.js → AsmrResetProgressModal-DqZ8um_v.js} +1 -1
- package/client/dist/assets/{AvSyncCalibrator-VoOEtoX9.js → AvSyncCalibrator-DH6KEsbi.js} +1 -1
- package/client/dist/assets/{Home-C3Vck_99.js → Home-bqn1BmP7.js} +1 -1
- package/client/dist/assets/Insights-KlshyXuf.js +1 -0
- package/client/dist/assets/{LibraryListPage-CUzEUs5k.js → LibraryListPage-Ba7501DJ.js} +1 -1
- package/client/dist/assets/{ListeningList-CoeQ17lz.js → ListeningList-CycltWkq.js} +1 -1
- package/client/dist/assets/Manga-C3foLd_W.js +1 -0
- package/client/dist/assets/{MangaInfoPage-wqYZN_sT.js → MangaInfoPage-CKgBcwjP.js} +1 -1
- package/client/dist/assets/{MangaReadPage-BbyExwBN.js → MangaReadPage-B0Nr5zbg.js} +1 -1
- package/client/dist/assets/{MangaResetProgressModal-Dg0xhJQI.js → MangaResetProgressModal-C9YlH9oi.js} +1 -1
- package/client/dist/assets/{Mature-ZKR5vMIv.js → Mature-DVvlLfAy.js} +1 -1
- package/client/dist/assets/{MediaCard-9NGAjN3E.js → MediaCard-Auk42bqx.js} +1 -1
- package/client/dist/assets/Music-BeCMeHS7.js +1 -0
- package/client/dist/assets/{OptionListMenu-DcHg1QsF.js → OptionListMenu-AHGTsUIM.js} +1 -1
- package/client/dist/assets/{Player-V9IueAzT.js → Player-Diz4QXSs.js} +6 -6
- package/client/dist/assets/{PlayerSettings-BZtjBWWq.js → PlayerSettings-B8CsR3hI.js} +1 -1
- package/client/dist/assets/QueueOptionsButton-tpZ79_8s.js +1 -0
- package/client/dist/assets/{QueueRail-CO2ocUNx.js → QueueRail-CvrVAD_w.js} +1 -1
- package/client/dist/assets/{Radio-CJ-ra4vb.js → Radio-s_2zeYYn.js} +1 -1
- package/client/dist/assets/{ReadingList-CSvUUtZ3.js → ReadingList-DLKfiYLy.js} +1 -1
- package/client/dist/assets/{ResetProgressModal-5FOWMuqi.js → ResetProgressModal-jPtyfyf0.js} +1 -1
- package/client/dist/assets/{Search-q0GUdNMS.js → Search-UfzxfJ8k.js} +1 -1
- package/client/dist/assets/Settings-CLP_y7EE.js +21 -0
- package/client/dist/assets/{Settings-AuFxQcJF.css → Settings-CwIWLSfY.css} +1 -1
- package/client/dist/assets/{SkeletonGrid-DY_7CXpX.js → SkeletonGrid-21to5FX0.js} +1 -1
- package/client/dist/assets/ToggleSwitch-BPil0d_k.css +1 -0
- package/client/dist/assets/ToggleSwitch-CN_ppEc9.js +1 -0
- package/client/dist/assets/{Trackers-Dn7P6AfI.js → Trackers-QqnmwIKk.js} +1 -1
- package/client/dist/assets/{Tv-BfaWoR72.js → Tv-D3yVtdDx.js} +4 -4
- package/client/dist/assets/{TvInfo-CgEVN57T.js → TvInfo-gue0nYi0.js} +1 -1
- package/client/dist/assets/{TvPopup-B-vYyDQF.js → TvPopup-CkXBuHHD.js} +1 -1
- package/client/dist/assets/{TvSearch-CnnVkms6.js → TvSearch-DLP_3Nf2.js} +1 -1
- package/client/dist/assets/{TvWatchlist-BLVF_row.js → TvWatchlist-DzgVXuh9.js} +1 -1
- package/client/dist/assets/{Watchlist-wd9cCDOK.js → Watchlist-DeO4iNhW.js} +1 -1
- package/client/dist/assets/{hls-Bej65gvf.js → hls-D3SWhYIU.js} +1 -1
- package/client/dist/assets/index-BGCpLf49.js +178 -0
- package/client/dist/assets/index-w_r2lTCe.css +1 -0
- package/client/dist/assets/{useAnimeInfoData-ZmMruFBq.js → useAnimeInfoData-CWRGC9fX.js} +1 -1
- package/client/dist/assets/{useAsmr-z-txLq1s.js → useAsmr-5n3wPm5z.js} +1 -1
- package/client/dist/assets/{useAsmrPopup-DU55UhPN.js → useAsmrPopup-BxGzhLmJ.js} +1 -1
- package/client/dist/assets/{useMangaLibrary-D92WQbf5.js → useMangaLibrary-DUteTFgU.js} +1 -1
- package/client/dist/assets/{useMangaPopup-TJOA229J.js → useMangaPopup-BWU1Tz5e.js} +1 -1
- package/client/dist/assets/{useProviders-fmZrOyDC.js → useProviders-mkl-w-e4.js} +1 -1
- package/client/dist/assets/{useTv-CmfxzpS-.js → useTv-Dl-E6HBp.js} +1 -1
- package/client/dist/assets/{useTvLibrary-0y9NZnsk.js → useTvLibrary-BVECcmlW.js} +1 -1
- package/client/dist/index.html +2 -2
- package/package.json +2 -2
- package/server/dist/app-hono.js +0 -6
- package/server/dist/config.js +0 -1
- package/server/dist/lib/{discord-roles-sync.service.js → recommendations.service.js} +0 -149
- package/server/dist/server.js +0 -2
- package/server/dist/shipped-defaults.js +0 -1
- package/server/dist/trpc/routers/discord.js +0 -4
- package/server/dist/trpc/routers/insights.js +1 -31
- package/server/dist/trpc/routers/settings.js +0 -10
- package/server/package.json +1 -1
- package/client/dist/assets/AnimeInfoPage-l0wIHS7j.js +0 -2
- package/client/dist/assets/Insights-nW34Wbg1.js +0 -1
- package/client/dist/assets/Manga-CeSb5K2w.js +0 -1
- package/client/dist/assets/Map-BtXwpBOC.js +0 -1
- package/client/dist/assets/Map-CXFqXmsZ.css +0 -1
- package/client/dist/assets/Music-CljVJFCj.js +0 -1
- package/client/dist/assets/QueueOptionsButton-CzzisJ3N.js +0 -1
- package/client/dist/assets/Settings-CyT9Lyhz.js +0 -21
- package/client/dist/assets/index-Cc1Up_NI.css +0 -1
- package/client/dist/assets/index-Dk0ASzEz.js +0 -178
- package/server/dist/utils/machine-id.js +0 -39
|
@@ -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-BGCpLf49.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-DUteTFgU.js";import{d as I}from"./index-BGCpLf49.js";import{p as s,a as k}from"./MediaCard-Auk42bqx.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{
|
|
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-BGCpLf49.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-Auk42bqx.js";import{T as g}from"./TvPopup-CkXBuHHD.js";import{c as m,i as f}from"./useTvLibrary-BVECcmlW.js";import{b as i}from"./vendor-query-BBT5_sHx.js";import{h as p}from"./index-BGCpLf49.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-BGCpLf49.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-BGCpLf49.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-w_r2lTCe.css">
|
|
41
41
|
</head>
|
|
42
42
|
|
|
43
43
|
<body>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@serifpersia/dango",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.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-08T01:33:46.617Z"
|
|
87
87
|
}
|
package/server/dist/app-hono.js
CHANGED
|
@@ -45,14 +45,8 @@ function mapMalMangaXmlStatus(status) {
|
|
|
45
45
|
return 'Planned';
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
|
-
const gatewayLog = logger.child({ module: 'DiscordGatewayRoutes' });
|
|
49
48
|
const TRACKER_TOKEN_KEY = 'tracker_anilist_token';
|
|
50
49
|
const TRACKER_USER_KEY = 'tracker_anilist_user';
|
|
51
|
-
function maskToken(t) {
|
|
52
|
-
if (!t)
|
|
53
|
-
return 'none';
|
|
54
|
-
return t.slice(0, 8) + '...' + t.slice(-4);
|
|
55
|
-
}
|
|
56
50
|
export function getHonoClientIp(c) {
|
|
57
51
|
try {
|
|
58
52
|
return getConnInfo(c).remote.address;
|
package/server/dist/config.js
CHANGED
|
@@ -166,7 +166,6 @@ export const CONFIG = {
|
|
|
166
166
|
RCLONE_REMOTE: process.env.RCLONE_REMOTE,
|
|
167
167
|
SYNC_PROVIDER: process.env.SYNC_PROVIDER,
|
|
168
168
|
DISCORD_CLIENT_ID: process.env.DISCORD_CLIENT_ID || SHIPPED_DEFAULTS.DISCORD_CLIENT_ID || undefined,
|
|
169
|
-
DISCORD_ROLES_WORKER_URL: process.env.DISCORD_ROLES_WORKER_URL || SHIPPED_DEFAULTS.DISCORD_ROLES_WORKER_URL || '',
|
|
170
169
|
APP_PASSWORD_HASH: process.env.APP_PASSWORD_HASH || '',
|
|
171
170
|
PROVIDER_REPO_URL: process.env.PROVIDER_REPO_URL || SHIPPED_DEFAULTS.PROVIDER_REPO_URL || '',
|
|
172
171
|
PROVIDER_ENABLED: process.env.PROVIDER_ENABLED || '',
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import logger from '../logger.js';
|
|
2
|
-
import { CONFIG } from '../config.js';
|
|
3
|
-
import { SettingsRepository } from '../repositories/settings.repository.js';
|
|
4
2
|
import { InsightsRepository } from '../repositories/insights.repository.js';
|
|
5
|
-
import { parseJsonBody } from '../utils/http.utils.js';
|
|
6
3
|
import { anilistRequest } from '../lib/anilist.js';
|
|
7
4
|
function parseGenres(raw) {
|
|
8
5
|
if (!raw)
|
|
@@ -196,11 +193,6 @@ export async function computeRecCandidates(taste) {
|
|
|
196
193
|
};
|
|
197
194
|
});
|
|
198
195
|
}
|
|
199
|
-
const SETTING_KEY = 'discordLinkedUser';
|
|
200
|
-
const SYNC_INTERVAL_MS = 10 * 60 * 1000;
|
|
201
|
-
let syncTimer = null;
|
|
202
|
-
let lastSyncedSeconds = null;
|
|
203
|
-
let lastSyncedTasteHash = null;
|
|
204
196
|
let recCache = null;
|
|
205
197
|
function tasteHashOf(taste) {
|
|
206
198
|
return JSON.stringify([taste.genreComp, taste.genreDrop, taste.knownIds.length]);
|
|
@@ -222,144 +214,3 @@ export async function getCachedRecommendations(db) {
|
|
|
222
214
|
const taste = await computeTasteProfile(db);
|
|
223
215
|
return refreshCandidatesIfNeeded(taste, tasteHashOf(taste));
|
|
224
216
|
}
|
|
225
|
-
export async function getLinkedDiscordUser(db) {
|
|
226
|
-
const row = await SettingsRepository.getByKey(db, SETTING_KEY);
|
|
227
|
-
if (!row?.value)
|
|
228
|
-
return null;
|
|
229
|
-
try {
|
|
230
|
-
return JSON.parse(row.value);
|
|
231
|
-
}
|
|
232
|
-
catch {
|
|
233
|
-
return null;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
export async function setLinkedDiscordUser(db, user) {
|
|
237
|
-
if (!user) {
|
|
238
|
-
await SettingsRepository.deleteByKey(db, SETTING_KEY);
|
|
239
|
-
lastSyncedSeconds = null;
|
|
240
|
-
lastSyncedTasteHash = null;
|
|
241
|
-
recCache = null;
|
|
242
|
-
}
|
|
243
|
-
else {
|
|
244
|
-
await SettingsRepository.upsert(db, SETTING_KEY, JSON.stringify(user));
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
export async function computeDiscordSyncStats(db) {
|
|
248
|
-
const [core, watchedShows] = (await Promise.all([
|
|
249
|
-
InsightsRepository.getCoreStats(db),
|
|
250
|
-
InsightsRepository.getWatchedShowsMeta(db),
|
|
251
|
-
]));
|
|
252
|
-
const genreCounts = {};
|
|
253
|
-
for (const show of watchedShows) {
|
|
254
|
-
if (!show.genres)
|
|
255
|
-
continue;
|
|
256
|
-
let genres = [];
|
|
257
|
-
try {
|
|
258
|
-
genres = show.genres.startsWith('[')
|
|
259
|
-
? JSON.parse(show.genres)
|
|
260
|
-
: show.genres.split(',').map((g) => g.trim());
|
|
261
|
-
}
|
|
262
|
-
catch {
|
|
263
|
-
// ignore
|
|
264
|
-
}
|
|
265
|
-
for (const g of genres) {
|
|
266
|
-
genreCounts[g] = (genreCounts[g] || 0) + 1;
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
const topGenre = Object.entries(genreCounts).sort((a, b) => b[1] - a[1])[0]?.[0] || '';
|
|
270
|
-
const genres = Object.entries(genreCounts)
|
|
271
|
-
.sort((a, b) => b[1] - a[1])
|
|
272
|
-
.slice(0, 3)
|
|
273
|
-
.map(([name]) => name);
|
|
274
|
-
const completedCount = core?.completedCount || 0;
|
|
275
|
-
const totalWatchlist = core?.totalWatchlist || 0;
|
|
276
|
-
return {
|
|
277
|
-
totalSeconds: core?.totalSeconds || 0,
|
|
278
|
-
topGenre,
|
|
279
|
-
genres,
|
|
280
|
-
totalEpisodes: core?.totalEpisodes || 0,
|
|
281
|
-
totalAnime: core?.totalAnime || 0,
|
|
282
|
-
completedCount,
|
|
283
|
-
completionRate: totalWatchlist > 0 ? Math.round((completedCount / totalWatchlist) * 100) : 0,
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
|
-
export async function syncDiscordRoles(db, force = false) {
|
|
287
|
-
const workerUrl = CONFIG.DISCORD_ROLES_WORKER_URL;
|
|
288
|
-
if (!workerUrl) {
|
|
289
|
-
return { success: false, message: 'DISCORD_ROLES_WORKER_URL not configured' };
|
|
290
|
-
}
|
|
291
|
-
const user = await getLinkedDiscordUser(db);
|
|
292
|
-
if (!user) {
|
|
293
|
-
return { success: false, message: 'No Discord user linked in database' };
|
|
294
|
-
}
|
|
295
|
-
const { totalSeconds, topGenre, genres, totalEpisodes, totalAnime, completedCount, completionRate, } = await computeDiscordSyncStats(db);
|
|
296
|
-
const taste = await computeTasteProfile(db);
|
|
297
|
-
const tasteHash = tasteHashOf(taste);
|
|
298
|
-
if (!force &&
|
|
299
|
-
lastSyncedSeconds !== null &&
|
|
300
|
-
totalSeconds === lastSyncedSeconds &&
|
|
301
|
-
lastSyncedTasteHash === tasteHash) {
|
|
302
|
-
return { success: true, message: 'Watch time unchanged, skipped sync', skipped: true };
|
|
303
|
-
}
|
|
304
|
-
taste.candidates = await refreshCandidatesIfNeeded(taste, tasteHash);
|
|
305
|
-
try {
|
|
306
|
-
const res = await fetch(`${workerUrl}/api/sync`, {
|
|
307
|
-
method: 'POST',
|
|
308
|
-
headers: { 'Content-Type': 'application/json' },
|
|
309
|
-
body: JSON.stringify({
|
|
310
|
-
discordId: user.id,
|
|
311
|
-
username: user.username,
|
|
312
|
-
totalSeconds,
|
|
313
|
-
topGenre,
|
|
314
|
-
genres,
|
|
315
|
-
totalEpisodes,
|
|
316
|
-
totalAnime,
|
|
317
|
-
completedCount,
|
|
318
|
-
completionRate,
|
|
319
|
-
taste,
|
|
320
|
-
force,
|
|
321
|
-
}),
|
|
322
|
-
});
|
|
323
|
-
const data = (await parseJsonBody(res).catch(() => ({})));
|
|
324
|
-
if (!res.ok || data.error) {
|
|
325
|
-
logger.warn({ error: data.error || res.statusText, code: data.code, failures: data.failures }, 'Discord role sync returned error');
|
|
326
|
-
return {
|
|
327
|
-
success: false,
|
|
328
|
-
message: data.error || 'Worker sync failed',
|
|
329
|
-
code: data.code,
|
|
330
|
-
failures: data.failures,
|
|
331
|
-
};
|
|
332
|
-
}
|
|
333
|
-
lastSyncedSeconds = totalSeconds;
|
|
334
|
-
lastSyncedTasteHash = tasteHash;
|
|
335
|
-
logger.info({
|
|
336
|
-
user: user.username,
|
|
337
|
-
rank: data.rank,
|
|
338
|
-
dere: data.dere,
|
|
339
|
-
totalHours: Math.round(totalSeconds / 3600),
|
|
340
|
-
}, 'Discord roles synced successfully');
|
|
341
|
-
return { success: true, message: data.message || 'Roles synced', dere: data.dere };
|
|
342
|
-
}
|
|
343
|
-
catch (err) {
|
|
344
|
-
logger.warn({ err: err?.message }, 'Failed to communicate with Discord roles worker');
|
|
345
|
-
return { success: false, message: err?.message || 'Network error' };
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
export function initDiscordRolesSync(db) {
|
|
349
|
-
const workerUrl = CONFIG.DISCORD_ROLES_WORKER_URL;
|
|
350
|
-
if (!workerUrl)
|
|
351
|
-
return;
|
|
352
|
-
setTimeout(() => {
|
|
353
|
-
syncDiscordRoles(db).catch((err) => {
|
|
354
|
-
logger.warn({ err: err?.message }, 'Startup Discord roles sync failed');
|
|
355
|
-
});
|
|
356
|
-
}, 5000).unref();
|
|
357
|
-
if (syncTimer)
|
|
358
|
-
clearInterval(syncTimer);
|
|
359
|
-
syncTimer = setInterval(() => {
|
|
360
|
-
syncDiscordRoles(db).catch((err) => {
|
|
361
|
-
logger.warn({ err: err?.message }, 'Periodic Discord roles sync failed');
|
|
362
|
-
});
|
|
363
|
-
}, SYNC_INTERVAL_MS);
|
|
364
|
-
syncTimer.unref();
|
|
365
|
-
}
|
package/server/dist/server.js
CHANGED
|
@@ -21,7 +21,6 @@ import { createHonoApp } from './app-hono.js';
|
|
|
21
21
|
import { startWatchlistDiscovery, stopWatchlistDiscovery } from './hono/watchlist.js';
|
|
22
22
|
import { checkAnilistStatus } from './lib/anilist.js';
|
|
23
23
|
import { offlineDb } from './lib/offline-db.js';
|
|
24
|
-
import { initDiscordRolesSync } from './lib/discord-roles-sync.service.js';
|
|
25
24
|
const app = createHonoApp(() => ({ shuttingDown: isShuttingDown, dbReady: !!db }), () => ({
|
|
26
25
|
shuttingDown: isShuttingDown,
|
|
27
26
|
dbsReady: !!db && !!mangaDb && !!tvDb && !!asmrDb,
|
|
@@ -156,7 +155,6 @@ async function main() {
|
|
|
156
155
|
await discordRPCService.setEnabled(isRpcEnabled);
|
|
157
156
|
discordGatewayService.setEnabled(isRpcEnabled);
|
|
158
157
|
checkAnilistStatus().catch(() => { });
|
|
159
|
-
initDiscordRolesSync(db);
|
|
160
158
|
if (CONFIG.PROVIDER_REPO_URL.trim()) {
|
|
161
159
|
setInterval(() => {
|
|
162
160
|
refreshRemoteProviders().catch((err) => logger.error({ err }, 'periodic providers refresh failed'));
|
|
@@ -2,6 +2,5 @@ export const SHIPPED_DEFAULTS = {
|
|
|
2
2
|
"GITHUB_CLIENT_ID": "Ov23liT1ZtPk7XtN9PZk",
|
|
3
3
|
"GOOGLE_AUTH_WORKER_URL": "https://google-auth-client.ramiserifpersia.workers.dev",
|
|
4
4
|
"DISCORD_CLIENT_ID": "1512253778022367426",
|
|
5
|
-
"DISCORD_ROLES_WORKER_URL": "https://dango-discord-roles.ramiserifpersia.workers.dev",
|
|
6
5
|
"PROVIDER_REPO_URL": "https://raw.githubusercontent.com/serifpersia/dango-providers/main/registry.json"
|
|
7
6
|
};
|
|
@@ -4,7 +4,6 @@ import { discordRPCService } from '../../discord-rpc.js';
|
|
|
4
4
|
import { discordGatewayService } from '../../discord-gateway.js';
|
|
5
5
|
import { getDlsitePoster, getMangadexCover } from '../../hono/watchlist.js';
|
|
6
6
|
import { updateEnvFile } from '../../utils/env.utils.js';
|
|
7
|
-
import { CONFIG } from '../../config.js';
|
|
8
7
|
import logger from '../../logger.js';
|
|
9
8
|
function maskToken(t) {
|
|
10
9
|
if (!t)
|
|
@@ -283,7 +282,4 @@ export const discordRouter = router({
|
|
|
283
282
|
throw failed('Failed to remove token');
|
|
284
283
|
}
|
|
285
284
|
}),
|
|
286
|
-
rolesConfig: protectedProcedure.query(() => {
|
|
287
|
-
return { workerUrl: CONFIG.DISCORD_ROLES_WORKER_URL || null };
|
|
288
|
-
}),
|
|
289
285
|
});
|
|
@@ -1,22 +1,6 @@
|
|
|
1
1
|
import { protectedProcedure, router } from '../index.js';
|
|
2
2
|
import { getWatchInsights, getGenreCards } from '../../lib/insights.js';
|
|
3
|
-
import {
|
|
4
|
-
import { defineSchema, optStr, reqObj, reqStr } from '../validation.js';
|
|
5
|
-
const discordUserInput = () => defineSchema((value) => {
|
|
6
|
-
if (value === undefined || value === null)
|
|
7
|
-
return {};
|
|
8
|
-
const raw = reqObj(value).user;
|
|
9
|
-
if (raw === undefined || raw === null)
|
|
10
|
-
return { user: null };
|
|
11
|
-
const obj = reqObj(raw);
|
|
12
|
-
return {
|
|
13
|
-
user: {
|
|
14
|
-
id: reqStr(obj, 'id'),
|
|
15
|
-
username: optStr(obj, 'username') ?? '',
|
|
16
|
-
avatar: optStr(obj, 'avatar') ?? null,
|
|
17
|
-
},
|
|
18
|
-
};
|
|
19
|
-
});
|
|
3
|
+
import { getCachedRecommendations } from '../../lib/recommendations.service.js';
|
|
20
4
|
export const insightsRouter = router({
|
|
21
5
|
summary: protectedProcedure.query(async ({ ctx }) => {
|
|
22
6
|
return getWatchInsights(ctx.db);
|
|
@@ -27,18 +11,4 @@ export const insightsRouter = router({
|
|
|
27
11
|
recommendations: protectedProcedure.query(async ({ ctx }) => {
|
|
28
12
|
return { candidates: await getCachedRecommendations(ctx.db) };
|
|
29
13
|
}),
|
|
30
|
-
discordSyncStats: protectedProcedure.query(async ({ ctx }) => {
|
|
31
|
-
return computeDiscordSyncStats(ctx.db);
|
|
32
|
-
}),
|
|
33
|
-
discordUser: protectedProcedure.query(async ({ ctx }) => {
|
|
34
|
-
return { user: await getLinkedDiscordUser(ctx.db) };
|
|
35
|
-
}),
|
|
36
|
-
setDiscordUser: protectedProcedure.input(discordUserInput()).mutation(async ({ ctx, input }) => {
|
|
37
|
-
const user = input.user ?? null;
|
|
38
|
-
await setLinkedDiscordUser(ctx.db, user);
|
|
39
|
-
return { success: true, user };
|
|
40
|
-
}),
|
|
41
|
-
discordSyncNow: protectedProcedure.mutation(async ({ ctx }) => {
|
|
42
|
-
return syncDiscordRoles(ctx.db, true);
|
|
43
|
-
}),
|
|
44
14
|
});
|
|
@@ -6,7 +6,6 @@ import { discordRPCService } from '../../discord-rpc.js';
|
|
|
6
6
|
import logger from '../../logger.js';
|
|
7
7
|
import { offlineDb } from '../../lib/offline-db.js';
|
|
8
8
|
import { translateTexts } from '../../lib/translate.js';
|
|
9
|
-
import { getMachineId } from '../../utils/machine-id.js';
|
|
10
9
|
import { getMalImportStatus, requestMalImportCancel } from '../../lib/mal-import.js';
|
|
11
10
|
import { defineSchema, reqObj } from '../validation.js';
|
|
12
11
|
import { keyInput, setSettingInput } from '../validation.js';
|
|
@@ -76,15 +75,6 @@ export const settingsRouter = router({
|
|
|
76
75
|
});
|
|
77
76
|
return { message: 'Offline database refresh started' };
|
|
78
77
|
}),
|
|
79
|
-
installationId: protectedProcedure.query(() => {
|
|
80
|
-
try {
|
|
81
|
-
return { id: getMachineId() };
|
|
82
|
-
}
|
|
83
|
-
catch (err) {
|
|
84
|
-
logger.error({ err }, 'Failed to get machine ID');
|
|
85
|
-
throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Failed to get machine ID' });
|
|
86
|
-
}
|
|
87
|
-
}),
|
|
88
78
|
translate: protectedProcedure.input(translateInput()).mutation(async ({ input }) => {
|
|
89
79
|
const texts = input.texts;
|
|
90
80
|
const source = input.source ?? 'ja';
|
package/server/package.json
CHANGED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/AnimeInfo-DkDW8o1k.js","assets/vendor-core-DfaOB3Rn.js","assets/vendor-icons-DrybRNxP.js","assets/useAnimeInfoData-ZmMruFBq.js","assets/vendor-query-BBT5_sHx.js","assets/index-Dk0ASzEz.js","assets/index-Cc1Up_NI.css","assets/QueueOptionsButton-CzzisJ3N.js","assets/vendor-ui-3qrARCPr.js","assets/QueueOptionsButton-CM15uQn8.css","assets/AnimeMetaDetails-BogOi_bM.js","assets/AnimeMetaDetails-BwNQnRCd.css","assets/SynopsisText-B3Sa5pRv.js","assets/useIsMobile-Dvx1uJ82.js","assets/SynopsisText-CYv2W3yR.css","assets/AnimeInfo-BFWtHlPC.css"])))=>i.map(i=>d[i]);
|
|
2
|
-
import{a2 as r,_ as t}from"./index-Dk0ASzEz.js";import{u as o,P as e,z as i}from"./vendor-core-DfaOB3Rn.js";import"./vendor-query-BBT5_sHx.js";import"./vendor-icons-DrybRNxP.js";const a=i(()=>t(()=>import("./AnimeInfo-DkDW8o1k.js"),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15])));function p(){return o(e,{fallback:o(r,{}),children:o(a,{})})}export{p as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{h as R,T as i,d as W,u as e,L as P}from"./vendor-core-DfaOB3Rn.js";import{b as C,u as O,a as A}from"./vendor-query-BBT5_sHx.js";import{t as p,a1 as F,d as V,z as S,f as k}from"./index-Dk0ASzEz.js";import{I as l}from"./vendor-icons-DrybRNxP.js";const Y="_header_1j07c_1",q="_fadeIn_1j07c_1",H="_personaBadge_1j07c_9",z="_personaInfo_1j07c_37",E="_personaLabel_1j07c_42",U="_personaValue_1j07c_51",K="_statsGrid_1j07c_57",Q="_slideUpIn_1j07c_1",J="_statCard_1j07c_65",X="_statIcon_1j07c_82",Z="_statInfo_1j07c_98",ee="_statValue_1j07c_103",ae="_statLabel_1j07c_112",te="_wideSection_1j07c_120",se="_sectionHeader_1j07c_132",ne="_yearSelect_1j07c_147",re="_heatmapLayout_1j07c_176",ce="_dayLabels_1j07c_183",le="_heatmapWrapper_1j07c_195",oe="_heatmapMonthLabels_1j07c_201",ie="_heatmapGrid_1j07c_212",de="_heatBox_1j07c_220",he="_hiddenBox_1j07c_229",me="_level0_1j07c_240",pe="_level1_1j07c_243",_e="_level2_1j07c_247",ue="_level3_1j07c_251",ge="_level4_1j07c_255",Ne="_heatmapFooter_1j07c_260",ve="_heatLegend_1j07c_267",ye="_chartsContainer_1j07c_277",be="_chartWrapper_1j07c_285",je="_hourlyChart_1j07c_312",fe="_hourlyBarContainer_1j07c_320",Ce="_hourlyBar_1j07c_320",Se="_hourlyLabel_1j07c_346",ke="_chartSubtext_1j07c_353",Le="_popScale_1j07c_365",Be="_popTrack_1j07c_369",we="_popThumb_1j07c_377",Ie="_popLabels_1j07c_389",De="_popDescription_1j07c_399",xe="_seasonalChart_1j07c_414",Te="_seasonalBarContainer_1j07c_422",Me="_seasonalBar_1j07c_422",$e="_seasonalLabel_1j07c_444",Ge="_genreList_1j07c_452",Re="_genreRow_1j07c_459",We="_genreInfo_1j07c_465",Pe="_genreName_1j07c_472",Oe="_genreCount_1j07c_479",Ae="_genreBarBg_1j07c_486",Fe="_genreBar_1j07c_486",Ve="_warningSection_1j07c_499",Ye="_warningHeader_1j07c_510",qe="_droppedGrid_1j07c_526",He="_droppedCard_1j07c_532",ze="_droppedName_1j07c_549",Ee="_droppedDate_1j07c_556",Ue="_genreGrid_1j07c_597",Ke="_genreCard_1j07c_609",Qe="_rankBadge_1j07c_618",Je="_rankNumber_1j07c_631",Xe="_genreTitle_1j07c_637",Ze="_genreStats_1j07c_645",ea="_posterRow_1j07c_653",aa="_miniPoster_1j07c_660",ta="_genreCardSkeleton_1j07c_674",sa="_pulse_1j07c_1",na="_skeletonRank_1j07c_682",ra="_skeletonTitle_1j07c_696",ca="_skeletonStats_1j07c_709",la="_skeletonPosters_1j07c_721",oa="_recSection_1j07c_752",ia="_recSubtext_1j07c_763",da="_recGrid_1j07c_769",ha="_recCard_1j07c_775",ma="_recCover_1j07c_790",pa="_recInfo_1j07c_798",_a="_recTitle_1j07c_805",ua="_recMatch_1j07c_816",ga="_recMeta_1j07c_822",Na="_recWhy_1j07c_827",va="_recNote_1j07c_832",ya="_recAddBtn_1j07c_838",a={header:Y,fadeIn:q,personaBadge:H,personaInfo:z,personaLabel:E,personaValue:U,statsGrid:K,slideUpIn:Q,statCard:J,statIcon:X,statInfo:Z,statValue:ee,statLabel:ae,wideSection:te,sectionHeader:se,yearSelect:ne,heatmapLayout:re,dayLabels:ce,heatmapWrapper:le,heatmapMonthLabels:oe,heatmapGrid:ie,heatBox:de,hiddenBox:he,level0:me,level1:pe,level2:_e,level3:ue,level4:ge,heatmapFooter:Ne,heatLegend:ve,chartsContainer:ye,chartWrapper:be,hourlyChart:je,hourlyBarContainer:fe,hourlyBar:Ce,hourlyLabel:Se,chartSubtext:ke,popScale:Le,popTrack:Be,popThumb:we,popLabels:Ie,popDescription:De,seasonalChart:xe,seasonalBarContainer:Te,seasonalBar:Me,seasonalLabel:$e,genreList:Ge,genreRow:Re,genreInfo:We,genreName:Pe,genreCount:Oe,genreBarBg:Ae,genreBar:Fe,warningSection:Ve,warningHeader:Ye,droppedGrid:qe,droppedCard:He,droppedName:ze,droppedDate:Ee,genreGrid:Ue,genreCard:Ke,rankBadge:Qe,rankNumber:Je,genreTitle:Xe,genreStats:Ze,posterRow:ea,miniPoster:aa,genreCardSkeleton:ta,pulse:sa,skeletonRank:na,skeletonTitle:ra,skeletonStats:ca,skeletonPosters:la,recSection:oa,recSubtext:ia,recGrid:da,recCard:ha,recCover:ma,recInfo:pa,recTitle:_a,recMatch:ua,recMeta:ga,recWhy:Na,recNote:va,recAddBtn:ya},Sa=()=>{R(()=>{document.title="Insights - dango"},[]);const{data:n,isLoading:L,isError:B}=C({queryKey:["insights"],queryFn:async()=>await p.insights.summary.query()}),{data:w,isLoading:_}=F(),{titlePreference:I}=V(),u=O(),{data:g}=C({queryKey:["insights-recommendations"],queryFn:async()=>await p.insights.recommendations.query(),staleTime:300*1e3,retry:1}),N=A({mutationFn:async t=>{await p.watchlist.add.mutate({id:String(t.id),name:t.title,thumbnail:t.cover||"",status:"Plan to Watch",type:t.format})},onSuccess:()=>{u.invalidateQueries({queryKey:["watchlist"]}),u.invalidateQueries({queryKey:["insights-recommendations"]}),S.success("Added to Plan to Watch")},onError:()=>S.error("Could not add to watchlist")}),v=i(()=>[...g?.candidates||[]].sort((t,s)=>s.matchPct-t.matchPct).slice(0,6),[g]),y=t=>{const s=t.name||t.englishName||t.nativeName||"";switch(I){case"nativeName":return t.nativeName||s;case"englishName":return t.englishName||s;default:return s}},[d,D]=W(new Date().getFullYear()),x=i(()=>{if(!n?.activityGrid)return[new Date().getFullYear()];const t=new Set(n.activityGrid.map(s=>parseInt(s.day.split("-")[0])));return t.add(new Date().getFullYear()),Array.from(t).sort((s,r)=>r-s)},[n]),b=i(()=>{if(!n?.activityGrid)return[];const t=new Map(n.activityGrid.map(m=>[m.day,m.count])),s=[],r=new Date(d,0,1),o=new Date(d,11,31),h=r.getDay(),c=new Date(r);for(c.setDate(c.getDate()-h);(c<=o||c.getDay()!==0)&&!(c>o&&c.getDay()===0);){const m=c.getFullYear(),$=String(c.getMonth()+1).padStart(2,"0"),G=String(c.getDate()).padStart(2,"0"),j=`${m}-${$}-${G}`,f=c<r||c>o;s.push({date:j,count:f?0:t.get(j)||0,month:c.getMonth(),isOutOfRange:f}),c.setDate(c.getDate()+1)}return s},[n,d]),T=i(()=>n?.seasonality?.length?Math.max(...n.seasonality.map(t=>t.seconds),1):0,[n]),M=i(()=>n?.hourlyDist?.length?Math.max(...n.hourlyDist.map(t=>t.count),1):0,[n]);return L||_?e("div",{className:a.loading,children:"Analyzing your anime lifestyle..."}):B?e("div",{className:a.error,children:"Could not load insights. Data might be syncing."}):n?e("div",{className:"page-container",children:[e("div",{className:a.header,children:[e("h2",{className:"section-title",children:"Watch Insights"}),e("div",{className:a.personaBadge,children:[e(l,{name:"user-astronaut"}),e("div",{className:a.personaInfo,children:[e("span",{className:a.personaLabel,children:"Your Persona"}),e("span",{className:a.personaValue,children:n.persona})]})]})]}),e("div",{className:a.statsGrid,children:[e("div",{className:a.statCard,children:[e("div",{className:a.statIcon,style:{background:"rgba(138, 79, 255, 0.2)",color:"var(--accent)"},children:e(l,{name:"clock"})}),e("div",{className:a.statInfo,children:[e("span",{className:a.statValue,children:[n.totalHours,"h"]}),e("span",{className:a.statLabel,children:"Watch Time"})]})]}),e("div",{className:a.statCard,children:[e("div",{className:a.statIcon,style:{background:"rgba(167, 139, 250, 0.2)",color:"#a78bfa"},children:e(l,{name:"bookmark"})}),e("div",{className:a.statInfo,children:[e("span",{className:a.statValue,children:n.totalAnime}),e("span",{className:a.statLabel,children:"Total Anime"})]})]}),e("div",{className:a.statCard,children:[e("div",{className:a.statIcon,style:{background:"rgba(34, 197, 94, 0.2)",color:"#22c55e"},children:e(l,{name:"check-circle"})}),e("div",{className:a.statInfo,children:[e("span",{className:a.statValue,children:n.totalEpisodes}),e("span",{className:a.statLabel,children:"Episodes Watched"})]})]}),e("div",{className:a.statCard,children:[e("div",{className:a.statIcon,style:{background:"rgba(34, 197, 94, 0.2)",color:"#22c55e"},children:e(l,{name:"check-circle"})}),e("div",{className:a.statInfo,children:[e("span",{className:a.statValue,children:[n.completionRate,"%"]}),e("span",{className:a.statLabel,children:"Completion Rate"})]})]}),e("div",{className:a.statCard,children:[e("div",{className:a.statIcon,style:{background:"rgba(45, 212, 191, 0.2)",color:"#2dd4bf"},children:e(l,{name:"tv"})}),e("div",{className:a.statInfo,children:[e("span",{className:a.statValue,children:n.completedAnime}),e("span",{className:a.statLabel,children:"Completed Shows"})]})]}),e("div",{className:a.statCard,children:[e("div",{className:a.statIcon,style:{background:"rgba(239, 68, 68, 0.2)",color:"#ef4444"},children:e(l,{name:"fire"})}),e("div",{className:a.statInfo,children:[e("span",{className:a.statValue,children:n.bingeFactor}),e("span",{className:a.statLabel,children:"Max Daily Binge"})]})]}),e("div",{className:a.statCard,children:[e("div",{className:a.statIcon,style:{background:"rgba(59, 130, 246, 0.2)",color:"#3b82f6"},children:e(l,{name:"history"})}),e("div",{className:a.statInfo,children:[e("span",{className:a.statValue,children:[n.avgSessionMinutes,"m"]}),e("span",{className:a.statLabel,children:"Avg. Session"})]})]}),e("div",{className:a.statCard,children:[e("div",{className:a.statIcon,style:{background:"rgba(251, 191, 36, 0.2)",color:"#fbbf24"},children:e(l,{name:"layer-group"})}),e("div",{className:a.statInfo,children:[e("span",{className:a.statValue,children:[n.avgCompletionDays,"d"]}),e("span",{className:a.statLabel,children:"Avg. Speed"})]})]})]}),e("div",{className:a.wideSection,children:[e("div",{className:a.sectionHeader,children:[e("h3",{children:"Activity"}),e("select",{className:a.yearSelect,value:d,onChange:t=>D(Number(t.currentTarget.value)),children:x.map(t=>e("option",{value:t,children:t},t))})]}),e("div",{className:a.heatmapLayout,children:[e("div",{className:a.dayLabels,children:[e("span",{style:{gridRow:2},children:"Mon"}),e("span",{style:{gridRow:4},children:"Wed"}),e("span",{style:{gridRow:6},children:"Fri"})]}),e("div",{className:a.heatmapWrapper,children:[e("div",{className:a.heatmapMonthLabels,children:(()=>{const t=[];let s=-1;return b.forEach((r,o)=>{if(r.month!==s&&!r.isOutOfRange){const h=Math.floor(o/7)+1;h>(t.length>0?t[t.length-1].props.style.gridColumn+2:-1)&&(t.push(e("span",{style:{gridColumn:h,whiteSpace:"nowrap"},children:new Date(0,r.month).toLocaleString("default",{month:"short"})},o)),s=r.month)}}),t})()}),e("div",{className:a.heatmapGrid,children:b.map((t,s)=>{let r=0;return t.count>0&&!t.isOutOfRange&&(r=1),t.count>2&&!t.isOutOfRange&&(r=2),t.count>5&&!t.isOutOfRange&&(r=3),t.count>10&&!t.isOutOfRange&&(r=4),e("div",{className:`${a.heatBox} ${a[`level${r}`]} ${t.isOutOfRange?a.hiddenBox:""}`,title:t.isOutOfRange?"":`${t.count} episodes on ${t.date}`},s)})}),e("div",{className:a.heatmapFooter,children:e("div",{className:a.heatLegend,children:[e("span",{children:"Less"}),e("div",{className:`${a.heatBox} ${a.level0}`}),e("div",{className:`${a.heatBox} ${a.level1}`}),e("div",{className:`${a.heatBox} ${a.level2}`}),e("div",{className:`${a.heatBox} ${a.level3}`}),e("div",{className:`${a.heatBox} ${a.level4}`}),e("span",{children:"More"})]})})]})]})]}),e("div",{className:a.chartsContainer,children:[e("div",{className:a.chartWrapper,children:[e("h3",{children:"Time Distribution (24h)"}),e("div",{className:a.hourlyChart,children:n.hourlyDist?.map((t,s)=>e("div",{className:a.hourlyBarContainer,children:[e("div",{className:a.hourlyBar,style:{height:`${t.count/M*100||2}%`,width:"100%",maxWidth:"12px"},title:`${t.count} watches at ${t.hour}:00`}),e("span",{className:a.hourlyLabel,style:{visibility:s%4===0?"visible":"hidden"},children:t.hour})]},s))}),e("div",{className:a.chartSubtext,children:(()=>{if(!n.hourlyDist?.length)return"Watch more to see your peak hours!";const t=parseInt([...n.hourlyDist].sort((s,r)=>r.count-s.count)[0].hour);return t>=6&&t<19?"You prefer daytime watching ☀️":"You're a confirmed Night Owl 🦉"})()})]}),e("div",{className:a.chartWrapper,children:[e("h3",{children:"Popularity Bias"}),e("div",{className:a.popScale,children:[e("div",{className:a.popTrack,children:e("div",{className:a.popThumb,style:{left:`${Math.max(0,Math.min(100,100-n.popularityScore*10))}%`}})}),e("div",{className:a.popLabels,children:[e("span",{children:"Mainstream"}),e("span",{children:"Underground"})]})]}),e("p",{className:a.popDescription,children:["Your taste score is ",e("strong",{children:[n.popularityScore,"/10"]}),".",n.popularityScore>=5?" You follow the big hits!":" You're a connoisseur of the obscure!"]})]}),e("div",{className:a.chartWrapper,children:[e("h3",{children:"Monthly Activity"}),e("div",{className:a.seasonalChart,children:n.seasonality?.map((t,s)=>e("div",{className:a.seasonalBarContainer,children:[e("div",{className:a.seasonalBar,style:{height:`${t.seconds/T*100||5}%`,width:"100%",maxWidth:"24px"},title:`${Math.round(t.seconds/3600)}h in ${new Date(0,s).toLocaleString("default",{month:"long"})}`}),e("span",{className:a.seasonalLabel,children:new Date(0,s).toLocaleString("default",{month:"short"})})]},s))})]})]}),e("div",{className:a.genreGrid,children:_?Array.from({length:4}).map((t,s)=>e("div",{className:a.genreCardSkeleton,children:[e("div",{className:a.skeletonRank}),e("div",{className:a.skeletonTitle}),e("div",{className:a.skeletonStats}),e("div",{className:a.skeletonPosters})]},s)):w?.map(t=>e("div",{className:a.genreCard,children:[e("div",{className:a.rankBadge,children:e("span",{className:a.rankNumber,children:t.rank})}),e("h3",{className:a.genreTitle,children:t.name}),e("div",{className:a.genreStats,children:[e("span",{children:[t.count," episodes"]}),e("span",{children:t.meanScore>0?`${t.meanScore.toFixed(1)} avg score`:"—"}),e("span",{children:t.timeWatched})]}),e("div",{className:a.posterRow,children:t.topShows.map(s=>e("img",{src:k(s.thumbnail),alt:y(s),className:a.miniPoster,title:y(s),loading:"lazy",decoding:"async"},s.id))})]},t.name))}),v.length>0&&e("div",{className:a.recSection,children:[e("h3",{children:"Recommended For You"}),e("p",{className:a.recSubtext,children:"From your library taste — updates automatically as you watch"}),e("div",{className:a.recGrid,children:v.map(t=>e("div",{className:a.recCard,children:[t.cover&&e("img",{src:k(t.cover),alt:t.title,className:a.recCover,loading:"lazy",decoding:"async"}),e("div",{className:a.recInfo,children:[e(P,{to:`/anime/${t.id}`,className:a.recTitle,children:t.title}),e("span",{className:a.recMatch,children:[t.matchPct,"% match"]}),e("span",{className:a.recMeta,children:[t.year,t.format,t.episodes?`${t.episodes}ep`:null].filter(Boolean).join(" · ")}),e("span",{className:a.recWhy,children:["Shares ",t.sharedGenres.join(", "),t.exemplars.length>0&&` — like ${t.exemplars.join(", ")}`]}),t.kind==="continue"&&e("span",{className:a.recNote,children:"Continue — you watched the earlier part."}),t.kind==="sequel"&&t.prequelTitle&&e("span",{className:a.recNote,children:['Sequel — start with "',t.prequelTitle,'" first.']}),e("button",{className:a.recAddBtn,onClick:()=>N.mutate(t),disabled:N.isPending,children:"+ Plan to Watch"})]})]},t.id))})]}),n.droppedShows?.length>0&&e("div",{className:a.warningSection,children:[e("div",{className:a.warningHeader,children:[e(l,{name:"exclamation-triangle"}),e("h3",{children:"Dusty Watchlist (Inactive 90+ days)"})]}),e("div",{className:a.droppedGrid,children:n.droppedShows.map(t=>e("div",{className:a.droppedCard,children:[e("span",{className:a.droppedName,children:t.name}),e("span",{className:a.droppedDate,children:["Last watched: ",new Date(t.lastActivity).toLocaleDateString()]})]},t.id))})]})]}):null};export{Sa as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{p as le,d as C,T as ne,h as T,u as a,m as re,S as se}from"./vendor-core-DfaOB3Rn.js";import{I as M}from"./vendor-icons-DrybRNxP.js";import{T as oe,M as ie,B as D,U as ce}from"./index-Dk0ASzEz.js";import{E as de}from"./ErrorMessage-DAxegITP.js";import{M as ue}from"./MediaCard-9NGAjN3E.js";import{u as ge,M as pe}from"./useMangaPopup-TJOA229J.js";import{f as he,u as ve,m as z,i as me,b as be,c as fe}from"./useMangaLibrary-D92WQbf5.js";import{u as Se}from"./useProviders-fmZrOyDC.js";import{s as t}from"./Manga.module-depGEacJ.js";import{p as d}from"./page.module-C1MlZzf3.js";import"./vendor-query-BBT5_sHx.js";import"./vendor-ui-3qrARCPr.js";import"./useIsMobile-Dvx1uJ82.js";import"./usePopup-DS9jMzp6.js";const ye=[{value:"popular",label:"Popular"},{value:"latest",label:"Latest"},{value:"rating",label:"Top Rated"},{value:"followed",label:"Most Followed"}],Ne=[{value:"",label:"Any Status"},{value:"ongoing",label:"Ongoing"},{value:"completed",label:"Completed"},{value:"hiatus",label:"Hiatus"},{value:"cancelled",label:"Cancelled"}],Ce=[{value:"",label:"Any Status"},{value:"publishing",label:"Publishing"},{value:"finished",label:"Finished"},{value:"on hiatus",label:"On Hiatus"},{value:"discontinued",label:"Discontinued"}],Te=[{value:"",label:"All Types"},{value:"manga",label:"Manga"},{value:"novel",label:"Novel"},{value:"one-shot",label:"One-Shot"},{value:"doujinshi",label:"Doujinshi"}],Me=[{value:"safe",label:"Safe"}],we=[{value:"safe",label:"Safe"},{value:"suggestive",label:"Suggestive"},{value:"erotica",label:"Erotica"},{value:"pornographic",label:"Pornographic"}],w="agreedToViewMature";function je(){const[r,I]=le(),[m,P]=C(()=>localStorage.getItem(w)==="true"),[k,b]=C(!1),[L,R]=C(r.get("q")||""),{options:$,isLoading:B,refetch:H}=Se(),u=ne(()=>$.filter(e=>e.kind==="manga").map(e=>({value:e.value,label:e.label})),[$]),f=r.get("provider")||"",i=u.some(e=>e.value===f)?f:u[0]?.value??f,S=r.get("q")||"",g=parseInt(r.get("page")||"1"),E=r.get("sort")||"popular",x=r.get("status")||"",A=r.get("type")||"",p=r.get("rating")||"safe",U=r.get("id")||"";T(()=>{document.title="Manga - dango"},[]),T(()=>{const e=()=>P(localStorage.getItem(w)==="true");return window.addEventListener("focus",e),window.addEventListener("storage",e),()=>{window.removeEventListener("focus",e),window.removeEventListener("storage",e)}},[]);const c=m,y=c?p:"safe",G=c?we:Me,o=(e,l=!1)=>{const n=new URLSearchParams(r);for(const[v,q]of Object.entries(e))q?n.set(v,q):n.delete(v);l&&n.delete("page"),I(n)},h=he({provider:i,query:S,page:g,sort:E,status:x,type:A,rating:y,mature:c}),N=h.data?.items??[],V=h.data?.hasNext??!1,{toggle:Y,bookmarkedIds:K}=ve(),{popup:s,openPopup:W,scheduleClose:F,cancelClose:O,closePopup:X}=ge();if(T(()=>{R(S)},[S]),U){const e=new URLSearchParams;c&&p!=="safe"&&e.set("rating",p);const l=r.get("chapter")||"";l&&e.set("chapter",l);const n=e.toString()?`?${e.toString()}`:"",v=`/manga/${i}/${encodeURIComponent(U)}${l?`/read${n}`:n}`;return a(re,{to:v,replace:!0})}const Q=e=>{e.preventDefault(),ce(),o({q:L},!0)},J=e=>{e.target.checked&&!m&&b(!0)},Z=()=>{localStorage.setItem(w,"true"),P(!0),b(!1),o({},!0)},_=()=>{b(!1)},j=e=>{const l=new URLSearchParams;c&&p!=="safe"&&l.set("rating",p);const n=l.toString()?`?${l.toString()}`:"";return`/manga/${e.provider}/${encodeURIComponent(e.id)}${n}`},ee=i==="mangapill"?Ce:Ne,ae=i==="mangapill",te=i==="mangadex";return a("div",{className:d.page,children:[a("div",{className:d.header,children:[a("h1",{className:d.pageTitle,children:[a(M,{name:"book"})," Manga"]}),a("form",{className:d.searchForm,onSubmit:Q,children:[a("input",{className:d.searchInput,value:L,onChange:e=>R(e.target.value),placeholder:"Search manga titles...","aria-label":"Search manga"}),a("button",{className:d.searchBtn,type:"submit","aria-label":"Search",children:a(M,{name:"search",size:14})})]}),a("select",{className:t.select,value:i,disabled:u.length===0,onChange:e=>{const l=new URLSearchParams(r);l.set("provider",e.target.value),l.delete("page"),l.delete("id"),l.delete("chapter"),l.delete("status"),l.delete("type"),I(l)},"aria-label":"Manga provider",children:u.length===0?a("option",{value:"",children:B?"Loading providers…":"No providers available"}):u.map(e=>a("option",{value:e.value,children:e.label},e.value))}),u.length===0&&!B&&a("button",{className:d.searchBtn,type:"button",onClick:()=>H(),"aria-label":"Retry loading providers",children:a(M,{name:"redo",size:14})})]}),a("div",{className:t.filterRow,children:[i==="mangadex"&&a("select",{className:t.select,value:E,onChange:e=>o({sort:e.target.value},!0),"aria-label":"Sort manga",children:ye.map(e=>a("option",{value:e.value,children:e.label},e.value))}),a("select",{className:t.select,value:x,onChange:e=>o({status:e.target.value},!0),"aria-label":"Filter by status",children:ee.map(e=>a("option",{value:e.value,children:e.label},e.label))}),ae&&a("select",{className:t.select,value:A,onChange:e=>o({type:e.target.value},!0),"aria-label":"Filter by type",children:Te.filter(e=>e.value!=="doujinshi"||c).map(e=>a("option",{value:e.value,children:e.label},e.value))}),te&&a("select",{className:t.select,value:y,onChange:e=>o({rating:e.target.value},!0),"aria-label":"Content rating",children:G.map(e=>a("option",{value:e.value,children:e.label},e.value))}),!m&&a("div",{className:t.matureToggleWrap,children:[a("label",{className:t.matureLabel,htmlFor:"manga-mature-toggle",children:"Mature"}),a(oe,{id:"manga-mature-toggle",isChecked:!1,onChange:J})]})]}),h.isError?a(de,{message:"Failed to load manga. Please try again."}):h.isLoading&&N.length===0?a("div",{className:t.grid,"aria-hidden":!0,children:Array.from({length:12}).map((e,l)=>a("div",{className:t.skeletonCard,children:[a("div",{className:`${t.skeletonThumb} ${t.shimmer}`}),a("div",{className:`${t.skeletonLine} ${t.shimmer}`,style:{width:"88%"}}),a("div",{className:`${t.skeletonLine} ${t.shimmer}`,style:{width:"55%"}})]},l))}):N.length===0?a("p",{className:t.statusMsg,children:"No titles found. Try another search or provider."}):a(se,{children:[a("div",{className:`${t.grid} ${h.isFetching?t.fetching:""}`,children:N.map(e=>{const l=z(e.provider,e.id);return a(ue,{item:{id:l,title:e.title,...fe(e),thumbnail:be(e.provider,e.cover),typeBadge:e.type||void 0,chapterBadge:e.latestChapter?`Ch. ${e.latestChapter}`:null,isAdult:me(e)},linkTo:j(e),hoverIcon:"info",display:{elements:{poster:{typeBadge:!0,chapterBadge:!0,adultBadge:!0},info:{title:!0,mobileBadges:!0,progress:!1,meta:!1}}},onOpenDetails:n=>W(n,{provider:e.provider,mangaId:e.id,title:e.title,altTitle:e.altTitle,cover:e.cover,contentRating:e.contentRating,readTarget:j(e),rating:y,mature:c}),onPopupHoverIntent:n=>n?O():F(),rawThumbnail:!0},`${e.provider}-${e.id}`)})}),a("nav",{className:t.pagination,children:[a("button",{className:t.pageBtn,disabled:g<=1,onClick:()=>o({page:String(g-1)}),children:"Previous"}),a("span",{className:t.pageIndicator,children:["Page ",g]}),a("button",{className:t.pageBtn,disabled:!V,onClick:()=>o({page:String(g+1)}),children:"Next"})]})]}),s&&a(pe,{data:s.data,anchorRect:s.rect,bookmarked:K.has(z(s.data.provider,s.data.mangaId)),onToggleBookmark:()=>Y({id:s.data.mangaId,provider:s.data.provider,title:s.data.title,cover:s.data.cover,altTitle:s.data.altTitle??void 0,contentRating:s.data.contentRating}),onMouseEnter:O,onMouseLeave:F,onRequestClose:X}),k&&a(ie,{isOpen:k,title:"Content Warning",onClose:_,children:a("div",{style:{padding:"var(--space-4)",textAlign:"center"},children:[a("p",{children:"This section contains mature content intended for adult audiences."}),a("p",{children:["By proceeding, you confirm that you are ",a("strong",{children:"18 years of age or older"})," (or the age of majority in your jurisdiction) and wish to view this content."]}),a("p",{style:{fontSize:"var(--font-size-xs)",color:"var(--text-secondary)",marginTop:"var(--space-4)"},children:["You can reset this preference at any time in the ",a("strong",{children:"Settings"})," page."]}),a("div",{style:{marginTop:"var(--space-4)",display:"flex",gap:"var(--space-2-5)",justifyContent:"center"},children:[a(D,{variant:"secondary",onClick:_,children:"Go Back"}),a(D,{onClick:Z,children:"I'm 18+, Continue"})]})]})})]})}export{je as default};
|