@serifpersia/dango 3.5.0 → 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.
- package/README.md +1 -15
- package/client/dist/assets/{AnimeCard-CpMObnqU.js → AnimeCard-BVnAhrys.js} +1 -1
- package/client/dist/assets/{AnimeInfo-DkDW8o1k.js → AnimeInfo-DYBLIXmE.js} +1 -1
- package/client/dist/assets/AnimeInfoPage-DnXV4EMC.js +2 -0
- package/client/dist/assets/{Asmr-B08Aimrk.js → Asmr-Dwlv-Af8.js} +2 -2
- package/client/dist/assets/{AsmrResetProgressModal-CZMbyJZz.js → AsmrResetProgressModal-CnF9ZTJQ.js} +1 -1
- package/client/dist/assets/{AvSyncCalibrator-VoOEtoX9.js → AvSyncCalibrator-Cr9n1euF.js} +1 -1
- package/client/dist/assets/Home-B_q2l74h.css +1 -0
- package/client/dist/assets/{Home-C3Vck_99.js → Home-CUZPz_wy.js} +1 -1
- package/client/dist/assets/Insights-hvaO1jbY.js +1 -0
- package/client/dist/assets/{LibraryListPage-CUzEUs5k.js → LibraryListPage-BeYz_I1y.js} +1 -1
- package/client/dist/assets/{ListeningList-CoeQ17lz.js → ListeningList-D-D-W7JK.js} +1 -1
- package/client/dist/assets/Manga-DqIR2B6F.js +1 -0
- package/client/dist/assets/{MangaInfoPage-wqYZN_sT.js → MangaInfoPage-CWqxWbb3.js} +1 -1
- package/client/dist/assets/{MangaReadPage-BbyExwBN.js → MangaReadPage-BlyJ-OdY.js} +1 -1
- package/client/dist/assets/{MangaResetProgressModal-Dg0xhJQI.js → MangaResetProgressModal-gvz9_X7z.js} +1 -1
- package/client/dist/assets/{Mature-ZKR5vMIv.js → Mature-B1Cuj67a.js} +1 -1
- package/client/dist/assets/MediaCard-GwFTnacn.js +1 -0
- package/client/dist/assets/Music-BEmRDuSo.js +1 -0
- package/client/dist/assets/{OptionListMenu-DcHg1QsF.js → OptionListMenu-Dlk9eHM7.js} +1 -1
- package/client/dist/assets/{Player-V9IueAzT.js → Player-khTFa_o1.js} +6 -6
- package/client/dist/assets/{PlayerSettings-BZtjBWWq.js → PlayerSettings-B16FnAO_.js} +1 -1
- package/client/dist/assets/QueueOptionsButton-DjBOibpt.js +1 -0
- package/client/dist/assets/{QueueRail-CO2ocUNx.js → QueueRail-DcLtEU46.js} +1 -1
- package/client/dist/assets/{Radio-CJ-ra4vb.js → Radio-rpaFuI72.js} +1 -1
- package/client/dist/assets/{ReadingList-CSvUUtZ3.js → ReadingList-DTnI5411.js} +1 -1
- package/client/dist/assets/{ResetProgressModal-5FOWMuqi.js → ResetProgressModal-Bcv92v7c.js} +1 -1
- package/client/dist/assets/{Search-q0GUdNMS.js → Search-DNxPl_On.js} +1 -1
- package/client/dist/assets/Settings-CQ-ykTG3.js +21 -0
- package/client/dist/assets/{Settings-AuFxQcJF.css → Settings-CwIWLSfY.css} +1 -1
- package/client/dist/assets/{SkeletonGrid-DY_7CXpX.js → SkeletonGrid-ZN-kS9re.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-EN1_ol5G.js} +1 -1
- package/client/dist/assets/{Tv-BfaWoR72.js → Tv-C-4wd-BS.js} +4 -4
- package/client/dist/assets/{TvInfo-CgEVN57T.js → TvInfo-Mpzun3PF.js} +1 -1
- package/client/dist/assets/{TvPopup-B-vYyDQF.js → TvPopup-YYgg9-7r.js} +1 -1
- package/client/dist/assets/{TvSearch-CnnVkms6.js → TvSearch-CdL9EA-S.js} +1 -1
- package/client/dist/assets/{TvWatchlist-BLVF_row.js → TvWatchlist-DD6nRESU.js} +1 -1
- package/client/dist/assets/{Watchlist-wd9cCDOK.js → Watchlist-CD8UqukO.js} +1 -1
- package/client/dist/assets/{hls-Bej65gvf.js → hls-E94cMCjR.js} +1 -1
- package/client/dist/assets/index-CZW1But9.js +178 -0
- package/client/dist/assets/index-w_r2lTCe.css +1 -0
- package/client/dist/assets/{useAnimeInfoData-ZmMruFBq.js → useAnimeInfoData-C9tOyy6E.js} +1 -1
- package/client/dist/assets/{useAsmr-z-txLq1s.js → useAsmr-B4HAapZD.js} +1 -1
- package/client/dist/assets/{useAsmrPopup-DU55UhPN.js → useAsmrPopup-trIV7nUr.js} +1 -1
- package/client/dist/assets/{useMangaLibrary-D92WQbf5.js → useMangaLibrary-CZ2Gke8p.js} +1 -1
- package/client/dist/assets/{useMangaPopup-TJOA229J.js → useMangaPopup-80Daa4y-.js} +1 -1
- package/client/dist/assets/{useProviders-fmZrOyDC.js → useProviders-CqMq_6ue.js} +1 -1
- package/client/dist/assets/{useTv-CmfxzpS-.js → useTv-CHDhiKWu.js} +1 -1
- package/client/dist/assets/{useTvLibrary-0y9NZnsk.js → useTvLibrary-DWUGDtld.js} +1 -1
- package/client/dist/index.html +2 -2
- package/package.json +2 -2
- package/server/dist/app-hono.js +2 -10
- package/server/dist/config.js +0 -1
- package/server/dist/db/schema-anime.js +0 -4
- package/server/dist/db/schema-asmr.js +0 -12
- package/server/dist/db/schema-tv.js +0 -15
- package/server/dist/discord-gateway.js +0 -6
- package/server/dist/discord-rpc.js +0 -14
- package/server/dist/github-sync.js +1 -5
- package/server/dist/hono/proxy.js +19 -2
- package/server/dist/hono/tv.js +1 -1
- package/server/dist/hono/watchlist.js +8 -13
- package/server/dist/lib/anilist.js +2 -26
- package/server/dist/lib/anischedule.js +0 -3
- package/server/dist/lib/mal.js +0 -9
- package/server/dist/lib/{discord-roles-sync.service.js → recommendations.service.js} +0 -149
- package/server/dist/lib/tracker/anilist-tracker.js +0 -3
- package/server/dist/lib/tracker/sync.service.js +0 -1
- package/server/dist/providers/manga/manga.types.js +1 -7
- package/server/dist/repositories/mal-cache.repository.js +0 -3
- package/server/dist/server.js +0 -2
- package/server/dist/shipped-defaults.js +0 -1
- package/server/dist/sync.js +0 -1
- package/server/dist/trpc/errors.js +0 -6
- package/server/dist/trpc/index.js +0 -1
- package/server/dist/trpc/routers/discord.js +0 -4
- package/server/dist/trpc/routers/discovery.js +1 -5
- package/server/dist/trpc/routers/insights.js +1 -31
- package/server/dist/trpc/routers/settings.js +0 -10
- package/server/dist/trpc/routers/watchlist.js +3 -3
- package/server/package.json +1 -1
- package/client/dist/assets/AnimeInfoPage-l0wIHS7j.js +0 -2
- package/client/dist/assets/Home-B6bte0tw.css +0 -1
- 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/MediaCard-9NGAjN3E.js +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/sync-config.js +0 -23
- package/server/dist/utils/machine-id.js +0 -39
|
@@ -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
|
-
}
|
|
@@ -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]);
|
|
@@ -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),
|
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
|
};
|
package/server/dist/sync.js
CHANGED
|
@@ -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',
|
|
@@ -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
|
});
|
|
@@ -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(
|
|
8
|
+
const started = triggerWatchlistDiscovery();
|
|
13
9
|
return { success: true, started, ...getWatchlistDiscoveryStatus() };
|
|
14
10
|
}),
|
|
15
11
|
});
|
|
@@ -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';
|
|
@@ -224,7 +224,7 @@ export const watchlistRouter = router({
|
|
|
224
224
|
}
|
|
225
225
|
const [watchedEpisodes, episodes] = await Promise.all([
|
|
226
226
|
WatchedEpisodesRepository.getByShow(db, showId),
|
|
227
|
-
resolveAvailableEpisodes(
|
|
227
|
+
resolveAvailableEpisodes(showId),
|
|
228
228
|
]);
|
|
229
229
|
const watchedSet = new Set(watchedEpisodes.map((ep) => ep.episodeNumber.toString()));
|
|
230
230
|
const finishedEpisodes = watchedEpisodes
|
|
@@ -247,7 +247,7 @@ export const watchlistRouter = router({
|
|
|
247
247
|
const [watchedEpisodes, queuedEpisodes, episodes] = await Promise.all([
|
|
248
248
|
WatchedEpisodesRepository.getByShow(db, showId),
|
|
249
249
|
QueueRepository.getByShow(db, showId),
|
|
250
|
-
resolveAvailableEpisodes(
|
|
250
|
+
resolveAvailableEpisodes(showId),
|
|
251
251
|
]);
|
|
252
252
|
const watchedSet = new Set(watchedEpisodes.map((ep) => ep.episodeNumber.toString()));
|
|
253
253
|
const queuedSet = new Set(queuedEpisodes.map((ep) => ep.episodeNumber.toString()));
|
|
@@ -541,7 +541,7 @@ async function getContinueWatchingData(db, limit) {
|
|
|
541
541
|
await backfillMissingPosters(db, enrichedRows);
|
|
542
542
|
return enrichedRows;
|
|
543
543
|
}
|
|
544
|
-
async function resolveAvailableEpisodes(
|
|
544
|
+
async function resolveAvailableEpisodes(showId) {
|
|
545
545
|
const episodeData = await getAnilistEpisodes(showId);
|
|
546
546
|
const episodes = Array.isArray(episodeData) && episodeData.length
|
|
547
547
|
? [...episodeData].sort((a, b) => parseFloat(a) - parseFloat(b))
|
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
|
-
._section-header_2p2l1_1{display:flex;justify-content:space-between;align-items:flex-end;margin-bottom:var(--space-8);gap:var(--space-4)}._sectionWrapper_2p2l1_9{margin-bottom:2.5rem}._sectionTitleNoMargin_2p2l1_13{margin-bottom:0}._title-wrapper_2p2l1_17{display:flex;align-items:center;gap:var(--space-6);flex:1}._header-controls_2p2l1_24{display:flex;align-items:center;gap:var(--space-2)}._header-select_2p2l1_30{width:auto;min-width:120px;height:34px;padding:0 var(--space-3);padding-right:2rem;background-color:var(--bg-tertiary);border:1px solid var(--border-primary);border-radius:var(--radius-sm);color:var(--text-primary);font-size:var(--font-size-sm);font-weight:700;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23a1a1aa' stroke-width='2' viewBox='0 0 12 12'%3E%3Cpolyline points='3 5 6 8 9 5'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right .5rem center;transition:all var(--transition-base)}._header-select_2p2l1_30:hover{border-color:var(--border-secondary);background-color:var(--bg-elevated)}._header-select_2p2l1_30:focus{outline:none;border-color:var(--accent)}._view-all-link_2p2l1_61{font-size:.85rem;font-weight:700;color:var(--text-secondary);text-decoration:none;white-space:nowrap;padding:8px 12px;border-radius:var(--radius-md);border:1px solid transparent;transition:all var(--transition-base)}._view-all-link_2p2l1_61:hover{color:var(--accent-light);background:var(--accent-subtle);border-color:var(--border-primary)}._collapse-button_2p2l1_79{width:40px;height:40px;border:1px solid var(--border-primary);background:var(--bg-secondary);color:var(--text-secondary);border-radius:var(--radius-md);display:inline-flex;align-items:center;justify-content:center;cursor:pointer;transition:all var(--transition-base)}._collapse-button_2p2l1_79:hover{background:var(--bg-elevated);color:var(--text-primary)}._title-link_2p2l1_98{color:inherit;text-decoration:none;display:inline-flex;align-items:center;transition:all var(--transition-base)}._title-link_2p2l1_98 .section-title{position:relative;font-size:1.5rem;font-weight:800;letter-spacing:-.01em}._title-link_2p2l1_98:hover,._continue-watching_2p2l1_117 ._title-link_2p2l1_98:hover .section-title{color:var(--accent)}@media(max-width:600px){._section-header_2p2l1_1{flex-direction:column;align-items:flex-start;gap:var(--space-4);margin-bottom:var(--space-6)}._title-wrapper_2p2l1_17{width:100%;justify-content:space-between}._title-link_2p2l1_98 .section-title{font-size:1.25rem}}._nav-arrows_2p2l1_139{display:flex;gap:8px;background:var(--bg-tertiary);padding:4px;border-radius:var(--radius-md);border:1px solid var(--border-primary)}._nav-button_2p2l1_148{background:transparent;border:none;color:var(--text-secondary);width:32px;height:32px;border-radius:var(--radius-sm);display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all var(--transition-base)}._nav-button_2p2l1_148:hover{background:var(--bg-elevated);color:var(--accent)}._nav-button_2p2l1_148:active{transform:scale(.9)}@media(hover:none),(pointer:coarse){._nav-button_2p2l1_148{width:44px;height:44px}}._carousel-container_2p2l1_178{position:relative;width:100%}._carousel_2p2l1_178{overflow:hidden}._carousel-inner_2p2l1_187{display:flex;gap:20px}._carousel-card_2p2l1_192{flex:0 0 calc((100% - (6 * 20px)) / 7);min-width:150px}@media(max-width:1400px){._carousel-card_2p2l1_192{flex:0 0 calc((100% - (5 * 20px)) / 6)}}@media(max-width:1200px){._carousel-card_2p2l1_192{flex:0 0 calc((100% - 80px)/5)}}@media(max-width:900px){._carousel-card_2p2l1_192{flex:0 0 calc((100% - 60px)/4);max-width:160px}}@media(max-width:768px){._carousel-inner_2p2l1_187{gap:12px}._carousel-card_2p2l1_192{flex:0 0 calc((100% - (2 * 12px)) / 3);min-width:0;max-width:140px}}@media(max-width:480px){._carousel-card_2p2l1_192{flex:0 0 calc((100% - (1 * 12px)) / 2.2);max-width:140px}}._sectionWrapper_c8uv6_2{margin-bottom:2.5rem}._sectionTitleNoMargin_c8uv6_6{margin-bottom:0}._section-header_c8uv6_10{display:flex;justify-content:space-between;align-items:flex-end;margin-bottom:var(--space-8);gap:var(--space-4)}._title-wrapper_c8uv6_18{display:flex;align-items:center;gap:var(--space-6);flex:1}@media(max-width:600px){._section-header_c8uv6_10{flex-direction:column;align-items:flex-start;gap:var(--space-4);margin-bottom:var(--space-6)}._title-wrapper_c8uv6_18{width:100%;justify-content:space-between}}._nav-arrows_c8uv6_40{display:flex;gap:8px;background:var(--bg-tertiary);padding:4px;border-radius:var(--radius-md);border:1px solid var(--border-primary)}._nav-button_c8uv6_49{background:transparent;border:none;color:var(--text-secondary);width:32px;height:32px;border-radius:var(--radius-sm);display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all var(--transition-base)}._nav-button_c8uv6_49:hover{background:var(--bg-elevated);color:var(--accent)}._nav-button_c8uv6_49:active{transform:scale(.9)}@media(hover:none),(pointer:coarse){._nav-button_c8uv6_49{width:44px;height:44px}}._timeSelect_c8uv6_80{width:120px;height:34px;padding:0 var(--space-3);padding-right:2rem;background-color:var(--bg-tertiary);border:1px solid var(--border-primary);border-radius:var(--radius-sm);color:var(--text-primary);font-size:var(--font-size-sm);font-weight:700;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23a1a1aa' stroke-width='2' viewBox='0 0 12 12'%3E%3Cpolyline points='3 5 6 8 9 5'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right .5rem center;transition:all var(--transition-base)}._timeSelect_c8uv6_80:hover{border-color:var(--border-secondary);background-color:var(--bg-elevated)}._timeSelect_c8uv6_80:focus{outline:none;border-color:var(--accent)}._carouselContainer_c8uv6_111{position:relative;width:100%}._carousel_c8uv6_111{overflow:hidden;padding:10px 0;margin:-10px 0}._carouselInner_c8uv6_122{display:flex;gap:15px}._carouselItem_c8uv6_127{flex:0 0 calc((100% - (6 * 15px)) / 7);min-width:120px;position:relative}@media(max-width:1200px){._carouselItem_c8uv6_127{flex:0 0 calc((100% - (5 * 15px)) / 6)}}@media(max-width:1024px){._carouselItem_c8uv6_127{flex:0 0 calc((100% - 60px)/5)}}@media(max-width:768px){._carouselItem_c8uv6_127{flex:0 0 calc((100% - (2 * 15px)) / 3)}}@media(max-width:480px){._carouselItem_c8uv6_127{flex:0 0 calc((100% - (2 * 10px)) / 3);min-width:100px}._carouselInner_c8uv6_122{gap:10px;align-items:flex-start}}._rankCard_c8uv6_164{width:100%}._rankPill_c8uv6_168{text-align:center;margin-top:4px;font-size:1.6rem;font-weight:900;line-height:1;letter-spacing:-.04em;color:var(--text-tertiary);font-variant-numeric:tabular-nums}._rankPill_c8uv6_168._rankGold_c8uv6_179{color:#d8b56b}._rankPill_c8uv6_168._rankSilver_c8uv6_183{color:#c3c9d1}._rankPill_c8uv6_168._rankBronze_c8uv6_187{color:#c08d5f}@media(max-width:768px){._rankPill_c8uv6_168{font-size:1.3rem}}._skeletonPoster_c8uv6_198,._skeletonText_c8uv6_199{position:relative;overflow:hidden;background-color:var(--bg-tertiary);border-radius:var(--radius-sm)}._skeletonPoster_c8uv6_198:after,._skeletonText_c8uv6_199:after{content:"";position:absolute;inset:0;transform:translate(-100%);background-image:linear-gradient(90deg,#fff0 0,#ffffff0d 20%,#ffffff1f 60%,#fff0);animation:_skeleton-wave_c8uv6_1 1.8s infinite ease-in-out}._skeletonPoster_c8uv6_198{width:100%;aspect-ratio:3 / 4}._skeletonText_c8uv6_199{width:80%;height:12px;margin-top:var(--space-2)}._scheduleSection_10dfe_1{margin-bottom:2.5rem}._sectionTitleRow_10dfe_5{display:flex;align-items:center;gap:1rem}._sectionTitleNoMargin_10dfe_11{margin-bottom:0}._sectionHeader_10dfe_15{display:flex;justify-content:space-between;align-items:center;margin-bottom:var(--space-6);gap:var(--space-4);flex-wrap:wrap;row-gap:var(--space-3)}._headerActions_10dfe_25{display:flex;align-items:center;gap:var(--space-3)}._timeSelect_10dfe_31{width:120px;height:34px;padding:0 var(--space-3);padding-right:2rem;background-color:var(--bg-tertiary);border:1px solid var(--border-primary);border-radius:var(--radius-sm);color:var(--text-primary);font-size:var(--font-size-sm);font-weight:700;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23a1a1aa' stroke-width='2' viewBox='0 0 12 12'%3E%3Cpolyline points='3 5 6 8 9 5'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right .5rem center;transition:all var(--transition-base)}._timeSelect_10dfe_31:hover{border-color:var(--border-secondary);background-color:var(--bg-elevated)}._timeSelect_10dfe_31:focus{outline:none;border-color:var(--accent)}._daySelectorContainer_10dfe_62{margin-bottom:var(--space-8);width:100%;position:relative}._daySelector_10dfe_62{display:flex;overflow-x:auto;padding:var(--space-2) var(--space-8);scrollbar-width:none;-webkit-overflow-scrolling:touch;width:100%;scroll-behavior:smooth;overscroll-behavior-x:contain}._daySelectorInner_10dfe_79{display:flex;gap:var(--space-2);justify-content:flex-start;margin:0 auto}._daySelector_10dfe_62::-webkit-scrollbar{display:none}._dayBtn_10dfe_90{background:#ffffff08;border:1px solid var(--border-primary);color:var(--text-secondary);padding:var(--space-2) var(--space-4);border-radius:var(--radius-lg);cursor:pointer;transition:all var(--transition-base);min-width:70px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;flex-shrink:0}._dayBtn_10dfe_90:hover{background:#ffffff14;border-color:var(--border-secondary);transform:translateY(-2px)}._dayBtn_10dfe_90._active_10dfe_113{background:var(--accent);border-color:var(--accent);color:var(--accent-text);box-shadow:0 8px 20px var(--accent-glow);transform:translateY(-4px)}._dayMonth_10dfe_121{font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;opacity:.8}._dayNum_10dfe_129{font-size:1.25rem;font-weight:800;line-height:1}._dayName_10dfe_135{font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.02em}._dayBtn_10dfe_90._active_10dfe_113 ._dayMonth_10dfe_121,._dayBtn_10dfe_90._active_10dfe_113 ._dayName_10dfe_135{opacity:1}._navArrows_10dfe_148{display:flex;gap:8px;background:var(--bg-tertiary);padding:4px;border-radius:var(--radius-md);border:1px solid var(--border-primary)}._navButton_10dfe_157{background:transparent;border:none;color:var(--text-secondary);width:32px;height:32px;border-radius:var(--radius-sm);display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all var(--transition-base)}._navButton_10dfe_157:hover{background:var(--bg-elevated);color:var(--accent)}._navButton_10dfe_157:active{transform:scale(.9)}._carouselContainer_10dfe_181{position:relative;width:100%;min-height:280px}._carousel_10dfe_181{overflow:hidden;padding-bottom:10px;min-height:260px}._carouselInner_10dfe_193{display:flex;gap:15px}._carouselCard_10dfe_198{flex:0 0 calc((100% - (6 * 15px)) / 7);min-width:150px}@media(max-width:1200px){._carouselCard_10dfe_198{flex:0 0 calc((100% - (5 * 15px)) / 6)}}@media(max-width:1024px){._carouselCard_10dfe_198{flex:0 0 calc((100% - 60px)/5)}}@media(max-width:768px){._carouselCard_10dfe_198{flex:0 0 calc((100% - (2 * 15px)) / 3);min-width:0}._daySelector_10dfe_62{justify-content:flex-start;padding-left:var(--space-4);padding-right:var(--space-4)}._dayBtn_10dfe_90{min-width:60px;padding:var(--space-2) var(--space-3)}}@media(max-width:480px){._carouselCard_10dfe_198{flex:0 0 calc((100% - (2 * 10px)) / 3);min-width:0}._carouselInner_10dfe_193{gap:10px;align-items:flex-start}}@media(max-width:600px){._daySelector_10dfe_62{display:flex;overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch;gap:0;padding:var(--space-1) var(--space-4);scroll-behavior:smooth;overscroll-behavior-x:contain}._daySelectorInner_10dfe_79{gap:0;margin:0;justify-content:flex-start}._dayBtn_10dfe_90{flex:0 0 14.2857%;min-width:0!important;padding:var(--space-1) 0!important;border-radius:var(--radius-md)!important}._dayMonth_10dfe_121{font-size:10px!important}._dayNum_10dfe_129{font-size:1rem!important}._dayName_10dfe_135{font-size:10px!important}._dayBtn_10dfe_90._active_10dfe_113{transform:translateY(-2px)!important}}._bannerContainer_rceop_1{width:100vw;max-width:100vw;position:relative;left:50%;right:50%;margin-left:-50vw;margin-right:-50vw;margin-top:calc(-1 * var(--header-height));margin-bottom:2.5rem;overflow:hidden;background-color:var(--bg-main);z-index:2}@media(max-width:1024px){._bannerContainer_rceop_1{margin-top:calc(-1 * (var(--header-height) + 52px))}}@media(max-width:848px){._bannerContainer_rceop_1{margin-top:-116px}}._hero_rceop_28{position:relative;width:100%;height:clamp(480px,72svh,660px);overflow:hidden;background-color:var(--bg-main)}._ambient_rceop_37{position:absolute;inset:-60px;width:calc(100% + 120px);height:calc(100% + 120px);object-fit:cover;object-position:center 22%;filter:blur(55px) brightness(.3) saturate(1.15);opacity:0;transition:opacity .6s ease}._ambientShow_rceop_49{opacity:1}._scrim_rceop_53{position:absolute;inset:0;z-index:1;background:linear-gradient(90deg,#050508c7,#0505086b 42%,#0505080f 70%),linear-gradient(0deg,var(--bg-main) 0%,rgba(12,13,18,.82) 16%,transparent 46%),linear-gradient(180deg,transparent 0%,transparent 72px,rgba(5,5,8,.22) 100%)}._progressLine_rceop_69{position:absolute;left:0;right:0;bottom:0;height:2px;z-index:6;background:#ffffff1a;overflow:hidden}._progressLine_rceop_69:after{content:"";position:absolute;inset:0;background:linear-gradient(90deg,var(--accent),var(--accent-light));transform-origin:left;animation:_progressFill_rceop_1 8s linear forwards}._paused_rceop_89 ._progressLine_rceop_69:after{animation-play-state:paused}@keyframes _progressFill_rceop_1{0%{transform:scaleX(0)}to{transform:scaleX(1)}}._dots_rceop_103{position:absolute;left:50%;transform:translate(-50%);bottom:.6rem;z-index:5;display:flex;align-items:center;gap:.5rem;padding:10px 16px}._dot_rceop_103{width:8px;height:8px;padding:0;border-radius:50%;border:none;background:#ffffff59;cursor:pointer;transition:background .2s ease,transform .2s ease}._dot_rceop_103:hover{background:#ffffffa6}._dotActive_rceop_132{background:var(--accent-light);transform:scale(1.25)}._viewport_rceop_138{position:absolute;inset:0;z-index:2;overflow:hidden}._track_rceop_145{display:flex;height:100%;transition:transform .45s cubic-bezier(.22,1,.36,1)}._slide_rceop_151{flex:0 0 100%;height:100%;display:flex;align-items:center;justify-content:center}._slideInner_rceop_159{width:100%;max-width:var(--max-width);margin:0 auto;padding:4rem var(--space-8) 3.5rem;display:flex;align-items:center;gap:3rem}._poster_rceop_169{width:230px;height:330px;object-fit:cover;border-radius:var(--radius-lg);flex-shrink:0;border:1px solid rgba(255,255,255,.14);box-shadow:0 30px 80px #0009}._info_rceop_179{max-width:620px}._kicker_rceop_183{display:flex;align-items:center;gap:.75rem;margin-bottom:.9rem}._featureLabel_rceop_190{padding:.3rem .75rem;background:var(--accent-subtle);border:1px solid var(--border-accent);color:var(--accent-light);font-size:.75rem;font-weight:700;text-transform:uppercase;border-radius:var(--radius-full);letter-spacing:.08em}._scoreChip_rceop_202{display:inline-flex;align-items:center;gap:.35rem;padding:.3rem .7rem;background:#00000073;border:1px solid var(--border-strong);border-radius:var(--radius-full);color:var(--accent-lighter);font-size:.8rem;font-weight:700;font-variant-numeric:tabular-nums;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}._slide_rceop_151 ._rise_rceop_220{opacity:1}._slide_rceop_151._active_rceop_224 ._rise_rceop_220{animation:_riseIn_rceop_1 .45s cubic-bezier(.22,1,.36,1) both}._slide_rceop_151._active_rceop_224 ._rise_rceop_220:nth-child(1){animation-delay:.03s}._slide_rceop_151._active_rceop_224 ._rise_rceop_220:nth-child(2){animation-delay:.07s}._slide_rceop_151._active_rceop_224 ._rise_rceop_220:nth-child(3){animation-delay:.11s}._slide_rceop_151._active_rceop_224 ._rise_rceop_220:nth-child(4){animation-delay:.15s}._slide_rceop_151._active_rceop_224 ._rise_rceop_220:nth-child(5){animation-delay:.19s}._slide_rceop_151._active_rceop_224 ._rise_rceop_220:nth-child(6){animation-delay:.23s}@keyframes _riseIn_rceop_1{0%{opacity:0;transform:translateY(26px)}to{opacity:1;transform:none}}._slide_rceop_151._active_rceop_224 ._poster_rceop_169{animation:_posterIn_rceop_1 .5s cubic-bezier(.22,1,.36,1)}@keyframes _posterIn_rceop_1{0%{opacity:0;transform:translate(-30px) scale(.97)}to{opacity:1;transform:none}}._metaRow_rceop_280{display:flex;align-items:center;flex-wrap:wrap;gap:.75rem;color:#ffffffb3;font-size:.9rem;font-weight:600;margin-bottom:.8rem}._metaItem_rceop_291{display:flex;align-items:center;gap:4px}._metaDivider_rceop_297{width:4px;height:4px;background:#ffffff4d;border-radius:50%}._title_rceop_304{display:block;font-size:3rem;line-height:1.04;cursor:pointer;max-width:800px;margin-bottom:.9rem;text-shadow:0 2px 26px rgba(0,0,0,.75),0 1px 3px rgba(0,0,0,.9)}._title_rceop_304:hover{color:var(--accent-light)}._genres_rceop_320{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem;margin-bottom:.9rem}._genreTag_rceop_328{color:#fffc;border:1px solid rgba(255,255,255,.28);padding:.32rem .75rem;border-radius:var(--radius-full);font-size:.7rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase}._summary_rceop_339{font-size:.96rem;line-height:1.65;margin:0 0 1.6rem;color:#fffc;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;max-width:750px}._actions_rceop_351{display:flex;align-items:center;gap:.8rem;flex-wrap:wrap}._watchBtn_rceop_358{display:inline-flex;align-items:center;justify-content:center;gap:.6rem;padding:.85rem 2.1rem;background:linear-gradient(135deg,var(--accent) 0%,var(--accent-dark) 100%);color:var(--accent-text);font-size:.94rem;font-weight:700;border:none;border-radius:var(--radius-md);cursor:pointer;box-shadow:0 6px 24px var(--accent-glow);transition:transform .2s cubic-bezier(.22,1,.36,1);letter-spacing:.02em}._watchBtn_rceop_358:hover{transform:translateY(-2px)}._detailsBtn_rceop_380{display:inline-flex;align-items:center;justify-content:center;gap:.6rem;padding:.85rem 1.8rem;background:#ffffff14;color:var(--text-primary);font-size:.94rem;font-weight:600;border:1px solid rgba(255,255,255,.2);border-radius:var(--radius-md);cursor:pointer;transition:background .2s ease}._detailsBtn_rceop_380:hover{background:#ffffff29;color:#fff}._navArrow_rceop_401{position:absolute;top:50%;transform:translateY(-50%);z-index:6;width:46px;height:46px;border-radius:50%;background:#0006;backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);border:1px solid rgba(255,255,255,.2);color:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;opacity:0;transition:opacity .3s ease,border-color .2s ease,color .2s ease}._hero_rceop_28:hover ._navArrow_rceop_401{opacity:.9}._navArrow_rceop_401:hover{border-color:var(--accent);color:var(--accent-light)}._prevArrow_rceop_434{left:1.2rem}._nextArrow_rceop_438{right:1.2rem}@media(max-width:768px){._hero_rceop_28{height:auto;min-height:92svh}._scrim_rceop_53{background:linear-gradient(0deg,#050508e6,#05050859 55%,#05050873)}._slideInner_rceop_159{flex-direction:column;justify-content:center;text-align:center;gap:1.3rem;padding:4.2rem var(--space-4) 2.4rem}._poster_rceop_169{width:172px;height:248px}._slide_rceop_151._active_rceop_224 ._poster_rceop_169{animation-name:_posterUp_rceop_1}@keyframes _posterUp_rceop_1{0%{opacity:0;transform:translateY(24px) scale(.97)}to{opacity:1;transform:none}}._kicker_rceop_183{justify-content:center}._title_rceop_304{font-size:1.6rem;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}._metaRow_rceop_280{justify-content:center;font-size:.8rem}._genres_rceop_320{justify-content:center}._genreTag_rceop_328{font-size:.66rem}._summary_rceop_339{display:none}._actions_rceop_351{width:100%}._watchBtn_rceop_358,._detailsBtn_rceop_380{flex:1;justify-content:center;padding:.85rem .5rem;font-size:.87rem}._navArrow_rceop_401{display:none}}@media(max-width:1024px){._slideInner_rceop_159{gap:2rem}._title_rceop_304{font-size:2.2rem}._poster_rceop_169{width:200px;height:288px}}@media(max-height:500px)and (orientation:landscape){._hero_rceop_28{height:92svh;min-height:360px}._slideInner_rceop_159{gap:1.5rem;padding:3.5rem var(--space-8) 3rem}._poster_rceop_169{width:140px;height:200px}._title_rceop_304{font-size:1.5rem}._summary_rceop_339{display:none}}._emptyState_19tmt_1{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:var(--space-16) var(--space-8);background:linear-gradient(to bottom,var(--bg-tertiary),var(--bg-main));border-radius:var(--radius-lg);border:1px solid var(--border-primary);text-align:center;gap:var(--space-4);width:100%;min-height:320px}._emptyStateIcon_19tmt_16{color:var(--accent);opacity:.4;margin-bottom:var(--space-2);filter:drop-shadow(0 0 20px var(--accent-glow))}._emptyStateTitle_19tmt_23{font-size:1.5rem;font-weight:800;margin:0;color:var(--text-primary)}._emptyStateText_19tmt_30{font-size:1rem;color:var(--text-secondary);max-width:340px;line-height:1.6}._select_1dw63_1{height:34px;padding:0 8px;padding-right:1.5rem;background-color:var(--bg-tertiary);border:1px solid var(--border-primary);border-radius:var(--radius-sm);color:var(--text-primary);font-size:var(--font-size-sm);font-weight:700;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23a1a1aa' stroke-width='2' viewBox='0 0 12 12'%3E%3Cpolyline points='3 5 6 8 9 5'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right .5rem center}._tabBar_irwbm_1{display:flex;align-items:center;gap:6px;margin-bottom:2.5rem;padding:6px;background:#ffffff0a;backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);border:1px solid var(--border-primary);border-radius:var(--radius-full);width:fit-content;max-width:100%;overflow-x:auto;scrollbar-width:none;box-shadow:0 4px 20px #0003;position:relative}._tabBar_irwbm_1::-webkit-scrollbar{display:none}._tabIndicator_irwbm_24{position:absolute;top:6px;bottom:6px;border-radius:var(--radius-full);background:linear-gradient(135deg,var(--accent) 0%,var(--accent-dark) 100%);box-shadow:0 4px 15px var(--accent-glow);transition:left .22s cubic-bezier(.2,1.2,.3,1),width .22s cubic-bezier(.2,1.2,.3,1);z-index:0;pointer-events:none}._tabButton_irwbm_38{border-radius:var(--radius-full)!important;font-weight:700!important;font-size:.85rem!important;padding:.65rem 1.4rem!important;letter-spacing:.02em;transition:color .25s ease!important;border:none!important;background:transparent!important;color:var(--text-muted)!important;position:relative;z-index:1;flex-shrink:0}._tabButton_irwbm_38:hover:not(:disabled){background:transparent!important;color:var(--text-muted)!important;box-shadow:none!important;transform:none!important}._tabButton_irwbm_38:active{transform:scale(.96)}._tabActive_irwbm_64{color:var(--accent-text)!important}._tabActive_irwbm_64:hover:not(:disabled){color:var(--accent-text)!important;transform:none!important}@media(max-width:600px){._tabBar_irwbm_1{width:100%;justify-content:flex-start}._tabButton_irwbm_38{flex:1;justify-content:center!important;padding:.65rem .5rem!important;text-align:center;font-size:.78rem!important}}._section-header_bt5c7_1{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--space-8)}._title-wrapper_bt5c7_8{display:flex;align-items:center;gap:var(--space-6)}._pagination-controls_bt5c7_14{display:flex;gap:8px;align-items:center;background:var(--bg-tertiary);padding:4px;border-radius:var(--radius-md);border:1px solid var(--border-primary)}._nav-button_bt5c7_24{background:transparent;border:none;color:var(--text-secondary);width:32px;height:32px;border-radius:var(--radius-sm);display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all var(--transition-base)}._nav-button_bt5c7_24:hover:not(:disabled){background:var(--bg-elevated);color:var(--accent)}._nav-button_bt5c7_24:disabled{opacity:.2;cursor:not-allowed}@media(hover:none),(pointer:coarse){._nav-button_bt5c7_24{width:44px;height:44px}}._page-info_bt5c7_55{font-size:.9rem;font-weight:800;min-width:32px;text-align:center;color:var(--text-primary)}@media(max-width:600px){._section-header_bt5c7_1{flex-direction:column;align-items:flex-start;gap:var(--space-4)}._title-wrapper_bt5c7_8{width:100%;justify-content:space-between}}._seasonGrid_bt5c7_76{display:grid;grid-template-columns:repeat(7,1fr);gap:var(--space-4)}@media(max-width:1200px){._seasonGrid_bt5c7_76{grid-template-columns:repeat(6,1fr)}}@media(max-width:1024px){._seasonGrid_bt5c7_76{grid-template-columns:repeat(5,1fr)}}@media(max-width:768px){._seasonGrid_bt5c7_76{grid-template-columns:repeat(3,1fr);gap:var(--space-2)}}@media(max-width:480px){._seasonGrid_bt5c7_76{grid-template-columns:repeat(3,1fr);gap:8px}}._emptyState_bt5c7_108{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:var(--space-16) var(--space-8);background:linear-gradient(to bottom,var(--bg-tertiary),var(--bg-main));border-radius:var(--radius-lg);border:1px solid var(--border-primary);text-align:center;gap:var(--space-4);width:100%;min-height:320px}._quickQueue_bt5c7_123{margin:0 0 2.5rem;border:1px solid var(--border-secondary);border-radius:var(--radius-md);background:var(--bg-secondary);overflow:hidden}._quickQueueHeader_bt5c7_131{width:100%;border:none;background:transparent;color:var(--text-primary);padding:var(--space-4) var(--space-5);display:flex;align-items:center;justify-content:space-between;cursor:pointer}._quickQueueTitle_bt5c7_143{display:flex;align-items:center;gap:var(--space-3);font-weight:800}._queueBadge_bt5c7_150{min-width:24px;height:24px;padding:0 8px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;background:var(--accent);color:var(--accent-text);font-size:.78rem;font-weight:800}._quickQueueList_bt5c7_164{display:flex;gap:var(--space-3);overflow-x:auto;padding:0 var(--space-5) var(--space-5);-webkit-user-select:none;user-select:none}._quickQueueItem_bt5c7_172._dragging_bt5c7_172{opacity:.5;background:var(--bg-secondary);border-style:dashed}._quickQueueItem_bt5c7_172{width:240px;flex:0 0 240px;display:grid;grid-template-columns:24px 54px minmax(0,1fr) 32px;align-items:center;gap:var(--space-2);padding:var(--space-2);border:1px solid var(--border-secondary);border-radius:var(--radius-md);background:var(--bg-primary)}._quickQueueDrag_bt5c7_191{display:inline-flex;align-items:center;justify-content:center;color:var(--text-muted);cursor:grab;border:none;background:transparent}._quickQueueThumb_bt5c7_201{width:54px;height:72px;object-fit:cover;border-radius:var(--radius-sm);background:var(--bg-tertiary)}._quickQueueMeta_bt5c7_209{min-width:0}._quickQueueName_bt5c7_213{display:block;width:100%;border:none;background:transparent;padding:0;text-align:left;color:var(--text-primary);font-weight:700;font-size:.85rem;text-decoration:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:pointer}._quickQueueEpisode_bt5c7_230{margin-top:.25rem;color:var(--text-secondary);font-size:.75rem}._quickQueueRemove_bt5c7_236{width:30px;height:30px;border:1px solid var(--border-secondary);background:var(--bg-tertiary);color:var(--text-secondary);border-radius:var(--radius-sm);cursor:pointer;display:inline-flex;align-items:center;justify-content:center}._quickQueueRemove_bt5c7_236:hover{color:var(--color-danger);border-color:var(--color-danger)}._posterLandscape_1smau_1{width:min(400px,38vw);aspect-ratio:16 / 9;height:auto;object-fit:cover;border-radius:var(--radius-lg);flex-shrink:0;border:1px solid rgba(255,255,255,.14);box-shadow:0 30px 80px #0009}@media(max-width:1024px){._posterLandscape_1smau_1{width:min(320px,36vw)}}@media(max-width:768px){._posterLandscape_1smau_1{width:100%;max-width:420px}}
|
|
@@ -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};
|