@ctrl/deluge 6.1.0 → 7.1.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 +9 -0
- package/dist/src/deluge.d.ts +16 -6
- package/dist/src/deluge.js +45 -22
- package/dist/src/normalizeTorrentData.d.ts +2 -2
- package/package.json +16 -16
package/README.md
CHANGED
@@ -70,6 +70,15 @@ const res = await client.removeTorrent('torrent_id', true);
|
|
70
70
|
console.log(res);
|
71
71
|
```
|
72
72
|
|
73
|
+
##### export and create from state
|
74
|
+
|
75
|
+
If you're shutting down the server often (serverless?) you can export the state
|
76
|
+
|
77
|
+
```ts
|
78
|
+
const state = client.exportState()
|
79
|
+
const client = Deluge.createFromState(config, state);
|
80
|
+
```
|
81
|
+
|
73
82
|
### See Also
|
74
83
|
transmission - https://github.com/scttcper/transmission
|
75
84
|
qbittorrent - https://github.com/scttcper/qbittorrent
|
package/dist/src/deluge.d.ts
CHANGED
@@ -1,11 +1,20 @@
|
|
1
1
|
import { ofetch } from 'ofetch';
|
2
|
-
import
|
2
|
+
import { Cookie } from 'tough-cookie';
|
3
|
+
import type { Jsonify } from 'type-fest';
|
4
|
+
import type { AddTorrentOptions as NormalizedAddTorrentOptions, AllClientData, NormalizedTorrent, TorrentClient, TorrentClientConfig, TorrentClientState } from '@ctrl/shared-torrent';
|
3
5
|
import type { AddTorrentOptions, AddTorrentResponse, BooleanStatus, ConfigResponse, DefaultResponse, DelugeSettings, GetHostsResponse, GetHostStatusResponse, ListMethods, PluginInfo, PluginsListResponse, StringStatus, TorrentFiles, TorrentInfo, TorrentListResponse, TorrentOptions, TorrentStatus, Tracker, UploadResponse } from './types.js';
|
6
|
+
interface DelugeState extends TorrentClientState {
|
7
|
+
auth: {
|
8
|
+
cookie?: Cookie;
|
9
|
+
msgId: number;
|
10
|
+
};
|
11
|
+
}
|
4
12
|
export declare class Deluge implements TorrentClient {
|
5
|
-
config:
|
6
|
-
|
7
|
-
|
8
|
-
constructor(options?: Partial<
|
13
|
+
static createFromState(config: Readonly<TorrentClientConfig>, state: Readonly<Jsonify<DelugeState>>): Deluge;
|
14
|
+
config: TorrentClientConfig;
|
15
|
+
state: DelugeState;
|
16
|
+
constructor(options?: Partial<TorrentClientConfig>);
|
17
|
+
exportState(): Jsonify<DelugeState>;
|
9
18
|
resetSession(): void;
|
10
19
|
getHosts(): Promise<GetHostsResponse>;
|
11
20
|
/**
|
@@ -69,7 +78,7 @@ export declare class Deluge implements TorrentClient {
|
|
69
78
|
/**
|
70
79
|
*
|
71
80
|
* @param torrentId torrent id from list torrents
|
72
|
-
* @param removeData true
|
81
|
+
* @param removeData (default: false) If true, remove the data from disk
|
73
82
|
*/
|
74
83
|
removeTorrent(torrentId: string, removeData?: boolean): Promise<BooleanStatus>;
|
75
84
|
changePassword(password: string): Promise<BooleanStatus>;
|
@@ -108,3 +117,4 @@ export declare class Deluge implements TorrentClient {
|
|
108
117
|
request<T extends object>(method: string, params?: any[], needsAuth?: boolean, autoConnect?: boolean): Promise<ReturnType<typeof ofetch.raw<T>>>;
|
109
118
|
private _validateAuth;
|
110
119
|
}
|
120
|
+
export {};
|
package/dist/src/deluge.js
CHANGED
@@ -12,15 +12,37 @@ const defaults = {
|
|
12
12
|
timeout: 5000,
|
13
13
|
};
|
14
14
|
export class Deluge {
|
15
|
+
static createFromState(config, state) {
|
16
|
+
const deluge = new Deluge(config);
|
17
|
+
deluge.state = {
|
18
|
+
...state,
|
19
|
+
auth: state.auth
|
20
|
+
? {
|
21
|
+
cookie: Cookie.fromJSON(state.auth.cookie),
|
22
|
+
msgId: state.auth.msgId,
|
23
|
+
}
|
24
|
+
: { msgId: 0 },
|
25
|
+
};
|
26
|
+
return deluge;
|
27
|
+
}
|
15
28
|
config;
|
16
|
-
|
17
|
-
_cookie;
|
29
|
+
state = { auth: { msgId: 0 } };
|
18
30
|
constructor(options = {}) {
|
19
31
|
this.config = { ...defaults, ...options };
|
20
32
|
}
|
33
|
+
exportState() {
|
34
|
+
return JSON.parse(JSON.stringify({
|
35
|
+
...this.state,
|
36
|
+
auth: this.state.auth
|
37
|
+
? {
|
38
|
+
cookie: this.state.auth.cookie.toJSON(),
|
39
|
+
msgId: this.state.auth.msgId,
|
40
|
+
}
|
41
|
+
: { msgId: 0 },
|
42
|
+
}));
|
43
|
+
}
|
21
44
|
resetSession() {
|
22
|
-
this.
|
23
|
-
this._msgId = 0;
|
45
|
+
this.state.auth = { msgId: 0 };
|
24
46
|
}
|
25
47
|
async getHosts() {
|
26
48
|
const res = await this.request('web.get_hosts', [], true, false);
|
@@ -75,15 +97,15 @@ export class Deluge {
|
|
75
97
|
*/
|
76
98
|
async checkSession() {
|
77
99
|
// cookie is missing or expires in x seconds
|
78
|
-
if (this.
|
100
|
+
if (this.state.auth.cookie) {
|
79
101
|
// eslint-disable-next-line new-cap
|
80
|
-
if (this.
|
102
|
+
if (this.state.auth.cookie.TTL() < 5000) {
|
81
103
|
this.resetSession();
|
82
104
|
return false;
|
83
105
|
}
|
84
106
|
return true;
|
85
107
|
}
|
86
|
-
if (this.
|
108
|
+
if (this.state.auth.cookie) {
|
87
109
|
try {
|
88
110
|
const check = await this.request('auth.check_session', undefined, false);
|
89
111
|
const body = await check.json();
|
@@ -108,7 +130,7 @@ export class Deluge {
|
|
108
130
|
if (!res.ok || !res.headers?.get('set-cookie')?.length) {
|
109
131
|
throw new Error('Auth failed, incorrect password');
|
110
132
|
}
|
111
|
-
this.
|
133
|
+
this.state.auth.cookie = Cookie.parse(res.headers.get('set-cookie'));
|
112
134
|
return true;
|
113
135
|
}
|
114
136
|
/**
|
@@ -167,8 +189,7 @@ export class Deluge {
|
|
167
189
|
retry: 0,
|
168
190
|
timeout: this.config.timeout,
|
169
191
|
parseResponse: JSON.parse,
|
170
|
-
|
171
|
-
agent: this.config.agent,
|
192
|
+
dispatcher: this.config.dispatcher,
|
172
193
|
});
|
173
194
|
return res;
|
174
195
|
}
|
@@ -188,7 +209,8 @@ export class Deluge {
|
|
188
209
|
}
|
189
210
|
async addTorrent(torrent, config = {}) {
|
190
211
|
let path;
|
191
|
-
|
212
|
+
const isUploaded = typeof torrent === 'string' && torrent.includes('delugeweb-');
|
213
|
+
if (isUint8Array(torrent) || !isUploaded) {
|
192
214
|
const upload = await this.upload(torrent);
|
193
215
|
if (!upload.success || !upload.files.length) {
|
194
216
|
throw new Error('Failed to upload');
|
@@ -196,7 +218,10 @@ export class Deluge {
|
|
196
218
|
path = upload.files[0];
|
197
219
|
}
|
198
220
|
else {
|
199
|
-
/**
|
221
|
+
/**
|
222
|
+
* Assume paths starting with /tmp/ are from {@link Deluge.upload}
|
223
|
+
* Example temp path: /run/deluged-temp/delugeweb-s0jy917j/ubuntu-20.10-desktop-amd64.iso.torrent
|
224
|
+
*/
|
200
225
|
path = torrent;
|
201
226
|
}
|
202
227
|
const options = {
|
@@ -278,9 +303,9 @@ export class Deluge {
|
|
278
303
|
/**
|
279
304
|
*
|
280
305
|
* @param torrentId torrent id from list torrents
|
281
|
-
* @param removeData true
|
306
|
+
* @param removeData (default: false) If true, remove the data from disk
|
282
307
|
*/
|
283
|
-
async removeTorrent(torrentId, removeData =
|
308
|
+
async removeTorrent(torrentId, removeData = false) {
|
284
309
|
const req = await this.request('core.remove_torrent', [torrentId, removeData]);
|
285
310
|
return req._data;
|
286
311
|
}
|
@@ -295,7 +320,7 @@ export class Deluge {
|
|
295
320
|
}
|
296
321
|
// update current password to new password
|
297
322
|
this.config.password = password;
|
298
|
-
this.
|
323
|
+
this.state.auth.cookie = Cookie.parse(res.headers.get('set-cookie'));
|
299
324
|
return body;
|
300
325
|
}
|
301
326
|
async getAllData() {
|
@@ -508,10 +533,9 @@ export class Deluge {
|
|
508
533
|
const req = await this.request('core.disable_plugin', plugins);
|
509
534
|
return req._data;
|
510
535
|
}
|
511
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
512
536
|
async request(method, params = [], needsAuth = true, autoConnect = true) {
|
513
|
-
if (this.
|
514
|
-
this.
|
537
|
+
if (this.state.auth.msgId === 4096) {
|
538
|
+
this.state.auth.msgId = 0;
|
515
539
|
}
|
516
540
|
if (needsAuth) {
|
517
541
|
await this._validateAuth();
|
@@ -523,7 +547,7 @@ export class Deluge {
|
|
523
547
|
}
|
524
548
|
}
|
525
549
|
const headers = {
|
526
|
-
Cookie: this.
|
550
|
+
Cookie: this.state.auth.cookie?.cookieString?.(),
|
527
551
|
};
|
528
552
|
const url = joinURL(this.config.baseUrl, this.config.path);
|
529
553
|
const res = await ofetch.raw(url, {
|
@@ -531,15 +555,14 @@ export class Deluge {
|
|
531
555
|
body: JSON.stringify({
|
532
556
|
method,
|
533
557
|
params,
|
534
|
-
id: this.
|
558
|
+
id: this.state.auth.msgId++,
|
535
559
|
}),
|
536
560
|
headers,
|
537
561
|
retry: 0,
|
538
562
|
timeout: this.config.timeout,
|
539
563
|
responseType: 'json',
|
540
564
|
parseResponse: JSON.parse,
|
541
|
-
|
542
|
-
agent: this.config.agent,
|
565
|
+
dispatcher: this.config.dispatcher,
|
543
566
|
});
|
544
567
|
const err = res.body?.error ?? (typeof res.body === 'string' && res.body);
|
545
568
|
if (err) {
|
@@ -1,3 +1,3 @@
|
|
1
|
-
import { NormalizedTorrent } from '@ctrl/shared-torrent';
|
2
|
-
import { Torrent } from './types.js';
|
1
|
+
import { type NormalizedTorrent } from '@ctrl/shared-torrent';
|
2
|
+
import type { Torrent } from './types.js';
|
3
3
|
export declare function normalizeTorrentData(id: string, torrent: Torrent): NormalizedTorrent;
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@ctrl/deluge",
|
3
|
-
"version": "
|
3
|
+
"version": "7.1.0",
|
4
4
|
"description": "TypeScript api wrapper for deluge using got",
|
5
5
|
"author": "Scott Cooper <scttcper@gmail.com>",
|
6
6
|
"license": "MIT",
|
@@ -23,7 +23,7 @@
|
|
23
23
|
"lint:eslint": "eslint .",
|
24
24
|
"lint:fix": "pnpm run '/^(lint:biome|lint:eslint):fix$/'",
|
25
25
|
"lint:eslint:fix": "eslint . --fix",
|
26
|
-
"lint:biome:fix": "biome check . --
|
26
|
+
"lint:biome:fix": "biome check . --write",
|
27
27
|
"prepare": "npm run build",
|
28
28
|
"build": "tsc",
|
29
29
|
"build:docs": "typedoc",
|
@@ -33,24 +33,24 @@
|
|
33
33
|
},
|
34
34
|
"dependencies": {
|
35
35
|
"@ctrl/magnet-link": "^4.0.2",
|
36
|
-
"@ctrl/shared-torrent": "^6.
|
36
|
+
"@ctrl/shared-torrent": "^6.2.1",
|
37
37
|
"node-fetch-native": "^1.6.4",
|
38
|
-
"ofetch": "^1.
|
39
|
-
"tough-cookie": "^
|
40
|
-
"
|
41
|
-
"
|
38
|
+
"ofetch": "^1.4.1",
|
39
|
+
"tough-cookie": "^5.0.0",
|
40
|
+
"type-fest": "^4.30.2",
|
41
|
+
"ufo": "^1.5.4",
|
42
|
+
"uint8array-extras": "^1.4.0"
|
42
43
|
},
|
43
44
|
"devDependencies": {
|
44
|
-
"@biomejs/biome": "1.
|
45
|
-
"@ctrl/eslint-config-biome": "3.1
|
46
|
-
"@sindresorhus/tsconfig": "
|
47
|
-
"@types/node": "
|
48
|
-
"@
|
49
|
-
"@vitest/coverage-v8": "1.6.0",
|
45
|
+
"@biomejs/biome": "1.9.4",
|
46
|
+
"@ctrl/eslint-config-biome": "4.3.1",
|
47
|
+
"@sindresorhus/tsconfig": "7.0.0",
|
48
|
+
"@types/node": "22.10.2",
|
49
|
+
"@vitest/coverage-v8": "2.1.8",
|
50
50
|
"p-wait-for": "5.0.2",
|
51
|
-
"typedoc": "0.
|
52
|
-
"typescript": "5.
|
53
|
-
"vitest": "1.
|
51
|
+
"typedoc": "0.27.5",
|
52
|
+
"typescript": "5.7.2",
|
53
|
+
"vitest": "2.1.8"
|
54
54
|
},
|
55
55
|
"publishConfig": {
|
56
56
|
"access": "public",
|