@serifpersia/dango 3.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +247 -0
  3. package/client/dist/assets/AnimeInfo-CMxs0nRH.css +1 -0
  4. package/client/dist/assets/AnimeInfo-DVdaocCl.js +1 -0
  5. package/client/dist/assets/AnimeInfoPage-Bx5EvGt-.js +2 -0
  6. package/client/dist/assets/Asmr-C2i9GKD4.css +1 -0
  7. package/client/dist/assets/Asmr-CIjmFtRH.js +2 -0
  8. package/client/dist/assets/Asmr.module-DPG2JhDJ.js +1 -0
  9. package/client/dist/assets/AvSyncCalibrator-CIYcyon5.css +1 -0
  10. package/client/dist/assets/AvSyncCalibrator-vqErH7Cm.js +10 -0
  11. package/client/dist/assets/ErrorMessage-BwSjzblw.js +1 -0
  12. package/client/dist/assets/ErrorMessage-CXoRbrLN.css +1 -0
  13. package/client/dist/assets/Home-D7YfGBUk.js +1 -0
  14. package/client/dist/assets/Home-DKCfEiwl.css +1 -0
  15. package/client/dist/assets/Insights-BljI64Ua.css +1 -0
  16. package/client/dist/assets/Insights-CLQGrlpX.js +1 -0
  17. package/client/dist/assets/Manga-DQ9HYnpk.js +1 -0
  18. package/client/dist/assets/Manga-H8Wb04w3.css +1 -0
  19. package/client/dist/assets/Map-CXFqXmsZ.css +1 -0
  20. package/client/dist/assets/Map-L_ryVBTq.js +1 -0
  21. package/client/dist/assets/Mature-BeWzAJ7B.js +1 -0
  22. package/client/dist/assets/Mature-DJmUUtlF.css +1 -0
  23. package/client/dist/assets/Player-CYpd__FP.js +30 -0
  24. package/client/dist/assets/Player-DreAhybc.css +1 -0
  25. package/client/dist/assets/PlayerRedirect-fxUAp9JV.js +1 -0
  26. package/client/dist/assets/PlayerSettings-BcsotxP9.js +1 -0
  27. package/client/dist/assets/PlayerSettings-Cqua1CDD.css +1 -0
  28. package/client/dist/assets/QueueRail-B9Pgbqc3.js +1 -0
  29. package/client/dist/assets/QueueRail-BnaltOP8.css +1 -0
  30. package/client/dist/assets/Radio-BvdY5twD.js +1 -0
  31. package/client/dist/assets/Radio-CUuYy3DY.css +1 -0
  32. package/client/dist/assets/Search-BzO-aRP7.css +1 -0
  33. package/client/dist/assets/Search-R9YLAXS1.js +1 -0
  34. package/client/dist/assets/Search.module-D8ZbQAiK.js +1 -0
  35. package/client/dist/assets/Settings-9kYcXdTR.js +21 -0
  36. package/client/dist/assets/Settings-DF8JThUL.css +1 -0
  37. package/client/dist/assets/SkeletonGrid-D5vRvX5q.js +1 -0
  38. package/client/dist/assets/SkeletonGrid-DEbYtO4H.css +1 -0
  39. package/client/dist/assets/SynopsisText-BlFw0R-0.js +1 -0
  40. package/client/dist/assets/SynopsisText-CUgOjOxt.css +1 -0
  41. package/client/dist/assets/Trackers-DfZlnnVq.js +2 -0
  42. package/client/dist/assets/Trackers-Dt9lR_uP.css +1 -0
  43. package/client/dist/assets/Tv-CVKC2YBs.css +1 -0
  44. package/client/dist/assets/Tv-Db1Wx_b7.js +15 -0
  45. package/client/dist/assets/Watchlist-B2nkNZqM.css +1 -0
  46. package/client/dist/assets/Watchlist-a77CYtzu.js +1 -0
  47. package/client/dist/assets/hls-6Owgw2Aj.js +1 -0
  48. package/client/dist/assets/hls-BOLXTnjL.js +42 -0
  49. package/client/dist/assets/index-B6qdXFtl.css +1 -0
  50. package/client/dist/assets/index-B8TPVaIS.js +30354 -0
  51. package/client/dist/assets/index-CpjgU8ou.js +178 -0
  52. package/client/dist/assets/useAnimeInfoData-BOfyi9UJ.js +1 -0
  53. package/client/dist/assets/useIsMobile-CM15uQn8.css +1 -0
  54. package/client/dist/assets/useIsMobile-Cb8HcKRj.js +1 -0
  55. package/client/dist/assets/useMatureConsent-CZMYBVXd.js +1 -0
  56. package/client/dist/assets/vendor-rLNfZm7Y.js +1 -0
  57. package/client/dist/av-sync-test.mp4 +0 -0
  58. package/client/dist/favicon.ico +0 -0
  59. package/client/dist/index.html +31 -0
  60. package/client/dist/logo-mochi.png +0 -0
  61. package/client/dist/logo-sakura.png +0 -0
  62. package/client/dist/logo.png +0 -0
  63. package/client/dist/placeholder.svg +4 -0
  64. package/client/dist/robots.txt +3 -0
  65. package/orchestrator.js +416 -0
  66. package/package.json +89 -0
  67. package/server/dist/app-auth.js +231 -0
  68. package/server/dist/config.js +133 -0
  69. package/server/dist/controllers/auth.controller.js +247 -0
  70. package/server/dist/controllers/data.controller.js +785 -0
  71. package/server/dist/controllers/insights.controller.js +197 -0
  72. package/server/dist/controllers/proxy.controller.js +665 -0
  73. package/server/dist/controllers/settings.controller.js +267 -0
  74. package/server/dist/controllers/watchlist.controller.js +967 -0
  75. package/server/dist/db.js +152 -0
  76. package/server/dist/discord-gateway.js +381 -0
  77. package/server/dist/discord-rpc.js +424 -0
  78. package/server/dist/github-sync.js +403 -0
  79. package/server/dist/google.js +549 -0
  80. package/server/dist/lib/anilist.js +1519 -0
  81. package/server/dist/lib/anischedule.js +202 -0
  82. package/server/dist/lib/ipc.js +32 -0
  83. package/server/dist/lib/kitsu.js +552 -0
  84. package/server/dist/lib/mal.js +886 -0
  85. package/server/dist/lib/migration.js +335 -0
  86. package/server/dist/lib/temp-ids.js +11 -0
  87. package/server/dist/lib/tmdb.js +71 -0
  88. package/server/dist/lib/tracker/anilist-tracker.js +250 -0
  89. package/server/dist/lib/tracker/sync.service.js +312 -0
  90. package/server/dist/logger.js +19 -0
  91. package/server/dist/providers/123anime.provider.js +240 -0
  92. package/server/dist/providers/anilight.provider.js +366 -0
  93. package/server/dist/providers/animepahe.provider.js +531 -0
  94. package/server/dist/providers/animeya.provider.js +746 -0
  95. package/server/dist/providers/base-provider.js +45 -0
  96. package/server/dist/providers/hn.provider.js +473 -0
  97. package/server/dist/providers/ht.provider.js +439 -0
  98. package/server/dist/providers/jasmr.provider.js +504 -0
  99. package/server/dist/providers/kaa.provider.js +388 -0
  100. package/server/dist/providers/manga/manga.types.js +10 -0
  101. package/server/dist/providers/manga/mangadex.provider.js +227 -0
  102. package/server/dist/providers/manga/mangapill.provider.js +232 -0
  103. package/server/dist/providers/megaplay.provider.js +583 -0
  104. package/server/dist/providers/op.provider.js +440 -0
  105. package/server/dist/providers/provider.interface.js +2 -0
  106. package/server/dist/providers/title-matching.js +234 -0
  107. package/server/dist/providers/wh.provider.js +600 -0
  108. package/server/dist/rclone.js +126 -0
  109. package/server/dist/repositories/insights.repository.js +43 -0
  110. package/server/dist/repositories/mal-cache.repository.js +66 -0
  111. package/server/dist/repositories/notifications.repository.js +40 -0
  112. package/server/dist/repositories/queue.repository.js +64 -0
  113. package/server/dist/repositories/settings.repository.js +15 -0
  114. package/server/dist/repositories/shows-meta.repository.js +43 -0
  115. package/server/dist/repositories/temp-show-ids.repository.js +54 -0
  116. package/server/dist/repositories/watched-episodes.repository.js +54 -0
  117. package/server/dist/repositories/watchlist.repository.js +74 -0
  118. package/server/dist/routes/asmr.routes.js +72 -0
  119. package/server/dist/routes/auth.routes.js +28 -0
  120. package/server/dist/routes/data.routes.js +50 -0
  121. package/server/dist/routes/discord-gateway.routes.js +57 -0
  122. package/server/dist/routes/insights.routes.js +12 -0
  123. package/server/dist/routes/lan-auth.routes.js +49 -0
  124. package/server/dist/routes/manga.routes.js +115 -0
  125. package/server/dist/routes/proxy.routes.js +15 -0
  126. package/server/dist/routes/radio.routes.js +143 -0
  127. package/server/dist/routes/settings.routes.js +27 -0
  128. package/server/dist/routes/tracker.routes.js +143 -0
  129. package/server/dist/routes/translate.routes.js +90 -0
  130. package/server/dist/routes/tv.routes.js +843 -0
  131. package/server/dist/routes/watchlist.routes.js +312 -0
  132. package/server/dist/server.js +310 -0
  133. package/server/dist/shipped-defaults.js +8 -0
  134. package/server/dist/sync-config.js +32 -0
  135. package/server/dist/sync.js +506 -0
  136. package/server/dist/utils/cookie.utils.js +17 -0
  137. package/server/dist/utils/db-utils.js +15 -0
  138. package/server/dist/utils/env.utils.js +83 -0
  139. package/server/dist/utils/machine-id.js +46 -0
  140. package/server/dist/utils/request-context.js +5 -0
  141. package/server/dist/utils/security.utils.js +99 -0
@@ -0,0 +1,202 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getAniScheduleShows = getAniScheduleShows;
4
+ exports.getAniScheduleSubFeed = getAniScheduleSubFeed;
5
+ exports.getAniScheduleHentaiFeed = getAniScheduleHentaiFeed;
6
+ exports.withScheduleFields = withScheduleFields;
7
+ exports.getScheduleFromAniSchedule = getScheduleFromAniSchedule;
8
+ exports.getAiredEpisodesFromAniScheduleFeed = getAiredEpisodesFromAniScheduleFeed;
9
+ exports.isAniScheduleAvailable = isAniScheduleAvailable;
10
+ const SUB_SCHEDULE_URL = 'https://raw.githubusercontent.com/RockinChaos/AniSchedule/master/raw/sub-schedule.json';
11
+ const SUB_FEED_URL = 'https://raw.githubusercontent.com/RockinChaos/AniSchedule/master/raw/sub-episode-feed.json';
12
+ const HENTAI_FEED_URL = 'https://raw.githubusercontent.com/RockinChaos/AniSchedule/master/raw/hentai-episode-feed.json';
13
+ const SCHEDULE_TTL_MS = 15 * 60 * 1000;
14
+ const FEED_TTL_MS = 10 * 60 * 1000;
15
+ const FETCH_TIMEOUT_MS = 10000;
16
+ const scheduleCache = { data: null, expiry: 0 };
17
+ const subFeedCache = { data: null, expiry: 0 };
18
+ const hentaiFeedCache = { data: null, expiry: 0 };
19
+ const inFlight = new Map();
20
+ async function fetchJson(url) {
21
+ const controller = new AbortController();
22
+ const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
23
+ try {
24
+ const response = await fetch(url, {
25
+ signal: controller.signal,
26
+ headers: { 'User-Agent': 'dango' },
27
+ });
28
+ if (!response.ok) {
29
+ throw new Error(`AniSchedule fetch failed with status ${response.status}`);
30
+ }
31
+ const json = (await response.json());
32
+ if (Array.isArray(json) && json.length === 0) {
33
+ throw new Error('AniSchedule returned an empty payload');
34
+ }
35
+ return json;
36
+ }
37
+ finally {
38
+ clearTimeout(timer);
39
+ }
40
+ }
41
+ function fetchCached(key, url, cache, ttlMs) {
42
+ if (cache.data !== null && Date.now() < cache.expiry) {
43
+ return Promise.resolve(cache.data);
44
+ }
45
+ const existing = inFlight.get(key);
46
+ if (existing)
47
+ return existing;
48
+ const request = fetchJson(url)
49
+ .then((data) => {
50
+ cache.data = data;
51
+ cache.expiry = Date.now() + ttlMs;
52
+ return data;
53
+ })
54
+ .catch((err) => {
55
+ inFlight.delete(key);
56
+ throw err;
57
+ });
58
+ inFlight.set(key, request);
59
+ return request;
60
+ }
61
+ function getAniScheduleShows() {
62
+ return fetchCached('anischedule:shows', SUB_SCHEDULE_URL, scheduleCache, SCHEDULE_TTL_MS);
63
+ }
64
+ function getAniScheduleSubFeed() {
65
+ return fetchCached('anischedule:subfeed', SUB_FEED_URL, subFeedCache, FEED_TTL_MS);
66
+ }
67
+ function getAniScheduleHentaiFeed() {
68
+ return fetchCached('anischedule:hentaifeed', HENTAI_FEED_URL, hentaiFeedCache, FEED_TTL_MS);
69
+ }
70
+ function withScheduleFields(show, episode, airingAt) {
71
+ const now = Math.floor(Date.now() / 1000);
72
+ return {
73
+ ...show,
74
+ episodeNumber: episode,
75
+ aired: airingAt <= now,
76
+ nextAiring: { episode, timeUntilAiring: airingAt - now },
77
+ nextEpisodeAirDate: new Date(airingAt * 1000).toLocaleDateString('en-US', {
78
+ month: 'short',
79
+ day: 'numeric',
80
+ year: 'numeric',
81
+ timeZone: 'UTC',
82
+ }),
83
+ airTime: new Date(airingAt * 1000).toLocaleTimeString('en-US', {
84
+ hour: '2-digit',
85
+ minute: '2-digit',
86
+ timeZone: 'UTC',
87
+ }),
88
+ };
89
+ }
90
+ function fromAniScheduleShow(s) {
91
+ const title = s.title;
92
+ const name = title?.romaji || title?.english || title?.native || 'Unknown';
93
+ return {
94
+ _id: s.id.toString(),
95
+ id: s.id.toString(),
96
+ anilistId: s.id,
97
+ name,
98
+ englishName: title?.english,
99
+ nativeName: title?.native,
100
+ names: {
101
+ romaji: title?.romaji,
102
+ english: title?.english,
103
+ native: title?.native,
104
+ },
105
+ thumbnail: s.coverImage?.extraLarge || s.coverImage?.medium || '',
106
+ bannerImage: s.bannerImage || undefined,
107
+ genres: s.genres?.map((g) => ({ name: g })),
108
+ type: s.format,
109
+ year: s.seasonYear ?? undefined,
110
+ isAdult: s.isAdult,
111
+ };
112
+ }
113
+ async function getScheduleFromAniSchedule(date, format, adult = false) {
114
+ const dayStart = Math.floor(date.getTime() / 1000);
115
+ const dayEnd = dayStart + 86400;
116
+ const now = Math.floor(Date.now() / 1000);
117
+ const formatFilter = format && format !== 'ALL' ? format : undefined;
118
+ const schedulePromise = getAniScheduleShows();
119
+ const subFeedPromise = getAniScheduleSubFeed();
120
+ const hentaiFeedPromise = adult ? getAniScheduleHentaiFeed() : Promise.resolve([]);
121
+ const [shows, subFeed, hentaiFeed] = await Promise.all([
122
+ schedulePromise,
123
+ subFeedPromise,
124
+ hentaiFeedPromise,
125
+ ]);
126
+ const showById = new Map();
127
+ for (const show of shows) {
128
+ showById.set(show.id, show);
129
+ }
130
+ const matchesAdult = (show) => (adult ? !!show.isAdult : !show.isAdult);
131
+ const bestByShow = new Map();
132
+ const missingMeta = new Map();
133
+ const consider = (id, episode, airingAt, entryFormat) => {
134
+ const show = showById.get(id);
135
+ if (show) {
136
+ if (formatFilter && show.format !== formatFilter)
137
+ return;
138
+ if (!matchesAdult(show))
139
+ return;
140
+ const key = show.idMal ?? show.id;
141
+ const current = bestByShow.get(key);
142
+ if (!current || airingAt > current.airingAt) {
143
+ bestByShow.set(key, {
144
+ show: fromAniScheduleShow(show),
145
+ episode,
146
+ airingAt,
147
+ aired: airingAt <= now,
148
+ });
149
+ }
150
+ return;
151
+ }
152
+ if (adult)
153
+ return;
154
+ if (formatFilter && entryFormat && entryFormat !== formatFilter)
155
+ return;
156
+ const existing = missingMeta.get(id);
157
+ if (!existing || airingAt > existing.airingAt) {
158
+ missingMeta.set(id, { id, episode, airingAt, format: entryFormat });
159
+ }
160
+ };
161
+ for (const show of shows) {
162
+ for (const node of show.airingSchedule.nodes) {
163
+ if (node.airingAt >= dayStart && node.airingAt < dayEnd) {
164
+ consider(show.id, node.episode, node.airingAt);
165
+ }
166
+ }
167
+ }
168
+ const feed = adult ? [...subFeed, ...hentaiFeed] : subFeed;
169
+ for (const entry of feed) {
170
+ const airedAt = Date.parse(entry.episode.airedAt) / 1000;
171
+ if (airedAt >= dayStart && airedAt < dayEnd) {
172
+ consider(entry.id, entry.episode.aired, airedAt, entry.format);
173
+ }
174
+ }
175
+ const entries = Array.from(bestByShow.entries())
176
+ .map(([, value]) => value)
177
+ .sort((a, b) => a.airingAt - b.airingAt);
178
+ return {
179
+ entries,
180
+ missingMeta: Array.from(missingMeta.values()),
181
+ };
182
+ }
183
+ async function getAiredEpisodesFromAniScheduleFeed(ids, startEpoch, endEpoch) {
184
+ const idSet = new Set(ids);
185
+ const [subFeed, hentaiFeed] = await Promise.all([
186
+ getAniScheduleSubFeed(),
187
+ getAniScheduleHentaiFeed(),
188
+ ]);
189
+ const results = [];
190
+ for (const entry of [...subFeed, ...hentaiFeed]) {
191
+ if (!idSet.has(entry.id))
192
+ continue;
193
+ const airedAt = Date.parse(entry.episode.airedAt) / 1000;
194
+ if (airedAt >= startEpoch && airedAt <= endEpoch) {
195
+ results.push({ mediaId: entry.id, episode: entry.episode.aired, airingAt: airedAt });
196
+ }
197
+ }
198
+ return results;
199
+ }
200
+ function isAniScheduleAvailable() {
201
+ return !!scheduleCache.data || !!subFeedCache.data;
202
+ }
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.notifySyncStart = notifySyncStart;
7
+ exports.notifySyncEnd = notifySyncEnd;
8
+ exports.notifyServerExit = notifyServerExit;
9
+ const logger_1 = __importDefault(require("../logger"));
10
+ function sendToParent(message) {
11
+ try {
12
+ if (typeof process.send === 'function') {
13
+ process.send(message);
14
+ }
15
+ }
16
+ catch {
17
+ // No IPC channel (dev under npm, or parent already gone).
18
+ // The stdout tag below remains the fallback signal.
19
+ }
20
+ }
21
+ function notifySyncStart(message) {
22
+ sendToParent({ type: 'SYNC_START', message });
23
+ logger_1.default.info(`[SYNC_START] ${message}`);
24
+ }
25
+ function notifySyncEnd() {
26
+ sendToParent({ type: 'SYNC_END' });
27
+ logger_1.default.info('[SYNC_END]');
28
+ }
29
+ function notifyServerExit() {
30
+ sendToParent({ type: 'SERVER_EXIT' });
31
+ logger_1.default.info('[SERVER_EXIT]');
32
+ }