@ctrl/deluge 3.3.0 → 4.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.
@@ -1,7 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  import { Response } from 'got';
3
3
  import { AddTorrentOptions as NormalizedAddTorrentOptions, AllClientData, NormalizedTorrent, TorrentClient, TorrentSettings } from '@ctrl/shared-torrent';
4
- import { AddTorrentOptions, BooleanStatus, ConfigResponse, DefaultResponse, DelugeSettings, GetHostsResponse, GetHostStatusResponse, ListMethods, PluginInfo, PluginsListResponse, StringStatus, TorrentFiles, TorrentInfo, TorrentListResponse, TorrentOptions, TorrentStatus, Tracker, UploadResponse, AddTorrentResponse } from './types';
4
+ import { AddTorrentOptions, AddTorrentResponse, BooleanStatus, ConfigResponse, DefaultResponse, DelugeSettings, GetHostsResponse, GetHostStatusResponse, ListMethods, PluginInfo, PluginsListResponse, StringStatus, TorrentFiles, TorrentInfo, TorrentListResponse, TorrentOptions, TorrentStatus, Tracker, UploadResponse } from './types.js';
5
5
  export declare class Deluge implements TorrentClient {
6
6
  config: TorrentSettings;
7
7
  private _msgId;
@@ -57,6 +57,13 @@ export declare class Deluge implements TorrentClient {
57
57
  */
58
58
  listMethods(auth?: boolean): Promise<ListMethods>;
59
59
  upload(torrent: string | Buffer): Promise<UploadResponse>;
60
+ /**
61
+ * Download a torrent from url, pass the result to {@link Deluge.addTorrent}
62
+ * @param url
63
+ * @param cookies
64
+ * @returns file path
65
+ */
66
+ downloadFromUrl(url: string, cookies?: string): Promise<string>;
60
67
  addTorrent(torrent: string | Buffer, config?: Partial<AddTorrentOptions>): Promise<AddTorrentResponse>;
61
68
  normalizedAddTorrent(torrent: string | Buffer, options?: Partial<NormalizedAddTorrentOptions>): Promise<NormalizedTorrent>;
62
69
  addTorrentMagnet(magnet: string, config?: Partial<AddTorrentOptions>): Promise<BooleanStatus>;
@@ -1,24 +1,37 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.Deluge = void 0;
7
- const fs_1 = require("fs");
8
- const form_data_1 = __importDefault(require("form-data"));
9
- const got_1 = __importDefault(require("got"));
10
- const tough_cookie_1 = require("tough-cookie");
11
- const url_join_1 = require("@ctrl/url-join");
12
- const shared_torrent_1 = require("@ctrl/shared-torrent");
1
+ import { existsSync } from 'fs';
2
+ import { File, FormData } from 'formdata-node';
3
+ import { fileFromPath } from 'formdata-node/file-from-path';
4
+ import got from 'got';
5
+ import { Cookie } from 'tough-cookie';
6
+ import { magnetDecode } from '@ctrl/magnet-link';
7
+ import { TorrentState, } from '@ctrl/shared-torrent';
8
+ import { urlJoin } from '@ctrl/url-join';
13
9
  const defaults = {
14
10
  baseUrl: 'http://localhost:8112/',
15
11
  path: '/json',
16
12
  password: 'deluge',
17
13
  timeout: 5000,
18
14
  };
19
- class Deluge {
15
+ export class Deluge {
20
16
  constructor(options = {}) {
21
- this._msgId = 0;
17
+ Object.defineProperty(this, "config", {
18
+ enumerable: true,
19
+ configurable: true,
20
+ writable: true,
21
+ value: void 0
22
+ });
23
+ Object.defineProperty(this, "_msgId", {
24
+ enumerable: true,
25
+ configurable: true,
26
+ writable: true,
27
+ value: 0
28
+ });
29
+ Object.defineProperty(this, "_cookie", {
30
+ enumerable: true,
31
+ configurable: true,
32
+ writable: true,
33
+ value: void 0
34
+ });
22
35
  this.config = { ...defaults, ...options };
23
36
  }
24
37
  resetSession() {
@@ -93,7 +106,7 @@ class Deluge {
93
106
  return true;
94
107
  }
95
108
  }
96
- catch (_b) {
109
+ catch {
97
110
  // do nothing
98
111
  }
99
112
  }
@@ -110,7 +123,7 @@ class Deluge {
110
123
  if (!res.body.result || !res.headers || !res.headers['set-cookie']) {
111
124
  throw new Error('Auth failed, incorrect password');
112
125
  }
113
- this._cookie = tough_cookie_1.Cookie.parse(res.headers['set-cookie'][0]);
126
+ this._cookie = Cookie.parse(res.headers['set-cookie'][0]);
114
127
  return true;
115
128
  }
116
129
  /**
@@ -152,36 +165,58 @@ class Deluge {
152
165
  if (!isConnected) {
153
166
  await this.connect();
154
167
  }
155
- const form = new form_data_1.default();
168
+ const form = new FormData();
169
+ const type = { type: 'application/x-bittorrent' };
156
170
  if (typeof torrent === 'string') {
157
- if (fs_1.existsSync(torrent)) {
158
- form.append('file', Buffer.from(fs_1.readFileSync(torrent)), 'temp.torrent');
171
+ if (existsSync(torrent)) {
172
+ const file = await fileFromPath(torrent, 'temp.torrent', type);
173
+ form.set('file', file);
159
174
  }
160
175
  else {
161
- form.append('file', Buffer.from(torrent, 'base64'), 'temp.torrent');
176
+ form.set('file', new File([Buffer.from(torrent, 'base64')], 'file.torrent', type));
162
177
  }
163
178
  }
164
179
  else {
165
- form.append('file', torrent, 'temp.torrent');
180
+ const file = new File([torrent], 'torrent', type);
181
+ form.set('file', file);
166
182
  }
167
- const url = url_join_1.urlJoin(this.config.baseUrl, '/upload');
168
- const res = await got_1.default.post(url, {
169
- headers: form.getHeaders(),
183
+ const url = urlJoin(this.config.baseUrl, '/upload');
184
+ const res = await got.post(url, {
170
185
  body: form,
171
- retry: 0,
186
+ retry: { limit: 0 },
187
+ timeout: { request: this.config.timeout },
172
188
  // allow proxy agent
173
- agent: this.config.agent,
174
- timeout: this.config.timeout,
189
+ ...(this.config.agent ? { agent: this.config.agent } : {}),
175
190
  });
176
191
  // repsonse is json but in a string, cannot use native got.json()
177
192
  return JSON.parse(res.body);
178
193
  }
194
+ /**
195
+ * Download a torrent from url, pass the result to {@link Deluge.addTorrent}
196
+ * @param url
197
+ * @param cookies
198
+ * @returns file path
199
+ */
200
+ async downloadFromUrl(url, cookies = '') {
201
+ const res = await this.request('web.download_torrent_from_url', [url, cookies]);
202
+ if (!res.body.result) {
203
+ throw new Error('Failed to download torrent');
204
+ }
205
+ return res.body.result;
206
+ }
179
207
  async addTorrent(torrent, config = {}) {
180
- const upload = await this.upload(torrent);
181
- if (!upload.success || !upload.files.length) {
182
- throw new Error('Failed to upload');
208
+ let path;
209
+ if (Buffer.isBuffer(torrent) || !torrent.startsWith('/tmp/')) {
210
+ const upload = await this.upload(torrent);
211
+ if (!upload.success || !upload.files.length) {
212
+ throw new Error('Failed to upload');
213
+ }
214
+ path = upload.files[0];
215
+ }
216
+ else {
217
+ /** Assume paths starting with /tmp/ are from {@link Deluge.addTorrent} */
218
+ path = torrent;
183
219
  }
184
- const path = upload.files[0];
185
220
  const options = {
186
221
  file_priorities: [],
187
222
  add_paused: false,
@@ -212,11 +247,21 @@ class Deluge {
212
247
  if (options.startPaused) {
213
248
  torrentOptions.add_paused = true;
214
249
  }
215
- if (!Buffer.isBuffer(torrent)) {
216
- torrent = Buffer.from(torrent);
250
+ let torrentHash;
251
+ if (typeof torrent === 'string' && torrent.startsWith('magnet:')) {
252
+ torrentHash = magnetDecode(torrent).infoHash;
253
+ if (!torrentHash) {
254
+ throw new Error('Magnet did not contain hash');
255
+ }
256
+ await this.addTorrentMagnet(torrent, torrentOptions);
257
+ }
258
+ else {
259
+ if (!Buffer.isBuffer(torrent)) {
260
+ torrent = Buffer.from(torrent);
261
+ }
262
+ const res = await this.addTorrent(torrent, torrentOptions);
263
+ torrentHash = res.result[0][1];
217
264
  }
218
- const res = await this.addTorrent(torrent, torrentOptions);
219
- const torrentHash = res.result[0][1];
220
265
  if (options.label) {
221
266
  // sets the label but it might not set the label right away
222
267
  // sometimes takes a few seconds for label to reflect in results
@@ -266,7 +311,7 @@ class Deluge {
266
311
  }
267
312
  // update current password to new password
268
313
  this.config.password = password;
269
- this._cookie = tough_cookie_1.Cookie.parse(res.headers['set-cookie'][0]);
314
+ this._cookie = Cookie.parse(res.headers['set-cookie'][0]);
270
315
  return res.body;
271
316
  }
272
317
  async getAllData() {
@@ -495,19 +540,19 @@ class Deluge {
495
540
  const headers = {
496
541
  Cookie: (_b = (_a = this._cookie) === null || _a === void 0 ? void 0 : _a.cookieString) === null || _b === void 0 ? void 0 : _b.call(_a),
497
542
  };
498
- const url = url_join_1.urlJoin(this.config.baseUrl, this.config.path);
499
- const res = await got_1.default.post(url, {
543
+ const url = urlJoin(this.config.baseUrl, this.config.path);
544
+ const res = await got.post(url, {
500
545
  json: {
501
546
  method,
502
547
  params,
503
548
  id: this._msgId++,
504
549
  },
505
550
  headers,
506
- retry: 0,
507
- // allow proxy agent
508
- agent: this.config.agent,
509
- timeout: this.config.timeout,
551
+ retry: { limit: 0 },
552
+ timeout: { request: this.config.timeout },
510
553
  responseType: 'json',
554
+ // allow proxy agent
555
+ ...(this.config.agent ? { agent: this.config.agent } : {}),
511
556
  });
512
557
  const err = (_d = (_c = res.body) === null || _c === void 0 ? void 0 : _c.error) !== null && _d !== void 0 ? _d : (typeof res.body === 'string' && res.body);
513
558
  if (err) {
@@ -518,9 +563,9 @@ class Deluge {
518
563
  _normalizeTorrentData(id, torrent) {
519
564
  const dateAdded = new Date(torrent.time_added * 1000).toISOString();
520
565
  // normalize state to enum
521
- let state = shared_torrent_1.TorrentState.unknown;
522
- if (Object.keys(shared_torrent_1.TorrentState).includes(torrent.state.toLowerCase())) {
523
- state = shared_torrent_1.TorrentState[torrent.state.toLowerCase()];
566
+ let state = TorrentState.unknown;
567
+ if (Object.keys(TorrentState).includes(torrent.state.toLowerCase())) {
568
+ state = TorrentState[torrent.state.toLowerCase()];
524
569
  }
525
570
  const isCompleted = torrent.progress >= 100;
526
571
  const result = {
@@ -560,4 +605,3 @@ class Deluge {
560
605
  }
561
606
  }
562
607
  }
563
- exports.Deluge = Deluge;
@@ -0,0 +1,2 @@
1
+ export * from './deluge.js';
2
+ export * from './types.js';
@@ -0,0 +1,2 @@
1
+ export * from './deluge.js';
2
+ export * from './types.js';
File without changes
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ctrl/deluge",
3
- "version": "3.3.0",
3
+ "version": "4.0.0",
4
4
  "description": "TypeScript api wrapper for deluge using got",
5
5
  "author": "Scott Cooper <scttcper@gmail.com>",
6
6
  "license": "MIT",
@@ -10,50 +10,52 @@
10
10
  "deluge",
11
11
  "typescript"
12
12
  ],
13
- "main": "dist/index.js",
14
- "types": "dist/index.d.ts",
13
+ "type": "module",
14
+ "main": "./dist/src/index.js",
15
+ "typings": "./dist/src/index.d.ts",
15
16
  "files": [
16
- "dist"
17
+ "dist/src"
17
18
  ],
18
19
  "sideEffects": false,
19
20
  "scripts": {
20
21
  "lint": "eslint --ext .js,.ts, .",
21
22
  "lint:fix": "eslint --fix --ext .js,.ts, .",
22
23
  "prepare": "npm run build",
23
- "build": "tsc -p tsconfig.build.json",
24
- "build:docs": "typedoc --out docs --hideGenerator --target ES6 --mode file src && touch docs/.nojekyll",
25
- "test": "jest --runInBand",
26
- "test:watch": "jest --watch --runInBand",
27
- "test:ci": "jest --runInBand --coverage --no-cache"
24
+ "build": "tsc",
25
+ "build:docs": "typedoc",
26
+ "test": "ava",
27
+ "test:watch": "ava --watch",
28
+ "test:ci": "c8 --reporter=text --reporter=lcov ava"
28
29
  },
29
30
  "dependencies": {
30
- "@ctrl/shared-torrent": "^3.0.4",
31
- "@ctrl/url-join": "^1.0.2",
32
- "form-data": "^3.0.0",
33
- "got": "^11.8.1",
31
+ "@ctrl/magnet-link": "^3.1.0",
32
+ "@ctrl/shared-torrent": "^4.1.0",
33
+ "@ctrl/url-join": "^2.0.0",
34
+ "formdata-node": "^4.3.2",
35
+ "got": "^12.0.1",
34
36
  "tough-cookie": "^4.0.0"
35
37
  },
36
38
  "devDependencies": {
37
- "@babel/plugin-transform-modules-commonjs": "7.12.1",
38
- "@babel/preset-typescript": "7.12.7",
39
- "@ctrl/eslint-config": "1.2.8",
40
- "@jest/globals": "26.6.2",
41
- "@types/node": "14.14.13",
42
- "@types/tough-cookie": "4.0.0",
43
- "jest": "26.6.3",
44
- "p-wait-for": "3.1.0",
45
- "typedoc": "0.19.2",
46
- "typescript": "4.1.3"
39
+ "@ctrl/eslint-config": "3.3.1",
40
+ "@sindresorhus/tsconfig": "2.0.0",
41
+ "@types/node": "17.0.21",
42
+ "@types/tough-cookie": "4.0.1",
43
+ "ava": "4.0.1",
44
+ "c8": "7.11.0",
45
+ "ts-node": "10.5.0",
46
+ "p-wait-for": "4.1.0",
47
+ "typedoc": "0.22.12",
48
+ "typescript": "4.5.5"
47
49
  },
48
- "jest": {
49
- "testEnvironment": "node"
50
- },
51
- "babel": {
52
- "presets": [
53
- "@babel/preset-typescript"
50
+ "ava": {
51
+ "files": [
52
+ "test/**/*.spec.ts"
54
53
  ],
55
- "plugins": [
56
- "@babel/plugin-transform-modules-commonjs"
54
+ "extensions": {
55
+ "ts": "module"
56
+ },
57
+ "nodeArguments": [
58
+ "--loader=ts-node/esm"
57
59
  ]
58
60
  },
59
61
  "publishConfig": {
@@ -63,6 +65,6 @@
63
65
  "branch": "master"
64
66
  },
65
67
  "engines": {
66
- "node": ">=10.19.0"
68
+ "node": ">=14.16"
67
69
  }
68
70
  }
package/dist/types.js DELETED
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });