@serifpersia/dango 3.5.1 → 3.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +1 -1
  2. package/client/dist/assets/{AnimeCard-B2ErWl4t.js → AnimeCard-BVnAhrys.js} +1 -1
  3. package/client/dist/assets/{AnimeInfo-Dfd4zWTx.js → AnimeInfo-DYBLIXmE.js} +1 -1
  4. package/client/dist/assets/{AnimeInfoPage-_DAHOnnx.js → AnimeInfoPage-DnXV4EMC.js} +2 -2
  5. package/client/dist/assets/{Asmr-CppKRwf3.js → Asmr-Dwlv-Af8.js} +1 -1
  6. package/client/dist/assets/{AsmrResetProgressModal-DqZ8um_v.js → AsmrResetProgressModal-CnF9ZTJQ.js} +1 -1
  7. package/client/dist/assets/{AvSyncCalibrator-DH6KEsbi.js → AvSyncCalibrator-Cr9n1euF.js} +1 -1
  8. package/client/dist/assets/Home-B_q2l74h.css +1 -0
  9. package/client/dist/assets/{Home-bqn1BmP7.js → Home-CUZPz_wy.js} +1 -1
  10. package/client/dist/assets/{Insights-KlshyXuf.js → Insights-hvaO1jbY.js} +1 -1
  11. package/client/dist/assets/{LibraryListPage-Ba7501DJ.js → LibraryListPage-BeYz_I1y.js} +1 -1
  12. package/client/dist/assets/{ListeningList-CycltWkq.js → ListeningList-D-D-W7JK.js} +1 -1
  13. package/client/dist/assets/{Manga-C3foLd_W.js → Manga-DqIR2B6F.js} +1 -1
  14. package/client/dist/assets/{MangaInfoPage-CKgBcwjP.js → MangaInfoPage-CWqxWbb3.js} +1 -1
  15. package/client/dist/assets/{MangaReadPage-B0Nr5zbg.js → MangaReadPage-BlyJ-OdY.js} +1 -1
  16. package/client/dist/assets/{MangaResetProgressModal-C9YlH9oi.js → MangaResetProgressModal-gvz9_X7z.js} +1 -1
  17. package/client/dist/assets/{Mature-DVvlLfAy.js → Mature-B1Cuj67a.js} +1 -1
  18. package/client/dist/assets/MediaCard-GwFTnacn.js +1 -0
  19. package/client/dist/assets/Music-BEmRDuSo.js +1 -0
  20. package/client/dist/assets/{OptionListMenu-AHGTsUIM.js → OptionListMenu-Dlk9eHM7.js} +1 -1
  21. package/client/dist/assets/{Player-Diz4QXSs.js → Player-khTFa_o1.js} +2 -2
  22. package/client/dist/assets/{PlayerSettings-B8CsR3hI.js → PlayerSettings-B16FnAO_.js} +1 -1
  23. package/client/dist/assets/{QueueOptionsButton-tpZ79_8s.js → QueueOptionsButton-DjBOibpt.js} +1 -1
  24. package/client/dist/assets/{QueueRail-CvrVAD_w.js → QueueRail-DcLtEU46.js} +1 -1
  25. package/client/dist/assets/{Radio-s_2zeYYn.js → Radio-rpaFuI72.js} +1 -1
  26. package/client/dist/assets/{ReadingList-DLKfiYLy.js → ReadingList-DTnI5411.js} +1 -1
  27. package/client/dist/assets/{ResetProgressModal-jPtyfyf0.js → ResetProgressModal-Bcv92v7c.js} +1 -1
  28. package/client/dist/assets/{Search-UfzxfJ8k.js → Search-DNxPl_On.js} +1 -1
  29. package/client/dist/assets/{Settings-CLP_y7EE.js → Settings-CQ-ykTG3.js} +1 -1
  30. package/client/dist/assets/{SkeletonGrid-21to5FX0.js → SkeletonGrid-ZN-kS9re.js} +1 -1
  31. package/client/dist/assets/{Trackers-QqnmwIKk.js → Trackers-EN1_ol5G.js} +1 -1
  32. package/client/dist/assets/{Tv-D3yVtdDx.js → Tv-C-4wd-BS.js} +1 -1
  33. package/client/dist/assets/{TvInfo-gue0nYi0.js → TvInfo-Mpzun3PF.js} +1 -1
  34. package/client/dist/assets/{TvPopup-CkXBuHHD.js → TvPopup-YYgg9-7r.js} +1 -1
  35. package/client/dist/assets/{TvSearch-DLP_3Nf2.js → TvSearch-CdL9EA-S.js} +1 -1
  36. package/client/dist/assets/{TvWatchlist-DzgVXuh9.js → TvWatchlist-DD6nRESU.js} +1 -1
  37. package/client/dist/assets/{Watchlist-DeO4iNhW.js → Watchlist-CD8UqukO.js} +1 -1
  38. package/client/dist/assets/{hls-D3SWhYIU.js → hls-E94cMCjR.js} +1 -1
  39. package/client/dist/assets/{index-BGCpLf49.js → index-CZW1But9.js} +3 -3
  40. package/client/dist/assets/{useAnimeInfoData-CWRGC9fX.js → useAnimeInfoData-C9tOyy6E.js} +1 -1
  41. package/client/dist/assets/{useAsmr-5n3wPm5z.js → useAsmr-B4HAapZD.js} +1 -1
  42. package/client/dist/assets/{useAsmrPopup-BxGzhLmJ.js → useAsmrPopup-trIV7nUr.js} +1 -1
  43. package/client/dist/assets/{useMangaLibrary-DUteTFgU.js → useMangaLibrary-CZ2Gke8p.js} +1 -1
  44. package/client/dist/assets/{useMangaPopup-BWU1Tz5e.js → useMangaPopup-80Daa4y-.js} +1 -1
  45. package/client/dist/assets/{useProviders-mkl-w-e4.js → useProviders-CqMq_6ue.js} +1 -1
  46. package/client/dist/assets/{useTv-Dl-E6HBp.js → useTv-CHDhiKWu.js} +1 -1
  47. package/client/dist/assets/{useTvLibrary-BVECcmlW.js → useTvLibrary-DWUGDtld.js} +1 -1
  48. package/client/dist/index.html +1 -1
  49. package/package.json +2 -2
  50. package/server/dist/app-hono.js +2 -4
  51. package/server/dist/db/schema-anime.js +0 -4
  52. package/server/dist/db/schema-asmr.js +0 -12
  53. package/server/dist/db/schema-tv.js +0 -15
  54. package/server/dist/discord-gateway.js +0 -6
  55. package/server/dist/discord-rpc.js +0 -14
  56. package/server/dist/github-sync.js +1 -5
  57. package/server/dist/hono/proxy.js +19 -2
  58. package/server/dist/hono/tv.js +1 -1
  59. package/server/dist/hono/watchlist.js +8 -13
  60. package/server/dist/lib/anilist.js +2 -26
  61. package/server/dist/lib/anischedule.js +0 -3
  62. package/server/dist/lib/mal.js +0 -9
  63. package/server/dist/lib/tracker/anilist-tracker.js +0 -3
  64. package/server/dist/lib/tracker/sync.service.js +0 -1
  65. package/server/dist/providers/manga/manga.types.js +1 -7
  66. package/server/dist/repositories/mal-cache.repository.js +0 -3
  67. package/server/dist/sync.js +0 -1
  68. package/server/dist/trpc/errors.js +0 -6
  69. package/server/dist/trpc/index.js +0 -1
  70. package/server/dist/trpc/routers/discovery.js +1 -5
  71. package/server/dist/trpc/routers/watchlist.js +3 -3
  72. package/server/package.json +1 -1
  73. package/client/dist/assets/Home-B6bte0tw.css +0 -1
  74. package/client/dist/assets/MediaCard-Auk42bqx.js +0 -1
  75. package/client/dist/assets/Music-BeCMeHS7.js +0 -1
  76. package/server/dist/sync-config.js +0 -23
@@ -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-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
+ 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-CZW1But9.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-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
+ 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-CZ2Gke8p.js";import{d as I}from"./index-CZW1But9.js";import{p as s,a as k}from"./MediaCard-GwFTnacn.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-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
+ 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-CZW1But9.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-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
+ 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-GwFTnacn.js";import{T as g}from"./TvPopup-YYgg9-7r.js";import{c as m,i as f}from"./useTvLibrary-DWUGDtld.js";import{b as i}from"./vendor-query-BBT5_sHx.js";import{h as p}from"./index-CZW1But9.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-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};
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-CZW1But9.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};
@@ -33,7 +33,7 @@
33
33
  background-color: #0c0d12;
34
34
  }
35
35
  </style>
36
- <script type="module" crossorigin src="/assets/index-BGCpLf49.js"></script>
36
+ <script type="module" crossorigin src="/assets/index-CZW1But9.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">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serifpersia/dango",
3
- "version": "3.5.1",
3
+ "version": "3.5.2",
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-08T01:33:46.617Z"
86
+ "versionDate": "2026-10-08T09:03:59.763Z"
87
87
  }
@@ -13,7 +13,7 @@ import { importMangaFromMalXmlItems, } from './lib/tracker/manga-sync.service.js
13
13
  import { LibraryRepository } from './repositories/library.repository.js';
14
14
  import { performAsmrWriteTransactionAsync, performMangaWriteTransactionAsync, performTvWriteTransactionAsync, performWriteTransactionAsync, KIND_SYNC, setKindManifestVersion, } from './sync.js';
15
15
  import { ANIME_SYNC_TABLES, ASMR_SYNC_TABLES, MANGA_SYNC_TABLES, TV_SYNC_TABLES, exportTables, importTables, normalizePayload, readPayloadVersion, } from './sync-payload.js';
16
- import { getMalImportStatus, prepareMalImport, executeMalImport, } from './lib/mal-import.js';
16
+ import { getMalImportStatus, prepareMalImport, executeMalImport } from './lib/mal-import.js';
17
17
  import { registerMusic } from './hono/music.js';
18
18
  import { registerAuth } from './hono/auth.js';
19
19
  import { registerTv } from './hono/tv.js';
@@ -45,8 +45,6 @@ function mapMalMangaXmlStatus(status) {
45
45
  return 'Planned';
46
46
  }
47
47
  }
48
- const TRACKER_TOKEN_KEY = 'tracker_anilist_token';
49
- const TRACKER_USER_KEY = 'tracker_anilist_user';
50
48
  export function getHonoClientIp(c) {
51
49
  try {
52
50
  return getConnInfo(c).remote.address;
@@ -584,7 +582,7 @@ export function createHonoApp(getState, getGuardState, getDbs, dbAdmin, provider
584
582
  });
585
583
  registerMusic(app);
586
584
  registerAuth(app, getDbs, runSync);
587
- registerTv(app, media.getApiCache, media.getTvProvider);
585
+ registerTv(app, media.getTvProvider);
588
586
  registerProxy(app);
589
587
  app.onError((err, c) => {
590
588
  logger.error({ err, url: c.req.path, method: c.req.method }, 'Unhandled error');
@@ -59,7 +59,3 @@ export const tempShowIds = sqliteTable('temp_show_ids', {
59
59
  thumbnail: text('thumbnail'),
60
60
  createdAt: integer('createdAt').notNull(),
61
61
  }, (t) => [primaryKey({ columns: [t.id] })]);
62
- export const legacyIdMapping = sqliteTable('legacy_id_mapping', {
63
- legacyId: text('legacyId').notNull(),
64
- numericId: text('numericId'),
65
- }, (t) => [primaryKey({ columns: [t.legacyId] })]);
@@ -1,16 +1,4 @@
1
1
  import { integer, primaryKey, real, sqliteTable, text } from 'drizzle-orm/sqlite-core';
2
- export const asmrLibrary = sqliteTable('asmr_library', {
3
- id: text('id').notNull(),
4
- rjCode: text('rjCode').notNull(),
5
- title: text('title'),
6
- thumbnail: text('thumbnail'),
7
- status: text('status'),
8
- isAdult: integer('isAdult'),
9
- lastTrackIndex: integer('lastTrackIndex'),
10
- lastTrackLabel: text('lastTrackLabel'),
11
- lastPosition: real('lastPosition'),
12
- updatedAt: integer('updatedAt'),
13
- }, (t) => [primaryKey({ columns: [t.id] })]);
14
2
  export const asmrProgress = sqliteTable('asmr_progress', {
15
3
  workId: text('workId').notNull(),
16
4
  trackIndex: integer('trackIndex').notNull(),
@@ -1,19 +1,4 @@
1
1
  import { integer, primaryKey, real, sqliteTable, text } from 'drizzle-orm/sqlite-core';
2
- export const tvLibrary = sqliteTable('tv_library', {
3
- id: text('id').notNull(),
4
- tmdbId: integer('tmdbId').notNull(),
5
- mediaType: text('mediaType').notNull(),
6
- title: text('title'),
7
- poster: text('poster'),
8
- backdrop: text('backdrop'),
9
- year: text('year'),
10
- overview: text('overview'),
11
- status: text('status'),
12
- adult: integer('adult'),
13
- lastSeason: integer('lastSeason'),
14
- lastEpisode: integer('lastEpisode'),
15
- updatedAt: integer('updatedAt'),
16
- }, (t) => [primaryKey({ columns: [t.id] })]);
17
2
  export const tvProgress = sqliteTable('tv_progress', {
18
3
  mediaId: text('mediaId').notNull(),
19
4
  season: integer('season').notNull(),
@@ -7,7 +7,6 @@ class DiscordGatewayService {
7
7
  gateway = null;
8
8
  heartbeat = null;
9
9
  token = null;
10
- isConnected = false;
11
10
  reconnectTimeout = null;
12
11
  lastActivity = null;
13
12
  isEnabled = false;
@@ -276,7 +275,6 @@ class DiscordGatewayService {
276
275
  clearInterval(this.heartbeat);
277
276
  this.heartbeat = null;
278
277
  }
279
- this.isConnected = false;
280
278
  }
281
279
  connect() {
282
280
  if (!this.isEnabled || !this.token || this.gateway)
@@ -285,7 +283,6 @@ class DiscordGatewayService {
285
283
  log.debug('Connecting Discord gateway');
286
284
  this.gateway = new WebSocket(wsUrl);
287
285
  let heartbeatInterval = 41250;
288
- let responded = false;
289
286
  this.gateway.on('message', (data) => {
290
287
  try {
291
288
  const msg = JSON.parse(data.toString());
@@ -343,8 +340,6 @@ class DiscordGatewayService {
343
340
  }
344
341
  else if (msg.op === 0) {
345
342
  if (msg.t === 'READY') {
346
- responded = true;
347
- this.isConnected = true;
348
343
  log.info(`Gateway READY as ${msg.d.user?.username || 'unknown'}`);
349
344
  if (this.lastActivity) {
350
345
  void this.updatePresence(this.lastActivity).catch((err) => log.warn({ err }, 'failed to restore presence after READY'));
@@ -374,7 +369,6 @@ class DiscordGatewayService {
374
369
  });
375
370
  }
376
371
  handleDisconnect() {
377
- this.isConnected = false;
378
372
  if (this.heartbeat) {
379
373
  clearInterval(this.heartbeat);
380
374
  this.heartbeat = null;
@@ -213,20 +213,6 @@ class DiscordRPCService {
213
213
  }
214
214
  discordGatewayService.disconnect();
215
215
  }
216
- formatTime(seconds) {
217
- if (isNaN(seconds) || seconds <= 0)
218
- return '00:00';
219
- const h = Math.floor(seconds / 3600);
220
- const m = Math.floor((seconds % 3600) / 60);
221
- const s = Math.floor(seconds % 60);
222
- const mm = String(m).padStart(2, '0');
223
- const ss = String(s).padStart(2, '0');
224
- if (h > 0) {
225
- const hh = String(h).padStart(2, '0');
226
- return `${hh}:${mm}:${ss}`;
227
- }
228
- return `${mm}:${ss}`;
229
- }
230
216
  async updatePresence(data) {
231
217
  this.lastActivity = data;
232
218
  if (data.sessionId) {
@@ -84,7 +84,6 @@ function normalizePayload(input) {
84
84
  }
85
85
  class GitHubSyncService {
86
86
  deviceState = { status: 'idle' };
87
- devicePromise = null;
88
87
  isAuthenticated() {
89
88
  return !!process.env.GITHUB_TOKEN;
90
89
  }
@@ -170,7 +169,7 @@ class GitHubSyncService {
170
169
  const verificationReady = new Promise((resolve) => {
171
170
  resolveVerification = resolve;
172
171
  });
173
- this.devicePromise = this.runDeviceAuth(db, runSyncSequence, resolveVerification);
172
+ void this.runDeviceAuth(db, runSyncSequence, resolveVerification);
174
173
  await verificationReady;
175
174
  return this.deviceState;
176
175
  }
@@ -364,9 +363,6 @@ class GitHubSyncService {
364
363
  resolveVerification();
365
364
  log.error({ err }, 'GitHub device authentication failed');
366
365
  }
367
- finally {
368
- this.devicePromise = null;
369
- }
370
366
  }
371
367
  async getOctokit() {
372
368
  if (!process.env.GITHUB_TOKEN) {
@@ -9,6 +9,7 @@ import { isSafeExternalUrl } from '../utils/security.utils.js';
9
9
  import { fetchWithRetry, linkAbort, setProxyHeaders } from '../utils/http.utils.js';
10
10
  import { MEGAPLAY_ORIGIN, isNexabloomMasterUrl, signNexabloomMasterUrl, } from '../utils/megaplay.utils.js';
11
11
  const proxyCache = new AppCache({ ttlSeconds: 30, maxKeys: 500 });
12
+ const imageCache = new AppCache({ ttlSeconds: 86400, maxKeys: 3000 });
12
13
  function assTimeToVtt(value) {
13
14
  const m = value.trim().match(/^(-?\d+):(\d{2}):(\d{2})[.:](\d{2,3})$/);
14
15
  if (!m)
@@ -784,6 +785,7 @@ export function registerProxy(app) {
784
785
  const targetUrl = url;
785
786
  const cookie = c.req.query('cookie') || '';
786
787
  const ua = c.req.query('ua') || '';
788
+ const strict = c.req.query('strict') === '1';
787
789
  const abort = new AbortController();
788
790
  linkAbort(c.req.raw.signal, abort);
789
791
  let refererValue = 'https://anilist.co/';
@@ -791,6 +793,16 @@ export function registerProxy(app) {
791
793
  'User-Agent': ua ||
792
794
  'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
793
795
  };
796
+ const cacheKey = `${targetUrl}|${cookie}|${ua}`;
797
+ const cached = imageCache.get(cacheKey);
798
+ if (cached) {
799
+ const hit = new Headers();
800
+ hit.set('Cache-Control', 'public, max-age=604800, immutable');
801
+ hit.set('Content-Type', cached.contentType);
802
+ hit.set('Access-Control-Allow-Origin', '*');
803
+ hit.set('X-Dango-Cache', 'hit');
804
+ return new Response(cached.body, { headers: hit });
805
+ }
794
806
  try {
795
807
  if (targetUrl.includes('animepahe')) {
796
808
  refererValue = 'https://animepahe.pw/';
@@ -818,7 +830,6 @@ export function registerProxy(app) {
818
830
  headers['User-Agent'] = uaParam;
819
831
  }
820
832
  headers['Referer'] = refererValue;
821
- let lastStatus = 0;
822
833
  let body = null;
823
834
  let contentType = 'image/webp';
824
835
  for (let attempt = 0; attempt < 3 && !body; attempt++) {
@@ -831,7 +842,6 @@ export function registerProxy(app) {
831
842
  throwHttpErrors: false,
832
843
  timeout: { request: 30000 },
833
844
  });
834
- lastStatus = resp.statusCode;
835
845
  if (resp.statusCode === 200 && resp.rawBody?.length) {
836
846
  body = Buffer.from(resp.rawBody);
837
847
  contentType = String(resp.headers['content-type'] || 'image/webp');
@@ -842,12 +852,17 @@ export function registerProxy(app) {
842
852
  }
843
853
  }
844
854
  if (body) {
855
+ imageCache.set(cacheKey, { body, contentType });
845
856
  const outHeaders = new Headers();
846
857
  outHeaders.set('Cache-Control', 'public, max-age=604800, immutable');
847
858
  outHeaders.set('Content-Type', contentType);
848
859
  outHeaders.set('Access-Control-Allow-Origin', '*');
849
860
  return new Response(body, { headers: outHeaders });
850
861
  }
862
+ // strict=1 callers retry another candidate instead of settling for the
863
+ // placeholder, which would otherwise read as a successful load.
864
+ if (strict)
865
+ return c.text('Not Found', 404);
851
866
  const placeholder = placeholderSvg();
852
867
  if (placeholder)
853
868
  return placeholder;
@@ -856,6 +871,8 @@ export function registerProxy(app) {
856
871
  catch {
857
872
  if (abort.signal.aborted)
858
873
  return new Response(null, { status: 499 });
874
+ if (strict)
875
+ return c.text('Not Found', 502);
859
876
  const placeholder = placeholderSvg();
860
877
  if (placeholder)
861
878
  return placeholder;
@@ -32,7 +32,7 @@ function isPlaylistBody(body) {
32
32
  .trimStart()
33
33
  .startsWith('#EXTM3U'));
34
34
  }
35
- export function registerTv(app, getApiCache, getTvProvider) {
35
+ export function registerTv(app, getTvProvider) {
36
36
  app.get('/api/tv/embed/:provider/:type/:tmdbId', async (c) => {
37
37
  const provider = c.req.param('provider');
38
38
  const type = c.req.param('type');
@@ -20,8 +20,8 @@ let discoveryTotal = 0;
20
20
  let discoveryDone = 0;
21
21
  let discoveryStopped = false;
22
22
  let triggerImpl = null;
23
- export function triggerWatchlistDiscovery(force = false) {
24
- return triggerImpl?.(force) ?? false;
23
+ export function triggerWatchlistDiscovery() {
24
+ return triggerImpl?.() ?? false;
25
25
  }
26
26
  export function stopWatchlistDiscovery() {
27
27
  discoveryStopped = true;
@@ -41,7 +41,7 @@ export function getWatchlistDiscoveryStatus() {
41
41
  }
42
42
  export function startWatchlistDiscovery(getDb) {
43
43
  const anilistIdCache = new Map();
44
- const getAnilistId = async (showId, showName) => {
44
+ const getAnilistId = async (showId) => {
45
45
  if (anilistIdCache.has(showId)) {
46
46
  return anilistIdCache.get(showId) || null;
47
47
  }
@@ -90,7 +90,7 @@ export function startWatchlistDiscovery(getDb) {
90
90
  return;
91
91
  const show = watchingShows[nextIndex];
92
92
  nextIndex += 1;
93
- const id = await getAnilistId(show.id, show.name);
93
+ const id = await getAnilistId(show.id);
94
94
  discoveryDone += 1;
95
95
  anilistResults.push({ show, id });
96
96
  }
@@ -177,13 +177,11 @@ export function startWatchlistDiscovery(getDb) {
177
177
  ]);
178
178
  const watchedSet = new Set(watchedEps.map((e) => e.toString()));
179
179
  const dismissedSet = new Set(dismissedEps.map((e) => e.episodeNumber.toString()));
180
- let inserted = false;
181
180
  for (const { episodeKey, airingAt } of episodes) {
182
181
  if (nowUnix - airingAt > 30 * 24 * 60 * 60)
183
182
  continue;
184
183
  if (!watchedSet.has(episodeKey) && !dismissedSet.has(episodeKey)) {
185
184
  await NotificationsRepository.addDiscovered(db, watchlistId, episodeKey);
186
- inserted = true;
187
185
  }
188
186
  }
189
187
  }
@@ -214,11 +212,9 @@ export function startWatchlistDiscovery(getDb) {
214
212
  ]);
215
213
  const watchedSet = new Set(watchedEps.map((e) => e.toString()));
216
214
  const dismissedSet = new Set(dismissedEps.map((e) => e.episodeNumber.toString()));
217
- let inserted = false;
218
215
  for (const { episodeKey } of episodes) {
219
216
  if (!watchedSet.has(episodeKey) && !dismissedSet.has(episodeKey)) {
220
217
  await NotificationsRepository.addDiscovered(db, watchlistId, episodeKey);
221
- inserted = true;
222
218
  }
223
219
  }
224
220
  }
@@ -241,14 +237,13 @@ export function startWatchlistDiscovery(getDb) {
241
237
  }
242
238
  }
243
239
  };
244
- triggerImpl = (force = false) => {
240
+ triggerImpl = () => {
245
241
  if (discoveryStopped || discoveryBusy)
246
242
  return false;
247
- const now = Date.now();
248
- if (!force && now - lastExternalDiscoveryAt < NUDGE_THROTTLE_MS)
243
+ if (Date.now() - lastExternalDiscoveryAt < NUDGE_THROTTLE_MS)
249
244
  return false;
250
- lastExternalDiscoveryAt = now;
251
- runDiscovery(force);
245
+ lastExternalDiscoveryAt = Date.now();
246
+ runDiscovery(true);
252
247
  return true;
253
248
  };
254
249
  discoveryIntervalId = setInterval(() => {
@@ -24,9 +24,6 @@ export function anilistUnavailable() {
24
24
  export function isAnilistRateLimited() {
25
25
  return anilistRateLimited && anilistCooldownUntil > Date.now();
26
26
  }
27
- export function markAnilistDownAtBoot() {
28
- anilistWasDownAtBoot = anilistUnavailable();
29
- }
30
27
  export async function checkAnilistStatus() {
31
28
  const available = await performAnilistStatusCheck();
32
29
  if (!available) {
@@ -995,7 +992,7 @@ export async function batchGetShowStatuses(ids) {
995
992
  for (let i = 0; i < ids.length; i += BATCH) {
996
993
  const batch = ids.slice(i, i + BATCH);
997
994
  const aliases = batch
998
- .map((id, idx) => `a${idx}: Media(id: $id${idx}, type: ANIME) { id status }`)
995
+ .map((_id, idx) => `a${idx}: Media(id: $id${idx}, type: ANIME) { id status }`)
999
996
  .join('\n');
1000
997
  const variables = {};
1001
998
  batch.forEach((id, idx) => {
@@ -1253,7 +1250,7 @@ export async function getAiredEpisodesForShows(ids, startDate, endDate) {
1253
1250
  for (let i = 0; i < ids.length; i += BATCH) {
1254
1251
  const batch = ids.slice(i, i + BATCH);
1255
1252
  const aliases = batch
1256
- .map((id, idx) => `a${idx}: Media(id: $id${idx}, type: ANIME) { id airingSchedule(perPage: 100) { nodes { episode airingAt } } }`)
1253
+ .map((_id, idx) => `a${idx}: Media(id: $id${idx}, type: ANIME) { id airingSchedule(perPage: 100) { nodes { episode airingAt } } }`)
1257
1254
  .join('\n');
1258
1255
  const variables = {};
1259
1256
  batch.forEach((id, idx) => {
@@ -1279,27 +1276,6 @@ export async function getAiredEpisodesForShows(ids, startDate, endDate) {
1279
1276
  setCachedAiredEpisodes(cacheKey, results);
1280
1277
  return results;
1281
1278
  }
1282
- export async function getAiredEpisodesForShow(id, startDate, endDate) {
1283
- const dayStart = Math.floor(startDate.getTime() / 1000);
1284
- const dayEnd = Math.floor(endDate.getTime() / 1000);
1285
- const query = `
1286
- query ($id: Int, $dayStart: Int, $dayEnd: Int) {
1287
- Media(id: $id, type: ANIME) {
1288
- id
1289
- airingSchedule(airingAt_greater: $dayStart, airingAt_lesser: $dayEnd) {
1290
- episode
1291
- airingAt
1292
- }
1293
- }
1294
- }
1295
- `;
1296
- const result = await anilistRequest(query, { id, dayStart, dayEnd });
1297
- const schedules = result?.data?.Media?.airingSchedule;
1298
- if (!schedules || schedules.length === 0)
1299
- return [];
1300
- const now = Math.floor(Date.now() / 1000);
1301
- return schedules.filter((s) => s.airingAt <= now).map((s) => s.episode);
1302
- }
1303
1279
  export async function getSchedule(date, format, adult = false) {
1304
1280
  if (format === 'ADULT') {
1305
1281
  adult = true;
@@ -189,6 +189,3 @@ export async function getAiredEpisodesFromAniScheduleFeed(ids, startEpoch, endEp
189
189
  }
190
190
  return results;
191
191
  }
192
- export function isAniScheduleAvailable() {
193
- return !!scheduleCache.data || !!subFeedCache.data;
194
- }
@@ -269,14 +269,6 @@ const MAL_STATUS_IDS = {
269
269
  cancelled: undefined,
270
270
  not_yet_released: '3',
271
271
  };
272
- const MAL_RATING_IDS = {
273
- g: '1',
274
- pg: '2',
275
- pg13: '3',
276
- r17: '4',
277
- r: '5',
278
- rx: '6',
279
- };
280
272
  const MAL_ORDER_IDS = {
281
273
  start_date: '2',
282
274
  score: '3',
@@ -617,7 +609,6 @@ export async function malSearchMedia(store, options = {}, enrichTitles = true) {
617
609
  }
618
610
  const url = `https://myanimelist.net/anime.php?${params.toString()}`;
619
611
  const key = `mal:search:${params.toString()}:page:${page}`;
620
- const parseHtml = (html) => parseSearchResults(html).map(toAnilistSearchMedia);
621
612
  const finish = (list) => enrichTitles ? enrichCardTitles(store, list) : Promise.resolve(list);
622
613
  let serverSorted = false;
623
614
  let html;
@@ -24,9 +24,6 @@ export const ANILIST_TO_MANGA_STATUS = {
24
24
  DROPPED: 'Dropped',
25
25
  PLANNING: 'Planned',
26
26
  };
27
- export async function exchangeAuthorizationCode() {
28
- throw new Error('Authorization Code flow removed — use Implicit Grant (response_type=token) instead.');
29
- }
30
27
  export class AniListTracker {
31
28
  token;
32
29
  constructor(token) {
@@ -13,7 +13,6 @@ import { getShowMetaById, getShowMetaByMalId, isAnilistRateLimited, searchAnilis
13
13
  import { kitsuSearchAnime } from '../kitsu.js';
14
14
  import { readTrackerSyncState, resolveStatus, } from './sync-state.js';
15
15
  const TOKEN_KEY = 'tracker_anilist_token';
16
- const USER_KEY = 'tracker_anilist_user';
17
16
  const SYNC_STATE_KEY = 'tracker_anilist_sync_state';
18
17
  async function getWatchedCount(db, showId) {
19
18
  const row = await dbGet(db, 'SELECT COUNT(DISTINCT episodeNumber) as total FROM watched_episodes WHERE showId = ?', [showId]);
@@ -1,7 +1 @@
1
- export const SAFE_RATINGS = ['safe'];
2
- export const MATURE_RATINGS = [
3
- 'safe',
4
- 'suggestive',
5
- 'erotica',
6
- 'pornographic',
7
- ];
1
+ export {};
@@ -44,9 +44,6 @@ export function malCachePruneExpired() {
44
44
  dbRun(db(), 'DELETE FROM mal_cache WHERE expires_at < ?', [now]);
45
45
  return row?.rows ?? 0;
46
46
  }
47
- export function malCacheDelete(key) {
48
- dbRun(db(), 'DELETE FROM mal_cache WHERE key = ?', [key]);
49
- }
50
47
  export function malCacheStore() {
51
48
  return {
52
49
  get: (key) => malCacheGet(key),
@@ -16,7 +16,6 @@ import { ANIME_SYNC_TABLES, exportTables, importTables, MANGA_SYNC_TABLES, TV_SY
16
16
  const log = logger.child({ module: 'Sync' });
17
17
  export const SYNC_TABLES = ANIME_SYNC_TABLES;
18
18
  export { MANGA_SYNC_TABLES, TV_SYNC_TABLES, ASMR_SYNC_TABLES };
19
- export const MEDIA_KINDS = ['anime', 'manga', 'tv', 'asmr'];
20
19
  function cap(s) {
21
20
  return s.length === 0 ? s : s[0].toUpperCase() + s.slice(1);
22
21
  }
@@ -1,10 +1,4 @@
1
1
  import { TRPCError } from '@trpc/server';
2
- export function isAuthErrorCause(value) {
3
- if (typeof value !== 'object' || value === null)
4
- return false;
5
- const code = value.code;
6
- return code === 'AUTH_REQUIRED' || code === 'LAN_AUTH_REQUIRED';
7
- }
8
2
  export function authRequiredError(provider) {
9
3
  return new TRPCError({
10
4
  code: 'FORBIDDEN',
@@ -10,7 +10,6 @@ const t = initTRPC.context().create({
10
10
  }),
11
11
  });
12
12
  export const router = t.router;
13
- export const publicProcedure = t.procedure;
14
13
  const lanGuard = t.middleware(({ ctx, next }) => {
15
14
  if (!ctx.lanAuthed)
16
15
  throw lanAuthRequiredError();
@@ -4,12 +4,8 @@ export const discoveryRouter = router({
4
4
  status: protectedProcedure.query(() => {
5
5
  return getWatchlistDiscoveryStatus();
6
6
  }),
7
- nudge: protectedProcedure.mutation(() => {
8
- const started = triggerWatchlistDiscovery(false);
9
- return { success: true, started, ...getWatchlistDiscoveryStatus() };
10
- }),
11
7
  refresh: protectedProcedure.mutation(() => {
12
- const started = triggerWatchlistDiscovery(true);
8
+ const started = triggerWatchlistDiscovery();
13
9
  return { success: true, started, ...getWatchlistDiscoveryStatus() };
14
10
  }),
15
11
  });