@adbjs/cli 1.0.0
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 +318 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1384 -0
- package/package.json +62 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1384 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
5
|
+
import { dirname, join } from "path";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
|
+
import { Command } from "commander";
|
|
8
|
+
|
|
9
|
+
// src/commands/auth.ts
|
|
10
|
+
import { AllDebridClient } from "@adbjs/sdk";
|
|
11
|
+
import * as clack from "@clack/prompts";
|
|
12
|
+
import chalk from "chalk";
|
|
13
|
+
import ora from "ora";
|
|
14
|
+
|
|
15
|
+
// src/config.ts
|
|
16
|
+
import Conf from "conf";
|
|
17
|
+
var Config = class {
|
|
18
|
+
store;
|
|
19
|
+
constructor() {
|
|
20
|
+
this.store = new Conf({
|
|
21
|
+
projectName: "alldebrid",
|
|
22
|
+
configName: "config"
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
getApiKey() {
|
|
26
|
+
return process.env.ALLDEBRID_API_KEY || this.store.get("apiKey");
|
|
27
|
+
}
|
|
28
|
+
setApiKey(apiKey) {
|
|
29
|
+
this.store.set("apiKey", apiKey);
|
|
30
|
+
}
|
|
31
|
+
clearApiKey() {
|
|
32
|
+
this.store.delete("apiKey");
|
|
33
|
+
}
|
|
34
|
+
hasApiKey() {
|
|
35
|
+
return !!this.getApiKey();
|
|
36
|
+
}
|
|
37
|
+
getConfigPath() {
|
|
38
|
+
return this.store.path;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
var config = new Config();
|
|
42
|
+
|
|
43
|
+
// src/utils/output.ts
|
|
44
|
+
var jsonMode = false;
|
|
45
|
+
function setJsonMode(enabled) {
|
|
46
|
+
jsonMode = enabled;
|
|
47
|
+
}
|
|
48
|
+
function isJsonMode() {
|
|
49
|
+
return jsonMode;
|
|
50
|
+
}
|
|
51
|
+
function output(data, formatter) {
|
|
52
|
+
if (jsonMode) {
|
|
53
|
+
console.log(JSON.stringify(data, null, 2));
|
|
54
|
+
} else {
|
|
55
|
+
formatter(data);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// src/commands/auth.ts
|
|
60
|
+
async function authLogin() {
|
|
61
|
+
clack.intro(chalk.cyan("AllDebrid Authentication"));
|
|
62
|
+
if (config.hasApiKey()) {
|
|
63
|
+
const shouldContinue = await clack.confirm({
|
|
64
|
+
message: "You are already authenticated. Do you want to login again?",
|
|
65
|
+
initialValue: false
|
|
66
|
+
});
|
|
67
|
+
if (clack.isCancel(shouldContinue) || !shouldContinue) {
|
|
68
|
+
clack.cancel("Authentication cancelled.");
|
|
69
|
+
process.exit(0);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const tempClient = new AllDebridClient({
|
|
73
|
+
apiKey: "",
|
|
74
|
+
agent: "@adbjs/cli"
|
|
75
|
+
});
|
|
76
|
+
let pinData;
|
|
77
|
+
try {
|
|
78
|
+
const spinner2 = ora("Generating PIN code...").start();
|
|
79
|
+
pinData = await tempClient.pin.generate();
|
|
80
|
+
spinner2.succeed("PIN code generated");
|
|
81
|
+
} catch (error) {
|
|
82
|
+
clack.log.error("Failed to generate PIN code");
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
if (!pinData) {
|
|
86
|
+
throw new Error("PIN generation failed");
|
|
87
|
+
}
|
|
88
|
+
clack.note(
|
|
89
|
+
`Visit: ${chalk.blue.underline(pinData.user_url)}
|
|
90
|
+
PIN Code: ${chalk.green.bold(pinData.pin)}
|
|
91
|
+
|
|
92
|
+
This PIN will expire in 10 minutes`,
|
|
93
|
+
"Authorization Required"
|
|
94
|
+
);
|
|
95
|
+
const spinner = ora("Waiting for authorization...").start();
|
|
96
|
+
try {
|
|
97
|
+
const apikey = await tempClient.pin.waitForAuth(pinData.check, pinData.pin, {
|
|
98
|
+
timeout: 6e5,
|
|
99
|
+
interval: 3e3
|
|
100
|
+
});
|
|
101
|
+
spinner.succeed(chalk.green("Successfully authenticated!"));
|
|
102
|
+
config.setApiKey(apikey);
|
|
103
|
+
clack.outro(
|
|
104
|
+
`Authentication successful!
|
|
105
|
+
API key saved to: ${config.getConfigPath()}`
|
|
106
|
+
);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
spinner.fail("Authentication failed or timed out");
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
async function authLogout() {
|
|
113
|
+
if (!config.hasApiKey()) {
|
|
114
|
+
console.log(chalk.yellow("You are not authenticated"));
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const shouldLogout = await clack.confirm({
|
|
118
|
+
message: "Are you sure you want to logout?",
|
|
119
|
+
initialValue: false
|
|
120
|
+
});
|
|
121
|
+
if (clack.isCancel(shouldLogout) || !shouldLogout) {
|
|
122
|
+
clack.cancel("Logout cancelled.");
|
|
123
|
+
process.exit(0);
|
|
124
|
+
}
|
|
125
|
+
config.clearApiKey();
|
|
126
|
+
console.log(chalk.green("Successfully logged out"));
|
|
127
|
+
console.log(chalk.dim(`Config file: ${config.getConfigPath()}`));
|
|
128
|
+
}
|
|
129
|
+
async function authStatus() {
|
|
130
|
+
const apiKey = config.getApiKey();
|
|
131
|
+
if (!apiKey) {
|
|
132
|
+
output({ authenticated: false }, () => {
|
|
133
|
+
console.log(chalk.yellow("Not authenticated"));
|
|
134
|
+
console.log(chalk.dim('\nRun "adb auth login" to authenticate'));
|
|
135
|
+
});
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
const client = new AllDebridClient({ apiKey, agent: "@adbjs/cli" });
|
|
140
|
+
const spinner = isJsonMode() ? null : ora("Verifying API key...").start();
|
|
141
|
+
const data = await client.user.getInfo();
|
|
142
|
+
spinner?.succeed("API key is valid");
|
|
143
|
+
output({ authenticated: true, valid: true, user: data?.user }, () => {
|
|
144
|
+
console.log(chalk.green("Authenticated"));
|
|
145
|
+
if (data?.user) {
|
|
146
|
+
const userInfo2 = data.user;
|
|
147
|
+
console.log(chalk.dim("\nUser Information:"));
|
|
148
|
+
console.log(` Username: ${chalk.cyan(userInfo2.username || "N/A")}`);
|
|
149
|
+
console.log(
|
|
150
|
+
` Premium: ${userInfo2.isPremium ? chalk.green("Yes") : chalk.red("No")}`
|
|
151
|
+
);
|
|
152
|
+
if (userInfo2.premiumUntil) {
|
|
153
|
+
const expiryDate = new Date(userInfo2.premiumUntil * 1e3);
|
|
154
|
+
console.log(` Premium Until: ${chalk.cyan(expiryDate.toLocaleDateString())}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
console.log(chalk.dim(`
|
|
158
|
+
Config: ${config.getConfigPath()}`));
|
|
159
|
+
});
|
|
160
|
+
} catch {
|
|
161
|
+
output({ authenticated: true, valid: false }, () => {
|
|
162
|
+
console.log(chalk.red("\nAPI key is invalid or expired"));
|
|
163
|
+
console.log(chalk.dim('Run "adb auth login" to re-authenticate'));
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
async function authInteractive() {
|
|
168
|
+
clack.intro(chalk.cyan("Authentication Menu"));
|
|
169
|
+
const action = await clack.select({
|
|
170
|
+
message: "What would you like to do?",
|
|
171
|
+
options: [
|
|
172
|
+
{ value: "login", label: "Login (Generate new API key)" },
|
|
173
|
+
{ value: "status", label: "Check authentication status" },
|
|
174
|
+
{ value: "logout", label: "Logout (Clear saved API key)" }
|
|
175
|
+
]
|
|
176
|
+
});
|
|
177
|
+
if (clack.isCancel(action)) {
|
|
178
|
+
clack.cancel("Operation cancelled.");
|
|
179
|
+
process.exit(0);
|
|
180
|
+
}
|
|
181
|
+
switch (action) {
|
|
182
|
+
case "login":
|
|
183
|
+
await authLogin();
|
|
184
|
+
break;
|
|
185
|
+
case "status":
|
|
186
|
+
await authStatus();
|
|
187
|
+
break;
|
|
188
|
+
case "logout":
|
|
189
|
+
await authLogout();
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// src/commands/host.ts
|
|
195
|
+
import chalk2 from "chalk";
|
|
196
|
+
import ora2 from "ora";
|
|
197
|
+
|
|
198
|
+
// src/utils/client.ts
|
|
199
|
+
import { AllDebridClient as AllDebridClient2 } from "@adbjs/sdk";
|
|
200
|
+
function createClient(apiKeyOverride) {
|
|
201
|
+
const apiKey = apiKeyOverride || config.getApiKey();
|
|
202
|
+
if (!apiKey) {
|
|
203
|
+
throw new Error(
|
|
204
|
+
'No API key found. Please run "adb auth login" or set ALLDEBRID_API_KEY environment variable.'
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
return new AllDebridClient2({
|
|
208
|
+
apiKey,
|
|
209
|
+
agent: "@adbjs/cli"
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// src/commands/host.ts
|
|
214
|
+
async function hostList(hostsOnly) {
|
|
215
|
+
const client = createClient();
|
|
216
|
+
const spinner = isJsonMode() ? null : ora2("Fetching supported hosts...").start();
|
|
217
|
+
try {
|
|
218
|
+
const hosts = await client.host.list();
|
|
219
|
+
spinner?.stop();
|
|
220
|
+
if (!hosts || !hosts.hosts && !hosts.streams && !hosts.redirectors) {
|
|
221
|
+
output({ hosts: null }, () => console.log(chalk2.yellow("No hosts information available")));
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
output(hosts, () => {
|
|
225
|
+
if (hostsOnly && hosts.hosts) {
|
|
226
|
+
console.log(chalk2.green(`
|
|
227
|
+
Supported Hosts (${Object.keys(hosts.hosts).length}):
|
|
228
|
+
`));
|
|
229
|
+
const sortedHosts = Object.entries(hosts.hosts).sort(([a], [b]) => a.localeCompare(b));
|
|
230
|
+
for (const [name, _] of sortedHosts) {
|
|
231
|
+
console.log(` ${chalk2.cyan(name)}`);
|
|
232
|
+
}
|
|
233
|
+
console.log("");
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
if (hosts.hosts) {
|
|
237
|
+
console.log(chalk2.bold("\nSupported Hosts:"));
|
|
238
|
+
console.log(chalk2.dim("\u2500".repeat(50)));
|
|
239
|
+
const sortedHosts = Object.entries(hosts.hosts).sort(([a], [b]) => a.localeCompare(b));
|
|
240
|
+
for (const [name, info] of sortedHosts) {
|
|
241
|
+
const typeStr = info.type ? `(${info.type})` : "";
|
|
242
|
+
console.log(` ${chalk2.cyan(name)} ${chalk2.dim(typeStr)}`);
|
|
243
|
+
}
|
|
244
|
+
console.log("");
|
|
245
|
+
}
|
|
246
|
+
if (hosts.streams && Object.keys(hosts.streams).length > 0) {
|
|
247
|
+
console.log(chalk2.bold("Streaming Hosts:"));
|
|
248
|
+
console.log(chalk2.dim("\u2500".repeat(50)));
|
|
249
|
+
const sortedStreams = Object.entries(hosts.streams).sort(([a], [b]) => a.localeCompare(b));
|
|
250
|
+
for (const [name] of sortedStreams) {
|
|
251
|
+
console.log(` ${chalk2.yellow(name)}`);
|
|
252
|
+
}
|
|
253
|
+
console.log("");
|
|
254
|
+
}
|
|
255
|
+
if (hosts.redirectors && Object.keys(hosts.redirectors).length > 0) {
|
|
256
|
+
console.log(chalk2.bold(`Supported Redirectors (${Object.keys(hosts.redirectors).length}):`));
|
|
257
|
+
console.log(chalk2.dim("\u2500".repeat(50)));
|
|
258
|
+
const sortedRedirectors = Object.keys(hosts.redirectors).sort((a, b) => a.localeCompare(b));
|
|
259
|
+
for (const redirector of sortedRedirectors) {
|
|
260
|
+
console.log(` ${chalk2.magenta(redirector)}`);
|
|
261
|
+
}
|
|
262
|
+
console.log("");
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
} catch (error) {
|
|
266
|
+
spinner?.fail("Failed to fetch hosts");
|
|
267
|
+
console.error(isJsonMode() ? JSON.stringify({ error: error.message }) : chalk2.red(error.message || "Unknown error"));
|
|
268
|
+
process.exit(1);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
async function hostDomains() {
|
|
272
|
+
const client = createClient();
|
|
273
|
+
const spinner = isJsonMode() ? null : ora2("Fetching all supported domains...").start();
|
|
274
|
+
try {
|
|
275
|
+
const result = await client.host.domains();
|
|
276
|
+
spinner?.stop();
|
|
277
|
+
const allDomains = [];
|
|
278
|
+
if (result?.hosts) {
|
|
279
|
+
allDomains.push(...result.hosts);
|
|
280
|
+
}
|
|
281
|
+
if (result?.streams) {
|
|
282
|
+
allDomains.push(...result.streams);
|
|
283
|
+
}
|
|
284
|
+
if (result?.redirectors) {
|
|
285
|
+
allDomains.push(...result.redirectors);
|
|
286
|
+
}
|
|
287
|
+
if (allDomains.length === 0) {
|
|
288
|
+
output({ domains: [] }, () => console.log(chalk2.yellow("No domains information available")));
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
output(result, () => {
|
|
292
|
+
console.log(chalk2.green(`
|
|
293
|
+
Supported Domains (${allDomains.length}):
|
|
294
|
+
`));
|
|
295
|
+
const sortedDomains = allDomains.sort((a, b) => a.localeCompare(b));
|
|
296
|
+
for (const domain of sortedDomains) {
|
|
297
|
+
console.log(` ${chalk2.cyan(domain)}`);
|
|
298
|
+
}
|
|
299
|
+
console.log("");
|
|
300
|
+
});
|
|
301
|
+
} catch (error) {
|
|
302
|
+
spinner?.fail("Failed to fetch domains");
|
|
303
|
+
console.error(isJsonMode() ? JSON.stringify({ error: error.message }) : chalk2.red(error.message || "Unknown error"));
|
|
304
|
+
process.exit(1);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// src/commands/link.ts
|
|
309
|
+
import * as clack2 from "@clack/prompts";
|
|
310
|
+
import chalk3 from "chalk";
|
|
311
|
+
import ora3 from "ora";
|
|
312
|
+
async function linkUnlock(url, password2) {
|
|
313
|
+
const client = createClient();
|
|
314
|
+
const spinner = isJsonMode() ? null : ora3("Unlocking link...").start();
|
|
315
|
+
try {
|
|
316
|
+
const result = await client.link.unlock(url, password2);
|
|
317
|
+
spinner?.succeed(chalk3.green("Link unlocked successfully!"));
|
|
318
|
+
output(result, () => {
|
|
319
|
+
if (result) {
|
|
320
|
+
console.log(chalk3.dim("\nUnlocked Link Information:"));
|
|
321
|
+
console.log(` Filename: ${chalk3.cyan(result.filename || "N/A")}`);
|
|
322
|
+
console.log(` Size: ${chalk3.cyan(formatBytes(result.filesize || 0))}`);
|
|
323
|
+
console.log(` Host: ${chalk3.cyan(result.host || "N/A")}`);
|
|
324
|
+
if (result.id) {
|
|
325
|
+
console.log(` ID: ${chalk3.cyan(result.id)}`);
|
|
326
|
+
}
|
|
327
|
+
console.log(`
|
|
328
|
+
${chalk3.blue.underline(result.link || "N/A")}`);
|
|
329
|
+
if (result.streams && result.streams.length > 0) {
|
|
330
|
+
console.log(chalk3.dim("\nAvailable Streams:"));
|
|
331
|
+
for (const stream of result.streams) {
|
|
332
|
+
console.log(` ${chalk3.yellow(JSON.stringify(stream))}`);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
} catch (error) {
|
|
338
|
+
spinner?.fail("Failed to unlock link");
|
|
339
|
+
console.error(isJsonMode() ? JSON.stringify({ error: error.message }) : chalk3.red(error.message || "Unknown error"));
|
|
340
|
+
process.exit(1);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
async function linkInfo(url, password2) {
|
|
344
|
+
const client = createClient();
|
|
345
|
+
const spinner = isJsonMode() ? null : ora3("Fetching link information...").start();
|
|
346
|
+
try {
|
|
347
|
+
const data = await client.link.infos(url, password2);
|
|
348
|
+
spinner?.stop();
|
|
349
|
+
if (!data?.infos || data.infos.length === 0) {
|
|
350
|
+
output({ infos: [] }, () => console.log(chalk3.yellow("No link information available")));
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
output(data, () => {
|
|
354
|
+
for (const info of data.infos) {
|
|
355
|
+
console.log(chalk3.bold("\nLink Information:"));
|
|
356
|
+
console.log(chalk3.dim("\u2500".repeat(50)));
|
|
357
|
+
console.log(`Filename: ${chalk3.cyan(info.filename || "N/A")}`);
|
|
358
|
+
console.log(`Size: ${chalk3.cyan(formatBytes(info.size || 0))}`);
|
|
359
|
+
console.log(`Host: ${chalk3.cyan(info.host || "N/A")}`);
|
|
360
|
+
if (info.hostDomain) {
|
|
361
|
+
console.log(`Host Domain: ${chalk3.cyan(info.hostDomain)}`);
|
|
362
|
+
}
|
|
363
|
+
if (info.link) {
|
|
364
|
+
console.log(`Link: ${chalk3.blue.underline(info.link)}`);
|
|
365
|
+
}
|
|
366
|
+
console.log("");
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
} catch (error) {
|
|
370
|
+
spinner?.fail("Failed to fetch link information");
|
|
371
|
+
console.error(isJsonMode() ? JSON.stringify({ error: error.message }) : chalk3.red(error.message || "Unknown error"));
|
|
372
|
+
process.exit(1);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
async function linkStream(id, stream) {
|
|
376
|
+
const client = createClient();
|
|
377
|
+
const spinner = isJsonMode() ? null : ora3("Fetching streaming link...").start();
|
|
378
|
+
try {
|
|
379
|
+
const result = await client.link.streaming(id, stream);
|
|
380
|
+
spinner?.succeed(chalk3.green("Streaming link retrieved!"));
|
|
381
|
+
output(result, () => {
|
|
382
|
+
if (result) {
|
|
383
|
+
console.log(chalk3.dim("\nStreaming Information:"));
|
|
384
|
+
console.log(` Filename: ${chalk3.cyan(result.filename || "N/A")}`);
|
|
385
|
+
console.log(` Size: ${chalk3.cyan(formatBytes(result.filesize || 0))}`);
|
|
386
|
+
if (result.delayed) {
|
|
387
|
+
console.log(chalk3.yellow(`
|
|
388
|
+
\u23F1 Delayed by ${result.delayed} seconds`));
|
|
389
|
+
}
|
|
390
|
+
console.log(`
|
|
391
|
+
${chalk3.blue.underline(result.link || "N/A")}`);
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
} catch (error) {
|
|
395
|
+
spinner?.fail("Failed to fetch streaming link");
|
|
396
|
+
console.error(isJsonMode() ? JSON.stringify({ error: error.message }) : chalk3.red(error.message || "Unknown error"));
|
|
397
|
+
process.exit(1);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
async function linkRedirector(url) {
|
|
401
|
+
const client = createClient();
|
|
402
|
+
const spinner = isJsonMode() ? null : ora3("Extracting links from redirector...").start();
|
|
403
|
+
try {
|
|
404
|
+
const data = await client.link.redirector(url);
|
|
405
|
+
spinner?.stop();
|
|
406
|
+
if (!data?.links || data.links.length === 0) {
|
|
407
|
+
output({ links: [] }, () => console.log(chalk3.yellow("No links found")));
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
output(data, () => {
|
|
411
|
+
console.log(chalk3.green(`
|
|
412
|
+
Found ${data.links.length} link(s):
|
|
413
|
+
`));
|
|
414
|
+
for (const link2 of data.links) {
|
|
415
|
+
console.log(` ${chalk3.blue.underline(link2)}`);
|
|
416
|
+
}
|
|
417
|
+
console.log("");
|
|
418
|
+
});
|
|
419
|
+
} catch (error) {
|
|
420
|
+
spinner?.fail("Failed to extract links from redirector");
|
|
421
|
+
console.error(isJsonMode() ? JSON.stringify({ error: error.message }) : chalk3.red(error.message || "Unknown error"));
|
|
422
|
+
process.exit(1);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
async function linkInteractive() {
|
|
426
|
+
clack2.intro(chalk3.cyan("Link Management"));
|
|
427
|
+
const action = await clack2.select({
|
|
428
|
+
message: "What would you like to do?",
|
|
429
|
+
options: [
|
|
430
|
+
{ value: "unlock", label: "Unlock premium link" },
|
|
431
|
+
{ value: "info", label: "Get link information" },
|
|
432
|
+
{ value: "stream", label: "Get streaming link" },
|
|
433
|
+
{ value: "redirector", label: "Extract from redirector" }
|
|
434
|
+
]
|
|
435
|
+
});
|
|
436
|
+
if (clack2.isCancel(action)) {
|
|
437
|
+
clack2.cancel("Operation cancelled.");
|
|
438
|
+
process.exit(0);
|
|
439
|
+
}
|
|
440
|
+
switch (action) {
|
|
441
|
+
case "unlock": {
|
|
442
|
+
const url = await clack2.text({
|
|
443
|
+
message: "Enter link to unlock:",
|
|
444
|
+
validate: (value) => {
|
|
445
|
+
if (!value)
|
|
446
|
+
return "Please enter a link";
|
|
447
|
+
return void 0;
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
if (clack2.isCancel(url)) {
|
|
451
|
+
clack2.cancel("Operation cancelled.");
|
|
452
|
+
process.exit(0);
|
|
453
|
+
}
|
|
454
|
+
const needsPassword = await clack2.confirm({
|
|
455
|
+
message: "Does this link require a password?",
|
|
456
|
+
initialValue: false
|
|
457
|
+
});
|
|
458
|
+
let password2;
|
|
459
|
+
if (!clack2.isCancel(needsPassword) && needsPassword) {
|
|
460
|
+
const passwordInput = await clack2.password({
|
|
461
|
+
message: "Enter password:"
|
|
462
|
+
});
|
|
463
|
+
if (clack2.isCancel(passwordInput)) {
|
|
464
|
+
clack2.cancel("Operation cancelled.");
|
|
465
|
+
process.exit(0);
|
|
466
|
+
}
|
|
467
|
+
password2 = passwordInput;
|
|
468
|
+
}
|
|
469
|
+
await linkUnlock(url, password2);
|
|
470
|
+
break;
|
|
471
|
+
}
|
|
472
|
+
case "info": {
|
|
473
|
+
const url = await clack2.text({
|
|
474
|
+
message: "Enter link URL:",
|
|
475
|
+
validate: (value) => {
|
|
476
|
+
if (!value)
|
|
477
|
+
return "Please enter a link";
|
|
478
|
+
return void 0;
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
if (clack2.isCancel(url)) {
|
|
482
|
+
clack2.cancel("Operation cancelled.");
|
|
483
|
+
process.exit(0);
|
|
484
|
+
}
|
|
485
|
+
await linkInfo(url);
|
|
486
|
+
break;
|
|
487
|
+
}
|
|
488
|
+
case "stream": {
|
|
489
|
+
const id = await clack2.text({
|
|
490
|
+
message: "Enter link ID:",
|
|
491
|
+
validate: (value) => {
|
|
492
|
+
if (!value)
|
|
493
|
+
return "Please enter a link ID";
|
|
494
|
+
return void 0;
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
if (clack2.isCancel(id)) {
|
|
498
|
+
clack2.cancel("Operation cancelled.");
|
|
499
|
+
process.exit(0);
|
|
500
|
+
}
|
|
501
|
+
const stream = await clack2.text({
|
|
502
|
+
message: 'Enter stream quality (e.g., "original", "1080p"):',
|
|
503
|
+
validate: (value) => {
|
|
504
|
+
if (!value)
|
|
505
|
+
return "Please enter a stream quality";
|
|
506
|
+
return void 0;
|
|
507
|
+
}
|
|
508
|
+
});
|
|
509
|
+
if (clack2.isCancel(stream)) {
|
|
510
|
+
clack2.cancel("Operation cancelled.");
|
|
511
|
+
process.exit(0);
|
|
512
|
+
}
|
|
513
|
+
await linkStream(id, stream);
|
|
514
|
+
break;
|
|
515
|
+
}
|
|
516
|
+
case "redirector": {
|
|
517
|
+
const url = await clack2.text({
|
|
518
|
+
message: "Enter redirector URL:",
|
|
519
|
+
validate: (value) => {
|
|
520
|
+
if (!value)
|
|
521
|
+
return "Please enter a redirector URL";
|
|
522
|
+
return void 0;
|
|
523
|
+
}
|
|
524
|
+
});
|
|
525
|
+
if (clack2.isCancel(url)) {
|
|
526
|
+
clack2.cancel("Operation cancelled.");
|
|
527
|
+
process.exit(0);
|
|
528
|
+
}
|
|
529
|
+
await linkRedirector(url);
|
|
530
|
+
break;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
function formatBytes(bytes) {
|
|
535
|
+
if (bytes === 0)
|
|
536
|
+
return "0 B";
|
|
537
|
+
const k = 1024;
|
|
538
|
+
const sizes = ["B", "KB", "MB", "GB", "TB"];
|
|
539
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
540
|
+
return `${Number.parseFloat((bytes / k ** i).toFixed(2))} ${sizes[i]}`;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// src/commands/magnet.ts
|
|
544
|
+
import { readFileSync } from "fs";
|
|
545
|
+
import * as clack3 from "@clack/prompts";
|
|
546
|
+
import chalk4 from "chalk";
|
|
547
|
+
import ora4 from "ora";
|
|
548
|
+
async function magnetUpload(magnetOrFile) {
|
|
549
|
+
const client = createClient();
|
|
550
|
+
const spinner = isJsonMode() ? null : ora4("Uploading magnet/torrent...").start();
|
|
551
|
+
try {
|
|
552
|
+
let result;
|
|
553
|
+
if (magnetOrFile.startsWith("magnet:")) {
|
|
554
|
+
result = await client.magnet.upload(magnetOrFile);
|
|
555
|
+
} else {
|
|
556
|
+
try {
|
|
557
|
+
const fileBuffer = readFileSync(magnetOrFile);
|
|
558
|
+
const file = new File([fileBuffer], magnetOrFile.split(/[\\/]/).pop() || "torrent.torrent");
|
|
559
|
+
result = await client.magnet.uploadFile(file);
|
|
560
|
+
} catch {
|
|
561
|
+
result = await client.magnet.upload(magnetOrFile);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
spinner?.succeed(chalk4.green("Magnet uploaded successfully!"));
|
|
565
|
+
if (result) {
|
|
566
|
+
const items = "magnets" in result ? result.magnets : "files" in result ? result.files : void 0;
|
|
567
|
+
if (items && items.length > 0) {
|
|
568
|
+
const item = items[0];
|
|
569
|
+
output(item, () => {
|
|
570
|
+
console.log(chalk4.dim("\nMagnet Information:"));
|
|
571
|
+
console.log(` ID: ${chalk4.cyan(item.id)}`);
|
|
572
|
+
console.log(` Name: ${chalk4.cyan(item.name)}`);
|
|
573
|
+
console.log(` Hash: ${chalk4.cyan(item.hash)}`);
|
|
574
|
+
console.log(` Size: ${chalk4.cyan(formatBytes2(item.size || 0))}`);
|
|
575
|
+
console.log(` Ready: ${item.ready ? chalk4.green("Yes") : chalk4.yellow("Processing")}`);
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
} catch (error) {
|
|
580
|
+
spinner?.fail("Failed to upload magnet");
|
|
581
|
+
console.error(isJsonMode() ? JSON.stringify({ error: error.message }) : chalk4.red(error.message || "Unknown error"));
|
|
582
|
+
process.exit(1);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
async function magnetList(statusFilter) {
|
|
586
|
+
const client = createClient();
|
|
587
|
+
const spinner = isJsonMode() ? null : ora4("Fetching magnets...").start();
|
|
588
|
+
try {
|
|
589
|
+
const result = await client.magnet.statusList(
|
|
590
|
+
statusFilter
|
|
591
|
+
);
|
|
592
|
+
spinner?.stop();
|
|
593
|
+
if (!result?.magnets || result.magnets.length === 0) {
|
|
594
|
+
output({ magnets: [] }, () => console.log(chalk4.yellow("No magnets found")));
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
output(result, () => {
|
|
598
|
+
console.log(chalk4.green(`
|
|
599
|
+
Found ${result.magnets.length} magnet(s):
|
|
600
|
+
`));
|
|
601
|
+
for (const magnet2 of result.magnets) {
|
|
602
|
+
const statusColor = getStatusColor(magnet2.status || "");
|
|
603
|
+
console.log(`${chalk4.bold(`#${magnet2.id}`)} - ${magnet2.filename}`);
|
|
604
|
+
console.log(` Status: ${statusColor(magnet2.status)}`);
|
|
605
|
+
console.log(` Size: ${formatBytes2(magnet2.size || 0)}`);
|
|
606
|
+
if (magnet2.status === "Downloading" && magnet2.downloaded !== void 0 && magnet2.size) {
|
|
607
|
+
const progress = Math.round(magnet2.downloaded / magnet2.size * 100);
|
|
608
|
+
console.log(
|
|
609
|
+
` Progress: ${chalk4.cyan(`${progress}%`)} (${formatBytes2(magnet2.downloaded)} / ${formatBytes2(magnet2.size)})`
|
|
610
|
+
);
|
|
611
|
+
if (magnet2.downloadSpeed) {
|
|
612
|
+
console.log(` Speed: ${chalk4.cyan(`${formatBytes2(magnet2.downloadSpeed)}/s`)}`);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
console.log("");
|
|
616
|
+
}
|
|
617
|
+
});
|
|
618
|
+
} catch (error) {
|
|
619
|
+
spinner?.fail("Failed to fetch magnets");
|
|
620
|
+
console.error(isJsonMode() ? JSON.stringify({ error: error.message }) : chalk4.red(error.message || "Unknown error"));
|
|
621
|
+
process.exit(1);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
async function magnetStatus(id, options) {
|
|
625
|
+
const client = createClient();
|
|
626
|
+
if (options?.live && !id) {
|
|
627
|
+
const session = options.session ?? Math.floor(Math.random() * 1e6);
|
|
628
|
+
const counter = options.counter ?? 0;
|
|
629
|
+
const spinner2 = isJsonMode() ? null : ora4("Fetching magnet status (live mode)...").start();
|
|
630
|
+
try {
|
|
631
|
+
const result = await client.magnet.statusLive({ session, counter });
|
|
632
|
+
spinner2?.stop();
|
|
633
|
+
if (!result?.magnets || result.magnets.length === 0) {
|
|
634
|
+
output({ magnets: [], session, counter: result?.counter ?? counter }, () => {
|
|
635
|
+
console.log(chalk4.yellow("No magnets found"));
|
|
636
|
+
console.log(chalk4.dim(`
|
|
637
|
+
Session: ${session} | Counter: ${result?.counter ?? counter}`));
|
|
638
|
+
});
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
output({ ...result, session }, () => {
|
|
642
|
+
console.log(
|
|
643
|
+
chalk4.green(
|
|
644
|
+
`
|
|
645
|
+
Found ${result.magnets.length} magnet(s)${result.fullsync ? " (full sync)" : " (delta)"}:
|
|
646
|
+
`
|
|
647
|
+
)
|
|
648
|
+
);
|
|
649
|
+
for (const magnet2 of result.magnets) {
|
|
650
|
+
const statusColor = getStatusColor(magnet2.status || "");
|
|
651
|
+
console.log(`${chalk4.bold(`#${magnet2.id}`)} - ${magnet2.filename}`);
|
|
652
|
+
console.log(` Status: ${statusColor(magnet2.status)}`);
|
|
653
|
+
console.log(` Size: ${formatBytes2(magnet2.size || 0)}`);
|
|
654
|
+
if (magnet2.status === "Downloading" && magnet2.downloaded !== void 0 && magnet2.size) {
|
|
655
|
+
const progress = Math.round(magnet2.downloaded / magnet2.size * 100);
|
|
656
|
+
const progressStr = `${formatBytes2(magnet2.downloaded)} / ${formatBytes2(magnet2.size)}`;
|
|
657
|
+
console.log(` Progress: ${chalk4.cyan(`${progress}%`)} (${progressStr})`);
|
|
658
|
+
if (magnet2.downloadSpeed) {
|
|
659
|
+
console.log(` Speed: ${chalk4.cyan(`${formatBytes2(magnet2.downloadSpeed)}/s`)}`);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
console.log("");
|
|
663
|
+
}
|
|
664
|
+
console.log(chalk4.dim(`Session: ${session} | Counter: ${result.counter ?? counter}`));
|
|
665
|
+
console.log(
|
|
666
|
+
chalk4.dim(
|
|
667
|
+
`Use these values for next call: --session ${session} --counter ${result.counter ?? counter}`
|
|
668
|
+
)
|
|
669
|
+
);
|
|
670
|
+
});
|
|
671
|
+
} catch (error) {
|
|
672
|
+
spinner2?.fail("Failed to fetch magnet status");
|
|
673
|
+
console.error(isJsonMode() ? JSON.stringify({ error: error.message }) : chalk4.red(error.message || "Unknown error"));
|
|
674
|
+
process.exit(1);
|
|
675
|
+
}
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
if (!id) {
|
|
679
|
+
const msg = "Error: Magnet ID required for standard mode";
|
|
680
|
+
console.error(isJsonMode() ? JSON.stringify({ error: msg }) : chalk4.red(msg));
|
|
681
|
+
if (!isJsonMode()) {
|
|
682
|
+
console.log(chalk4.dim("Usage: adb magnet status <id>"));
|
|
683
|
+
console.log(chalk4.dim(" or: adb magnet status --live [--session <n>] [--counter <n>]"));
|
|
684
|
+
}
|
|
685
|
+
process.exit(1);
|
|
686
|
+
}
|
|
687
|
+
const spinner = isJsonMode() ? null : ora4("Fetching magnet status...").start();
|
|
688
|
+
try {
|
|
689
|
+
const result = await client.magnet.status(Number.parseInt(id));
|
|
690
|
+
spinner?.stop();
|
|
691
|
+
if (!result?.magnets || result.magnets.length === 0) {
|
|
692
|
+
output({ magnet: null }, () => console.log(chalk4.yellow("Magnet not found")));
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
const magnet2 = result.magnets[0];
|
|
696
|
+
output(magnet2, () => {
|
|
697
|
+
console.log(chalk4.bold(`
|
|
698
|
+
Magnet #${magnet2?.id}`));
|
|
699
|
+
console.log(chalk4.dim("\u2500".repeat(50)));
|
|
700
|
+
console.log(`Filename: ${chalk4.cyan(magnet2?.filename || "N/A")}`);
|
|
701
|
+
console.log(`Status: ${getStatusColor(magnet2?.status || "")(magnet2?.status)}`);
|
|
702
|
+
console.log(`Size: ${chalk4.cyan(formatBytes2(magnet2?.size || 0))}`);
|
|
703
|
+
if (magnet2?.status === "Downloading" && magnet2.downloaded !== void 0 && magnet2.size) {
|
|
704
|
+
const progress = Math.round(magnet2.downloaded / magnet2.size * 100);
|
|
705
|
+
console.log(
|
|
706
|
+
`Progress: ${chalk4.cyan(`${progress}%`)} (${formatBytes2(magnet2.downloaded)} / ${formatBytes2(magnet2.size)})`
|
|
707
|
+
);
|
|
708
|
+
if (magnet2.downloadSpeed) {
|
|
709
|
+
console.log(`Speed: ${chalk4.cyan(`${formatBytes2(magnet2.downloadSpeed)}/s`)}`);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
console.log("");
|
|
713
|
+
});
|
|
714
|
+
} catch (error) {
|
|
715
|
+
spinner?.fail("Failed to fetch magnet status");
|
|
716
|
+
console.error(isJsonMode() ? JSON.stringify({ error: error.message }) : chalk4.red(error.message || "Unknown error"));
|
|
717
|
+
process.exit(1);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
async function magnetWatch(id) {
|
|
721
|
+
const client = createClient();
|
|
722
|
+
const magnetId = Number.parseInt(id);
|
|
723
|
+
console.log(chalk4.cyan(`Monitoring magnet #${id}...
|
|
724
|
+
`));
|
|
725
|
+
try {
|
|
726
|
+
await client.magnet.watch(magnetId, {
|
|
727
|
+
interval: 2e3,
|
|
728
|
+
maxAttempts: 0,
|
|
729
|
+
stopOnStatus: "",
|
|
730
|
+
// Empty string won't match any real status
|
|
731
|
+
onUpdate: (status) => {
|
|
732
|
+
if (!status?.magnets || !Array.isArray(status.magnets)) {
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
const magnet2 = status.magnets[0];
|
|
736
|
+
if (!magnet2) {
|
|
737
|
+
return;
|
|
738
|
+
}
|
|
739
|
+
process.stdout.write("\r\x1B[K");
|
|
740
|
+
const currentStatus = magnet2.status || magnet2.statusCode?.toString() || "Processing";
|
|
741
|
+
const statusStr = getStatusColor(currentStatus)(currentStatus);
|
|
742
|
+
let progress = 0;
|
|
743
|
+
if (magnet2.status === "Ready" || magnet2.statusCode === 4) {
|
|
744
|
+
progress = 100;
|
|
745
|
+
} else if (magnet2.downloaded !== void 0 && magnet2.size) {
|
|
746
|
+
progress = Math.round(magnet2.downloaded / magnet2.size * 100);
|
|
747
|
+
}
|
|
748
|
+
const speed = magnet2.downloadSpeed ? `${formatBytes2(magnet2.downloadSpeed)}/s` : "N/A";
|
|
749
|
+
process.stdout.write(
|
|
750
|
+
`Status: ${statusStr} | Progress: ${chalk4.cyan(`${progress}%`)} | Speed: ${chalk4.cyan(speed)}`
|
|
751
|
+
);
|
|
752
|
+
if (magnet2.status === "Ready" || magnet2.statusCode === 4) {
|
|
753
|
+
console.log(chalk4.green("\n\nDownload complete!"));
|
|
754
|
+
process.exit(0);
|
|
755
|
+
} else if (magnet2.status === "Error") {
|
|
756
|
+
console.log(chalk4.red("\n\nDownload failed!"));
|
|
757
|
+
process.exit(1);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
});
|
|
761
|
+
} catch (error) {
|
|
762
|
+
console.error(chalk4.red(`
|
|
763
|
+
|
|
764
|
+
Error: ${error.message || "Unknown error"}`));
|
|
765
|
+
process.exit(1);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
async function magnetDelete(id) {
|
|
769
|
+
const client = createClient();
|
|
770
|
+
if (!isJsonMode()) {
|
|
771
|
+
const shouldDelete = await clack3.confirm({
|
|
772
|
+
message: `Delete magnet #${id}?`,
|
|
773
|
+
initialValue: false
|
|
774
|
+
});
|
|
775
|
+
if (clack3.isCancel(shouldDelete) || !shouldDelete) {
|
|
776
|
+
clack3.cancel("Deletion cancelled.");
|
|
777
|
+
return;
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
const spinner = isJsonMode() ? null : ora4("Deleting magnet...").start();
|
|
781
|
+
try {
|
|
782
|
+
await client.magnet.delete(Number.parseInt(id));
|
|
783
|
+
output({ success: true, id: Number.parseInt(id) }, () => {
|
|
784
|
+
spinner?.succeed(chalk4.green(`Magnet #${id} deleted successfully`));
|
|
785
|
+
});
|
|
786
|
+
} catch (error) {
|
|
787
|
+
spinner?.fail("Failed to delete magnet");
|
|
788
|
+
console.error(isJsonMode() ? JSON.stringify({ error: error.message }) : chalk4.red(error.message || "Unknown error"));
|
|
789
|
+
process.exit(1);
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
async function magnetRestart(id) {
|
|
793
|
+
const client = createClient();
|
|
794
|
+
const spinner = isJsonMode() ? null : ora4("Restarting magnet...").start();
|
|
795
|
+
try {
|
|
796
|
+
await client.magnet.restart(Number.parseInt(id));
|
|
797
|
+
output({ success: true, id: Number.parseInt(id) }, () => {
|
|
798
|
+
spinner?.succeed(chalk4.green(`Magnet #${id} restarted successfully`));
|
|
799
|
+
});
|
|
800
|
+
} catch (error) {
|
|
801
|
+
spinner?.fail("Failed to restart magnet");
|
|
802
|
+
console.error(isJsonMode() ? JSON.stringify({ error: error.message }) : chalk4.red(error.message || "Unknown error"));
|
|
803
|
+
process.exit(1);
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
async function magnetFiles(id) {
|
|
807
|
+
const client = createClient();
|
|
808
|
+
const spinner = isJsonMode() ? null : ora4("Fetching download links...").start();
|
|
809
|
+
try {
|
|
810
|
+
const data = await client.magnet.files(Number.parseInt(id));
|
|
811
|
+
spinner?.stop();
|
|
812
|
+
if (!data?.magnets || data.magnets.length === 0) {
|
|
813
|
+
output({ files: [] }, () => console.log(chalk4.yellow("No files available yet")));
|
|
814
|
+
return;
|
|
815
|
+
}
|
|
816
|
+
output(data, () => {
|
|
817
|
+
console.log(chalk4.green(`
|
|
818
|
+
Download Links:
|
|
819
|
+
`));
|
|
820
|
+
for (const magnet2 of data.magnets) {
|
|
821
|
+
if (magnet2.files && magnet2.files.length > 0) {
|
|
822
|
+
extractFiles(magnet2.files, 0);
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
});
|
|
826
|
+
} catch (error) {
|
|
827
|
+
spinner?.fail("Failed to fetch files");
|
|
828
|
+
console.error(isJsonMode() ? JSON.stringify({ error: error.message }) : chalk4.red(error.message || "Unknown error"));
|
|
829
|
+
process.exit(1);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
function extractFiles(files, level) {
|
|
833
|
+
for (const file of files) {
|
|
834
|
+
const indent = " ".repeat(level);
|
|
835
|
+
if (file.l && file.l.length > 0) {
|
|
836
|
+
console.log(`${indent}${chalk4.bold(file.n)}`);
|
|
837
|
+
file.l.forEach((link2) => {
|
|
838
|
+
console.log(`${indent} ${chalk4.blue.underline(link2)}`);
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
if (file.e && file.e.length > 0) {
|
|
842
|
+
console.log(`${indent}${chalk4.dim(`${file.n}/`)}`);
|
|
843
|
+
extractFiles(file.e, level + 1);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
async function magnetInteractive() {
|
|
848
|
+
clack3.intro(chalk4.cyan("Magnet Management"));
|
|
849
|
+
const action = await clack3.select({
|
|
850
|
+
message: "What would you like to do?",
|
|
851
|
+
options: [
|
|
852
|
+
{ value: "list", label: "List all magnets" },
|
|
853
|
+
{ value: "upload", label: "Upload new magnet/torrent" },
|
|
854
|
+
{ value: "status", label: "Check magnet status" },
|
|
855
|
+
{ value: "watch", label: "Monitor magnet progress" },
|
|
856
|
+
{ value: "files", label: "Get download links" },
|
|
857
|
+
{ value: "delete", label: "Delete magnet" },
|
|
858
|
+
{ value: "restart", label: "Restart failed magnet" }
|
|
859
|
+
]
|
|
860
|
+
});
|
|
861
|
+
if (clack3.isCancel(action)) {
|
|
862
|
+
clack3.cancel("Operation cancelled.");
|
|
863
|
+
process.exit(0);
|
|
864
|
+
}
|
|
865
|
+
switch (action) {
|
|
866
|
+
case "list":
|
|
867
|
+
await magnetList();
|
|
868
|
+
break;
|
|
869
|
+
case "upload": {
|
|
870
|
+
const magnet2 = await clack3.text({
|
|
871
|
+
message: "Enter magnet link or torrent file path:",
|
|
872
|
+
validate: (value) => {
|
|
873
|
+
if (!value)
|
|
874
|
+
return "Please enter a magnet link or file path";
|
|
875
|
+
return void 0;
|
|
876
|
+
}
|
|
877
|
+
});
|
|
878
|
+
if (clack3.isCancel(magnet2)) {
|
|
879
|
+
clack3.cancel("Operation cancelled.");
|
|
880
|
+
process.exit(0);
|
|
881
|
+
}
|
|
882
|
+
await magnetUpload(magnet2);
|
|
883
|
+
break;
|
|
884
|
+
}
|
|
885
|
+
case "status":
|
|
886
|
+
case "watch":
|
|
887
|
+
case "files":
|
|
888
|
+
case "delete":
|
|
889
|
+
case "restart": {
|
|
890
|
+
const id = await clack3.text({
|
|
891
|
+
message: "Enter magnet ID:",
|
|
892
|
+
validate: (value) => {
|
|
893
|
+
if (!value || Number.isNaN(Number.parseInt(value))) {
|
|
894
|
+
return "Please enter a valid magnet ID";
|
|
895
|
+
}
|
|
896
|
+
return void 0;
|
|
897
|
+
}
|
|
898
|
+
});
|
|
899
|
+
if (clack3.isCancel(id)) {
|
|
900
|
+
clack3.cancel("Operation cancelled.");
|
|
901
|
+
process.exit(0);
|
|
902
|
+
}
|
|
903
|
+
if (action === "status")
|
|
904
|
+
await magnetStatus(id);
|
|
905
|
+
else if (action === "watch")
|
|
906
|
+
await magnetWatch(id);
|
|
907
|
+
else if (action === "files")
|
|
908
|
+
await magnetFiles(id);
|
|
909
|
+
else if (action === "delete")
|
|
910
|
+
await magnetDelete(id);
|
|
911
|
+
else if (action === "restart")
|
|
912
|
+
await magnetRestart(id);
|
|
913
|
+
break;
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
function formatBytes2(bytes) {
|
|
918
|
+
if (bytes === 0)
|
|
919
|
+
return "0 B";
|
|
920
|
+
const k = 1024;
|
|
921
|
+
const sizes = ["B", "KB", "MB", "GB", "TB"];
|
|
922
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
923
|
+
return `${Number.parseFloat((bytes / k ** i).toFixed(2))} ${sizes[i]}`;
|
|
924
|
+
}
|
|
925
|
+
function getStatusColor(status) {
|
|
926
|
+
switch (status) {
|
|
927
|
+
case "Ready":
|
|
928
|
+
return chalk4.green;
|
|
929
|
+
case "Downloading":
|
|
930
|
+
return chalk4.blue;
|
|
931
|
+
case "Error":
|
|
932
|
+
return chalk4.red;
|
|
933
|
+
case "Expired":
|
|
934
|
+
return chalk4.gray;
|
|
935
|
+
default:
|
|
936
|
+
return chalk4.yellow;
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
// src/commands/user.ts
|
|
941
|
+
import * as clack4 from "@clack/prompts";
|
|
942
|
+
import chalk5 from "chalk";
|
|
943
|
+
import ora5 from "ora";
|
|
944
|
+
async function userInfo() {
|
|
945
|
+
const client = createClient();
|
|
946
|
+
const spinner = isJsonMode() ? null : ora5("Fetching user information...").start();
|
|
947
|
+
try {
|
|
948
|
+
const data = await client.user.getInfo();
|
|
949
|
+
spinner?.stop();
|
|
950
|
+
output(data, () => {
|
|
951
|
+
if (data?.user) {
|
|
952
|
+
const userInfo2 = data.user;
|
|
953
|
+
console.log(chalk5.bold("\nUser Information:"));
|
|
954
|
+
console.log(chalk5.dim("\u2500".repeat(50)));
|
|
955
|
+
console.log(`Username: ${chalk5.cyan(userInfo2.username || "N/A")}`);
|
|
956
|
+
console.log(`Email: ${chalk5.cyan(userInfo2.email || "N/A")}`);
|
|
957
|
+
console.log(`Premium: ${userInfo2.isPremium ? chalk5.green("Yes") : chalk5.yellow("No")}`);
|
|
958
|
+
if (userInfo2.premiumUntil) {
|
|
959
|
+
const expiryDate = new Date(userInfo2.premiumUntil * 1e3);
|
|
960
|
+
console.log(`Premium Until: ${chalk5.cyan(expiryDate.toLocaleDateString())}`);
|
|
961
|
+
}
|
|
962
|
+
if (userInfo2.remainingTrialQuota !== void 0) {
|
|
963
|
+
console.log(`Remaining Trial Quota: ${chalk5.cyan(formatBytes3(userInfo2.remainingTrialQuota))}`);
|
|
964
|
+
}
|
|
965
|
+
if (userInfo2.fidelityPoints !== void 0) {
|
|
966
|
+
console.log(`Fidelity Points: ${chalk5.cyan(userInfo2.fidelityPoints)}`);
|
|
967
|
+
}
|
|
968
|
+
console.log("");
|
|
969
|
+
}
|
|
970
|
+
});
|
|
971
|
+
} catch (error) {
|
|
972
|
+
spinner?.fail("Failed to fetch user information");
|
|
973
|
+
console.error(isJsonMode() ? JSON.stringify({ error: error.message }) : chalk5.red(error.message || "Unknown error"));
|
|
974
|
+
process.exit(1);
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
async function userSavedList() {
|
|
978
|
+
const client = createClient();
|
|
979
|
+
const spinner = isJsonMode() ? null : ora5("Fetching saved links...").start();
|
|
980
|
+
try {
|
|
981
|
+
const result = await client.user.getLinks();
|
|
982
|
+
spinner?.stop();
|
|
983
|
+
if (!result?.links || result.links.length === 0) {
|
|
984
|
+
output({ links: [] }, () => console.log(chalk5.yellow("No saved links found")));
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
output(result, () => {
|
|
988
|
+
console.log(chalk5.green(`
|
|
989
|
+
Found ${result.links.length} saved link(s):
|
|
990
|
+
`));
|
|
991
|
+
for (const link2 of result.links) {
|
|
992
|
+
console.log(`${chalk5.bold(link2.filename || "N/A")}`);
|
|
993
|
+
console.log(` Link: ${chalk5.blue.underline(link2.link || "N/A")}`);
|
|
994
|
+
console.log(` Size: ${chalk5.cyan(formatBytes3(link2.size || 0))}`);
|
|
995
|
+
console.log(` Host: ${chalk5.cyan(link2.host || "N/A")}`);
|
|
996
|
+
if (link2.date) {
|
|
997
|
+
const date = new Date(link2.date * 1e3);
|
|
998
|
+
console.log(` Date: ${chalk5.dim(date.toLocaleString())}`);
|
|
999
|
+
}
|
|
1000
|
+
console.log("");
|
|
1001
|
+
}
|
|
1002
|
+
});
|
|
1003
|
+
} catch (error) {
|
|
1004
|
+
spinner?.fail("Failed to fetch saved links");
|
|
1005
|
+
console.error(isJsonMode() ? JSON.stringify({ error: error.message }) : chalk5.red(error.message || "Unknown error"));
|
|
1006
|
+
process.exit(1);
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
async function userSavedAdd(urls) {
|
|
1010
|
+
const client = createClient();
|
|
1011
|
+
const spinner = isJsonMode() ? null : ora5("Saving link(s)...").start();
|
|
1012
|
+
try {
|
|
1013
|
+
await client.user.saveLink(urls);
|
|
1014
|
+
const count = Array.isArray(urls) ? urls.length : 1;
|
|
1015
|
+
output({ success: true, count }, () => {
|
|
1016
|
+
spinner?.succeed(chalk5.green(`${count} link(s) saved successfully!`));
|
|
1017
|
+
});
|
|
1018
|
+
} catch (error) {
|
|
1019
|
+
spinner?.fail("Failed to save link(s)");
|
|
1020
|
+
console.error(isJsonMode() ? JSON.stringify({ error: error.message }) : chalk5.red(error.message || "Unknown error"));
|
|
1021
|
+
process.exit(1);
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
async function userSavedDelete(links) {
|
|
1025
|
+
const client = createClient();
|
|
1026
|
+
if (!isJsonMode()) {
|
|
1027
|
+
const shouldDelete = await clack4.confirm({
|
|
1028
|
+
message: `Delete ${Array.isArray(links) ? links.length : 1} saved link(s)?`,
|
|
1029
|
+
initialValue: false
|
|
1030
|
+
});
|
|
1031
|
+
if (clack4.isCancel(shouldDelete) || !shouldDelete) {
|
|
1032
|
+
clack4.cancel("Deletion cancelled.");
|
|
1033
|
+
return;
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
const spinner = isJsonMode() ? null : ora5("Deleting saved link(s)...").start();
|
|
1037
|
+
try {
|
|
1038
|
+
await client.user.deleteLink(links);
|
|
1039
|
+
const count = Array.isArray(links) ? links.length : 1;
|
|
1040
|
+
output({ success: true, count }, () => {
|
|
1041
|
+
spinner?.succeed(chalk5.green(`${count} saved link(s) deleted successfully`));
|
|
1042
|
+
});
|
|
1043
|
+
} catch (error) {
|
|
1044
|
+
spinner?.fail("Failed to delete saved link(s)");
|
|
1045
|
+
console.error(isJsonMode() ? JSON.stringify({ error: error.message }) : chalk5.red(error.message || "Unknown error"));
|
|
1046
|
+
process.exit(1);
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
async function userHistory() {
|
|
1050
|
+
const client = createClient();
|
|
1051
|
+
const spinner = isJsonMode() ? null : ora5("Fetching download history...").start();
|
|
1052
|
+
try {
|
|
1053
|
+
const result = await client.user.getHistory();
|
|
1054
|
+
spinner?.stop();
|
|
1055
|
+
if (!result?.links || result.links.length === 0) {
|
|
1056
|
+
output({ links: [] }, () => console.log(chalk5.yellow("No download history found")));
|
|
1057
|
+
return;
|
|
1058
|
+
}
|
|
1059
|
+
output(result, () => {
|
|
1060
|
+
console.log(chalk5.green(`
|
|
1061
|
+
Download History (${result.links.length} item(s)):
|
|
1062
|
+
`));
|
|
1063
|
+
for (const item of result.links) {
|
|
1064
|
+
console.log(`${chalk5.bold(item.filename || "N/A")}`);
|
|
1065
|
+
console.log(` Link: ${chalk5.blue.underline(item.link || "N/A")}`);
|
|
1066
|
+
if (item.date) {
|
|
1067
|
+
const date = new Date(item.date * 1e3);
|
|
1068
|
+
console.log(` Date: ${chalk5.dim(date.toLocaleString())}`);
|
|
1069
|
+
}
|
|
1070
|
+
console.log("");
|
|
1071
|
+
}
|
|
1072
|
+
});
|
|
1073
|
+
} catch (error) {
|
|
1074
|
+
spinner?.fail("Failed to fetch download history");
|
|
1075
|
+
console.error(isJsonMode() ? JSON.stringify({ error: error.message }) : chalk5.red(error.message || "Unknown error"));
|
|
1076
|
+
process.exit(1);
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
async function userHistoryClear() {
|
|
1080
|
+
const client = createClient();
|
|
1081
|
+
if (!isJsonMode()) {
|
|
1082
|
+
const shouldClear = await clack4.confirm({
|
|
1083
|
+
message: "Clear your entire download history?",
|
|
1084
|
+
initialValue: false
|
|
1085
|
+
});
|
|
1086
|
+
if (clack4.isCancel(shouldClear) || !shouldClear) {
|
|
1087
|
+
clack4.cancel("Operation cancelled.");
|
|
1088
|
+
return;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
const spinner = isJsonMode() ? null : ora5("Clearing download history...").start();
|
|
1092
|
+
try {
|
|
1093
|
+
await client.user.clearHistory();
|
|
1094
|
+
output({ success: true }, () => {
|
|
1095
|
+
spinner?.succeed(chalk5.green("Download history cleared successfully"));
|
|
1096
|
+
});
|
|
1097
|
+
} catch (error) {
|
|
1098
|
+
spinner?.fail("Failed to clear download history");
|
|
1099
|
+
console.error(isJsonMode() ? JSON.stringify({ error: error.message }) : chalk5.red(error.message || "Unknown error"));
|
|
1100
|
+
process.exit(1);
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
async function userInteractive() {
|
|
1104
|
+
clack4.intro(chalk5.cyan("User Management"));
|
|
1105
|
+
const action = await clack4.select({
|
|
1106
|
+
message: "What would you like to do?",
|
|
1107
|
+
options: [
|
|
1108
|
+
{ value: "info", label: "View account information" },
|
|
1109
|
+
{ value: "saved-list", label: "List saved links" },
|
|
1110
|
+
{ value: "saved-add", label: "Save new link" },
|
|
1111
|
+
{ value: "saved-delete", label: "Delete saved link" },
|
|
1112
|
+
{ value: "history", label: "View download history" },
|
|
1113
|
+
{ value: "history-clear", label: "Clear download history" }
|
|
1114
|
+
]
|
|
1115
|
+
});
|
|
1116
|
+
if (clack4.isCancel(action)) {
|
|
1117
|
+
clack4.cancel("Operation cancelled.");
|
|
1118
|
+
process.exit(0);
|
|
1119
|
+
}
|
|
1120
|
+
switch (action) {
|
|
1121
|
+
case "info":
|
|
1122
|
+
await userInfo();
|
|
1123
|
+
break;
|
|
1124
|
+
case "saved-list":
|
|
1125
|
+
await userSavedList();
|
|
1126
|
+
break;
|
|
1127
|
+
case "saved-add": {
|
|
1128
|
+
const link2 = await clack4.text({
|
|
1129
|
+
message: "Enter link to save:",
|
|
1130
|
+
validate: (value) => {
|
|
1131
|
+
if (!value)
|
|
1132
|
+
return "Please enter a link";
|
|
1133
|
+
return void 0;
|
|
1134
|
+
}
|
|
1135
|
+
});
|
|
1136
|
+
if (clack4.isCancel(link2)) {
|
|
1137
|
+
clack4.cancel("Operation cancelled.");
|
|
1138
|
+
process.exit(0);
|
|
1139
|
+
}
|
|
1140
|
+
await userSavedAdd(link2);
|
|
1141
|
+
break;
|
|
1142
|
+
}
|
|
1143
|
+
case "saved-delete": {
|
|
1144
|
+
const link2 = await clack4.text({
|
|
1145
|
+
message: "Enter link to delete:",
|
|
1146
|
+
validate: (value) => {
|
|
1147
|
+
if (!value)
|
|
1148
|
+
return "Please enter a link";
|
|
1149
|
+
return void 0;
|
|
1150
|
+
}
|
|
1151
|
+
});
|
|
1152
|
+
if (clack4.isCancel(link2)) {
|
|
1153
|
+
clack4.cancel("Operation cancelled.");
|
|
1154
|
+
process.exit(0);
|
|
1155
|
+
}
|
|
1156
|
+
await userSavedDelete(link2);
|
|
1157
|
+
break;
|
|
1158
|
+
}
|
|
1159
|
+
case "history":
|
|
1160
|
+
await userHistory();
|
|
1161
|
+
break;
|
|
1162
|
+
case "history-clear":
|
|
1163
|
+
await userHistoryClear();
|
|
1164
|
+
break;
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
function formatBytes3(bytes) {
|
|
1168
|
+
if (bytes === 0)
|
|
1169
|
+
return "0 B";
|
|
1170
|
+
const k = 1024;
|
|
1171
|
+
const sizes = ["B", "KB", "MB", "GB", "TB"];
|
|
1172
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
1173
|
+
return `${Number.parseFloat((bytes / k ** i).toFixed(2))} ${sizes[i]}`;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
// src/commands/voucher.ts
|
|
1177
|
+
import * as clack5 from "@clack/prompts";
|
|
1178
|
+
import chalk6 from "chalk";
|
|
1179
|
+
import ora6 from "ora";
|
|
1180
|
+
async function voucherBalance() {
|
|
1181
|
+
const client = createClient();
|
|
1182
|
+
const spinner = isJsonMode() ? null : ora6("Fetching voucher balance...").start();
|
|
1183
|
+
try {
|
|
1184
|
+
const balance = await client.voucher.getBalance();
|
|
1185
|
+
spinner?.stop();
|
|
1186
|
+
output(balance, () => {
|
|
1187
|
+
console.log(chalk6.bold("\nVoucher Balance:"));
|
|
1188
|
+
console.log(chalk6.dim("\u2500".repeat(50)));
|
|
1189
|
+
if (balance?.balance !== void 0) {
|
|
1190
|
+
console.log(`Balance: ${chalk6.cyan(balance.balance)}`);
|
|
1191
|
+
}
|
|
1192
|
+
console.log("");
|
|
1193
|
+
});
|
|
1194
|
+
} catch (error) {
|
|
1195
|
+
spinner?.fail("Failed to fetch voucher balance");
|
|
1196
|
+
console.error(isJsonMode() ? JSON.stringify({ error: error.message }) : chalk6.red(error.message || "Unknown error"));
|
|
1197
|
+
process.exit(1);
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
async function voucherList(quantity) {
|
|
1201
|
+
const client = createClient();
|
|
1202
|
+
const spinner = isJsonMode() ? null : ora6("Fetching vouchers...").start();
|
|
1203
|
+
try {
|
|
1204
|
+
const result = await client.voucher.getVouchers(quantity);
|
|
1205
|
+
spinner?.stop();
|
|
1206
|
+
if (!result?.codes || result.codes.length === 0) {
|
|
1207
|
+
output({ codes: [] }, () => console.log(chalk6.yellow("No vouchers found")));
|
|
1208
|
+
return;
|
|
1209
|
+
}
|
|
1210
|
+
output(result, () => {
|
|
1211
|
+
console.log(chalk6.green(`
|
|
1212
|
+
Vouchers (${result.codes.length}):
|
|
1213
|
+
`));
|
|
1214
|
+
for (const code of result.codes) {
|
|
1215
|
+
console.log(` ${chalk6.cyan(code)}`);
|
|
1216
|
+
}
|
|
1217
|
+
if (result.partialList) {
|
|
1218
|
+
console.log(chalk6.yellow("\n(Partial list - not all vouchers available)"));
|
|
1219
|
+
}
|
|
1220
|
+
console.log("");
|
|
1221
|
+
});
|
|
1222
|
+
} catch (error) {
|
|
1223
|
+
spinner?.fail("Failed to fetch vouchers");
|
|
1224
|
+
console.error(isJsonMode() ? JSON.stringify({ error: error.message }) : chalk6.red(error.message || "Unknown error"));
|
|
1225
|
+
process.exit(1);
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
async function voucherGenerate(quantity, days) {
|
|
1229
|
+
const client = createClient();
|
|
1230
|
+
if (!isJsonMode()) {
|
|
1231
|
+
const shouldGenerate = await clack5.confirm({
|
|
1232
|
+
message: `Generate ${quantity} voucher(s) for ${days} days?`,
|
|
1233
|
+
initialValue: false
|
|
1234
|
+
});
|
|
1235
|
+
if (clack5.isCancel(shouldGenerate) || !shouldGenerate) {
|
|
1236
|
+
clack5.cancel("Operation cancelled.");
|
|
1237
|
+
return;
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
const spinner = isJsonMode() ? null : ora6("Generating voucher(s)...").start();
|
|
1241
|
+
try {
|
|
1242
|
+
const result = await client.voucher.generateVouchers(quantity, days);
|
|
1243
|
+
spinner?.succeed(chalk6.green(`${quantity} voucher(s) generated successfully!`));
|
|
1244
|
+
output(result, () => {
|
|
1245
|
+
if (result?.codes && result.codes.length > 0) {
|
|
1246
|
+
console.log(chalk6.bold("\nGenerated Voucher Codes:\n"));
|
|
1247
|
+
for (const code of result.codes) {
|
|
1248
|
+
console.log(` ${chalk6.cyan(code)}`);
|
|
1249
|
+
}
|
|
1250
|
+
if (result.pricePerVoucher !== void 0) {
|
|
1251
|
+
console.log(chalk6.dim(`
|
|
1252
|
+
Price per voucher: $${result.pricePerVoucher}`));
|
|
1253
|
+
}
|
|
1254
|
+
console.log("");
|
|
1255
|
+
}
|
|
1256
|
+
});
|
|
1257
|
+
} catch (error) {
|
|
1258
|
+
spinner?.fail("Failed to generate voucher(s)");
|
|
1259
|
+
console.error(isJsonMode() ? JSON.stringify({ error: error.message }) : chalk6.red(error.message || "Unknown error"));
|
|
1260
|
+
process.exit(1);
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
async function voucherInteractive() {
|
|
1264
|
+
clack5.intro(chalk6.cyan("Voucher Management (Reseller)"));
|
|
1265
|
+
const action = await clack5.select({
|
|
1266
|
+
message: "What would you like to do?",
|
|
1267
|
+
options: [
|
|
1268
|
+
{ value: "balance", label: "Check balance" },
|
|
1269
|
+
{ value: "list", label: "List vouchers" },
|
|
1270
|
+
{ value: "generate", label: "Generate vouchers" }
|
|
1271
|
+
]
|
|
1272
|
+
});
|
|
1273
|
+
if (clack5.isCancel(action)) {
|
|
1274
|
+
clack5.cancel("Operation cancelled.");
|
|
1275
|
+
process.exit(0);
|
|
1276
|
+
}
|
|
1277
|
+
switch (action) {
|
|
1278
|
+
case "balance":
|
|
1279
|
+
await voucherBalance();
|
|
1280
|
+
break;
|
|
1281
|
+
case "list": {
|
|
1282
|
+
const quantityInput = await clack5.text({
|
|
1283
|
+
message: "How many vouchers to list? (optional)",
|
|
1284
|
+
validate: (value) => {
|
|
1285
|
+
if (value && Number.isNaN(Number.parseInt(value))) {
|
|
1286
|
+
return "Please enter a valid number";
|
|
1287
|
+
}
|
|
1288
|
+
return void 0;
|
|
1289
|
+
}
|
|
1290
|
+
});
|
|
1291
|
+
if (clack5.isCancel(quantityInput)) {
|
|
1292
|
+
clack5.cancel("Operation cancelled.");
|
|
1293
|
+
process.exit(0);
|
|
1294
|
+
}
|
|
1295
|
+
const quantity = quantityInput ? Number.parseInt(quantityInput) : void 0;
|
|
1296
|
+
await voucherList(quantity);
|
|
1297
|
+
break;
|
|
1298
|
+
}
|
|
1299
|
+
case "generate": {
|
|
1300
|
+
const quantityInput = await clack5.text({
|
|
1301
|
+
message: "How many vouchers to generate?",
|
|
1302
|
+
validate: (value) => {
|
|
1303
|
+
const num = Number.parseInt(value);
|
|
1304
|
+
if (Number.isNaN(num) || num <= 0) {
|
|
1305
|
+
return "Please enter a valid positive number";
|
|
1306
|
+
}
|
|
1307
|
+
return void 0;
|
|
1308
|
+
}
|
|
1309
|
+
});
|
|
1310
|
+
if (clack5.isCancel(quantityInput)) {
|
|
1311
|
+
clack5.cancel("Operation cancelled.");
|
|
1312
|
+
process.exit(0);
|
|
1313
|
+
}
|
|
1314
|
+
const daysInput = await clack5.text({
|
|
1315
|
+
message: "Duration in days?",
|
|
1316
|
+
validate: (value) => {
|
|
1317
|
+
const num = Number.parseInt(value);
|
|
1318
|
+
if (Number.isNaN(num) || num <= 0) {
|
|
1319
|
+
return "Please enter a valid positive number";
|
|
1320
|
+
}
|
|
1321
|
+
return void 0;
|
|
1322
|
+
}
|
|
1323
|
+
});
|
|
1324
|
+
if (clack5.isCancel(daysInput)) {
|
|
1325
|
+
clack5.cancel("Operation cancelled.");
|
|
1326
|
+
process.exit(0);
|
|
1327
|
+
}
|
|
1328
|
+
await voucherGenerate(Number.parseInt(quantityInput), Number.parseInt(daysInput));
|
|
1329
|
+
break;
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
// src/index.ts
|
|
1335
|
+
var __dirname2 = dirname(fileURLToPath(import.meta.url));
|
|
1336
|
+
var packageJson = JSON.parse(
|
|
1337
|
+
readFileSync2(join(__dirname2, "../package.json"), "utf-8")
|
|
1338
|
+
);
|
|
1339
|
+
var program = new Command();
|
|
1340
|
+
program.name("adb").description("AllDebrid CLI - Manage your AllDebrid account from the terminal").version(packageJson.version).option("--api-key <key>", "AllDebrid API key (overrides config file)").option("--json", "Output results in JSON format").hook("preAction", (thisCommand) => {
|
|
1341
|
+
const opts = thisCommand.optsWithGlobals();
|
|
1342
|
+
if (opts.json) {
|
|
1343
|
+
setJsonMode(true);
|
|
1344
|
+
}
|
|
1345
|
+
});
|
|
1346
|
+
var auth = program.command("auth").description("Manage authentication").action(authInteractive);
|
|
1347
|
+
auth.command("login").description("Login with PIN authentication").action(authLogin);
|
|
1348
|
+
auth.command("logout").description("Logout and clear saved API key").action(authLogout);
|
|
1349
|
+
auth.command("status").description("Check authentication status").action(authStatus);
|
|
1350
|
+
var magnet = program.command("magnet").description("Manage magnets and torrents").action(magnetInteractive);
|
|
1351
|
+
magnet.command("upload <magnet-or-file>").description("Upload magnet link or torrent file").action(magnetUpload);
|
|
1352
|
+
magnet.command("list").description("List all magnets").option("-s, --status <status>", "Filter by status (active|ready|expired|error)").action(async (options) => magnetList(options.status));
|
|
1353
|
+
magnet.command("status [id]").description("Get magnet status by ID, or all magnets with --live").option("-l, --live", "Use live mode (delta sync) for monitoring all magnets").option("-s, --session <number>", "Session ID for live mode (auto-generated if not provided)").option("-c, --counter <number>", "Counter for live mode synchronization").action(async (id, options) => {
|
|
1354
|
+
const opts = {
|
|
1355
|
+
live: options.live,
|
|
1356
|
+
session: options.session ? Number.parseInt(options.session) : void 0,
|
|
1357
|
+
counter: options.counter ? Number.parseInt(options.counter) : void 0
|
|
1358
|
+
};
|
|
1359
|
+
await magnetStatus(id, opts);
|
|
1360
|
+
});
|
|
1361
|
+
magnet.command("watch <id>").description("Monitor magnet progress in real-time").action(async (id) => magnetWatch(id));
|
|
1362
|
+
magnet.command("files <id>").description("Get download links for magnet").action(magnetFiles);
|
|
1363
|
+
magnet.command("delete <id>").description("Delete magnet").action(magnetDelete);
|
|
1364
|
+
magnet.command("restart <id>").description("Restart failed magnet").action(magnetRestart);
|
|
1365
|
+
var link = program.command("link").description("Manage premium links").action(linkInteractive);
|
|
1366
|
+
link.command("unlock <url>").description("Unlock premium link").option("-p, --password <password>", "Password for protected link").action(async (url, options) => linkUnlock(url, options.password));
|
|
1367
|
+
link.command("info <url>").description("Get link information").option("-p, --password <password>", "Password for protected link").action(async (url, options) => linkInfo(url, options.password));
|
|
1368
|
+
link.command("stream <id> <stream>").description('Get streaming link (e.g., "original", "1080p")').action(linkStream);
|
|
1369
|
+
link.command("redirector <url>").description("Extract links from redirector").action(linkRedirector);
|
|
1370
|
+
var user = program.command("user").description("User account management").action(userInteractive);
|
|
1371
|
+
user.command("info").description("View account information").action(userInfo);
|
|
1372
|
+
user.command("saved-list").description("List saved links").action(userSavedList);
|
|
1373
|
+
user.command("saved-add <url>").description("Save a link").action(userSavedAdd);
|
|
1374
|
+
user.command("saved-delete <link>").description("Delete a saved link").action(userSavedDelete);
|
|
1375
|
+
user.command("history").description("View download history").action(userHistory);
|
|
1376
|
+
user.command("history-clear").description("Clear download history").action(userHistoryClear);
|
|
1377
|
+
var host = program.command("host").description("List supported hosts").action(async () => hostList(false));
|
|
1378
|
+
host.command("list").description("List all supported hosts with status").option("--hosts-only", "Show only host names").action(async (options) => hostList(options.hostsOnly));
|
|
1379
|
+
host.command("domains").description("List all supported domains").action(hostDomains);
|
|
1380
|
+
var voucher = program.command("voucher").description("Manage vouchers (reseller accounts only)").action(voucherInteractive);
|
|
1381
|
+
voucher.command("balance").description("Check voucher balance").action(voucherBalance);
|
|
1382
|
+
voucher.command("list").description("List vouchers").option("-q, --quantity <n>", "Number of vouchers to list").action(async (options) => voucherList(options.quantity ? Number.parseInt(options.quantity) : void 0));
|
|
1383
|
+
voucher.command("generate <quantity> <days>").description("Generate vouchers").action(async (quantity, days) => voucherGenerate(Number.parseInt(quantity), Number.parseInt(days)));
|
|
1384
|
+
program.parse();
|