@serifpersia/dango 3.3.9 → 3.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/client/dist/assets/{AnimeCard-URCiiy5W.js → AnimeCard-B0oMgXBm.js} +1 -1
- package/client/dist/assets/{AnimeInfo-e3z3er9t.js → AnimeInfo-o0Udf0og.js} +1 -1
- package/client/dist/assets/{AnimeInfoPage-B7Djlmy_.js → AnimeInfoPage-CojMIEuf.js} +2 -2
- package/client/dist/assets/Asmr-2V3yCCiK.js +2 -0
- package/client/dist/assets/AsmrResetProgressModal-C9R7HlNa.js +1 -0
- package/client/dist/assets/AvSyncCalibrator-Bo3820j3.js +10 -0
- package/client/dist/assets/Home-C8uXTzIM.js +1 -0
- package/client/dist/assets/Insights-CRqBfZuK.js +1 -0
- package/client/dist/assets/{LibraryListPage-B0qWqhb_.js → LibraryListPage-B_r51cRi.js} +1 -1
- package/client/dist/assets/{ListeningList-CSqD8j1C.js → ListeningList-BWnwvJTt.js} +1 -1
- package/client/dist/assets/{Manga-Cg2YuObF.js → Manga-CI5cZg3h.js} +1 -1
- package/client/dist/assets/{MangaInfoPage-DcArhEsy.js → MangaInfoPage-BtkOrO34.js} +1 -1
- package/client/dist/assets/MangaReadPage-Uv72AYdY.js +1 -0
- package/client/dist/assets/{MangaResetProgressModal-D_yT3d1v.js → MangaResetProgressModal-CPMEqZyi.js} +1 -1
- package/client/dist/assets/Mature-DXHWvoY5.js +1 -0
- package/client/dist/assets/MediaCard-DzA336CA.js +1 -0
- package/client/dist/assets/Music-C4dM0BQx.js +1 -0
- package/client/dist/assets/OptionListMenu-CpwxAC3J.js +1 -0
- package/client/dist/assets/Player-CpMvWTkH.js +56 -0
- package/client/dist/assets/PlayerSettings-pMU85k7p.js +1 -0
- package/client/dist/assets/QueueOptionsButton-1M7MdKzM.js +1 -0
- package/client/dist/assets/{QueueRail-B7f1-e6i.js → QueueRail-Bpla2xD8.js} +1 -1
- package/client/dist/assets/Radio-DlmTC-qG.js +1 -0
- package/client/dist/assets/{ReadingList-BaIem8H1.js → ReadingList-wJMDUybm.js} +1 -1
- package/client/dist/assets/{ResetProgressModal-DES5Y-Fl.js → ResetProgressModal-CByRM1Fh.js} +1 -1
- package/client/dist/assets/Search-B94D0tRM.js +1 -0
- package/client/dist/assets/Settings-CcU3oNY8.js +21 -0
- package/client/dist/assets/{SkeletonGrid-BxfgjP4i.js → SkeletonGrid-BJyZkg_K.js} +1 -1
- package/client/dist/assets/Trackers-vz-gqxtm.js +2 -0
- package/client/dist/assets/Tv-Rji_lvQo.js +4 -0
- package/client/dist/assets/Tv-ZEA45gXK.css +1 -0
- package/client/dist/assets/TvInfo-Ciujd6os.js +1 -0
- package/client/dist/assets/TvPopup-CqlVRF-Y.js +1 -0
- package/client/dist/assets/{TvSearch-BWDwWnHe.js → TvSearch-BcKXQue9.js} +1 -1
- package/client/dist/assets/{TvWatchlist-D3n5_4MI.js → TvWatchlist-sjsiup2h.js} +1 -1
- package/client/dist/assets/Watchlist-DAMdvt7Z.js +1 -0
- package/client/dist/assets/{hls-BO_L1WoN.js → hls-Do_n10_Y.js} +1 -1
- package/client/dist/assets/index-B5SLDCAi.js +178 -0
- package/client/dist/assets/useAnimeInfoData-DU9X90no.js +1 -0
- package/client/dist/assets/useAsmr-D6cSjbvt.js +1 -0
- package/client/dist/assets/{useAsmrPopup-D_o9-QlR.js → useAsmrPopup-DK1Vx-HV.js} +1 -1
- package/client/dist/assets/useMangaLibrary-DcxPn0RM.js +1 -0
- package/client/dist/assets/{useMangaPopup-TFzkC-tG.js → useMangaPopup-BLwvRZn0.js} +1 -1
- package/client/dist/assets/useProviders-D3L1Chqc.js +1 -0
- package/client/dist/assets/useTv-B546u-Rx.js +1 -0
- package/client/dist/assets/useTvLibrary-C2rPeCVT.js +1 -0
- package/client/dist/assets/{vendor-query-BXRECSI6.js → vendor-query-BUTye89G.js} +1 -1
- package/client/dist/index.html +2 -2
- package/orchestrator.js +1 -2
- package/package.json +6 -6
- package/server/dist/app-auth.js +9 -29
- package/server/dist/app-hono.js +621 -0
- package/server/dist/config.js +0 -1
- package/server/dist/db/drizzle.js +32 -0
- package/server/dist/db/schema-anime.js +64 -0
- package/server/dist/db/schema-asmr.js +25 -0
- package/server/dist/db/schema-manga.js +31 -0
- package/server/dist/db/schema-tv.js +33 -0
- package/server/dist/db.js +75 -4
- package/server/dist/discord-gateway.js +1 -1
- package/server/dist/google.js +0 -7
- package/server/dist/hono/asmr.js +1 -0
- package/server/dist/hono/auth.js +56 -0
- package/server/dist/hono/music.js +419 -0
- package/server/dist/{controllers/proxy.controller.js → hono/proxy.js} +390 -394
- package/server/dist/hono/tv.js +197 -0
- package/server/dist/hono/watchlist.js +733 -0
- package/server/dist/lib/anilist.js +3 -3
- package/server/dist/lib/insights.js +185 -0
- package/server/dist/lib/ipc.js +1 -2
- package/server/dist/lib/kitsu.js +1 -28
- package/server/dist/lib/mal-import.js +291 -0
- package/server/dist/lib/migration.js +20 -34
- package/server/dist/lib/offline-db.js +36 -36
- package/server/dist/lib/tracker/manga-sync.service.js +21 -21
- package/server/dist/lib/tracker/sync.service.js +20 -20
- package/server/dist/lib/translate.js +79 -0
- package/server/dist/lib/ytmusic.js +0 -2
- package/server/dist/providers/title-matching.js +0 -1
- package/server/dist/repositories/asmr.repository.js +90 -87
- package/server/dist/repositories/insights.repository.js +24 -13
- package/server/dist/repositories/library.repository.js +33 -93
- package/server/dist/repositories/manga.repository.js +108 -116
- package/server/dist/repositories/notifications.repository.js +50 -31
- package/server/dist/repositories/queue.repository.js +36 -25
- package/server/dist/repositories/settings.repository.js +18 -8
- package/server/dist/repositories/shows-meta.repository.js +54 -41
- package/server/dist/repositories/temp-show-ids.repository.js +43 -31
- package/server/dist/repositories/tv.repository.js +98 -115
- package/server/dist/repositories/watched-episodes.repository.js +52 -20
- package/server/dist/repositories/watchlist.repository.js +36 -48
- package/server/dist/server.js +59 -151
- package/server/dist/sync.js +41 -4
- package/server/dist/trpc/context.js +7 -0
- package/server/dist/trpc/errors.js +21 -0
- package/server/dist/trpc/index.js +19 -0
- package/server/dist/trpc/router.js +49 -0
- package/server/dist/trpc/routers/asmr-library.js +122 -0
- package/server/dist/trpc/routers/asmr-progress.js +133 -0
- package/server/dist/trpc/routers/asmr.js +87 -0
- package/server/dist/trpc/routers/auth.js +247 -0
- package/server/dist/trpc/routers/continue-watching.js +83 -0
- package/server/dist/trpc/routers/data.js +1039 -0
- package/server/dist/trpc/routers/discord.js +288 -0
- package/server/dist/trpc/routers/discovery.js +15 -0
- package/server/dist/trpc/routers/insights.js +45 -0
- package/server/dist/trpc/routers/manga-library.js +280 -0
- package/server/dist/trpc/routers/manga-progress.js +181 -0
- package/server/dist/trpc/routers/manga.js +201 -0
- package/server/dist/{controllers/music.controller.js → trpc/routers/music.js} +155 -288
- package/server/dist/trpc/routers/notifications.js +80 -0
- package/server/dist/trpc/routers/progress.js +15 -0
- package/server/dist/trpc/routers/queue.js +95 -0
- package/server/dist/{routes/radio.routes.js → trpc/routers/radio.js} +30 -23
- package/server/dist/trpc/routers/settings.js +105 -0
- package/server/dist/trpc/routers/tracker.js +219 -0
- package/server/dist/trpc/routers/tv-library.js +145 -0
- package/server/dist/trpc/routers/tv-progress.js +171 -0
- package/server/dist/trpc/routers/tv.js +565 -0
- package/server/dist/trpc/routers/watchlist.js +564 -0
- package/server/dist/trpc/validation.js +159 -0
- package/server/dist/utils/security.utils.js +0 -18
- package/server/package.json +5 -10
- package/client/dist/assets/Asmr-C28TfSvX.js +0 -2
- package/client/dist/assets/AsmrResetProgressModal-6Xh71AgR.js +0 -1
- package/client/dist/assets/AvSyncCalibrator-BwCtRW0P.js +0 -10
- package/client/dist/assets/Home-BJdbHYja.js +0 -1
- package/client/dist/assets/Insights-CjRy42YE.js +0 -1
- package/client/dist/assets/MangaReadPage-YCETZRte.js +0 -1
- package/client/dist/assets/Mature-BGxRWkV5.js +0 -1
- package/client/dist/assets/MediaCard-CAzoxsRS.js +0 -1
- package/client/dist/assets/Music-Cgo-yQ7E.js +0 -1
- package/client/dist/assets/OptionListMenu--Owe9Jle.js +0 -1
- package/client/dist/assets/Player-yRXG2BrP.js +0 -56
- package/client/dist/assets/PlayerSettings-DrZLa0CC.js +0 -1
- package/client/dist/assets/QueueOptionsButton-BVZyPyKf.js +0 -1
- package/client/dist/assets/Radio-BFjxlzuF.js +0 -1
- package/client/dist/assets/Search-BOBo0Ogh.js +0 -1
- package/client/dist/assets/Settings-DOvNQ0gX.js +0 -21
- package/client/dist/assets/Trackers-DZ9KqOWv.js +0 -2
- package/client/dist/assets/Tv-5mATEU4p.js +0 -4
- package/client/dist/assets/Tv-C2SWcVzN.css +0 -1
- package/client/dist/assets/TvInfo-CF-5C5Fs.js +0 -1
- package/client/dist/assets/TvPopup-Dfqifj3s.js +0 -1
- package/client/dist/assets/Watchlist-B8MHNsAU.js +0 -1
- package/client/dist/assets/index-D2RkUJIN.js +0 -178
- package/client/dist/assets/useAnimeInfoData-BWShDHqE.js +0 -1
- package/client/dist/assets/useAsmr-FyfD9G7b.js +0 -1
- package/client/dist/assets/useMangaLibrary-BJU5x8Vz.js +0 -1
- package/client/dist/assets/useProviders-DDRxa8vl.js +0 -1
- package/client/dist/assets/useTv-Bh6WmNnZ.js +0 -1
- package/client/dist/assets/useTvLibrary-_Pqm8re1.js +0 -1
- package/server/dist/controllers/asmr-library.controller.js +0 -288
- package/server/dist/controllers/auth.controller.js +0 -225
- package/server/dist/controllers/data.controller.js +0 -767
- package/server/dist/controllers/insights.controller.js +0 -203
- package/server/dist/controllers/manga-library.controller.js +0 -350
- package/server/dist/controllers/settings.controller.js +0 -609
- package/server/dist/controllers/tv-library.controller.js +0 -314
- package/server/dist/controllers/watchlist.controller.js +0 -1069
- package/server/dist/request-logger.js +0 -16
- package/server/dist/routes/asmr-library.routes.js +0 -23
- package/server/dist/routes/asmr.routes.js +0 -81
- package/server/dist/routes/auth.routes.js +0 -25
- package/server/dist/routes/data.routes.js +0 -47
- package/server/dist/routes/discord-gateway.routes.js +0 -51
- package/server/dist/routes/insights.routes.js +0 -35
- package/server/dist/routes/lan-auth.routes.js +0 -46
- package/server/dist/routes/manga-library.routes.js +0 -25
- package/server/dist/routes/manga.routes.js +0 -141
- package/server/dist/routes/music.routes.js +0 -20
- package/server/dist/routes/providers.routes.js +0 -17
- package/server/dist/routes/proxy.routes.js +0 -12
- package/server/dist/routes/settings.routes.js +0 -24
- package/server/dist/routes/tracker.routes.js +0 -287
- package/server/dist/routes/translate.routes.js +0 -88
- package/server/dist/routes/tv-library.routes.js +0 -23
- package/server/dist/routes/tv.routes.js +0 -629
- package/server/dist/routes/watchlist.routes.js +0 -341
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { eq, inArray, sql } from 'drizzle-orm';
|
|
2
|
+
import { getDrizzle } from '../db/drizzle.js';
|
|
3
|
+
import { asmrLibrary, asmrProgress } from '../db/schema-asmr.js';
|
|
2
4
|
export const ASMR_STATUSES = [
|
|
3
5
|
'Listening',
|
|
4
6
|
'Completed',
|
|
@@ -10,114 +12,115 @@ export function buildAsmrId(rjCode) {
|
|
|
10
12
|
return String(rjCode).trim().toUpperCase();
|
|
11
13
|
}
|
|
12
14
|
export const AsmrLibraryRepository = {
|
|
13
|
-
getById: (db, id) =>
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
getById: async (db, id) => {
|
|
16
|
+
const rows = await getDrizzle(db).all(sql `SELECT * FROM asmr_library WHERE id = ${id}`);
|
|
17
|
+
return rows[0];
|
|
18
|
+
},
|
|
19
|
+
exists: async (db, id) => {
|
|
20
|
+
const rows = await getDrizzle(db).all(sql `SELECT EXISTS(SELECT 1 FROM asmr_library WHERE id = ${id}) as inLibrary`);
|
|
21
|
+
return !!(rows[0] && rows[0].inLibrary);
|
|
17
22
|
},
|
|
18
23
|
getAll: (db, status, limit, offset) => {
|
|
19
|
-
|
|
20
|
-
const params = [];
|
|
24
|
+
const q = sql `SELECT * FROM asmr_library`;
|
|
21
25
|
if (status && status !== 'All') {
|
|
22
|
-
|
|
23
|
-
params.push(status);
|
|
26
|
+
q.append(sql ` WHERE status = ${status}`);
|
|
24
27
|
}
|
|
25
|
-
|
|
28
|
+
q.append(sql ` ORDER BY updatedAt DESC`);
|
|
26
29
|
if (limit !== undefined && offset !== undefined) {
|
|
27
|
-
|
|
28
|
-
params.push(limit, offset);
|
|
30
|
+
q.append(sql ` LIMIT ${limit} OFFSET ${offset}`);
|
|
29
31
|
}
|
|
30
|
-
return
|
|
32
|
+
return getDrizzle(db).all(q);
|
|
31
33
|
},
|
|
32
|
-
getCount: (db, status) => {
|
|
33
|
-
let query = 'SELECT COUNT(*) as total FROM asmr_library';
|
|
34
|
-
const params = [];
|
|
34
|
+
getCount: async (db, status) => {
|
|
35
35
|
if (status && status !== 'All') {
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
const rows = await getDrizzle(db).all(sql `SELECT COUNT(*) as total FROM asmr_library WHERE status = ${status}`);
|
|
37
|
+
return rows[0]?.total || 0;
|
|
38
38
|
}
|
|
39
|
-
const
|
|
40
|
-
return
|
|
39
|
+
const rows = await getDrizzle(db).all(sql `SELECT COUNT(*) as total FROM asmr_library`);
|
|
40
|
+
return rows[0]?.total || 0;
|
|
41
|
+
},
|
|
42
|
+
getIds: async (db) => {
|
|
43
|
+
const rows = await getDrizzle(db).all(sql `SELECT id FROM asmr_library`);
|
|
44
|
+
return rows.map((r) => r.id);
|
|
41
45
|
},
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
updateStatus: (db, id, status) =>
|
|
46
|
+
upsert: (db, data) => getDrizzle(db).run(sql `
|
|
47
|
+
INSERT INTO asmr_library (id, rjCode, title, thumbnail, status, isAdult, updatedAt)
|
|
48
|
+
VALUES (${data.id}, ${data.rjCode}, ${data.title}, ${data.thumbnail}, ${data.status}, ${data.isAdult ? 1 : 0}, strftime('%s', 'now'))
|
|
49
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
50
|
+
rjCode = COALESCE(NULLIF(EXCLUDED.rjCode, ''), asmr_library.rjCode),
|
|
51
|
+
title = COALESCE(NULLIF(EXCLUDED.title, ''), asmr_library.title),
|
|
52
|
+
thumbnail = COALESCE(NULLIF(EXCLUDED.thumbnail, ''), asmr_library.thumbnail),
|
|
53
|
+
status = COALESCE(NULLIF(EXCLUDED.status, ''), asmr_library.status),
|
|
54
|
+
isAdult = COALESCE(EXCLUDED.isAdult, asmr_library.isAdult),
|
|
55
|
+
updatedAt = strftime('%s', 'now')`),
|
|
56
|
+
updateStatus: (db, id, status) => getDrizzle(db).run(sql `
|
|
57
|
+
UPDATE asmr_library SET status = ${status}, updatedAt = strftime('%s', 'now') WHERE id = ${id}`),
|
|
53
58
|
updateStatusMany: (db, ids, status) => {
|
|
54
59
|
if (ids.length === 0)
|
|
55
|
-
return;
|
|
56
|
-
|
|
57
|
-
|
|
60
|
+
return Promise.resolve();
|
|
61
|
+
return getDrizzle(db).run(sql `
|
|
62
|
+
UPDATE asmr_library SET status = ${status}, updatedAt = strftime('%s', 'now') WHERE id IN (${sql.join(ids.map((id) => sql `${id}`), sql `, `)})`);
|
|
58
63
|
},
|
|
59
|
-
touchProgress: (db, id, progress) =>
|
|
60
|
-
|
|
64
|
+
touchProgress: (db, id, progress) => getDrizzle(db).run(sql `
|
|
65
|
+
UPDATE asmr_library SET lastTrackIndex = ${progress.trackIndex}, lastTrackLabel = ${progress.trackLabel}, lastPosition = ${progress.position}, updatedAt = strftime('%s', 'now') WHERE id = ${id}`),
|
|
66
|
+
delete: (db, id) => getDrizzle(db).delete(asmrLibrary).where(eq(asmrLibrary.id, id)),
|
|
61
67
|
deleteMany: (db, ids) => {
|
|
62
68
|
if (ids.length === 0)
|
|
63
|
-
return;
|
|
64
|
-
|
|
65
|
-
dbRun(db, `DELETE FROM asmr_library WHERE id IN (${placeholders})`, ids);
|
|
69
|
+
return Promise.resolve();
|
|
70
|
+
return getDrizzle(db).delete(asmrLibrary).where(inArray(asmrLibrary.id, ids));
|
|
66
71
|
},
|
|
67
72
|
};
|
|
68
73
|
export const AsmrProgressRepository = {
|
|
69
|
-
getByWork: (db, workId) =>
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
deleteByWork: (db, workId) =>
|
|
74
|
+
getByWork: (db, workId) => getDrizzle(db).all(sql `
|
|
75
|
+
SELECT workId, trackIndex, trackLabel, currentTime, duration, updatedAt FROM asmr_progress WHERE workId = ${workId} ORDER BY updatedAt DESC`),
|
|
76
|
+
getTrack: async (db, workId, trackIndex) => {
|
|
77
|
+
const rows = await getDrizzle(db).all(sql `
|
|
78
|
+
SELECT workId, trackIndex, trackLabel, currentTime, duration, updatedAt FROM asmr_progress WHERE workId = ${workId} AND trackIndex = ${trackIndex}`);
|
|
79
|
+
return rows[0];
|
|
80
|
+
},
|
|
81
|
+
getLatest: async (db, workId) => {
|
|
82
|
+
const rows = await getDrizzle(db).all(sql `
|
|
83
|
+
SELECT workId, trackIndex, trackLabel, currentTime, duration, updatedAt FROM asmr_progress WHERE workId = ${workId} ORDER BY updatedAt DESC LIMIT 1`);
|
|
84
|
+
return rows[0];
|
|
85
|
+
},
|
|
86
|
+
upsert: (db, data) => getDrizzle(db).run(sql `
|
|
87
|
+
INSERT INTO asmr_progress (workId, trackIndex, trackLabel, currentTime, duration, title, thumbnail, rjCode, isAdult, updatedAt)
|
|
88
|
+
VALUES (${data.workId}, ${data.trackIndex}, ${data.trackLabel}, ${data.currentTime}, ${data.duration}, ${data.title ?? null}, ${data.thumbnail ?? null}, ${data.rjCode ?? null}, ${data.isAdult ?? null}, strftime('%s', 'now'))
|
|
89
|
+
ON CONFLICT(workId, trackIndex) DO UPDATE SET
|
|
90
|
+
trackLabel = COALESCE(NULLIF(EXCLUDED.trackLabel, ''), asmr_progress.trackLabel),
|
|
91
|
+
currentTime = EXCLUDED.currentTime,
|
|
92
|
+
duration = EXCLUDED.duration,
|
|
93
|
+
title = COALESCE(EXCLUDED.title, asmr_progress.title),
|
|
94
|
+
thumbnail = COALESCE(EXCLUDED.thumbnail, asmr_progress.thumbnail),
|
|
95
|
+
rjCode = COALESCE(EXCLUDED.rjCode, asmr_progress.rjCode),
|
|
96
|
+
isAdult = COALESCE(EXCLUDED.isAdult, asmr_progress.isAdult),
|
|
97
|
+
updatedAt = strftime('%s', 'now')`),
|
|
98
|
+
deleteByWork: (db, workId) => getDrizzle(db).delete(asmrProgress).where(eq(asmrProgress.workId, workId)),
|
|
94
99
|
deleteMany: (db, ids) => {
|
|
95
100
|
if (ids.length === 0)
|
|
96
|
-
return;
|
|
97
|
-
|
|
98
|
-
dbRun(db, `DELETE FROM asmr_progress WHERE workId IN (${placeholders})`, ids);
|
|
101
|
+
return Promise.resolve();
|
|
102
|
+
return getDrizzle(db).delete(asmrProgress).where(inArray(asmrProgress.workId, ids));
|
|
99
103
|
},
|
|
100
|
-
deleteTrack: (db, workId, trackIndex) =>
|
|
101
|
-
|
|
102
|
-
trackIndex,
|
|
103
|
-
]),
|
|
104
|
+
deleteTrack: (db, workId, trackIndex) => getDrizzle(db).run(sql `
|
|
105
|
+
DELETE FROM asmr_progress WHERE workId = ${workId} AND trackIndex = ${trackIndex}`),
|
|
104
106
|
getContinueListening: (db, limit) => {
|
|
105
107
|
const limitClause = typeof limit === 'number' ? `LIMIT ${limit}` : '';
|
|
106
|
-
return
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
108
|
+
return getDrizzle(db).all(sql `
|
|
109
|
+
SELECT p.workId as id,
|
|
110
|
+
COALESCE(l.rjCode, p.rjCode, p.workId) as rjCode,
|
|
111
|
+
COALESCE(l.title, p.title) as title,
|
|
112
|
+
COALESCE(l.thumbnail, p.thumbnail) as thumbnail,
|
|
113
|
+
COALESCE(l.isAdult, p.isAdult) as isAdult,
|
|
114
|
+
l.status as watchlistStatus,
|
|
115
|
+
p.trackIndex, p.trackLabel, p.currentTime, p.duration, p.updatedAt as progressAt
|
|
116
|
+
FROM (
|
|
117
|
+
SELECT *, ROW_NUMBER() OVER (PARTITION BY workId ORDER BY updatedAt DESC) as rn
|
|
118
|
+
FROM asmr_progress
|
|
119
|
+
) p
|
|
120
|
+
LEFT JOIN asmr_library l ON p.workId = l.id
|
|
121
|
+
WHERE p.rn = 1
|
|
122
|
+
AND (l.status IS NULL OR l.status = 'Listening')
|
|
123
|
+
ORDER BY p.updatedAt DESC
|
|
124
|
+
${sql.raw(limitClause)}`);
|
|
122
125
|
},
|
|
123
126
|
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { sql } from 'drizzle-orm';
|
|
2
|
+
import { getDrizzle } from '../db/drizzle.js';
|
|
2
3
|
export const InsightsRepository = {
|
|
3
|
-
getCoreStats: (db) =>
|
|
4
|
+
getCoreStats: async (db) => (await getDrizzle(db).all(sql `
|
|
5
|
+
SELECT
|
|
4
6
|
(SELECT SUM(
|
|
5
7
|
CASE WHEN we.currentTime > 0 THEN we.currentTime
|
|
6
8
|
WHEN we.currentTime = 0 AND we.duration = 0 THEN
|
|
@@ -16,10 +18,13 @@ export const InsightsRepository = {
|
|
|
16
18
|
(SELECT COUNT(*) FROM watched_episodes) as totalEpisodes,
|
|
17
19
|
(SELECT COUNT(DISTINCT showId) FROM watched_episodes) as totalAnime,
|
|
18
20
|
(SELECT COUNT(*) FROM watchlist WHERE status = 'Completed') as completedCount,
|
|
19
|
-
(SELECT COUNT(*) FROM watchlist) as totalWatchlist`),
|
|
20
|
-
getActivityGrid: (db) =>
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
(SELECT COUNT(*) FROM watchlist) as totalWatchlist`))[0],
|
|
22
|
+
getActivityGrid: (db) => getDrizzle(db).all(sql `
|
|
23
|
+
SELECT date(watchedAt) as day, COUNT(*) as count FROM watched_episodes WHERE NOT (currentTime = 0 AND duration = 0) GROUP BY day`),
|
|
24
|
+
getHourlyDist: (db) => getDrizzle(db).all(sql `
|
|
25
|
+
SELECT strftime('%H', watchedAt) as hour, COUNT(*) as count FROM watched_episodes WHERE NOT (currentTime = 0 AND duration = 0) GROUP BY hour`),
|
|
26
|
+
getSeasonality: (db) => getDrizzle(db).all(sql `
|
|
27
|
+
SELECT strftime('%m', we.watchedAt) as month, SUM(
|
|
23
28
|
CASE WHEN we.currentTime > 0 THEN we.currentTime
|
|
24
29
|
WHEN we.currentTime = 0 AND we.duration = 0 THEN
|
|
25
30
|
COALESCE(sm.episodeDuration * 60,
|
|
@@ -32,7 +37,8 @@ export const InsightsRepository = {
|
|
|
32
37
|
FROM watched_episodes we
|
|
33
38
|
LEFT JOIN shows_meta sm ON sm.id = we.showId
|
|
34
39
|
GROUP BY month`),
|
|
35
|
-
getAllWatches: (db) =>
|
|
40
|
+
getAllWatches: (db) => getDrizzle(db).all(sql `
|
|
41
|
+
SELECT we.watchedAt, we.currentTime,
|
|
36
42
|
CASE WHEN we.currentTime > 0 THEN we.currentTime
|
|
37
43
|
WHEN we.currentTime = 0 AND we.duration = 0 THEN
|
|
38
44
|
COALESCE(sm.episodeDuration * 60,
|
|
@@ -45,23 +51,27 @@ export const InsightsRepository = {
|
|
|
45
51
|
FROM watched_episodes we
|
|
46
52
|
LEFT JOIN shows_meta sm ON sm.id = we.showId
|
|
47
53
|
ORDER BY we.watchedAt ASC`),
|
|
48
|
-
getWatchedShowsMeta: (db) =>
|
|
54
|
+
getWatchedShowsMeta: (db) => getDrizzle(db).all(sql `
|
|
55
|
+
SELECT DISTINCT sm.id, sm.genres, sm.popularityScore
|
|
49
56
|
FROM shows_meta sm
|
|
50
57
|
JOIN watched_episodes we ON sm.id = we.showId`),
|
|
51
|
-
getDroppedShows: (db) =>
|
|
58
|
+
getDroppedShows: (db) => getDrizzle(db).all(sql `
|
|
59
|
+
SELECT w.id, w.name, MAX(we.watchedAt) as lastActivity
|
|
52
60
|
FROM watchlist w
|
|
53
61
|
JOIN watched_episodes we ON w.id = we.showId
|
|
54
62
|
WHERE w.status = 'Watching' AND NOT (we.currentTime = 0 AND we.duration = 0)
|
|
55
63
|
GROUP BY w.id
|
|
56
64
|
HAVING lastActivity < date('now', '-90 days')`),
|
|
57
|
-
getCompletionVelocities: (db) =>
|
|
65
|
+
getCompletionVelocities: (db) => getDrizzle(db).all(sql `
|
|
66
|
+
SELECT
|
|
58
67
|
(julianday(MAX(we.watchedAt)) - julianday(MIN(we.watchedAt))) as daysToFinish
|
|
59
68
|
FROM watchlist w
|
|
60
69
|
JOIN watched_episodes we ON w.id = we.showId
|
|
61
70
|
WHERE w.status = 'Completed'
|
|
62
71
|
GROUP BY w.id
|
|
63
72
|
HAVING SUM(we.currentTime) > 0`),
|
|
64
|
-
getWatchedEpisodesWithMeta: (db) =>
|
|
73
|
+
getWatchedEpisodesWithMeta: (db) => getDrizzle(db).all(sql `
|
|
74
|
+
SELECT
|
|
65
75
|
we.showId,
|
|
66
76
|
we.currentTime,
|
|
67
77
|
we.duration,
|
|
@@ -82,7 +92,8 @@ export const InsightsRepository = {
|
|
|
82
92
|
sm.thumbnail
|
|
83
93
|
FROM watched_episodes we
|
|
84
94
|
JOIN shows_meta sm ON we.showId = sm.id`),
|
|
85
|
-
getLibraryShowsWithGenres: (db) =>
|
|
95
|
+
getLibraryShowsWithGenres: (db) => getDrizzle(db).all(sql `
|
|
96
|
+
SELECT
|
|
86
97
|
w.id,
|
|
87
98
|
w.status,
|
|
88
99
|
COALESCE(NULLIF(sm.englishName, ''), sm.name, w.name) as title,
|
|
@@ -91,5 +102,5 @@ export const InsightsRepository = {
|
|
|
91
102
|
COALESCE(sm.popularityScore, 0) as popularityScore
|
|
92
103
|
FROM watchlist w
|
|
93
104
|
LEFT JOIN shows_meta sm ON sm.id = w.id`),
|
|
94
|
-
getAllAnilistIds: (db) =>
|
|
105
|
+
getAllAnilistIds: (db) => getDrizzle(db).all(sql `SELECT anilistId FROM shows_meta WHERE anilistId IS NOT NULL`),
|
|
95
106
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { sql } from 'drizzle-orm';
|
|
2
|
+
import { getDrizzle } from '../db/drizzle.js';
|
|
2
3
|
const LIBRARY_TABLES = [
|
|
3
4
|
'watchlist',
|
|
4
5
|
'watched_episodes',
|
|
@@ -12,97 +13,36 @@ const LIBRARY_TABLES = [
|
|
|
12
13
|
const MANGA_LIBRARY_TABLES = ['manga_library', 'manga_progress'];
|
|
13
14
|
const TV_LIBRARY_TABLES = ['tv_library', 'tv_progress'];
|
|
14
15
|
const ASMR_LIBRARY_TABLES = ['asmr_library', 'asmr_progress'];
|
|
16
|
+
async function countTables(db, tables) {
|
|
17
|
+
const counts = {};
|
|
18
|
+
for (const table of tables) {
|
|
19
|
+
try {
|
|
20
|
+
const rows = await getDrizzle(db).all(sql `SELECT COUNT(*) AS rows FROM ${sql.raw(`"${table}"`)}`);
|
|
21
|
+
counts[table] = rows[0]?.rows ?? 0;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
counts[table] = 0;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return counts;
|
|
28
|
+
}
|
|
29
|
+
async function clearTables(db, tables) {
|
|
30
|
+
for (const table of tables) {
|
|
31
|
+
try {
|
|
32
|
+
await getDrizzle(db).run(sql `DELETE FROM ${sql.raw(`"${table}"`)}`);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// ignore
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
15
39
|
export const LibraryRepository = {
|
|
16
|
-
countAll: (db) =>
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
counts[table] = 0;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
return counts;
|
|
28
|
-
},
|
|
29
|
-
clearAll: (db) => {
|
|
30
|
-
for (const table of LIBRARY_TABLES) {
|
|
31
|
-
try {
|
|
32
|
-
dbRun(db, `DELETE FROM "${table}"`);
|
|
33
|
-
}
|
|
34
|
-
catch {
|
|
35
|
-
// ignore
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
countManga: (db) => {
|
|
40
|
-
const counts = {};
|
|
41
|
-
for (const table of MANGA_LIBRARY_TABLES) {
|
|
42
|
-
try {
|
|
43
|
-
counts[table] =
|
|
44
|
-
dbGet(db, `SELECT COUNT(*) AS rows FROM "${table}"`)?.rows ?? 0;
|
|
45
|
-
}
|
|
46
|
-
catch {
|
|
47
|
-
counts[table] = 0;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
return counts;
|
|
51
|
-
},
|
|
52
|
-
clearManga: (db) => {
|
|
53
|
-
for (const table of MANGA_LIBRARY_TABLES) {
|
|
54
|
-
try {
|
|
55
|
-
dbRun(db, `DELETE FROM "${table}"`);
|
|
56
|
-
}
|
|
57
|
-
catch {
|
|
58
|
-
// ignore
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
},
|
|
62
|
-
countTv: (db) => {
|
|
63
|
-
const counts = {};
|
|
64
|
-
for (const table of TV_LIBRARY_TABLES) {
|
|
65
|
-
try {
|
|
66
|
-
counts[table] =
|
|
67
|
-
dbGet(db, `SELECT COUNT(*) AS rows FROM "${table}"`)?.rows ?? 0;
|
|
68
|
-
}
|
|
69
|
-
catch {
|
|
70
|
-
counts[table] = 0;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
return counts;
|
|
74
|
-
},
|
|
75
|
-
clearTv: (db) => {
|
|
76
|
-
for (const table of TV_LIBRARY_TABLES) {
|
|
77
|
-
try {
|
|
78
|
-
dbRun(db, `DELETE FROM "${table}"`);
|
|
79
|
-
}
|
|
80
|
-
catch {
|
|
81
|
-
// ignore
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
},
|
|
85
|
-
countAsmr: (db) => {
|
|
86
|
-
const counts = {};
|
|
87
|
-
for (const table of ASMR_LIBRARY_TABLES) {
|
|
88
|
-
try {
|
|
89
|
-
counts[table] =
|
|
90
|
-
dbGet(db, `SELECT COUNT(*) AS rows FROM "${table}"`)?.rows ?? 0;
|
|
91
|
-
}
|
|
92
|
-
catch {
|
|
93
|
-
counts[table] = 0;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
return counts;
|
|
97
|
-
},
|
|
98
|
-
clearAsmr: (db) => {
|
|
99
|
-
for (const table of ASMR_LIBRARY_TABLES) {
|
|
100
|
-
try {
|
|
101
|
-
dbRun(db, `DELETE FROM "${table}"`);
|
|
102
|
-
}
|
|
103
|
-
catch {
|
|
104
|
-
// ignore
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
},
|
|
40
|
+
countAll: (db) => countTables(db, LIBRARY_TABLES),
|
|
41
|
+
clearAll: (db) => clearTables(db, LIBRARY_TABLES),
|
|
42
|
+
countManga: (db) => countTables(db, MANGA_LIBRARY_TABLES),
|
|
43
|
+
clearManga: (db) => clearTables(db, MANGA_LIBRARY_TABLES),
|
|
44
|
+
countTv: (db) => countTables(db, TV_LIBRARY_TABLES),
|
|
45
|
+
clearTv: (db) => clearTables(db, TV_LIBRARY_TABLES),
|
|
46
|
+
countAsmr: (db) => countTables(db, ASMR_LIBRARY_TABLES),
|
|
47
|
+
clearAsmr: (db) => clearTables(db, ASMR_LIBRARY_TABLES),
|
|
108
48
|
};
|