ani-web 1.5.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.

Potentially problematic release.


This version of ani-web might be problematic. Click here for more details.

Files changed (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +174 -0
  3. package/client/dist/assets/AnimeInfo-C7DQp7Oo.js +1 -0
  4. package/client/dist/assets/AnimeInfo-Sb3YiXHJ.css +1 -0
  5. package/client/dist/assets/AnimeInfoPage-DJA7AJQ8.js +2 -0
  6. package/client/dist/assets/Button-Fq9KaUOg.css +1 -0
  7. package/client/dist/assets/Button-o0l9V_NG.js +1 -0
  8. package/client/dist/assets/ErrorMessage-Ddf2zmRx.js +1 -0
  9. package/client/dist/assets/ErrorMessage-FOxXyZC9.css +1 -0
  10. package/client/dist/assets/Home-CKHJA97j.css +1 -0
  11. package/client/dist/assets/Home-Dey0azy1.js +1 -0
  12. package/client/dist/assets/Insights-BSRcCkDs.css +1 -0
  13. package/client/dist/assets/Insights-CogjPOd_.js +1 -0
  14. package/client/dist/assets/MAL-CYArH4yf.js +1 -0
  15. package/client/dist/assets/MAL-DeQNXXPx.css +1 -0
  16. package/client/dist/assets/Player-BWFN9gud.js +9 -0
  17. package/client/dist/assets/Player-CBCYW7uG.css +1 -0
  18. package/client/dist/assets/PlayerSettings-BgStUrrP.css +1 -0
  19. package/client/dist/assets/PlayerSettings-rWZuATQf.js +1 -0
  20. package/client/dist/assets/RemoveConfirmationModal-BBiogSdf.css +1 -0
  21. package/client/dist/assets/RemoveConfirmationModal-CLYqyGOv.js +1 -0
  22. package/client/dist/assets/Search-DZAWgKwq.js +1 -0
  23. package/client/dist/assets/Search-lWsVQ0Ke.css +1 -0
  24. package/client/dist/assets/Settings-Bv9fX-x3.css +1 -0
  25. package/client/dist/assets/Settings-DyisJGeD.js +1 -0
  26. package/client/dist/assets/ToggleSwitch-CLnWnAuY.js +1 -0
  27. package/client/dist/assets/ToggleSwitch-DInRb7iM.css +1 -0
  28. package/client/dist/assets/Watchlist-2dVYksxq.css +1 -0
  29. package/client/dist/assets/Watchlist-CuqJISI3.js +1 -0
  30. package/client/dist/assets/hls.light-DcbkToIY.js +27 -0
  31. package/client/dist/assets/index-BK_Zaqaw.css +1 -0
  32. package/client/dist/assets/index-CHVF4D4L.js +178 -0
  33. package/client/dist/assets/useAnimeInfoData-Cr58brCY.js +1 -0
  34. package/client/dist/assets/useIsMobile-gHo4t6g6.js +1 -0
  35. package/client/dist/assets/vendor-DdbgYKo4.js +3 -0
  36. package/client/dist/favicon.ico +0 -0
  37. package/client/dist/index.html +35 -0
  38. package/client/dist/logo.png +0 -0
  39. package/client/dist/placeholder.svg +4 -0
  40. package/client/dist/robots.txt +3 -0
  41. package/client/package.json +54 -0
  42. package/orchestrator.js +302 -0
  43. package/package.json +69 -0
  44. package/server/dist/config.js +86 -0
  45. package/server/dist/constants.json +1359 -0
  46. package/server/dist/controllers/auth.controller.js +213 -0
  47. package/server/dist/controllers/data.controller.js +126 -0
  48. package/server/dist/controllers/insights.controller.js +125 -0
  49. package/server/dist/controllers/proxy.controller.js +235 -0
  50. package/server/dist/controllers/settings.controller.js +147 -0
  51. package/server/dist/controllers/watchlist.controller.js +499 -0
  52. package/server/dist/db.js +231 -0
  53. package/server/dist/github-sync.js +279 -0
  54. package/server/dist/google.js +274 -0
  55. package/server/dist/logger.js +21 -0
  56. package/server/dist/providers/123anime.provider.js +229 -0
  57. package/server/dist/providers/allanime.provider.js +773 -0
  58. package/server/dist/providers/animepahe.provider.js +313 -0
  59. package/server/dist/providers/animeya.provider.js +799 -0
  60. package/server/dist/providers/provider.interface.js +2 -0
  61. package/server/dist/rclone.js +126 -0
  62. package/server/dist/repositories/insights.repository.js +30 -0
  63. package/server/dist/repositories/notifications.repository.js +22 -0
  64. package/server/dist/repositories/settings.repository.js +13 -0
  65. package/server/dist/repositories/shows-meta.repository.js +39 -0
  66. package/server/dist/repositories/watched-episodes.repository.js +60 -0
  67. package/server/dist/repositories/watchlist.repository.js +49 -0
  68. package/server/dist/routes/auth.routes.js +23 -0
  69. package/server/dist/routes/data.routes.js +43 -0
  70. package/server/dist/routes/insights.routes.js +11 -0
  71. package/server/dist/routes/proxy.routes.js +13 -0
  72. package/server/dist/routes/settings.routes.js +26 -0
  73. package/server/dist/routes/watchlist.routes.js +26 -0
  74. package/server/dist/server.js +179 -0
  75. package/server/dist/sync-config.js +28 -0
  76. package/server/dist/sync.js +383 -0
  77. package/server/dist/utils/db-utils.js +36 -0
  78. package/server/dist/utils/env.utils.js +70 -0
  79. package/server/package.json +54 -0
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,126 @@
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.rcloneService = void 0;
7
+ const child_process_1 = require("child_process");
8
+ const logger_1 = __importDefault(require("./logger"));
9
+ const config_1 = require("./config");
10
+ class RcloneService {
11
+ activeRemote = null;
12
+ executeCommand(command) {
13
+ return new Promise((resolve, reject) => {
14
+ (0, child_process_1.exec)(command, (err, stdout, stderr) => {
15
+ if (err) {
16
+ if (stderr)
17
+ logger_1.default.warn({ stderr }, 'Rclone command warning');
18
+ return reject(new Error(stderr || err.message));
19
+ }
20
+ resolve(stdout.trim());
21
+ });
22
+ });
23
+ }
24
+ executeRcloneArgs(args) {
25
+ return new Promise((resolve, reject) => {
26
+ const process = (0, child_process_1.spawn)('rclone', args, { stdio: 'ignore' });
27
+ process.on('close', (code) => {
28
+ if (code === 0)
29
+ resolve();
30
+ else
31
+ reject(new Error(`Rclone exited with code ${code}`));
32
+ });
33
+ process.on('error', (err) => reject(err));
34
+ });
35
+ }
36
+ async listRemotes() {
37
+ try {
38
+ const remotesStr = await this.executeCommand('rclone listremotes');
39
+ return remotesStr
40
+ .split('\n')
41
+ .map((r) => r.trim())
42
+ .filter((r) => r !== '')
43
+ .map((r) => r.replace(/:$/, ''));
44
+ }
45
+ catch {
46
+ return [];
47
+ }
48
+ }
49
+ async init() {
50
+ try {
51
+ await this.executeCommand('rclone version');
52
+ const remotes = await this.listRemotes();
53
+ if (config_1.CONFIG.RCLONE_REMOTE) {
54
+ const found = remotes.find((r) => r.toLowerCase() === config_1.CONFIG.RCLONE_REMOTE?.toLowerCase());
55
+ if (found) {
56
+ this.activeRemote = found;
57
+ logger_1.default.info(`Rclone initialized with manual remote: ${this.activeRemote}`);
58
+ return true;
59
+ }
60
+ else {
61
+ logger_1.default.warn(`Configured RCLONE_REMOTE '${config_1.CONFIG.RCLONE_REMOTE}' not found in rclone listremotes.`);
62
+ }
63
+ }
64
+ if (remotes.length > 0 && !config_1.CONFIG.RCLONE_REMOTE) {
65
+ logger_1.default.info({ remotes }, 'Rclone available but no manual remote is configured in settings.');
66
+ return false;
67
+ }
68
+ return false;
69
+ }
70
+ catch (error) {
71
+ logger_1.default.warn({ err: error }, 'Rclone initialization failed');
72
+ return false;
73
+ }
74
+ }
75
+ isActive() {
76
+ return this.activeRemote !== null;
77
+ }
78
+ getRemoteName() {
79
+ return this.activeRemote || 'unknown';
80
+ }
81
+ async downloadFile(remoteFolder, fileName, localPath) {
82
+ if (!this.activeRemote)
83
+ throw new Error('Rclone not active');
84
+ const remotePath = `${this.activeRemote}:${remoteFolder}/${fileName}`;
85
+ await this.executeRcloneArgs(['copyto', remotePath, localPath]);
86
+ }
87
+ async uploadFile(localPath, remoteFolder, fileName) {
88
+ if (!this.activeRemote)
89
+ throw new Error('Rclone not active');
90
+ const remotePath = `${this.activeRemote}:${remoteFolder}/${fileName}`;
91
+ await this.executeRcloneArgs(['copyto', localPath, remotePath]);
92
+ }
93
+ executeRcloneArgsWithOutput(args) {
94
+ return new Promise((resolve, reject) => {
95
+ const process = (0, child_process_1.spawn)('rclone', args, { stdio: 'pipe' });
96
+ let stdout = '';
97
+ let stderr = '';
98
+ process.stdout?.on('data', (data) => (stdout += data));
99
+ process.stderr?.on('data', (data) => (stderr += data));
100
+ process.on('close', (code) => {
101
+ if (code === 0)
102
+ resolve(stdout.trim());
103
+ else {
104
+ if (stderr)
105
+ logger_1.default.warn({ stderr }, 'Rclone command warning');
106
+ reject(new Error(stderr || `Rclone exited with code ${code}`));
107
+ }
108
+ });
109
+ process.on('error', (err) => reject(err));
110
+ });
111
+ }
112
+ async fileExists(remoteFolder, fileName) {
113
+ if (!this.activeRemote)
114
+ return false;
115
+ try {
116
+ const remotePath = `${this.activeRemote}:${remoteFolder}/${fileName}`;
117
+ const output = await this.executeRcloneArgsWithOutput(['lsjson', remotePath]);
118
+ const json = JSON.parse(output);
119
+ return json && json.length > 0;
120
+ }
121
+ catch {
122
+ return false;
123
+ }
124
+ }
125
+ }
126
+ exports.rcloneService = new RcloneService();
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InsightsRepository = void 0;
4
+ const db_utils_1 = require("../utils/db-utils");
5
+ exports.InsightsRepository = {
6
+ getCoreStats: (db) => (0, db_utils_1.dbGet)(db, `SELECT
7
+ (SELECT SUM(currentTime) FROM watched_episodes) as totalSeconds,
8
+ (SELECT COUNT(*) FROM watched_episodes) as totalEpisodes,
9
+ (SELECT COUNT(*) FROM watchlist WHERE status = 'Completed') as completedCount,
10
+ (SELECT COUNT(*) FROM watchlist) as totalWatchlist`),
11
+ getActivityGrid: (db) => (0, db_utils_1.dbAll)(db, `SELECT date(watchedAt) as day, COUNT(*) as count FROM watched_episodes GROUP BY day`),
12
+ getHourlyDist: (db) => (0, db_utils_1.dbAll)(db, `SELECT strftime('%H', watchedAt) as hour, COUNT(*) as count FROM watched_episodes GROUP BY hour`),
13
+ getSeasonality: (db) => (0, db_utils_1.dbAll)(db, `SELECT strftime('%m', watchedAt) as month, SUM(currentTime) as seconds FROM watched_episodes GROUP BY month`),
14
+ getAllWatches: (db) => (0, db_utils_1.dbAll)(db, 'SELECT watchedAt, currentTime FROM watched_episodes ORDER BY watchedAt ASC'),
15
+ getWatchedShowsMeta: (db) => (0, db_utils_1.dbAll)(db, `SELECT DISTINCT sm.id, sm.genres, sm.popularityScore
16
+ FROM shows_meta sm
17
+ JOIN watched_episodes we ON sm.id = we.showId`),
18
+ getDroppedShows: (db) => (0, db_utils_1.dbAll)(db, `SELECT w.id, w.name, MAX(we.watchedAt) as lastActivity
19
+ FROM watchlist w
20
+ JOIN watched_episodes we ON w.id = we.showId
21
+ WHERE w.status = 'Watching'
22
+ GROUP BY w.id
23
+ HAVING lastActivity < date('now', '-90 days')`),
24
+ getCompletionVelocities: (db) => (0, db_utils_1.dbAll)(db, `SELECT
25
+ (julianday(MAX(we.watchedAt)) - julianday(MIN(we.watchedAt))) as daysToFinish
26
+ FROM watchlist w
27
+ JOIN watched_episodes we ON w.id = we.showId
28
+ WHERE w.status = 'Completed'
29
+ GROUP BY w.id`),
30
+ };
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NotificationsRepository = void 0;
4
+ const db_utils_1 = require("../utils/db-utils");
5
+ exports.NotificationsRepository = {
6
+ getDismissedByShow: (db, showId) => (0, db_utils_1.dbAll)(db, 'SELECT episodeNumber FROM dismissed_notifications WHERE showId = ?', [showId]),
7
+ getDiscoveredByShow: (db, showId) => (0, db_utils_1.dbAll)(db, 'SELECT episodeNumber FROM discovered_notifications WHERE showId = ?', [showId]),
8
+ addDiscovered: (db, showId, episodeNumber) => (0, db_utils_1.dbRun)(db, 'INSERT OR IGNORE INTO discovered_notifications (showId, episodeNumber) VALUES (?, ?)', [showId, episodeNumber]),
9
+ addDismissed: (db, showId, episodeNumber) => (0, db_utils_1.dbRun)(db, 'INSERT OR IGNORE INTO dismissed_notifications (showId, episodeNumber) VALUES (?, ?)', [showId, episodeNumber]),
10
+ dismissFromDiscovered: (db, showId) => {
11
+ if (showId) {
12
+ return (0, db_utils_1.dbRun)(db, 'INSERT OR IGNORE INTO dismissed_notifications (showId, episodeNumber) SELECT showId, episodeNumber FROM discovered_notifications WHERE showId = ?', [showId]);
13
+ }
14
+ else {
15
+ return (0, db_utils_1.dbRun)(db, 'INSERT OR IGNORE INTO dismissed_notifications (showId, episodeNumber) SELECT showId, episodeNumber FROM discovered_notifications');
16
+ }
17
+ },
18
+ deleteByShow: (db, showId) => Promise.all([
19
+ (0, db_utils_1.dbRun)(db, 'DELETE FROM dismissed_notifications WHERE showId = ?', [showId]),
20
+ (0, db_utils_1.dbRun)(db, 'DELETE FROM discovered_notifications WHERE showId = ?', [showId]),
21
+ ]),
22
+ };
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SettingsRepository = void 0;
4
+ const db_utils_1 = require("../utils/db-utils");
5
+ exports.SettingsRepository = {
6
+ getByKey: (db, key) => (0, db_utils_1.dbGet)(db, 'SELECT value FROM settings WHERE key = ?', [key]),
7
+ upsert: (db, key, value) => (0, db_utils_1.dbRun)(db, 'INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)', [key, value]),
8
+ clearWatchlist: (db) => (0, db_utils_1.dbRun)(db, 'DELETE FROM watchlist'),
9
+ upsertWatchlistBatch: (db, shows) => {
10
+ const stmt = db.prepare('INSERT OR REPLACE INTO watchlist (id, name, thumbnail, status) VALUES (?, ?, ?, ?)');
11
+ shows.forEach((show) => stmt.run(show.id, show.name, show.thumbnail, show.status));
12
+ },
13
+ };
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ShowsMetaRepository = void 0;
4
+ const db_utils_1 = require("../utils/db-utils");
5
+ exports.ShowsMetaRepository = {
6
+ getById: (db, id) => (0, db_utils_1.dbGet)(db, 'SELECT * FROM shows_meta WHERE id = ?', [id]),
7
+ getStatus: async (db, id) => {
8
+ const row = await (0, db_utils_1.dbGet)(db, 'SELECT status FROM shows_meta WHERE id = ?', [
9
+ id,
10
+ ]);
11
+ return row?.status;
12
+ },
13
+ upsert: (db, data) => (0, db_utils_1.dbRun)(db, `INSERT INTO shows_meta (id, name, thumbnail, nativeName, englishName, genres, popularityScore, status, episodeCount, type)
14
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
15
+ ON CONFLICT(id) DO UPDATE SET
16
+ name = COALESCE(EXCLUDED.name, shows_meta.name),
17
+ thumbnail = COALESCE(EXCLUDED.thumbnail, shows_meta.thumbnail),
18
+ nativeName = COALESCE(EXCLUDED.nativeName, shows_meta.nativeName),
19
+ englishName = COALESCE(EXCLUDED.englishName, shows_meta.englishName),
20
+ genres = COALESCE(EXCLUDED.genres, shows_meta.genres),
21
+ popularityScore = COALESCE(EXCLUDED.popularityScore, shows_meta.popularityScore),
22
+ status = COALESCE(EXCLUDED.status, shows_meta.status),
23
+ episodeCount = COALESCE(EXCLUDED.episodeCount, shows_meta.episodeCount),
24
+ type = COALESCE(EXCLUDED.type, shows_meta.type)`, [
25
+ data.id,
26
+ data.name,
27
+ data.thumbnail,
28
+ data.nativeName || '',
29
+ data.englishName || '',
30
+ data.genres || '',
31
+ data.popularityScore || 0,
32
+ data.status || '',
33
+ data.episodeCount || 0,
34
+ data.type || '',
35
+ ]),
36
+ updateEpisodeCount: (db, id, episodeCount) => (0, db_utils_1.dbRun)(db, 'UPDATE shows_meta SET episodeCount = ? WHERE id = ?', [episodeCount, id]),
37
+ updateType: (db, id, type) => (0, db_utils_1.dbRun)(db, 'UPDATE shows_meta SET type = ? WHERE id = ?', [type, id]),
38
+ updateThumbnail: (db, id, thumbnail) => (0, db_utils_1.dbRun)(db, 'UPDATE shows_meta SET thumbnail = ? WHERE id = ?', [thumbnail, id]),
39
+ };
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WatchedEpisodesRepository = void 0;
4
+ const db_utils_1 = require("../utils/db-utils");
5
+ exports.WatchedEpisodesRepository = {
6
+ getByShowAndEpisode: (db, showId, episodeNumber) => (0, db_utils_1.dbGet)(db, 'SELECT currentTime, duration FROM watched_episodes WHERE showId = ? AND episodeNumber = ?', [showId, episodeNumber]),
7
+ getWatchedEpisodeNumbers: async (db, showId) => {
8
+ const rows = await (0, db_utils_1.dbAll)(db, 'SELECT episodeNumber FROM watched_episodes WHERE showId = ?', [showId]);
9
+ return rows.map((r) => r.episodeNumber);
10
+ },
11
+ upsert: (db, data) => (0, db_utils_1.dbRun)(db, 'INSERT OR REPLACE INTO watched_episodes (showId, episodeNumber, watchedAt, currentTime, duration) VALUES (?, ?, CURRENT_TIMESTAMP, ?, ?)', [data.showId, data.episodeNumber, data.currentTime, data.duration]),
12
+ deleteByShow: (db, showId) => (0, db_utils_1.dbRun)(db, 'DELETE FROM watched_episodes WHERE showId = ?', [showId]),
13
+ getContinueWatching: (db, limit) => {
14
+ const limitClause = typeof limit === 'number' ? `LIMIT ${limit}` : '';
15
+ const query = `
16
+ SELECT
17
+ w.id as _id,
18
+ w.id as id,
19
+ w.name as name,
20
+ w.thumbnail as thumbnail,
21
+ w.nativeName as nativeName,
22
+ w.englishName as englishName,
23
+ w.type as type,
24
+ sm.episodeCount,
25
+ sm.type as smType,
26
+ (SELECT COUNT(DISTINCT episodeNumber) FROM watched_episodes WHERE showId = w.id) as watchedCount,
27
+ we.episodeNumber, we.currentTime, we.duration, we.watchedAt
28
+ FROM (
29
+ SELECT *, ROW_NUMBER() OVER(PARTITION BY showId ORDER BY watchedAt DESC) as rn
30
+ FROM watched_episodes
31
+ ) we
32
+ JOIN watchlist w ON we.showId = w.id
33
+ LEFT JOIN shows_meta sm ON we.showId = sm.id
34
+ WHERE we.rn = 1 AND w.status = 'Watching'
35
+ ORDER BY we.watchedAt DESC
36
+ ${limitClause}
37
+ `;
38
+ return (0, db_utils_1.dbAll)(db, query);
39
+ },
40
+ getUpNextShows: (db) => {
41
+ const query = `
42
+ SELECT w.id, w.name, w.thumbnail, w.nativeName, w.englishName, w.type, sm.episodeCount, sm.type as smType
43
+ FROM watchlist w
44
+ LEFT JOIN shows_meta sm ON w.id = sm.id
45
+ LEFT JOIN (
46
+ SELECT showId, MAX(watchedAt) as lastActivity
47
+ FROM watched_episodes
48
+ GROUP BY showId
49
+ ) we ON w.id = we.showId
50
+ WHERE w.status = 'Watching'
51
+ ORDER BY we.lastActivity DESC
52
+ LIMIT 15
53
+ `;
54
+ return (0, db_utils_1.dbAll)(db, query);
55
+ },
56
+ getEpisodesForShows: (db, showIds) => {
57
+ const placeholders = showIds.map(() => '?').join(',');
58
+ return (0, db_utils_1.dbAll)(db, `SELECT showId, episodeNumber, currentTime, duration, watchedAt FROM watched_episodes WHERE showId IN (${placeholders})`, showIds);
59
+ },
60
+ };
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WatchlistRepository = void 0;
4
+ const db_utils_1 = require("../utils/db-utils");
5
+ exports.WatchlistRepository = {
6
+ getById: (db, id) => (0, db_utils_1.dbGet)(db, 'SELECT * FROM watchlist WHERE id = ?', [id]),
7
+ exists: async (db, id) => {
8
+ const row = await (0, db_utils_1.dbGet)(db, 'SELECT EXISTS(SELECT 1 FROM watchlist WHERE id = ?) as inWatchlist', [id]);
9
+ return !!(row && row.inWatchlist);
10
+ },
11
+ getAll: (db, status, limit, offset) => {
12
+ let query = 'SELECT * FROM watchlist';
13
+ const params = [];
14
+ if (status && status !== 'All') {
15
+ query += ' WHERE status = ?';
16
+ params.push(status);
17
+ }
18
+ query += ' ORDER BY rowid DESC';
19
+ if (limit !== undefined && offset !== undefined) {
20
+ query += ' LIMIT ? OFFSET ?';
21
+ params.push(limit, offset);
22
+ }
23
+ return (0, db_utils_1.dbAll)(db, query, params);
24
+ },
25
+ getCount: async (db, status) => {
26
+ let query = 'SELECT COUNT(*) as total FROM watchlist';
27
+ const params = [];
28
+ if (status && status !== 'All') {
29
+ query += ' WHERE status = ?';
30
+ params.push(status);
31
+ }
32
+ const row = await (0, db_utils_1.dbGet)(db, query, params);
33
+ return row?.total || 0;
34
+ },
35
+ upsert: (db, data) => (0, db_utils_1.dbRun)(db, 'INSERT OR REPLACE INTO watchlist (id, name, thumbnail, status, nativeName, englishName, type) VALUES (?, ?, ?, ?, ?, ?, ?)', [
36
+ data.id,
37
+ data.name,
38
+ data.thumbnail,
39
+ data.status,
40
+ data.nativeName,
41
+ data.englishName,
42
+ data.type,
43
+ ]),
44
+ updateStatus: (db, id, status) => (0, db_utils_1.dbRun)(db, 'UPDATE watchlist SET status = ? WHERE id = ?', [status, id]),
45
+ updateType: (db, id, type) => (0, db_utils_1.dbRun)(db, 'UPDATE watchlist SET type = ? WHERE id = ?', [type, id]),
46
+ updateThumbnail: (db, id, thumbnail) => (0, db_utils_1.dbRun)(db, 'UPDATE watchlist SET thumbnail = ? WHERE id = ?', [thumbnail, id]),
47
+ delete: (db, id) => (0, db_utils_1.dbRun)(db, 'DELETE FROM watchlist WHERE id = ?', [id]),
48
+ getWatchingShows: (db) => (0, db_utils_1.dbAll)(db, "SELECT id, name, thumbnail, nativeName, englishName FROM watchlist WHERE status = 'Watching'"),
49
+ };
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createAuthRouter = createAuthRouter;
4
+ const express_1 = require("express");
5
+ const auth_controller_1 = require("../controllers/auth.controller");
6
+ function createAuthRouter(runSyncSequence) {
7
+ const router = (0, express_1.Router)();
8
+ const controller = new auth_controller_1.AuthController(runSyncSequence);
9
+ router.get('/config-status', controller.getConfigStatus);
10
+ router.get('/google-auth', controller.getGoogleAuthSettings);
11
+ router.post('/google-auth', controller.updateGoogleAuthSettings);
12
+ router.get('/github/status', controller.getGitHubAuthStatus);
13
+ router.post('/github/start', controller.startGitHubDeviceAuth);
14
+ router.get('/github/poll', controller.pollGitHubDeviceAuth);
15
+ router.post('/github/logout', controller.logoutGitHub);
16
+ router.get('/settings/rclone', controller.getRcloneSettings);
17
+ router.post('/settings/rclone', controller.updateRcloneSettings);
18
+ router.get('/google', controller.getAuthUrl);
19
+ router.get('/google/callback', controller.handleCallback);
20
+ router.get('/user', controller.getUserProfile);
21
+ router.post('/logout', controller.logout);
22
+ return router;
23
+ }
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createDataRouter = createDataRouter;
4
+ const express_1 = require("express");
5
+ const data_controller_1 = require("../controllers/data.controller");
6
+ function makeCacheMiddleware(cache, keyFn, ttl, validate = (d) => Array.isArray(d) && d.length > 0) {
7
+ return (req, res, next) => {
8
+ const cacheKey = keyFn(req);
9
+ const cached = cache.get(cacheKey);
10
+ if (cached)
11
+ return res.json(cached);
12
+ const originalJson = res.json.bind(res);
13
+ res.json = (data) => {
14
+ if (validate(data)) {
15
+ if (ttl !== undefined) {
16
+ cache.set(cacheKey, data, ttl);
17
+ }
18
+ else {
19
+ cache.set(cacheKey, data);
20
+ }
21
+ }
22
+ return originalJson(data);
23
+ };
24
+ next();
25
+ };
26
+ }
27
+ function createDataRouter(apiCache, providers) {
28
+ const router = (0, express_1.Router)();
29
+ const controller = new data_controller_1.DataController(providers);
30
+ router.get('/popular/:timeframe', makeCacheMiddleware(apiCache, (req) => `popular-${req.params.timeframe.toLowerCase()}`), controller.getPopular);
31
+ router.get('/schedule/:date', makeCacheMiddleware(apiCache, (req) => `schedule-${req.params.date}`), controller.getSchedule);
32
+ router.get('/latest-releases', makeCacheMiddleware(apiCache, () => 'latest-releases', 300), controller.getLatestReleases);
33
+ router.get('/search', makeCacheMiddleware(apiCache, (req) => `search-${JSON.stringify(req.query)}`, 1800), controller.search);
34
+ router.get('/skip-times/:showId/:episodeNumber', controller.getSkipTimes);
35
+ router.get('/video', controller.getVideo);
36
+ router.get('/episodes', controller.getEpisodes);
37
+ router.get('/seasonal', makeCacheMiddleware(apiCache, (req) => `seasonal-14-${req.query.page || 1}`, 1800), controller.getSeasonal);
38
+ router.get('/show-meta/:id', makeCacheMiddleware(apiCache, (req) => `meta-${req.params.id}`, 3600, (d) => !!d), controller.getShowMeta);
39
+ router.get('/show-details/:id', controller.getShowDetails);
40
+ router.get('/allmanga-details/:id', controller.getAllmangaDetails);
41
+ router.get('/genres-and-tags', controller.getGenresAndTags);
42
+ return router;
43
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createInsightsRouter = createInsightsRouter;
4
+ const express_1 = require("express");
5
+ const insights_controller_1 = require("../controllers/insights.controller");
6
+ function createInsightsRouter(provider) {
7
+ const router = (0, express_1.Router)();
8
+ const controller = new insights_controller_1.InsightsController(provider);
9
+ router.get('/insights', controller.getWatchInsights);
10
+ return router;
11
+ }
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createProxyRouter = createProxyRouter;
4
+ const express_1 = require("express");
5
+ const proxy_controller_1 = require("../controllers/proxy.controller");
6
+ function createProxyRouter() {
7
+ const router = (0, express_1.Router)();
8
+ const controller = new proxy_controller_1.ProxyController();
9
+ router.get('/proxy', controller.handleProxy);
10
+ router.get('/subtitle-proxy', controller.handleSubtitleProxy);
11
+ router.get('/image-proxy', controller.handleImageProxy);
12
+ return router;
13
+ }
@@ -0,0 +1,26 @@
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.createSettingsRouter = createSettingsRouter;
7
+ const express_1 = require("express");
8
+ const settings_controller_1 = require("../controllers/settings.controller");
9
+ const multer_1 = __importDefault(require("multer"));
10
+ const config_1 = require("../config");
11
+ function createSettingsRouter(provider, getDb, initializeDatabase, setDb) {
12
+ const router = (0, express_1.Router)();
13
+ const controller = new settings_controller_1.SettingsController(provider);
14
+ router.get('/settings', controller.getSettings);
15
+ router.post('/settings', controller.updateSettings);
16
+ router.get('/backup-db', controller.backupDatabase);
17
+ const restoreStorage = (0, multer_1.default)({
18
+ storage: multer_1.default.diskStorage({
19
+ destination: (_req, _f, cb) => cb(null, config_1.CONFIG.ROOT),
20
+ filename: (_r, _f, cb) => cb(null, `restore_temp.db`),
21
+ }),
22
+ });
23
+ router.post('/restore-db', restoreStorage.single('dbfile'), (req, res) => controller.restoreDatabase(req, res, getDb(), initializeDatabase, setDb));
24
+ router.post('/import/mal-xml', (0, multer_1.default)().single('xmlfile'), controller.importMalXml);
25
+ return router;
26
+ }
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createWatchlistRouter = createWatchlistRouter;
4
+ const express_1 = require("express");
5
+ const watchlist_controller_1 = require("../controllers/watchlist.controller");
6
+ function createWatchlistRouter(provider) {
7
+ const router = (0, express_1.Router)();
8
+ const controller = new watchlist_controller_1.WatchlistController(provider);
9
+ router.get('/continue-watching', controller.getContinueWatching);
10
+ router.get('/continue-watching/fast', controller.getContinueWatchingFast);
11
+ router.get('/continue-watching/up-next', controller.getContinueWatchingUpNext);
12
+ router.get('/continue-watching/all', controller.getAllContinueWatching);
13
+ router.post('/continue-watching/remove', controller.removeContinueWatching);
14
+ router.post('/update-progress', controller.updateProgress);
15
+ router.get('/watchlist', controller.getWatchlist);
16
+ router.get('/watchlist/check/:showId', controller.checkWatchlist);
17
+ router.post('/watchlist/add', controller.addToWatchlist);
18
+ router.post('/watchlist/remove', controller.removeFromWatchlist);
19
+ router.post('/watchlist/status', controller.updateWatchlistStatus);
20
+ router.get('/episode-progress/:showId/:episodeNumber', controller.getEpisodeProgress);
21
+ router.get('/watched-episodes/:showId', controller.getWatchedEpisodes);
22
+ router.get('/notifications', controller.getNotifications);
23
+ router.post('/notifications/dismiss', controller.dismissNotification);
24
+ router.post('/notifications/clear-all', controller.clearAllNotifications);
25
+ return router;
26
+ }