@serifpersia/dango 3.6.7 → 3.6.8
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-C3P9zWi9.js → AnimeCard-DraA_TF9.js} +1 -1
- package/client/dist/assets/{AnimeInfo-Et6687Tl.js → AnimeInfo-BJ7pzs-P.js} +1 -1
- package/client/dist/assets/{AnimeInfoPage-DX4eNnlH.js → AnimeInfoPage-B_esUr5C.js} +2 -2
- package/client/dist/assets/{Asmr-CCdEWrFi.js → Asmr-Ckuh2xfW.js} +1 -1
- package/client/dist/assets/{AsmrResetProgressModal-DgEWBJOw.js → AsmrResetProgressModal-BS6UFJN4.js} +1 -1
- package/client/dist/assets/{AvSyncCalibrator-CQ2fjf2E.js → AvSyncCalibrator-DwHCd9yB.js} +1 -1
- package/client/dist/assets/{Home-DUkUTTTy.js → Home-DuM1EuvN.js} +1 -1
- package/client/dist/assets/{Insights-QCh4xW12.js → Insights-D3Pd9c9V.js} +1 -1
- package/client/dist/assets/{LibraryListPage-BoTxRqHz.js → LibraryListPage-Dm2yVn0-.js} +1 -1
- package/client/dist/assets/{ListeningList-DguKjI_t.js → ListeningList-D-zt6EXZ.js} +1 -1
- package/client/dist/assets/{Manga-HydR-L7o.js → Manga-JwprMKBk.js} +1 -1
- package/client/dist/assets/{MangaInfoPage-CBakEI9a.js → MangaInfoPage-DaeyJl2p.js} +1 -1
- package/client/dist/assets/{MangaReadPage-DwAR3iPy.js → MangaReadPage-COg0fHI9.js} +1 -1
- package/client/dist/assets/{MangaResetProgressModal-DGzl8vsO.js → MangaResetProgressModal-kguXv0_M.js} +1 -1
- package/client/dist/assets/{Mature-Pi0TxKuF.js → Mature-IHDaasrs.js} +1 -1
- package/client/dist/assets/{MediaCard--cuFxOCS.js → MediaCard-CpwsrXo5.js} +1 -1
- package/client/dist/assets/{Music-CQpyXTLH.js → Music-Dks4tPeK.js} +1 -1
- package/client/dist/assets/{OptionListMenu-B3D39dGS.js → OptionListMenu-11CcAsy8.js} +1 -1
- package/client/dist/assets/{Player-CsH4x_I_.js → Player-DQoEQkHL.js} +2 -2
- package/client/dist/assets/{PlayerSettings-DGxBsi3F.js → PlayerSettings-D4Ud4kv4.js} +1 -1
- package/client/dist/assets/{QueueOptionsButton-Djq4Cpex.js → QueueOptionsButton-B8PlPKjC.js} +1 -1
- package/client/dist/assets/{QueueRail-DOrYgNVX.js → QueueRail-B4Dok7U3.js} +1 -1
- package/client/dist/assets/{Radio-DF6g6odd.js → Radio-BHK6LSk4.js} +1 -1
- package/client/dist/assets/{ReadingList-DwYoBrNk.js → ReadingList-BCsxIz57.js} +1 -1
- package/client/dist/assets/{ResetProgressModal-CMF86mX6.js → ResetProgressModal-BXHxSfy-.js} +1 -1
- package/client/dist/assets/{Search-DFkhuk-x.js → Search-PK1ds07O.js} +1 -1
- package/client/dist/assets/{Settings-DBB2r0VQ.js → Settings-Bxk_x55l.js} +1 -1
- package/client/dist/assets/{SkeletonGrid-DJelJgAv.js → SkeletonGrid-CpJCZSRN.js} +1 -1
- package/client/dist/assets/{Trackers-DGYXFhYZ.js → Trackers-RieCh_84.js} +1 -1
- package/client/dist/assets/{Tv-C5MDGD2Z.js → Tv-DLytPJUj.js} +1 -1
- package/client/dist/assets/{TvInfo-DrKuK13u.js → TvInfo-C8djKebR.js} +1 -1
- package/client/dist/assets/{TvPopup-DtHilRDT.js → TvPopup-40JGGJDk.js} +1 -1
- package/client/dist/assets/{TvSearch-CzNxdu_w.js → TvSearch-A3hbospf.js} +1 -1
- package/client/dist/assets/{TvWatchlist-D7p4br6S.js → TvWatchlist-DuXjqmZM.js} +1 -1
- package/client/dist/assets/{Watchlist-DrOzswl2.js → Watchlist-B9wGBh0u.js} +1 -1
- package/client/dist/assets/{hls-BGCX7mJy.js → hls-CZ5X3Ya-.js} +1 -1
- package/client/dist/assets/{index-CnfZwsds.js → index-dRhc9-ol.js} +2 -2
- package/client/dist/assets/{useAnimeInfoData-DYXWBPF-.js → useAnimeInfoData-ZzDtLfvD.js} +1 -1
- package/client/dist/assets/{useAsmr-BbhQ59bk.js → useAsmr-CKOdHgol.js} +1 -1
- package/client/dist/assets/{useAsmrPopup-SymV1J-b.js → useAsmrPopup-SFHPhpcl.js} +1 -1
- package/client/dist/assets/{useMangaLibrary-DuesWQaE.js → useMangaLibrary-CKATe31P.js} +1 -1
- package/client/dist/assets/{useMangaPopup-D57OVGUr.js → useMangaPopup-C75QuYgY.js} +1 -1
- package/client/dist/assets/{useProviders-mpQb_dix.js → useProviders-CMtvZbEi.js} +1 -1
- package/client/dist/assets/{useTv-DGflCsSI.js → useTv-DUX4zYMr.js} +1 -1
- package/client/dist/assets/{useTvLibrary-BqeSmyc4.js → useTvLibrary-By4Gt-R_.js} +1 -1
- package/client/dist/index.html +1 -1
- package/package.json +2 -2
- package/server/dist/app-auth.js +1 -157
- package/server/dist/app-hono.js +7 -557
- package/server/dist/config.js +1 -174
- package/server/dist/db/drizzle.js +1 -16
- package/server/dist/db/schema-anime.js +1 -61
- package/server/dist/db/schema-asmr.js +1 -13
- package/server/dist/db/schema-manga.js +1 -31
- package/server/dist/db/schema-tv.js +1 -18
- package/server/dist/db.js +1 -217
- package/server/dist/discord-gateway.js +1 -385
- package/server/dist/discord-rpc.js +1 -413
- package/server/dist/github-sync.js +1 -508
- package/server/dist/google.js +1 -741
- package/server/dist/hono/asmr.js +1 -10
- package/server/dist/hono/auth.js +3 -26
- package/server/dist/hono/music.js +1 -209
- package/server/dist/hono/proxy.js +36 -783
- package/server/dist/hono/tv.js +5 -200
- package/server/dist/hono/watchlist.js +2 -338
- package/server/dist/lib/anilist.js +26 -1458
- package/server/dist/lib/anischedule.js +1 -191
- package/server/dist/lib/insights.js +1 -185
- package/server/dist/lib/ipc.js +1 -23
- package/server/dist/lib/kitsu.js +1 -517
- package/server/dist/lib/mal-import.js +1 -291
- package/server/dist/lib/mal.js +1 -957
- package/server/dist/lib/migration.js +1 -310
- package/server/dist/lib/offline-db.js +4 -384
- package/server/dist/lib/potoken.js +1 -135
- package/server/dist/lib/recommendations.service.js +1 -216
- package/server/dist/lib/temp-ids.js +1 -3
- package/server/dist/lib/tmdb.js +1 -72
- package/server/dist/lib/tracker/anilist-tracker.js +8 -245
- package/server/dist/lib/tracker/manga-sync.service.js +1 -773
- package/server/dist/lib/tracker/sync-state.js +1 -21
- package/server/dist/lib/tracker/sync.service.js +1 -476
- package/server/dist/lib/translate.js +3 -79
- package/server/dist/lib/ump.js +1 -106
- package/server/dist/lib/ytmusic.js +1 -162
- package/server/dist/logger.js +1 -16
- package/server/dist/providers/manga/manga.types.js +0 -1
- package/server/dist/providers/provider.interface.js +0 -1
- package/server/dist/providers/remote-loader.js +2 -614
- package/server/dist/providers/remote-types.js +1 -159
- package/server/dist/providers/title-matching.js +1 -226
- package/server/dist/providers/tv.types.js +0 -1
- package/server/dist/rclone.js +2 -120
- package/server/dist/repositories/asmr.repository.js +11 -46
- package/server/dist/repositories/insights.repository.js +11 -25
- package/server/dist/repositories/library.repository.js +3 -94
- package/server/dist/repositories/mal-cache.repository.js +1 -52
- package/server/dist/repositories/manga.repository.js +14 -58
- package/server/dist/repositories/notifications.repository.js +6 -52
- package/server/dist/repositories/queue.repository.js +5 -58
- package/server/dist/repositories/settings.repository.js +2 -29
- package/server/dist/repositories/shows-meta.repository.js +3 -56
- package/server/dist/repositories/temp-show-ids.repository.js +3 -63
- package/server/dist/repositories/tv.repository.js +11 -54
- package/server/dist/repositories/watched-episodes.repository.js +6 -55
- package/server/dist/repositories/watchlist.repository.js +3 -54
- package/server/dist/scripts/backfill-episode-duration.js +1 -42
- package/server/dist/server.js +1 -310
- package/server/dist/shipped-defaults.js +1 -6
- package/server/dist/sync-payload.js +1 -91
- package/server/dist/sync.js +3 -647
- package/server/dist/trpc/context.js +1 -7
- package/server/dist/trpc/errors.js +1 -15
- package/server/dist/trpc/index.js +1 -18
- package/server/dist/trpc/router.js +1 -49
- package/server/dist/trpc/routers/asmr-library.js +1 -112
- package/server/dist/trpc/routers/asmr-progress.js +1 -121
- package/server/dist/trpc/routers/asmr.js +1 -87
- package/server/dist/trpc/routers/auth.js +1 -194
- package/server/dist/trpc/routers/continue-watching.js +2 -58
- package/server/dist/trpc/routers/data.js +1 -1026
- package/server/dist/trpc/routers/discord.js +1 -285
- package/server/dist/trpc/routers/discovery.js +1 -11
- package/server/dist/trpc/routers/insights.js +1 -14
- package/server/dist/trpc/routers/manga-library.js +1 -263
- package/server/dist/trpc/routers/manga-progress.js +1 -169
- package/server/dist/trpc/routers/manga.js +1 -201
- package/server/dist/trpc/routers/music.js +1 -655
- package/server/dist/trpc/routers/notifications.js +1 -80
- package/server/dist/trpc/routers/progress.js +1 -109
- package/server/dist/trpc/routers/queue.js +1 -93
- package/server/dist/trpc/routers/radio.js +1 -145
- package/server/dist/trpc/routers/settings.js +1 -96
- package/server/dist/trpc/routers/tracker.js +1 -213
- package/server/dist/trpc/routers/tv-library.js +1 -135
- package/server/dist/trpc/routers/tv-progress.js +1 -159
- package/server/dist/trpc/routers/tv.js +1 -551
- package/server/dist/trpc/routers/watchlist.js +2 -549
- package/server/dist/trpc/validation.js +1 -258
- package/server/dist/utils/cache.utils.js +1 -25
- package/server/dist/utils/cookie.utils.js +1 -13
- package/server/dist/utils/db-utils.js +5 -17
- package/server/dist/utils/env.utils.js +5 -77
- package/server/dist/utils/http.utils.js +1 -82
- package/server/dist/utils/request-context.js +1 -2
- package/server/dist/utils/security.utils.js +1 -76
- package/server/package.json +3 -2
|
@@ -1,310 +1 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { searchAnilistByTitle, getShowMetaById } from './anilist.js';
|
|
3
|
-
import { isTempShowId } from './temp-ids.js';
|
|
4
|
-
import { WatchlistRepository } from '../repositories/watchlist.repository.js';
|
|
5
|
-
import { ShowsMetaRepository } from '../repositories/shows-meta.repository.js';
|
|
6
|
-
import { dbGet, dbRun } from '../utils/db-utils.js';
|
|
7
|
-
import logger from '../logger.js';
|
|
8
|
-
const inFlightMigrations = new Map();
|
|
9
|
-
async function consolidateFromNumeric(db, numericId) {
|
|
10
|
-
const metaRow = dbGet(db, 'SELECT anilistId FROM shows_meta WHERE id = ? AND anilistId IS NOT NULL', [numericId]);
|
|
11
|
-
let trueAnilistId;
|
|
12
|
-
if (metaRow?.anilistId != null && String(metaRow.anilistId) !== numericId) {
|
|
13
|
-
trueAnilistId = metaRow.anilistId;
|
|
14
|
-
}
|
|
15
|
-
else if (!metaRow) {
|
|
16
|
-
if (await WatchlistRepository.exists(db, numericId)) {
|
|
17
|
-
const meta = await getShowMetaById(numericId);
|
|
18
|
-
if (meta?.anilistId && meta.anilistId !== parseInt(numericId)) {
|
|
19
|
-
trueAnilistId = meta.anilistId;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
if (trueAnilistId) {
|
|
24
|
-
const canonicalId = String(trueAnilistId);
|
|
25
|
-
if (await WatchlistRepository.exists(db, numericId)) {
|
|
26
|
-
logger.info({ aliasId: numericId, canonicalId }, 'Migrating watchlist from MAL alias to canonical ID');
|
|
27
|
-
await performWriteTransactionAsync(db, async (tx) => {
|
|
28
|
-
const aliasWatchlist = await WatchlistRepository.getById(tx, numericId);
|
|
29
|
-
const aliasShowsMeta = await ShowsMetaRepository.getById(tx, numericId);
|
|
30
|
-
tx.run('UPDATE OR IGNORE watchlist SET id = ?, thumbnail = ? WHERE id = ?', [
|
|
31
|
-
canonicalId,
|
|
32
|
-
aliasWatchlist?.thumbnail || '',
|
|
33
|
-
numericId,
|
|
34
|
-
]);
|
|
35
|
-
tx.run('DELETE FROM watchlist WHERE id = ?', [numericId]);
|
|
36
|
-
tx.run('UPDATE OR IGNORE shows_meta SET id = ?, anilistId = ?, thumbnail = ? WHERE id = ?', [
|
|
37
|
-
canonicalId,
|
|
38
|
-
trueAnilistId,
|
|
39
|
-
aliasShowsMeta?.thumbnail || '',
|
|
40
|
-
numericId,
|
|
41
|
-
]);
|
|
42
|
-
tx.run('DELETE FROM shows_meta WHERE id = ?', [numericId]);
|
|
43
|
-
tx.run('UPDATE OR IGNORE watched_episodes SET showId = ? WHERE showId = ?', [
|
|
44
|
-
canonicalId,
|
|
45
|
-
numericId,
|
|
46
|
-
]);
|
|
47
|
-
tx.run('DELETE FROM watched_episodes WHERE showId = ?', [numericId]);
|
|
48
|
-
tx.run('UPDATE OR IGNORE queue SET showId = ? WHERE showId = ?', [canonicalId, numericId]);
|
|
49
|
-
tx.run('DELETE FROM queue WHERE showId = ?', [numericId]);
|
|
50
|
-
tx.run('UPDATE OR IGNORE dismissed_notifications SET showId = ? WHERE showId = ?', [
|
|
51
|
-
canonicalId,
|
|
52
|
-
numericId,
|
|
53
|
-
]);
|
|
54
|
-
tx.run('DELETE FROM dismissed_notifications WHERE showId = ?', [numericId]);
|
|
55
|
-
tx.run('UPDATE OR IGNORE discovered_notifications SET showId = ? WHERE showId = ?', [
|
|
56
|
-
canonicalId,
|
|
57
|
-
numericId,
|
|
58
|
-
]);
|
|
59
|
-
tx.run('DELETE FROM discovered_notifications WHERE showId = ?', [numericId]);
|
|
60
|
-
tx.run('INSERT OR REPLACE INTO legacy_id_mapping (legacyId, numericId) VALUES (?, ?)', [
|
|
61
|
-
numericId,
|
|
62
|
-
canonicalId,
|
|
63
|
-
]);
|
|
64
|
-
});
|
|
65
|
-
return canonicalId;
|
|
66
|
-
}
|
|
67
|
-
if (await WatchlistRepository.exists(db, canonicalId)) {
|
|
68
|
-
const existing = dbGet(db, 'SELECT numericId FROM legacy_id_mapping WHERE legacyId = ?', [numericId]);
|
|
69
|
-
if (!existing || existing.numericId !== canonicalId) {
|
|
70
|
-
dbRun(db, 'INSERT OR REPLACE INTO legacy_id_mapping (legacyId, numericId) VALUES (?, ?)', [
|
|
71
|
-
numericId,
|
|
72
|
-
canonicalId,
|
|
73
|
-
]);
|
|
74
|
-
logger.info({ aliasId: numericId, canonicalId }, 'Mapped numeric alias to canonical ID');
|
|
75
|
-
}
|
|
76
|
-
return canonicalId;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
if (await WatchlistRepository.exists(db, numericId))
|
|
80
|
-
return numericId;
|
|
81
|
-
let legacyId;
|
|
82
|
-
const legacyRow = dbGet(db, 'SELECT legacyId FROM legacy_id_mapping WHERE numericId = ? AND legacyId IN (SELECT id FROM watchlist)', [numericId]);
|
|
83
|
-
if (legacyRow) {
|
|
84
|
-
legacyId = legacyRow.legacyId;
|
|
85
|
-
}
|
|
86
|
-
if (!legacyId && trueAnilistId) {
|
|
87
|
-
const metaByAnilist = dbGet(db, 'SELECT id FROM shows_meta WHERE anilistId = ? AND id IN (SELECT id FROM watchlist)', [trueAnilistId]);
|
|
88
|
-
if (metaByAnilist) {
|
|
89
|
-
legacyId = metaByAnilist.id;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
if (!legacyId)
|
|
93
|
-
return numericId;
|
|
94
|
-
logger.info({ legacyId, numericId }, 'Consolidating watchlist entry from legacy to numeric ID');
|
|
95
|
-
const aniListId = parseInt(numericId);
|
|
96
|
-
await performWriteTransactionAsync(db, async (tx) => {
|
|
97
|
-
const legacyWatchlist = await WatchlistRepository.getById(tx, legacyId);
|
|
98
|
-
const legacyShowsMeta = await ShowsMetaRepository.getById(tx, legacyId);
|
|
99
|
-
tx.run('UPDATE OR IGNORE watchlist SET id = ?, thumbnail = ? WHERE id = ?', [
|
|
100
|
-
numericId,
|
|
101
|
-
legacyWatchlist?.thumbnail || '',
|
|
102
|
-
legacyId,
|
|
103
|
-
]);
|
|
104
|
-
tx.run('DELETE FROM watchlist WHERE id = ?', [legacyId]);
|
|
105
|
-
tx.run('UPDATE OR IGNORE shows_meta SET id = ?, anilistId = ?, thumbnail = ? WHERE id = ?', [
|
|
106
|
-
numericId,
|
|
107
|
-
aniListId,
|
|
108
|
-
legacyShowsMeta?.thumbnail || '',
|
|
109
|
-
legacyId,
|
|
110
|
-
]);
|
|
111
|
-
tx.run('DELETE FROM shows_meta WHERE id = ?', [legacyId]);
|
|
112
|
-
tx.run('UPDATE OR IGNORE watched_episodes SET showId = ? WHERE showId = ?', [
|
|
113
|
-
numericId,
|
|
114
|
-
legacyId,
|
|
115
|
-
]);
|
|
116
|
-
tx.run('DELETE FROM watched_episodes WHERE showId = ?', [legacyId]);
|
|
117
|
-
tx.run('UPDATE OR IGNORE queue SET showId = ? WHERE showId = ?', [numericId, legacyId]);
|
|
118
|
-
tx.run('DELETE FROM queue WHERE showId = ?', [legacyId]);
|
|
119
|
-
tx.run('UPDATE OR IGNORE dismissed_notifications SET showId = ? WHERE showId = ?', [
|
|
120
|
-
numericId,
|
|
121
|
-
legacyId,
|
|
122
|
-
]);
|
|
123
|
-
tx.run('DELETE FROM dismissed_notifications WHERE showId = ?', [legacyId]);
|
|
124
|
-
tx.run('UPDATE OR IGNORE discovered_notifications SET showId = ? WHERE showId = ?', [
|
|
125
|
-
numericId,
|
|
126
|
-
legacyId,
|
|
127
|
-
]);
|
|
128
|
-
tx.run('DELETE FROM discovered_notifications WHERE showId = ?', [legacyId]);
|
|
129
|
-
tx.run('INSERT OR REPLACE INTO legacy_id_mapping (legacyId, numericId) VALUES (?, ?)', [
|
|
130
|
-
legacyId,
|
|
131
|
-
numericId,
|
|
132
|
-
]);
|
|
133
|
-
});
|
|
134
|
-
return numericId;
|
|
135
|
-
}
|
|
136
|
-
async function migrateId(db, legacyId) {
|
|
137
|
-
const isNumeric = /^\d+$/.test(legacyId);
|
|
138
|
-
if (isNumeric) {
|
|
139
|
-
return consolidateFromNumeric(db, legacyId);
|
|
140
|
-
}
|
|
141
|
-
try {
|
|
142
|
-
const mapping = dbGet(db, 'SELECT numericId FROM legacy_id_mapping WHERE legacyId = ?', [legacyId]);
|
|
143
|
-
if (mapping) {
|
|
144
|
-
const mappedMeta = (await ShowsMetaRepository.getById(db, mapping.numericId));
|
|
145
|
-
const canonicalId = mappedMeta?.anilistId ? String(mappedMeta.anilistId) : undefined;
|
|
146
|
-
if (!canonicalId || canonicalId === mapping.numericId) {
|
|
147
|
-
return consolidateFromNumeric(db, mapping.numericId);
|
|
148
|
-
}
|
|
149
|
-
await performWriteTransactionAsync(db, async (tx) => {
|
|
150
|
-
const legacyWatchlist = await WatchlistRepository.getById(tx, mapping.numericId);
|
|
151
|
-
const legacyShowsMeta = await ShowsMetaRepository.getById(tx, mapping.numericId);
|
|
152
|
-
tx.run('UPDATE OR IGNORE watchlist SET id = ?, thumbnail = ? WHERE id = ?', [
|
|
153
|
-
canonicalId,
|
|
154
|
-
legacyWatchlist?.thumbnail || '',
|
|
155
|
-
mapping.numericId,
|
|
156
|
-
]);
|
|
157
|
-
tx.run('DELETE FROM watchlist WHERE id = ?', [mapping.numericId]);
|
|
158
|
-
tx.run('UPDATE OR IGNORE shows_meta SET id = ?, anilistId = ?, thumbnail = ? WHERE id = ?', [
|
|
159
|
-
canonicalId,
|
|
160
|
-
parseInt(canonicalId),
|
|
161
|
-
legacyShowsMeta?.thumbnail || '',
|
|
162
|
-
mapping.numericId,
|
|
163
|
-
]);
|
|
164
|
-
tx.run('DELETE FROM shows_meta WHERE id = ?', [mapping.numericId]);
|
|
165
|
-
tx.run('UPDATE OR IGNORE watched_episodes SET showId = ? WHERE showId = ?', [
|
|
166
|
-
canonicalId,
|
|
167
|
-
mapping.numericId,
|
|
168
|
-
]);
|
|
169
|
-
tx.run('DELETE FROM watched_episodes WHERE showId = ?', [mapping.numericId]);
|
|
170
|
-
tx.run('UPDATE OR IGNORE queue SET showId = ? WHERE showId = ?', [
|
|
171
|
-
canonicalId,
|
|
172
|
-
mapping.numericId,
|
|
173
|
-
]);
|
|
174
|
-
tx.run('DELETE FROM queue WHERE showId = ?', [mapping.numericId]);
|
|
175
|
-
tx.run('UPDATE OR IGNORE dismissed_notifications SET showId = ? WHERE showId = ?', [
|
|
176
|
-
canonicalId,
|
|
177
|
-
mapping.numericId,
|
|
178
|
-
]);
|
|
179
|
-
tx.run('DELETE FROM dismissed_notifications WHERE showId = ?', [mapping.numericId]);
|
|
180
|
-
tx.run('UPDATE OR IGNORE discovered_notifications SET showId = ? WHERE showId = ?', [
|
|
181
|
-
canonicalId,
|
|
182
|
-
mapping.numericId,
|
|
183
|
-
]);
|
|
184
|
-
tx.run('DELETE FROM discovered_notifications WHERE showId = ?', [mapping.numericId]);
|
|
185
|
-
tx.run('UPDATE legacy_id_mapping SET numericId = ? WHERE legacyId = ?', [
|
|
186
|
-
canonicalId,
|
|
187
|
-
legacyId,
|
|
188
|
-
]);
|
|
189
|
-
});
|
|
190
|
-
logger.info({ legacyId, previousId: mapping.numericId, newId: canonicalId }, 'Canonicalized migrated show ID');
|
|
191
|
-
return canonicalId;
|
|
192
|
-
}
|
|
193
|
-
let showName;
|
|
194
|
-
const localMeta = (await ShowsMetaRepository.getById(db, legacyId));
|
|
195
|
-
if (localMeta && localMeta.name) {
|
|
196
|
-
showName = localMeta.name;
|
|
197
|
-
}
|
|
198
|
-
else {
|
|
199
|
-
const metaByAnilist = dbGet(db, 'SELECT id, name FROM shows_meta WHERE anilistId = ?', [parseInt(legacyId) || 0]);
|
|
200
|
-
if (metaByAnilist && metaByAnilist.name) {
|
|
201
|
-
showName = metaByAnilist.name;
|
|
202
|
-
}
|
|
203
|
-
else {
|
|
204
|
-
const watchlistEntry = await WatchlistRepository.getById(db, legacyId);
|
|
205
|
-
if (watchlistEntry && watchlistEntry.name) {
|
|
206
|
-
showName = watchlistEntry.name;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
if (!showName) {
|
|
211
|
-
logger.warn({ id: legacyId }, 'No show name found for legacy ID migration');
|
|
212
|
-
return legacyId;
|
|
213
|
-
}
|
|
214
|
-
const aniListShow = await searchAnilistByTitle(showName);
|
|
215
|
-
if (!aniListShow) {
|
|
216
|
-
logger.warn({ id: legacyId, showName }, 'No AniList match found for legacy ID migration');
|
|
217
|
-
return legacyId;
|
|
218
|
-
}
|
|
219
|
-
const newId = String(aniListShow.id);
|
|
220
|
-
let newThumbnail;
|
|
221
|
-
try {
|
|
222
|
-
const freshMeta = await getShowMetaById(newId);
|
|
223
|
-
newThumbnail = freshMeta?.thumbnail;
|
|
224
|
-
}
|
|
225
|
-
catch {
|
|
226
|
-
newThumbnail = undefined;
|
|
227
|
-
}
|
|
228
|
-
await performWriteTransactionAsync(db, async (tx) => {
|
|
229
|
-
tx.run('INSERT OR REPLACE INTO legacy_id_mapping (legacyId, numericId) VALUES (?, ?)', [
|
|
230
|
-
legacyId,
|
|
231
|
-
newId,
|
|
232
|
-
]);
|
|
233
|
-
const legacyWatchlist = await WatchlistRepository.getById(tx, legacyId);
|
|
234
|
-
if (legacyWatchlist) {
|
|
235
|
-
const newWatchlistExists = await WatchlistRepository.getById(tx, newId);
|
|
236
|
-
if (newWatchlistExists) {
|
|
237
|
-
await WatchlistRepository.delete(tx, legacyId);
|
|
238
|
-
}
|
|
239
|
-
else {
|
|
240
|
-
tx.run('UPDATE watchlist SET id = ?, thumbnail = ? WHERE id = ?', [
|
|
241
|
-
newId,
|
|
242
|
-
newThumbnail || legacyWatchlist.thumbnail || '',
|
|
243
|
-
legacyId,
|
|
244
|
-
]);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
const legacyShowsMeta = await ShowsMetaRepository.getById(tx, legacyId);
|
|
248
|
-
if (legacyShowsMeta) {
|
|
249
|
-
const newShowsMetaExists = await ShowsMetaRepository.getById(tx, newId);
|
|
250
|
-
if (newShowsMetaExists) {
|
|
251
|
-
tx.run('DELETE FROM shows_meta WHERE id = ?', [legacyId]);
|
|
252
|
-
}
|
|
253
|
-
else {
|
|
254
|
-
tx.run('UPDATE shows_meta SET id = ?, anilistId = ?, thumbnail = ? WHERE id = ?', [
|
|
255
|
-
newId,
|
|
256
|
-
aniListShow.id,
|
|
257
|
-
newThumbnail || legacyShowsMeta.thumbnail || '',
|
|
258
|
-
legacyId,
|
|
259
|
-
]);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
tx.run('UPDATE OR IGNORE watched_episodes SET showId = ? WHERE showId = ?', [newId, legacyId]);
|
|
263
|
-
tx.run('DELETE FROM watched_episodes WHERE showId = ?', [legacyId]);
|
|
264
|
-
tx.run('UPDATE OR IGNORE queue SET showId = ? WHERE showId = ?', [newId, legacyId]);
|
|
265
|
-
tx.run('DELETE FROM queue WHERE showId = ?', [legacyId]);
|
|
266
|
-
tx.run('UPDATE OR IGNORE dismissed_notifications SET showId = ? WHERE showId = ?', [
|
|
267
|
-
newId,
|
|
268
|
-
legacyId,
|
|
269
|
-
]);
|
|
270
|
-
tx.run('DELETE FROM dismissed_notifications WHERE showId = ?', [legacyId]);
|
|
271
|
-
tx.run('UPDATE OR IGNORE discovered_notifications SET showId = ? WHERE showId = ?', [
|
|
272
|
-
newId,
|
|
273
|
-
legacyId,
|
|
274
|
-
]);
|
|
275
|
-
tx.run('DELETE FROM discovered_notifications WHERE showId = ?', [legacyId]);
|
|
276
|
-
});
|
|
277
|
-
logger.info({ legacyId, newId, showName }, 'Successfully migrated legacy show ID to numeric ID');
|
|
278
|
-
return newId;
|
|
279
|
-
}
|
|
280
|
-
catch (err) {
|
|
281
|
-
logger.error({ err, legacyId }, 'Error migrating legacy show ID');
|
|
282
|
-
return legacyId;
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
export function getMigratedId(db, legacyId) {
|
|
286
|
-
if (isTempShowId(legacyId))
|
|
287
|
-
return Promise.resolve(legacyId);
|
|
288
|
-
if (/^(mal-\d+|-\d+)$/i.test(legacyId)) {
|
|
289
|
-
const mapping = dbGet(db, 'SELECT numericId FROM legacy_id_mapping WHERE legacyId = ?', [legacyId]);
|
|
290
|
-
if (mapping)
|
|
291
|
-
return consolidateFromNumeric(db, mapping.numericId);
|
|
292
|
-
return Promise.resolve(legacyId);
|
|
293
|
-
}
|
|
294
|
-
if (/^\d+$/.test(legacyId)) {
|
|
295
|
-
const existing = inFlightMigrations.get(legacyId);
|
|
296
|
-
if (existing)
|
|
297
|
-
return existing;
|
|
298
|
-
const migration = migrateId(db, legacyId);
|
|
299
|
-
inFlightMigrations.set(legacyId, migration);
|
|
300
|
-
migration.then(() => inFlightMigrations.delete(legacyId), () => inFlightMigrations.delete(legacyId));
|
|
301
|
-
return migration;
|
|
302
|
-
}
|
|
303
|
-
const existing = inFlightMigrations.get(legacyId);
|
|
304
|
-
if (existing)
|
|
305
|
-
return existing;
|
|
306
|
-
const migration = migrateId(db, legacyId);
|
|
307
|
-
inFlightMigrations.set(legacyId, migration);
|
|
308
|
-
migration.then(() => inFlightMigrations.delete(legacyId), () => inFlightMigrations.delete(legacyId));
|
|
309
|
-
return migration;
|
|
310
|
-
}
|
|
1
|
+
import{performWriteTransactionAsync as I}from"../sync.js";import{searchAnilistByTitle as D,getShowMetaById as f}from"./anilist.js";import{isTempShowId as p}from"./temp-ids.js";import{WatchlistRepository as d}from"../repositories/watchlist.repository.js";import{ShowsMetaRepository as l}from"../repositories/shows-meta.repository.js";import{dbGet as m,dbRun as S}from"../utils/db-utils.js";import h from"../logger.js";const w=new Map;async function O(a,i){const u=m(a,"SELECT anilistId FROM shows_meta WHERE id = ? AND anilistId IS NOT NULL",[i]);let t;if(u?.anilistId!=null&&String(u.anilistId)!==i)t=u.anilistId;else if(!u&&await d.exists(a,i)){const s=await f(i);s?.anilistId&&s.anilistId!==parseInt(i)&&(t=s.anilistId)}if(t){const s=String(t);if(await d.exists(a,i))return h.info({aliasId:i,canonicalId:s},"Migrating watchlist from MAL alias to canonical ID"),await I(a,async e=>{const E=await d.getById(e,i),o=await l.getById(e,i);e.run("UPDATE OR IGNORE watchlist SET id = ?, thumbnail = ? WHERE id = ?",[s,E?.thumbnail||"",i]),e.run("DELETE FROM watchlist WHERE id = ?",[i]),e.run("UPDATE OR IGNORE shows_meta SET id = ?, anilistId = ?, thumbnail = ? WHERE id = ?",[s,t,o?.thumbnail||"",i]),e.run("DELETE FROM shows_meta WHERE id = ?",[i]),e.run("UPDATE OR IGNORE watched_episodes SET showId = ? WHERE showId = ?",[s,i]),e.run("DELETE FROM watched_episodes WHERE showId = ?",[i]),e.run("UPDATE OR IGNORE queue SET showId = ? WHERE showId = ?",[s,i]),e.run("DELETE FROM queue WHERE showId = ?",[i]),e.run("UPDATE OR IGNORE dismissed_notifications SET showId = ? WHERE showId = ?",[s,i]),e.run("DELETE FROM dismissed_notifications WHERE showId = ?",[i]),e.run("UPDATE OR IGNORE discovered_notifications SET showId = ? WHERE showId = ?",[s,i]),e.run("DELETE FROM discovered_notifications WHERE showId = ?",[i]),e.run("INSERT OR REPLACE INTO legacy_id_mapping (legacyId, numericId) VALUES (?, ?)",[i,s])}),s;if(await d.exists(a,s)){const e=m(a,"SELECT numericId FROM legacy_id_mapping WHERE legacyId = ?",[i]);return(!e||e.numericId!==s)&&(S(a,"INSERT OR REPLACE INTO legacy_id_mapping (legacyId, numericId) VALUES (?, ?)",[i,s]),h.info({aliasId:i,canonicalId:s},"Mapped numeric alias to canonical ID")),s}}if(await d.exists(a,i))return i;let n;const R=m(a,"SELECT legacyId FROM legacy_id_mapping WHERE numericId = ? AND legacyId IN (SELECT id FROM watchlist)",[i]);if(R&&(n=R.legacyId),!n&&t){const s=m(a,"SELECT id FROM shows_meta WHERE anilistId = ? AND id IN (SELECT id FROM watchlist)",[t]);s&&(n=s.id)}if(!n)return i;h.info({legacyId:n,numericId:i},"Consolidating watchlist entry from legacy to numeric ID");const c=parseInt(i);return await I(a,async s=>{const e=await d.getById(s,n),E=await l.getById(s,n);s.run("UPDATE OR IGNORE watchlist SET id = ?, thumbnail = ? WHERE id = ?",[i,e?.thumbnail||"",n]),s.run("DELETE FROM watchlist WHERE id = ?",[n]),s.run("UPDATE OR IGNORE shows_meta SET id = ?, anilistId = ?, thumbnail = ? WHERE id = ?",[i,c,E?.thumbnail||"",n]),s.run("DELETE FROM shows_meta WHERE id = ?",[n]),s.run("UPDATE OR IGNORE watched_episodes SET showId = ? WHERE showId = ?",[i,n]),s.run("DELETE FROM watched_episodes WHERE showId = ?",[n]),s.run("UPDATE OR IGNORE queue SET showId = ? WHERE showId = ?",[i,n]),s.run("DELETE FROM queue WHERE showId = ?",[n]),s.run("UPDATE OR IGNORE dismissed_notifications SET showId = ? WHERE showId = ?",[i,n]),s.run("DELETE FROM dismissed_notifications WHERE showId = ?",[n]),s.run("UPDATE OR IGNORE discovered_notifications SET showId = ? WHERE showId = ?",[i,n]),s.run("DELETE FROM discovered_notifications WHERE showId = ?",[n]),s.run("INSERT OR REPLACE INTO legacy_id_mapping (legacyId, numericId) VALUES (?, ?)",[n,i])}),i}async function g(a,i){if(/^\d+$/.test(i))return O(a,i);try{const t=m(a,"SELECT numericId FROM legacy_id_mapping WHERE legacyId = ?",[i]);if(t){const E=await l.getById(a,t.numericId),o=E?.anilistId?String(E.anilistId):void 0;return!o||o===t.numericId?O(a,t.numericId):(await I(a,async r=>{const T=await d.getById(r,t.numericId),W=await l.getById(r,t.numericId);r.run("UPDATE OR IGNORE watchlist SET id = ?, thumbnail = ? WHERE id = ?",[o,T?.thumbnail||"",t.numericId]),r.run("DELETE FROM watchlist WHERE id = ?",[t.numericId]),r.run("UPDATE OR IGNORE shows_meta SET id = ?, anilistId = ?, thumbnail = ? WHERE id = ?",[o,parseInt(o),W?.thumbnail||"",t.numericId]),r.run("DELETE FROM shows_meta WHERE id = ?",[t.numericId]),r.run("UPDATE OR IGNORE watched_episodes SET showId = ? WHERE showId = ?",[o,t.numericId]),r.run("DELETE FROM watched_episodes WHERE showId = ?",[t.numericId]),r.run("UPDATE OR IGNORE queue SET showId = ? WHERE showId = ?",[o,t.numericId]),r.run("DELETE FROM queue WHERE showId = ?",[t.numericId]),r.run("UPDATE OR IGNORE dismissed_notifications SET showId = ? WHERE showId = ?",[o,t.numericId]),r.run("DELETE FROM dismissed_notifications WHERE showId = ?",[t.numericId]),r.run("UPDATE OR IGNORE discovered_notifications SET showId = ? WHERE showId = ?",[o,t.numericId]),r.run("DELETE FROM discovered_notifications WHERE showId = ?",[t.numericId]),r.run("UPDATE legacy_id_mapping SET numericId = ? WHERE legacyId = ?",[o,i])}),h.info({legacyId:i,previousId:t.numericId,newId:o},"Canonicalized migrated show ID"),o)}let n;const R=await l.getById(a,i);if(R&&R.name)n=R.name;else{const E=m(a,"SELECT id, name FROM shows_meta WHERE anilistId = ?",[parseInt(i)||0]);if(E&&E.name)n=E.name;else{const o=await d.getById(a,i);o&&o.name&&(n=o.name)}}if(!n)return h.warn({id:i},"No show name found for legacy ID migration"),i;const c=await D(n);if(!c)return h.warn({id:i,showName:n},"No AniList match found for legacy ID migration"),i;const s=String(c.id);let e;try{e=(await f(s))?.thumbnail}catch{e=void 0}return await I(a,async E=>{E.run("INSERT OR REPLACE INTO legacy_id_mapping (legacyId, numericId) VALUES (?, ?)",[i,s]);const o=await d.getById(E,i);o&&(await d.getById(E,s)?await d.delete(E,i):E.run("UPDATE watchlist SET id = ?, thumbnail = ? WHERE id = ?",[s,e||o.thumbnail||"",i]));const r=await l.getById(E,i);r&&(await l.getById(E,s)?E.run("DELETE FROM shows_meta WHERE id = ?",[i]):E.run("UPDATE shows_meta SET id = ?, anilistId = ?, thumbnail = ? WHERE id = ?",[s,c.id,e||r.thumbnail||"",i])),E.run("UPDATE OR IGNORE watched_episodes SET showId = ? WHERE showId = ?",[s,i]),E.run("DELETE FROM watched_episodes WHERE showId = ?",[i]),E.run("UPDATE OR IGNORE queue SET showId = ? WHERE showId = ?",[s,i]),E.run("DELETE FROM queue WHERE showId = ?",[i]),E.run("UPDATE OR IGNORE dismissed_notifications SET showId = ? WHERE showId = ?",[s,i]),E.run("DELETE FROM dismissed_notifications WHERE showId = ?",[i]),E.run("UPDATE OR IGNORE discovered_notifications SET showId = ? WHERE showId = ?",[s,i]),E.run("DELETE FROM discovered_notifications WHERE showId = ?",[i])}),h.info({legacyId:i,newId:s,showName:n},"Successfully migrated legacy show ID to numeric ID"),s}catch(t){return h.error({err:t,legacyId:i},"Error migrating legacy show ID"),i}}function G(a,i){if(p(i))return Promise.resolve(i);if(/^(mal-\d+|-\d+)$/i.test(i)){const n=m(a,"SELECT numericId FROM legacy_id_mapping WHERE legacyId = ?",[i]);return n?O(a,n.numericId):Promise.resolve(i)}if(/^\d+$/.test(i)){const n=w.get(i);if(n)return n;const R=g(a,i);return w.set(i,R),R.then(()=>w.delete(i),()=>w.delete(i)),R}const u=w.get(i);if(u)return u;const t=g(a,i);return w.set(i,t),t.then(()=>w.delete(i),()=>w.delete(i)),t}export{G as getMigratedId};
|