@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
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { integer, primaryKey, real, sqliteTable, text } from 'drizzle-orm/sqlite-core';
|
|
2
|
+
export const watchedEpisodes = sqliteTable('watched_episodes', {
|
|
3
|
+
showId: text('showId').notNull(),
|
|
4
|
+
episodeNumber: text('episodeNumber').notNull(),
|
|
5
|
+
watchedAt: text('watchedAt'),
|
|
6
|
+
currentTime: real('currentTime'),
|
|
7
|
+
duration: real('duration'),
|
|
8
|
+
}, (t) => [primaryKey({ columns: [t.showId, t.episodeNumber] })]);
|
|
9
|
+
export const watchlist = sqliteTable('watchlist', {
|
|
10
|
+
id: text('id').notNull(),
|
|
11
|
+
name: text('name'),
|
|
12
|
+
thumbnail: text('thumbnail'),
|
|
13
|
+
status: text('status'),
|
|
14
|
+
nativeName: text('nativeName'),
|
|
15
|
+
englishName: text('englishName'),
|
|
16
|
+
type: text('type'),
|
|
17
|
+
}, (t) => [primaryKey({ columns: [t.id] })]);
|
|
18
|
+
export const showsMeta = sqliteTable('shows_meta', {
|
|
19
|
+
id: text('id').notNull(),
|
|
20
|
+
name: text('name'),
|
|
21
|
+
thumbnail: text('thumbnail'),
|
|
22
|
+
nativeName: text('nativeName'),
|
|
23
|
+
englishName: text('englishName'),
|
|
24
|
+
episodeCount: integer('episodeCount'),
|
|
25
|
+
status: text('status'),
|
|
26
|
+
genres: text('genres'),
|
|
27
|
+
popularityScore: integer('popularityScore'),
|
|
28
|
+
type: text('type'),
|
|
29
|
+
anilistId: integer('anilistId'),
|
|
30
|
+
isAdult: integer('isAdult'),
|
|
31
|
+
episodeDuration: integer('episodeDuration'),
|
|
32
|
+
}, (t) => [primaryKey({ columns: [t.id] })]);
|
|
33
|
+
export const settings = sqliteTable('settings', {
|
|
34
|
+
key: text('key').notNull(),
|
|
35
|
+
value: text('value'),
|
|
36
|
+
}, (t) => [primaryKey({ columns: [t.key] })]);
|
|
37
|
+
export const queue = sqliteTable('queue', {
|
|
38
|
+
id: integer('id'),
|
|
39
|
+
showId: text('showId').notNull(),
|
|
40
|
+
episodeNumber: text('episodeNumber').notNull(),
|
|
41
|
+
queueOrder: integer('queue_order').notNull(),
|
|
42
|
+
});
|
|
43
|
+
export const discoveredNotifications = sqliteTable('discovered_notifications', {
|
|
44
|
+
showId: text('showId').notNull(),
|
|
45
|
+
episodeNumber: text('episodeNumber').notNull(),
|
|
46
|
+
discoveredAt: text('discoveredAt'),
|
|
47
|
+
}, (t) => [primaryKey({ columns: [t.showId, t.episodeNumber] })]);
|
|
48
|
+
export const dismissedNotifications = sqliteTable('dismissed_notifications', {
|
|
49
|
+
showId: text('showId').notNull(),
|
|
50
|
+
episodeNumber: text('episodeNumber').notNull(),
|
|
51
|
+
dismissedAt: text('dismissedAt'),
|
|
52
|
+
}, (t) => [primaryKey({ columns: [t.showId, t.episodeNumber] })]);
|
|
53
|
+
export const tempShowIds = sqliteTable('temp_show_ids', {
|
|
54
|
+
id: text('id').notNull(),
|
|
55
|
+
provider: text('provider').notNull(),
|
|
56
|
+
nativeId: text('nativeId').notNull(),
|
|
57
|
+
title: text('title').notNull(),
|
|
58
|
+
thumbnail: text('thumbnail'),
|
|
59
|
+
createdAt: integer('createdAt').notNull(),
|
|
60
|
+
}, (t) => [primaryKey({ columns: [t.id] })]);
|
|
61
|
+
export const legacyIdMapping = sqliteTable('legacy_id_mapping', {
|
|
62
|
+
legacyId: text('legacyId').notNull(),
|
|
63
|
+
numericId: text('numericId'),
|
|
64
|
+
}, (t) => [primaryKey({ columns: [t.legacyId] })]);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { integer, primaryKey, real, sqliteTable, text } from 'drizzle-orm/sqlite-core';
|
|
2
|
+
export const asmrLibrary = sqliteTable('asmr_library', {
|
|
3
|
+
id: text('id').notNull(),
|
|
4
|
+
rjCode: text('rjCode').notNull(),
|
|
5
|
+
title: text('title'),
|
|
6
|
+
thumbnail: text('thumbnail'),
|
|
7
|
+
status: text('status'),
|
|
8
|
+
isAdult: integer('isAdult'),
|
|
9
|
+
lastTrackIndex: integer('lastTrackIndex'),
|
|
10
|
+
lastTrackLabel: text('lastTrackLabel'),
|
|
11
|
+
lastPosition: real('lastPosition'),
|
|
12
|
+
updatedAt: integer('updatedAt'),
|
|
13
|
+
}, (t) => [primaryKey({ columns: [t.id] })]);
|
|
14
|
+
export const asmrProgress = sqliteTable('asmr_progress', {
|
|
15
|
+
workId: text('workId').notNull(),
|
|
16
|
+
trackIndex: integer('trackIndex').notNull(),
|
|
17
|
+
trackLabel: text('trackLabel'),
|
|
18
|
+
currentTime: real('currentTime'),
|
|
19
|
+
duration: real('duration'),
|
|
20
|
+
updatedAt: integer('updatedAt'),
|
|
21
|
+
title: text('title'),
|
|
22
|
+
thumbnail: text('thumbnail'),
|
|
23
|
+
rjCode: text('rjCode'),
|
|
24
|
+
isAdult: integer('isAdult'),
|
|
25
|
+
}, (t) => [primaryKey({ columns: [t.workId, t.trackIndex] })]);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { integer, primaryKey, sqliteTable, text } from 'drizzle-orm/sqlite-core';
|
|
2
|
+
export const mangaLibrary = sqliteTable('manga_library', {
|
|
3
|
+
id: text('id').notNull(),
|
|
4
|
+
provider: text('provider').notNull(),
|
|
5
|
+
mangaId: text('mangaId').notNull(),
|
|
6
|
+
title: text('title'),
|
|
7
|
+
cover: text('cover'),
|
|
8
|
+
status: text('status'),
|
|
9
|
+
author: text('author'),
|
|
10
|
+
altTitle: text('altTitle'),
|
|
11
|
+
contentRating: text('contentRating'),
|
|
12
|
+
lastChapterId: text('lastChapterId'),
|
|
13
|
+
lastChapterNumber: text('lastChapterNumber'),
|
|
14
|
+
lastPage: integer('lastPage'),
|
|
15
|
+
updatedAt: integer('updatedAt'),
|
|
16
|
+
anilistId: integer('anilistId'),
|
|
17
|
+
anilistIdSource: text('anilistIdSource'),
|
|
18
|
+
}, (t) => [primaryKey({ columns: [t.id] })]);
|
|
19
|
+
export const mangaProgress = sqliteTable('manga_progress', {
|
|
20
|
+
mangaId: text('mangaId').notNull(),
|
|
21
|
+
chapterId: text('chapterId').notNull(),
|
|
22
|
+
chapterNumber: text('chapterNumber'),
|
|
23
|
+
page: integer('page'),
|
|
24
|
+
pageCount: integer('pageCount'),
|
|
25
|
+
updatedAt: integer('updatedAt'),
|
|
26
|
+
title: text('title'),
|
|
27
|
+
cover: text('cover'),
|
|
28
|
+
provider: text('provider'),
|
|
29
|
+
altTitle: text('altTitle'),
|
|
30
|
+
contentRating: text('contentRating'),
|
|
31
|
+
}, (t) => [primaryKey({ columns: [t.mangaId, t.chapterId] })]);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { integer, primaryKey, real, sqliteTable, text } from 'drizzle-orm/sqlite-core';
|
|
2
|
+
export const tvLibrary = sqliteTable('tv_library', {
|
|
3
|
+
id: text('id').notNull(),
|
|
4
|
+
tmdbId: integer('tmdbId').notNull(),
|
|
5
|
+
mediaType: text('mediaType').notNull(),
|
|
6
|
+
title: text('title'),
|
|
7
|
+
poster: text('poster'),
|
|
8
|
+
backdrop: text('backdrop'),
|
|
9
|
+
year: text('year'),
|
|
10
|
+
overview: text('overview'),
|
|
11
|
+
status: text('status'),
|
|
12
|
+
adult: integer('adult'),
|
|
13
|
+
lastSeason: integer('lastSeason'),
|
|
14
|
+
lastEpisode: integer('lastEpisode'),
|
|
15
|
+
updatedAt: integer('updatedAt'),
|
|
16
|
+
}, (t) => [primaryKey({ columns: [t.id] })]);
|
|
17
|
+
export const tvProgress = sqliteTable('tv_progress', {
|
|
18
|
+
mediaId: text('mediaId').notNull(),
|
|
19
|
+
season: integer('season').notNull(),
|
|
20
|
+
episode: integer('episode').notNull(),
|
|
21
|
+
currentTime: real('currentTime'),
|
|
22
|
+
duration: real('duration'),
|
|
23
|
+
updatedAt: integer('updatedAt'),
|
|
24
|
+
title: text('title'),
|
|
25
|
+
poster: text('poster'),
|
|
26
|
+
backdrop: text('backdrop'),
|
|
27
|
+
year: text('year'),
|
|
28
|
+
overview: text('overview'),
|
|
29
|
+
tmdbId: integer('tmdbId'),
|
|
30
|
+
mediaType: text('mediaType'),
|
|
31
|
+
adult: integer('adult'),
|
|
32
|
+
completed: integer('completed'),
|
|
33
|
+
}, (t) => [primaryKey({ columns: [t.mediaId, t.season, t.episode] })]);
|
package/server/dist/db.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
3
|
import fs from 'fs';
|
|
3
4
|
import path from 'path';
|
|
4
5
|
import logger from './logger.js';
|
|
6
|
+
const txOwner = new AsyncLocalStorage();
|
|
5
7
|
export class DatabaseWrapper {
|
|
6
8
|
db;
|
|
7
9
|
isClosed = false;
|
|
8
10
|
statementCache = new Map();
|
|
11
|
+
txDepth = 0;
|
|
12
|
+
txQueue = Promise.resolve();
|
|
9
13
|
constructor(_dbPath, db) {
|
|
10
14
|
this.db = db;
|
|
11
15
|
}
|
|
@@ -31,15 +35,82 @@ export class DatabaseWrapper {
|
|
|
31
35
|
}
|
|
32
36
|
}
|
|
33
37
|
serialize(cb) {
|
|
34
|
-
this.
|
|
38
|
+
const outer = this.txDepth === 0;
|
|
39
|
+
const level = this.txDepth;
|
|
40
|
+
this.run(outer ? 'BEGIN IMMEDIATE' : `SAVEPOINT dango_sp_${level}`);
|
|
41
|
+
this.txDepth = level + 1;
|
|
35
42
|
try {
|
|
36
|
-
cb
|
|
37
|
-
this.db.exec('COMMIT');
|
|
43
|
+
txOwner.run(this, cb);
|
|
38
44
|
}
|
|
39
45
|
catch (e) {
|
|
40
|
-
this.
|
|
46
|
+
this.txDepth = level;
|
|
47
|
+
try {
|
|
48
|
+
this.run(outer ? 'ROLLBACK' : `ROLLBACK TO SAVEPOINT dango_sp_${level}`);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// ignore
|
|
52
|
+
}
|
|
41
53
|
throw e;
|
|
42
54
|
}
|
|
55
|
+
this.txDepth = level;
|
|
56
|
+
this.run(outer ? 'COMMIT' : `RELEASE SAVEPOINT dango_sp_${level}`);
|
|
57
|
+
}
|
|
58
|
+
acquireTxQueue() {
|
|
59
|
+
const prev = this.txQueue;
|
|
60
|
+
let release;
|
|
61
|
+
const current = new Promise((res) => {
|
|
62
|
+
release = res;
|
|
63
|
+
});
|
|
64
|
+
this.txQueue = prev.then(() => current);
|
|
65
|
+
return prev.then(() => release);
|
|
66
|
+
}
|
|
67
|
+
async transact(fn) {
|
|
68
|
+
if (txOwner.getStore() === this) {
|
|
69
|
+
const level = this.txDepth;
|
|
70
|
+
this.run(`SAVEPOINT dango_sp_${level}`);
|
|
71
|
+
this.txDepth = level + 1;
|
|
72
|
+
try {
|
|
73
|
+
await fn(this);
|
|
74
|
+
}
|
|
75
|
+
catch (e) {
|
|
76
|
+
this.txDepth = level;
|
|
77
|
+
try {
|
|
78
|
+
this.run(`ROLLBACK TO SAVEPOINT dango_sp_${level}`);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// ignore
|
|
82
|
+
}
|
|
83
|
+
throw e;
|
|
84
|
+
}
|
|
85
|
+
this.txDepth = level;
|
|
86
|
+
this.run(`RELEASE SAVEPOINT dango_sp_${level}`);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const release = await this.acquireTxQueue();
|
|
90
|
+
try {
|
|
91
|
+
await txOwner.run(this, async () => {
|
|
92
|
+
this.run('BEGIN IMMEDIATE');
|
|
93
|
+
this.txDepth = 1;
|
|
94
|
+
try {
|
|
95
|
+
await fn(this);
|
|
96
|
+
}
|
|
97
|
+
catch (e) {
|
|
98
|
+
this.txDepth = 0;
|
|
99
|
+
try {
|
|
100
|
+
this.run('ROLLBACK');
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// ignore
|
|
104
|
+
}
|
|
105
|
+
throw e;
|
|
106
|
+
}
|
|
107
|
+
this.txDepth = 0;
|
|
108
|
+
this.run('COMMIT');
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
release();
|
|
113
|
+
}
|
|
43
114
|
}
|
|
44
115
|
close(cb) {
|
|
45
116
|
if (this.isClosed) {
|
package/server/dist/google.js
CHANGED
|
@@ -13,8 +13,6 @@ export class GoogleDriveService {
|
|
|
13
13
|
tokens = {};
|
|
14
14
|
folderIdCache = new Map();
|
|
15
15
|
constructor() {
|
|
16
|
-
// Client ID/secret now live in Cloudflare Worker (GOOGLE_AUTH_WORKER_URL).
|
|
17
|
-
// Legacy user-owned .env credentials are optional fallback only.
|
|
18
16
|
if (!CONFIG.GOOGLE_AUTH_WORKER_URL && !CONFIG.GOOGLE_CLIENT_ID) {
|
|
19
17
|
logger.error('GOOGLE_AUTH_WORKER_URL is missing and no GOOGLE_CLIENT_ID fallback!');
|
|
20
18
|
}
|
|
@@ -47,7 +45,6 @@ export class GoogleDriveService {
|
|
|
47
45
|
}
|
|
48
46
|
}
|
|
49
47
|
getGoogleClientConfig() {
|
|
50
|
-
// Legacy fallback only. Preferred path is Worker (no secret in dango).
|
|
51
48
|
return {
|
|
52
49
|
clientId: CONFIG.GOOGLE_CLIENT_ID || '',
|
|
53
50
|
clientSecret: CONFIG.GOOGLE_CLIENT_SECRET || '',
|
|
@@ -95,7 +92,6 @@ export class GoogleDriveService {
|
|
|
95
92
|
if (!this.tokens.refresh_token) {
|
|
96
93
|
throw new Error('Missing refresh token');
|
|
97
94
|
}
|
|
98
|
-
// Preferred: secret stays in Worker
|
|
99
95
|
if (this.useWorker()) {
|
|
100
96
|
await this.refreshViaWorker();
|
|
101
97
|
return;
|
|
@@ -206,7 +202,6 @@ export class GoogleDriveService {
|
|
|
206
202
|
return !!this.tokens.refresh_token;
|
|
207
203
|
}
|
|
208
204
|
async getAuthUrl() {
|
|
209
|
-
// Preferred: Worker builds URL with bundled client_id, no secret needed here
|
|
210
205
|
if (this.useWorker()) {
|
|
211
206
|
try {
|
|
212
207
|
const url = new URL(`${CONFIG.GOOGLE_AUTH_WORKER_URL}/auth-url`);
|
|
@@ -235,7 +230,6 @@ export class GoogleDriveService {
|
|
|
235
230
|
return url.toString();
|
|
236
231
|
}
|
|
237
232
|
async handleCallback(code) {
|
|
238
|
-
// Preferred: Worker exchanges code with secret, dango never sees secret
|
|
239
233
|
if (this.useWorker()) {
|
|
240
234
|
try {
|
|
241
235
|
const data = await this.postJson(`${CONFIG.GOOGLE_AUTH_WORKER_URL}/exchange`, { code, redirect_uri: CONFIG.GOOGLE_REDIRECT_URI });
|
|
@@ -247,7 +241,6 @@ export class GoogleDriveService {
|
|
|
247
241
|
throw error;
|
|
248
242
|
}
|
|
249
243
|
}
|
|
250
|
-
// Legacy fallback: user-owned client_id/secret in .env
|
|
251
244
|
const { clientId, clientSecret } = this.getGoogleClientConfig();
|
|
252
245
|
const params = new URLSearchParams({
|
|
253
246
|
code,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import logger from '../logger.js';
|
|
2
|
+
import { googleDriveService } from '../google.js';
|
|
3
|
+
import { CONFIG } from '../config.js';
|
|
4
|
+
import { updateEnvFile } from '../utils/env.utils.js';
|
|
5
|
+
export function registerAuth(app, getDbs, runSync) {
|
|
6
|
+
app.get('/api/auth/google/callback', async (c) => {
|
|
7
|
+
const code = c.req.query('code');
|
|
8
|
+
if (!code) {
|
|
9
|
+
return c.text('No code provided', 400);
|
|
10
|
+
}
|
|
11
|
+
await googleDriveService.handleCallback(code);
|
|
12
|
+
const user = await googleDriveService.getUserProfile();
|
|
13
|
+
await updateEnvFile({ SYNC_PROVIDER: 'google' });
|
|
14
|
+
logger.info('User logged in. Syncing database (please wait)...');
|
|
15
|
+
const dbs = getDbs();
|
|
16
|
+
try {
|
|
17
|
+
await runSync(dbs.db, dbs.mangaDb, 'google');
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
logger.error({ err }, 'Post-login sync failed');
|
|
21
|
+
}
|
|
22
|
+
const responseHtml = `
|
|
23
|
+
<html>
|
|
24
|
+
<head><meta name="viewport" content="width=device-width, initial-scale=1" /></head>
|
|
25
|
+
<body>
|
|
26
|
+
<h1>Authentication Successful</h1>
|
|
27
|
+
<p>Database synced. Returning to dango...</p>
|
|
28
|
+
<p><a href="/?google_auth=success">Tap here if you are not redirected</a></p>
|
|
29
|
+
<script>
|
|
30
|
+
(function () {
|
|
31
|
+
var payload = { type: 'GOOGLE_AUTH_SUCCESS', user: ${JSON.stringify(user)} };
|
|
32
|
+
try {
|
|
33
|
+
if (window.opener && !window.opener.closed) {
|
|
34
|
+
window.opener.postMessage(payload, window.location.origin);
|
|
35
|
+
try {
|
|
36
|
+
window.opener.postMessage(payload, 'http://localhost:${CONFIG.PORT}');
|
|
37
|
+
} catch (e) {}
|
|
38
|
+
try {
|
|
39
|
+
window.opener.postMessage(payload, 'http://127.0.0.1:${CONFIG.PORT}');
|
|
40
|
+
} catch (e) {}
|
|
41
|
+
setTimeout(function () { window.close(); }, 300);
|
|
42
|
+
setTimeout(function () { window.location.href = '/?google_auth=success'; }, 1500);
|
|
43
|
+
} else {
|
|
44
|
+
window.location.href = '/?google_auth=success';
|
|
45
|
+
}
|
|
46
|
+
} catch (e) {
|
|
47
|
+
window.location.href = '/?google_auth=success';
|
|
48
|
+
}
|
|
49
|
+
})();
|
|
50
|
+
</script>
|
|
51
|
+
</body>
|
|
52
|
+
</html>
|
|
53
|
+
`;
|
|
54
|
+
return c.html(responseHtml);
|
|
55
|
+
});
|
|
56
|
+
}
|