@psychout98/tadaima 1.0.2 → 1.0.4

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 (70) hide show
  1. package/dist/chunk-6O3GWKMO.js +16979 -0
  2. package/dist/chunk-7TPZ4T2V.js +37 -0
  3. package/dist/chunk-KDW3UEKL.js +105 -0
  4. package/dist/config-YQZEYLLR.js +7 -0
  5. package/dist/daemon-YZQZNLEX.js +14 -0
  6. package/dist/download-handler-R6AJCG4O.js +462 -0
  7. package/dist/index.js +253 -257
  8. package/dist/logger-XTDECBFK.js +85 -0
  9. package/dist/service-GBG6YHQW.js +199 -0
  10. package/dist/setup-OLV7C7ON.js +100 -0
  11. package/dist/status-writer-RGH2PULB.js +31 -0
  12. package/dist/tui-ZE4672PT.js +77 -0
  13. package/dist/updater-HXBNBU36.js +163 -0
  14. package/dist/ws-client-CLD6QAFC.js +178 -0
  15. package/package.json +6 -5
  16. package/dist/config.d.ts +0 -23
  17. package/dist/config.d.ts.map +0 -1
  18. package/dist/config.js +0 -25
  19. package/dist/config.js.map +0 -1
  20. package/dist/daemon.d.ts +0 -8
  21. package/dist/daemon.d.ts.map +0 -1
  22. package/dist/daemon.js +0 -91
  23. package/dist/daemon.js.map +0 -1
  24. package/dist/download-handler.d.ts +0 -15
  25. package/dist/download-handler.d.ts.map +0 -1
  26. package/dist/download-handler.js +0 -203
  27. package/dist/download-handler.js.map +0 -1
  28. package/dist/downloader.d.ts +0 -11
  29. package/dist/downloader.d.ts.map +0 -1
  30. package/dist/downloader.js +0 -65
  31. package/dist/downloader.js.map +0 -1
  32. package/dist/index.d.ts +0 -2
  33. package/dist/index.d.ts.map +0 -1
  34. package/dist/index.js.map +0 -1
  35. package/dist/logger.d.ts +0 -2
  36. package/dist/logger.d.ts.map +0 -1
  37. package/dist/logger.js +0 -74
  38. package/dist/logger.js.map +0 -1
  39. package/dist/organizer.d.ts +0 -12
  40. package/dist/organizer.d.ts.map +0 -1
  41. package/dist/organizer.js +0 -42
  42. package/dist/organizer.js.map +0 -1
  43. package/dist/rd-client.d.ts +0 -25
  44. package/dist/rd-client.d.ts.map +0 -1
  45. package/dist/rd-client.js +0 -129
  46. package/dist/rd-client.js.map +0 -1
  47. package/dist/service.d.ts +0 -3
  48. package/dist/service.d.ts.map +0 -1
  49. package/dist/service.js +0 -187
  50. package/dist/service.js.map +0 -1
  51. package/dist/setup.d.ts +0 -2
  52. package/dist/setup.d.ts.map +0 -1
  53. package/dist/setup.js +0 -92
  54. package/dist/setup.js.map +0 -1
  55. package/dist/status-writer.d.ts +0 -20
  56. package/dist/status-writer.d.ts.map +0 -1
  57. package/dist/status-writer.js +0 -34
  58. package/dist/status-writer.js.map +0 -1
  59. package/dist/tui.d.ts +0 -14
  60. package/dist/tui.d.ts.map +0 -1
  61. package/dist/tui.js +0 -73
  62. package/dist/tui.js.map +0 -1
  63. package/dist/updater.d.ts +0 -27
  64. package/dist/updater.d.ts.map +0 -1
  65. package/dist/updater.js +0 -191
  66. package/dist/updater.js.map +0 -1
  67. package/dist/ws-client.d.ts +0 -26
  68. package/dist/ws-client.d.ts.map +0 -1
  69. package/dist/ws-client.js +0 -155
  70. package/dist/ws-client.js.map +0 -1
@@ -0,0 +1,178 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ createMessageId,
4
+ createTimestamp
5
+ } from "./chunk-6O3GWKMO.js";
6
+ import {
7
+ config
8
+ } from "./chunk-7TPZ4T2V.js";
9
+
10
+ // src/ws-client.ts
11
+ import WebSocket from "ws";
12
+ import { platform } from "os";
13
+ import { statfs } from "fs/promises";
14
+ var HEARTBEAT_INTERVAL = 3e4;
15
+ var MAX_BACKOFF = 3e4;
16
+ async function getDiskFreeBytes(dirPath) {
17
+ try {
18
+ const stats = await statfs(dirPath);
19
+ return stats.bavail * stats.bsize;
20
+ } catch {
21
+ return 0;
22
+ }
23
+ }
24
+ var AgentWebSocket = class {
25
+ ws = null;
26
+ backoff = 1e3;
27
+ heartbeatTimer = null;
28
+ reconnectTimer = null;
29
+ messageQueue = [];
30
+ onMessage = null;
31
+ stopped = false;
32
+ startTime = Date.now();
33
+ activeJobs = 0;
34
+ mediaDir;
35
+ constructor() {
36
+ this.mediaDir = config.get("directories.movies") || config.get("directories.tv") || "/";
37
+ }
38
+ connect() {
39
+ this.stopped = false;
40
+ const relayUrl = config.get("relay");
41
+ const deviceToken = config.get("deviceToken");
42
+ if (!relayUrl || !deviceToken) {
43
+ console.error("Not configured. Run `tadaima-agent setup` first.");
44
+ return;
45
+ }
46
+ const wsUrl = relayUrl.replace(/^http/, "ws").replace(/\/$/, "");
47
+ const url = `${wsUrl}/ws/agent?token=${deviceToken}`;
48
+ this.ws = new WebSocket(url);
49
+ this.ws.on("open", () => {
50
+ console.log("Connected to relay");
51
+ this.backoff = 1e3;
52
+ this.sendHello().catch(() => {
53
+ });
54
+ this.startHeartbeat();
55
+ this.drainQueue();
56
+ });
57
+ this.ws.on("message", (data) => {
58
+ try {
59
+ const msg = JSON.parse(data.toString());
60
+ if (this.onMessage) {
61
+ this.onMessage(msg);
62
+ }
63
+ } catch (err) {
64
+ const raw = data.toString().slice(0, 200);
65
+ console.error("Failed to parse WebSocket message:", err, "raw:", raw);
66
+ }
67
+ });
68
+ this.ws.on("close", () => {
69
+ console.log("Disconnected from relay");
70
+ this.cleanup();
71
+ this.scheduleReconnect();
72
+ });
73
+ this.ws.on("error", (err) => {
74
+ console.error("WebSocket error:", err.message);
75
+ this.cleanup();
76
+ this.scheduleReconnect();
77
+ });
78
+ }
79
+ stop() {
80
+ this.stopped = true;
81
+ this.cleanup();
82
+ if (this.ws) {
83
+ this.ws.close(1e3, "Agent stopped");
84
+ this.ws = null;
85
+ }
86
+ }
87
+ setMessageHandler(handler) {
88
+ this.onMessage = handler;
89
+ }
90
+ send(message) {
91
+ const data = JSON.stringify(message);
92
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
93
+ try {
94
+ this.ws.send(data);
95
+ } catch (err) {
96
+ console.error("Send failed, re-queuing message:", err);
97
+ this.messageQueue.push(data);
98
+ this.cleanup();
99
+ this.scheduleReconnect();
100
+ }
101
+ } else {
102
+ this.messageQueue.push(data);
103
+ }
104
+ }
105
+ setActiveJobs(count) {
106
+ this.activeJobs = count;
107
+ }
108
+ async sendHello() {
109
+ this.send({
110
+ id: createMessageId(),
111
+ type: "agent:hello",
112
+ timestamp: createTimestamp(),
113
+ payload: {
114
+ version: "0.0.0",
115
+ platform: platform(),
116
+ activeJobs: this.activeJobs,
117
+ diskFreeBytes: await getDiskFreeBytes(this.mediaDir)
118
+ }
119
+ });
120
+ }
121
+ async sendHeartbeat() {
122
+ this.send({
123
+ id: createMessageId(),
124
+ type: "agent:heartbeat",
125
+ timestamp: createTimestamp(),
126
+ payload: {
127
+ activeJobs: this.activeJobs,
128
+ diskFreeBytes: await getDiskFreeBytes(this.mediaDir),
129
+ uptimeSeconds: Math.floor((Date.now() - this.startTime) / 1e3)
130
+ }
131
+ });
132
+ }
133
+ startHeartbeat() {
134
+ this.stopHeartbeat();
135
+ this.heartbeatTimer = setInterval(
136
+ () => {
137
+ this.sendHeartbeat().catch(() => {
138
+ });
139
+ },
140
+ HEARTBEAT_INTERVAL
141
+ );
142
+ }
143
+ stopHeartbeat() {
144
+ if (this.heartbeatTimer) {
145
+ clearInterval(this.heartbeatTimer);
146
+ this.heartbeatTimer = null;
147
+ }
148
+ }
149
+ drainQueue() {
150
+ while (this.messageQueue.length > 0 && this.ws?.readyState === WebSocket.OPEN) {
151
+ try {
152
+ this.ws.send(this.messageQueue[0]);
153
+ this.messageQueue.shift();
154
+ } catch (err) {
155
+ console.error("Drain failed, will retry on reconnect:", err);
156
+ this.cleanup();
157
+ this.scheduleReconnect();
158
+ return;
159
+ }
160
+ }
161
+ }
162
+ cleanup() {
163
+ this.stopHeartbeat();
164
+ if (this.reconnectTimer) {
165
+ clearTimeout(this.reconnectTimer);
166
+ this.reconnectTimer = null;
167
+ }
168
+ }
169
+ scheduleReconnect() {
170
+ if (this.stopped) return;
171
+ this.backoff = Math.min(this.backoff * 2, MAX_BACKOFF);
172
+ console.log(`Reconnecting in ${this.backoff / 1e3}s...`);
173
+ this.reconnectTimer = setTimeout(() => this.connect(), this.backoff);
174
+ }
175
+ };
176
+ export {
177
+ AgentWebSocket
178
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@psychout98/tadaima",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "CLI download agent for Tadaima — a self-hosted media download orchestrator",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -40,19 +40,20 @@
40
40
  "dependencies": {
41
41
  "conf": "^15.1.0",
42
42
  "prompts": "^2.4.2",
43
- "ws": "^8.20.0",
44
- "@tadaima/shared": "0.0.0"
43
+ "ws": "^8.20.0"
45
44
  },
46
45
  "devDependencies": {
47
46
  "@types/node": "^25.5.2",
48
47
  "@types/prompts": "^2.4.9",
49
48
  "@types/ws": "^8.18.1",
49
+ "tsup": "^8.0.0",
50
50
  "tsx": "^4.19.0",
51
51
  "typescript": "^5.7.0",
52
- "vitest": "^4.1.2"
52
+ "vitest": "^4.1.2",
53
+ "@tadaima/shared": "0.0.0"
53
54
  },
54
55
  "scripts": {
55
- "build": "tsc",
56
+ "build": "tsup",
56
57
  "dev": "tsx watch src/index.ts",
57
58
  "lint": "eslint src/ --ignore-pattern src/__tests__/",
58
59
  "test": "vitest run",
package/dist/config.d.ts DELETED
@@ -1,23 +0,0 @@
1
- import Conf from "conf";
2
- export interface AgentConfig {
3
- relay: string;
4
- deviceToken: string;
5
- deviceId: string;
6
- deviceName: string;
7
- profileName: string;
8
- directories: {
9
- movies: string;
10
- tv: string;
11
- staging: string;
12
- };
13
- realDebrid: {
14
- apiKey: string;
15
- };
16
- maxConcurrentDownloads: number;
17
- rdPollInterval: number;
18
- lastUpdateCheck: string;
19
- updateChannel: "stable";
20
- previousBinaryPath: string;
21
- }
22
- export declare const config: Conf<AgentConfig>;
23
- //# sourceMappingURL=config.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE;QACX,MAAM,EAAE,MAAM,CAAC;QACf,EAAE,EAAE,MAAM,CAAC;QACX,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,UAAU,EAAE;QACV,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,sBAAsB,EAAE,MAAM,CAAC;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,QAAQ,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,eAAO,MAAM,MAAM,mBAsBjB,CAAC"}
package/dist/config.js DELETED
@@ -1,25 +0,0 @@
1
- import Conf from "conf";
2
- export const config = new Conf({
3
- projectName: "tadaima",
4
- defaults: {
5
- relay: "",
6
- deviceToken: "",
7
- deviceId: "",
8
- deviceName: "",
9
- profileName: "",
10
- directories: {
11
- movies: "",
12
- tv: "",
13
- staging: "",
14
- },
15
- realDebrid: {
16
- apiKey: "",
17
- },
18
- maxConcurrentDownloads: 2,
19
- rdPollInterval: 30,
20
- lastUpdateCheck: "",
21
- updateChannel: "stable",
22
- previousBinaryPath: "",
23
- },
24
- });
25
- //# sourceMappingURL=config.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAuBxB,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,IAAI,CAAc;IAC1C,WAAW,EAAE,SAAS;IACtB,QAAQ,EAAE;QACR,KAAK,EAAE,EAAE;QACT,WAAW,EAAE,EAAE;QACf,QAAQ,EAAE,EAAE;QACZ,UAAU,EAAE,EAAE;QACd,WAAW,EAAE,EAAE;QACf,WAAW,EAAE;YACX,MAAM,EAAE,EAAE;YACV,EAAE,EAAE,EAAE;YACN,OAAO,EAAE,EAAE;SACZ;QACD,UAAU,EAAE;YACV,MAAM,EAAE,EAAE;SACX;QACD,sBAAsB,EAAE,CAAC;QACzB,cAAc,EAAE,EAAE;QAClB,eAAe,EAAE,EAAE;QACnB,aAAa,EAAE,QAAQ;QACvB,kBAAkB,EAAE,EAAE;KACvB;CACF,CAAC,CAAC"}
package/dist/daemon.d.ts DELETED
@@ -1,8 +0,0 @@
1
- export declare function getLogPath(): string;
2
- export declare function startDaemon(): void;
3
- export declare function stopDaemon(): void;
4
- export declare function getDaemonStatus(): {
5
- running: boolean;
6
- pid?: number;
7
- };
8
- //# sourceMappingURL=daemon.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AAoBA,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,wBAAgB,WAAW,IAAI,IAAI,CAsClC;AAED,wBAAgB,UAAU,IAAI,IAAI,CAuBjC;AAED,wBAAgB,eAAe,IAAI;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAqBpE"}
package/dist/daemon.js DELETED
@@ -1,91 +0,0 @@
1
- import { readFileSync, writeFileSync, unlinkSync, existsSync, mkdirSync, createWriteStream, } from "node:fs";
2
- import { dirname, join } from "node:path";
3
- import { spawn } from "node:child_process";
4
- import { config } from "./config.js";
5
- function getPidPath() {
6
- return join(dirname(config.path), "tadaima.pid");
7
- }
8
- function getLogDir() {
9
- return join(dirname(config.path), "logs");
10
- }
11
- export function getLogPath() {
12
- return join(getLogDir(), "tadaima.log");
13
- }
14
- export function startDaemon() {
15
- const pidPath = getPidPath();
16
- if (existsSync(pidPath)) {
17
- const oldPid = parseInt(readFileSync(pidPath, "utf-8").trim(), 10);
18
- if (Number.isNaN(oldPid)) {
19
- console.log("Stale PID file (invalid contents). Removing.");
20
- unlinkSync(pidPath);
21
- }
22
- else {
23
- try {
24
- process.kill(oldPid, 0);
25
- console.log(`Agent already running (PID ${oldPid})`);
26
- return;
27
- }
28
- catch {
29
- unlinkSync(pidPath);
30
- }
31
- }
32
- }
33
- const logDir = getLogDir();
34
- mkdirSync(logDir, { recursive: true });
35
- const logPath = getLogPath();
36
- const logStream = createWriteStream(logPath, { flags: "a" });
37
- const child = spawn(process.execPath, [process.argv[1], "start"], {
38
- detached: true,
39
- stdio: ["ignore", logStream, logStream],
40
- env: { ...process.env, TADAIMA_DAEMON: "1" },
41
- });
42
- child.unref();
43
- if (child.pid) {
44
- writeFileSync(pidPath, String(child.pid));
45
- console.log(`Agent started in background (PID ${child.pid})`);
46
- console.log(`Logs: ${logPath}`);
47
- }
48
- }
49
- export function stopDaemon() {
50
- const pidPath = getPidPath();
51
- if (!existsSync(pidPath)) {
52
- console.log("Agent is not running.");
53
- return;
54
- }
55
- const pid = parseInt(readFileSync(pidPath, "utf-8").trim(), 10);
56
- if (Number.isNaN(pid)) {
57
- console.log("Stale PID file (invalid contents). Removing.");
58
- unlinkSync(pidPath);
59
- return;
60
- }
61
- try {
62
- process.kill(pid, "SIGTERM");
63
- console.log(`Sent SIGTERM to PID ${pid}`);
64
- unlinkSync(pidPath);
65
- }
66
- catch {
67
- console.log(`Process ${pid} not found. Cleaning up PID file.`);
68
- unlinkSync(pidPath);
69
- }
70
- }
71
- export function getDaemonStatus() {
72
- const pidPath = getPidPath();
73
- if (!existsSync(pidPath)) {
74
- return { running: false };
75
- }
76
- const pid = parseInt(readFileSync(pidPath, "utf-8").trim(), 10);
77
- if (Number.isNaN(pid)) {
78
- console.log("Stale PID file (invalid contents). Removing.");
79
- unlinkSync(pidPath);
80
- return { running: false };
81
- }
82
- try {
83
- process.kill(pid, 0);
84
- return { running: true, pid };
85
- }
86
- catch {
87
- unlinkSync(pidPath);
88
- return { running: false };
89
- }
90
- }
91
- //# sourceMappingURL=daemon.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"daemon.js","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"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"}
@@ -1,15 +0,0 @@
1
- import type { AgentWebSocket } from "./ws-client.js";
2
- export declare class DownloadHandler {
3
- private ws;
4
- private activeJobs;
5
- private semaphore;
6
- constructor(ws: AgentWebSocket);
7
- get activeCount(): number;
8
- handleRequest(msg: Record<string, unknown>): Promise<void>;
9
- handleCancel(msg: Record<string, unknown>): void;
10
- handleCacheCheck(msg: Record<string, unknown>): Promise<void>;
11
- private executeDownload;
12
- private sendProgress;
13
- private sendMessage;
14
- }
15
- //# sourceMappingURL=download-handler.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"download-handler.d.ts","sourceRoot":"","sources":["../src/download-handler.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAsBrD,qBAAa,eAAe;IAC1B,OAAO,CAAC,EAAE,CAAiB;IAC3B,OAAO,CAAC,UAAU,CAAkC;IACpD,OAAO,CAAC,SAAS,CAAS;gBAEd,EAAE,EAAE,cAAc;IAK9B,IAAI,WAAW,IAAI,MAAM,CAExB;IAEK,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IA4EhE,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAS1C,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;YAcrD,eAAe;IA0G7B,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,WAAW;CAQpB"}
@@ -1,203 +0,0 @@
1
- import { join } from "node:path";
2
- import { rm } from "node:fs/promises";
3
- import { createMessageId, createTimestamp } from "@tadaima/shared";
4
- import { config } from "./config.js";
5
- import { rdClient } from "./rd-client.js";
6
- import { downloadFile } from "./downloader.js";
7
- import { organizeFile } from "./organizer.js";
8
- export class DownloadHandler {
9
- ws;
10
- activeJobs = new Map();
11
- semaphore;
12
- constructor(ws) {
13
- this.ws = ws;
14
- this.semaphore = config.get("maxConcurrentDownloads");
15
- }
16
- get activeCount() {
17
- return this.activeJobs.size;
18
- }
19
- async handleRequest(msg) {
20
- if (typeof msg.id !== "string" || !msg.id) {
21
- console.error("download:request missing valid msg.id, ignoring:", msg);
22
- return;
23
- }
24
- if (msg.payload == null || typeof msg.payload !== "object") {
25
- console.error("download:request missing valid msg.payload, ignoring:", msg.id);
26
- return;
27
- }
28
- const payload = msg.payload;
29
- const requestId = msg.id;
30
- if (typeof payload.magnet !== "string" || !payload.magnet) {
31
- console.error("download:request missing required payload.magnet, ignoring:", requestId);
32
- return;
33
- }
34
- if (typeof payload.title !== "string" || !payload.title) {
35
- console.error("download:request missing required payload.title, ignoring:", requestId);
36
- return;
37
- }
38
- if (this.activeJobs.size >= this.semaphore) {
39
- this.sendMessage("download:rejected", {
40
- requestId,
41
- reason: "queue_full",
42
- });
43
- return;
44
- }
45
- const jobId = createMessageId();
46
- const abortController = new AbortController();
47
- const meta = {
48
- tmdbId: payload.tmdbId,
49
- imdbId: payload.imdbId,
50
- title: payload.title,
51
- year: payload.year,
52
- mediaType: payload.mediaType,
53
- season: payload.season,
54
- episode: payload.episode,
55
- episodeTitle: payload.episodeTitle,
56
- magnet: payload.magnet,
57
- torrentName: payload.torrentName,
58
- expectedSize: payload.expectedSize,
59
- };
60
- const job = {
61
- jobId,
62
- requestId,
63
- abortController,
64
- phase: "adding",
65
- meta,
66
- };
67
- this.activeJobs.set(jobId, job);
68
- this.ws.setActiveJobs(this.activeJobs.size);
69
- this.sendMessage("download:accepted", { jobId, requestId });
70
- try {
71
- await this.executeDownload(job);
72
- }
73
- catch (err) {
74
- const errMsg = err instanceof Error ? err.message : String(err);
75
- const retryable = !errMsg.includes("Cancelled");
76
- this.sendMessage("download:failed", {
77
- jobId,
78
- error: errMsg,
79
- phase: job.phase,
80
- retryable,
81
- _meta: meta,
82
- });
83
- }
84
- finally {
85
- this.activeJobs.delete(jobId);
86
- this.ws.setActiveJobs(this.activeJobs.size);
87
- }
88
- }
89
- handleCancel(msg) {
90
- const payload = msg.payload;
91
- const jobId = payload.jobId;
92
- const job = this.activeJobs.get(jobId);
93
- if (job) {
94
- job.abortController.abort();
95
- }
96
- }
97
- async handleCacheCheck(msg) {
98
- const payload = msg.payload;
99
- const requestId = payload.requestId;
100
- const infoHashes = payload.infoHashes;
101
- try {
102
- const cached = await rdClient.checkCache(infoHashes);
103
- this.sendMessage("cache:result", { requestId, cached });
104
- }
105
- catch (err) {
106
- console.warn("Cache check failed", err);
107
- this.sendMessage("cache:result", { requestId, cached: {} });
108
- }
109
- }
110
- async executeDownload(job) {
111
- const { meta, abortController } = job;
112
- const signal = abortController.signal;
113
- // Phase: adding
114
- job.phase = "adding";
115
- this.sendProgress(job.jobId, "adding", 0);
116
- console.log(`[${job.jobId}] Adding magnet to RD...`);
117
- const { id: torrentId } = await rdClient.addMagnet(meta.magnet);
118
- if (signal.aborted)
119
- throw new Error("Cancelled");
120
- await rdClient.selectFiles(torrentId);
121
- if (signal.aborted)
122
- throw new Error("Cancelled");
123
- // Phase: waiting
124
- job.phase = "waiting";
125
- this.sendProgress(job.jobId, "waiting", 0);
126
- console.log(`[${job.jobId}] Waiting for RD to process...`);
127
- const links = await rdClient.pollUntilReady(torrentId, undefined, undefined, (progress) => this.sendProgress(job.jobId, "waiting", progress), signal);
128
- // Phase: unrestricting
129
- job.phase = "unrestricting";
130
- this.sendProgress(job.jobId, "unrestricting", 0);
131
- console.log(`[${job.jobId}] Unrestricting ${links.length} links...`);
132
- const unrestricted = await rdClient.unrestrictAll(links);
133
- if (signal.aborted)
134
- throw new Error("Cancelled");
135
- // Phase: downloading
136
- job.phase = "downloading";
137
- console.log(`[${job.jobId}] Downloading files...`);
138
- const stagingDir = config.get("directories.staging") || "/tmp/tadaima/staging";
139
- const downloadedFiles = [];
140
- let totalSize = 0;
141
- for (const file of unrestricted) {
142
- if (signal.aborted)
143
- throw new Error("Cancelled");
144
- const destPath = join(stagingDir, job.jobId, file.filename);
145
- console.log(`[${job.jobId}] Downloading: ${file.filename}`);
146
- const size = await downloadFile(file.url, destPath, (progress) => {
147
- const pct = progress.totalBytes > 0
148
- ? Math.round((progress.downloadedBytes / progress.totalBytes) * 100)
149
- : 0;
150
- this.sendMessage("download:progress", {
151
- jobId: job.jobId,
152
- phase: "downloading",
153
- progress: pct,
154
- downloadedBytes: progress.downloadedBytes,
155
- totalBytes: progress.totalBytes,
156
- speedBps: progress.speedBps,
157
- eta: progress.eta,
158
- });
159
- }, signal);
160
- downloadedFiles.push(destPath);
161
- totalSize += size;
162
- }
163
- // Phase: organizing
164
- job.phase = "organizing";
165
- this.sendProgress(job.jobId, "organizing", 0);
166
- console.log(`[${job.jobId}] Organizing files...`);
167
- let finalPath = "";
168
- for (const filePath of downloadedFiles) {
169
- finalPath = await organizeFile({
170
- title: meta.title,
171
- year: meta.year,
172
- tmdbId: meta.tmdbId,
173
- mediaType: meta.mediaType,
174
- season: meta.season,
175
- episode: meta.episode,
176
- episodeTitle: meta.episodeTitle,
177
- sourcePath: filePath,
178
- });
179
- }
180
- // Clean staging
181
- await rm(join(stagingDir, job.jobId), { recursive: true, force: true }).catch(() => { });
182
- // Done!
183
- console.log(`[${job.jobId}] Complete: ${finalPath}`);
184
- this.sendMessage("download:completed", {
185
- jobId: job.jobId,
186
- filePath: finalPath,
187
- finalSize: totalSize,
188
- _meta: meta,
189
- });
190
- }
191
- sendProgress(jobId, phase, progress) {
192
- this.sendMessage("download:progress", { jobId, phase, progress });
193
- }
194
- sendMessage(type, payload) {
195
- this.ws.send({
196
- id: createMessageId(),
197
- type,
198
- timestamp: createTimestamp(),
199
- payload,
200
- });
201
- }
202
- }
203
- //# sourceMappingURL=download-handler.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"download-handler.js","sourceRoot":"","sources":["../src/download-handler.ts"],"names":[],"mappings":"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"}
@@ -1,11 +0,0 @@
1
- export interface DownloadProgress {
2
- downloadedBytes: number;
3
- totalBytes: number;
4
- speedBps: number;
5
- eta: number;
6
- }
7
- /**
8
- * Download a file via HTTP with progress reporting.
9
- */
10
- export declare function downloadFile(url: string, destPath: string, onProgress?: (progress: DownloadProgress) => void, signal?: AbortSignal, baseDir?: string): Promise<number>;
11
- //# sourceMappingURL=downloader.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"downloader.d.ts","sourceRoot":"","sources":["../src/downloader.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,gBAAgB;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,gBAAgB,KAAK,IAAI,EACjD,MAAM,CAAC,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,CAqEjB"}