@ctrl/transmission 2.5.0 → 4.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.
@@ -0,0 +1,2 @@
1
+ export * from './transmission.js';
2
+ export * from './types.js';
@@ -0,0 +1,2 @@
1
+ export * from './transmission.js';
2
+ export * from './types.js';
@@ -1,45 +1,38 @@
1
- /// <reference types="node" />
1
+ /// <reference types="node" resolution-mode="require"/>
2
2
  import { Response } from 'got';
3
3
  import { AddTorrentOptions as NormalizedAddTorrentOptions, AllClientData, NormalizedTorrent, TorrentClient, TorrentSettings } from '@ctrl/shared-torrent';
4
- import { AddTorrentOptions, AddTorrentResponse, DefaultResponse, FreeSpaceResponse, GetTorrentRepsonse, RenamePathOptions, SessionArguments, SessionResponse, SetTorrentOptions, TorrentIds } from './types';
5
- /**
6
- * TODO: remove when hash is available on normalized torrent
7
- * @deprecated
8
- */
9
- export declare type TransmissionNormalizedTorrent = NormalizedTorrent & {
10
- hash: string;
11
- };
4
+ import { AddTorrentOptions, AddTorrentResponse, DefaultResponse, FreeSpaceResponse, GetTorrentRepsonse, NormalizedTorrentIds, RenamePathOptions, SessionArguments, SessionResponse, SetTorrentOptions } from './types.js';
12
5
  export declare class Transmission implements TorrentClient {
13
6
  config: TorrentSettings;
14
7
  sessionId?: string;
15
8
  constructor(options?: Partial<TorrentSettings>);
16
9
  getSession(): Promise<SessionResponse>;
17
10
  setSession(args: Partial<SessionArguments>): Promise<SessionResponse>;
18
- queueTop(ids: TorrentIds): Promise<DefaultResponse>;
19
- queueBottom(ids: TorrentIds): Promise<DefaultResponse>;
20
- queueUp(ids: TorrentIds): Promise<DefaultResponse>;
21
- queueDown(ids: TorrentIds): Promise<DefaultResponse>;
11
+ queueTop(id: NormalizedTorrentIds): Promise<DefaultResponse>;
12
+ queueBottom(id: NormalizedTorrentIds): Promise<DefaultResponse>;
13
+ queueUp(id: NormalizedTorrentIds): Promise<DefaultResponse>;
14
+ queueDown(id: NormalizedTorrentIds): Promise<DefaultResponse>;
22
15
  freeSpace(path?: string): Promise<FreeSpaceResponse>;
23
- pauseTorrent(ids: TorrentIds): Promise<DefaultResponse>;
24
- resumeTorrent(ids: TorrentIds): Promise<DefaultResponse>;
25
- verifyTorrent(ids: TorrentIds): Promise<DefaultResponse>;
16
+ pauseTorrent(id: NormalizedTorrentIds): Promise<DefaultResponse>;
17
+ resumeTorrent(id: NormalizedTorrentIds): Promise<DefaultResponse>;
18
+ verifyTorrent(id: NormalizedTorrentIds): Promise<DefaultResponse>;
26
19
  /**
27
20
  * ask tracker for more peers
28
21
  */
29
- reannounceTorrent(ids: TorrentIds): Promise<DefaultResponse>;
30
- moveTorrent(ids: TorrentIds, location: string): Promise<DefaultResponse>;
22
+ reannounceTorrent(id: NormalizedTorrentIds): Promise<DefaultResponse>;
23
+ moveTorrent(id: NormalizedTorrentIds, location: string): Promise<DefaultResponse>;
31
24
  /**
32
25
  * Torrent Mutators
33
26
  */
34
- setTorrent(ids: TorrentIds, options?: Partial<SetTorrentOptions>): Promise<DefaultResponse>;
27
+ setTorrent(id: NormalizedTorrentIds, options?: Partial<SetTorrentOptions>): Promise<DefaultResponse>;
35
28
  /**
36
29
  * Renaming a Torrent's Path
37
30
  */
38
- renamePath(ids: TorrentIds, options?: Partial<RenamePathOptions>): Promise<DefaultResponse>;
31
+ renamePath(id: NormalizedTorrentIds, options?: Partial<RenamePathOptions>): Promise<DefaultResponse>;
39
32
  /**
40
33
  * Removing a Torrent
41
34
  */
42
- removeTorrent(ids: TorrentIds, removeData?: boolean): Promise<AddTorrentResponse>;
35
+ removeTorrent(id: NormalizedTorrentIds, removeData?: boolean): Promise<AddTorrentResponse>;
43
36
  /**
44
37
  * An alias for {@link Transmission.addMagnet}
45
38
  */
@@ -56,10 +49,11 @@ export declare class Transmission implements TorrentClient {
56
49
  * @param torrent a string of file path or contents of the file as base64 string
57
50
  */
58
51
  addTorrent(torrent: string | Buffer, options?: Partial<AddTorrentOptions>): Promise<AddTorrentResponse>;
59
- normalizedAddTorrent(torrent: string | Buffer, options?: Partial<NormalizedAddTorrentOptions>): Promise<TransmissionNormalizedTorrent>;
60
- getTorrent(id: TorrentIds): Promise<TransmissionNormalizedTorrent>;
52
+ normalizedAddTorrent(torrent: string | Buffer, options?: Partial<NormalizedAddTorrentOptions>): Promise<NormalizedTorrent>;
53
+ getTorrent(id: NormalizedTorrentIds): Promise<NormalizedTorrent>;
61
54
  getAllData(): Promise<AllClientData>;
62
- listTorrents(ids?: TorrentIds, additionalFields?: string[]): Promise<GetTorrentRepsonse>;
55
+ listTorrents(id?: NormalizedTorrentIds, additionalFields?: string[]): Promise<GetTorrentRepsonse>;
63
56
  request<T>(method: string, args?: any): Promise<Response<T>>;
57
+ private _handleNormalizedIds;
64
58
  private _normalizeTorrentData;
65
59
  }
@@ -1,13 +1,8 @@
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.Transmission = void 0;
7
- const fs_1 = require("fs");
8
- const got_1 = __importDefault(require("got"));
9
- const shared_torrent_1 = require("@ctrl/shared-torrent");
10
- const url_join_1 = require("@ctrl/url-join");
1
+ import { existsSync, readFileSync } from 'fs';
2
+ import got from 'got';
3
+ import { magnetDecode } from '@ctrl/magnet-link';
4
+ import { TorrentState, } from '@ctrl/shared-torrent';
5
+ import { urlJoin } from '@ctrl/url-join';
11
6
  const defaults = {
12
7
  baseUrl: 'http://localhost:9091/',
13
8
  path: '/transmission/rpc',
@@ -15,8 +10,20 @@ const defaults = {
15
10
  password: '',
16
11
  timeout: 5000,
17
12
  };
18
- class Transmission {
13
+ export class Transmission {
19
14
  constructor(options = {}) {
15
+ Object.defineProperty(this, "config", {
16
+ enumerable: true,
17
+ configurable: true,
18
+ writable: true,
19
+ value: void 0
20
+ });
21
+ Object.defineProperty(this, "sessionId", {
22
+ enumerable: true,
23
+ configurable: true,
24
+ writable: true,
25
+ value: void 0
26
+ });
20
27
  this.config = { ...defaults, ...options };
21
28
  }
22
29
  async getSession() {
@@ -27,19 +34,23 @@ class Transmission {
27
34
  const res = await this.request('session-set', args);
28
35
  return res.body;
29
36
  }
30
- async queueTop(ids) {
37
+ async queueTop(id) {
38
+ const ids = this._handleNormalizedIds(id);
31
39
  const res = await this.request('queue-move-top', { ids });
32
40
  return res.body;
33
41
  }
34
- async queueBottom(ids) {
42
+ async queueBottom(id) {
43
+ const ids = this._handleNormalizedIds(id);
35
44
  const res = await this.request('queue-move-bottom', { ids });
36
45
  return res.body;
37
46
  }
38
- async queueUp(ids) {
47
+ async queueUp(id) {
48
+ const ids = this._handleNormalizedIds(id);
39
49
  const res = await this.request('queue-move-up', { ids });
40
50
  return res.body;
41
51
  }
42
- async queueDown(ids) {
52
+ async queueDown(id) {
53
+ const ids = this._handleNormalizedIds(id);
43
54
  const res = await this.request('queue-move-down', { ids });
44
55
  return res.body;
45
56
  }
@@ -47,26 +58,31 @@ class Transmission {
47
58
  const res = await this.request('free-space', { path });
48
59
  return res.body;
49
60
  }
50
- async pauseTorrent(ids) {
61
+ async pauseTorrent(id) {
62
+ const ids = this._handleNormalizedIds(id);
51
63
  const res = await this.request('torrent-stop', { ids });
52
64
  return res.body;
53
65
  }
54
- async resumeTorrent(ids) {
66
+ async resumeTorrent(id) {
67
+ const ids = this._handleNormalizedIds(id);
55
68
  const res = await this.request('torrent-start', { ids });
56
69
  return res.body;
57
70
  }
58
- async verifyTorrent(ids) {
71
+ async verifyTorrent(id) {
72
+ const ids = this._handleNormalizedIds(id);
59
73
  const res = await this.request('torrent-verify', { ids });
60
74
  return res.body;
61
75
  }
62
76
  /**
63
77
  * ask tracker for more peers
64
78
  */
65
- async reannounceTorrent(ids) {
79
+ async reannounceTorrent(id) {
80
+ const ids = this._handleNormalizedIds(id);
66
81
  const res = await this.request('torrent-reannounce', { ids });
67
82
  return res.body;
68
83
  }
69
- async moveTorrent(ids, location) {
84
+ async moveTorrent(id, location) {
85
+ const ids = this._handleNormalizedIds(id);
70
86
  const res = await this.request('torrent-set-location', {
71
87
  ids,
72
88
  move: true,
@@ -77,7 +93,8 @@ class Transmission {
77
93
  /**
78
94
  * Torrent Mutators
79
95
  */
80
- async setTorrent(ids, options = {}) {
96
+ async setTorrent(id, options = {}) {
97
+ const ids = this._handleNormalizedIds(id);
81
98
  options.ids = ids;
82
99
  const res = await this.request('torrent-set', options);
83
100
  return res.body;
@@ -85,7 +102,8 @@ class Transmission {
85
102
  /**
86
103
  * Renaming a Torrent's Path
87
104
  */
88
- async renamePath(ids, options = {}) {
105
+ async renamePath(id, options = {}) {
106
+ const ids = this._handleNormalizedIds(id);
89
107
  options.ids = ids;
90
108
  const res = await this.request('torrent-rename-path', options);
91
109
  return res.body;
@@ -93,7 +111,8 @@ class Transmission {
93
111
  /**
94
112
  * Removing a Torrent
95
113
  */
96
- async removeTorrent(ids, removeData = true) {
114
+ async removeTorrent(id, removeData = true) {
115
+ const ids = this._handleNormalizedIds(id);
97
116
  const res = await this.request('torrent-remove', {
98
117
  ids,
99
118
  'delete-local-data': removeData,
@@ -133,8 +152,8 @@ class Transmission {
133
152
  ...options,
134
153
  };
135
154
  if (typeof torrent === 'string') {
136
- args.metainfo = (0, fs_1.existsSync)(torrent)
137
- ? Buffer.from((0, fs_1.readFileSync)(torrent)).toString('base64')
155
+ args.metainfo = existsSync(torrent)
156
+ ? Buffer.from(readFileSync(torrent)).toString('base64')
138
157
  : Buffer.from(torrent, 'base64').toString('base64');
139
158
  }
140
159
  else {
@@ -148,15 +167,25 @@ class Transmission {
148
167
  if (options.startPaused) {
149
168
  torrentOptions.paused = true;
150
169
  }
151
- if (!Buffer.isBuffer(torrent)) {
152
- torrent = Buffer.from(torrent);
170
+ let torrentHash;
171
+ if (typeof torrent === 'string' && torrent.startsWith('magnet:')) {
172
+ torrentHash = magnetDecode(torrent).infoHash;
173
+ if (!torrentHash) {
174
+ throw new Error('Magnet did not contain hash');
175
+ }
176
+ await this.addMagnet(torrent, torrentOptions);
177
+ }
178
+ else {
179
+ if (!Buffer.isBuffer(torrent)) {
180
+ torrent = Buffer.from(torrent);
181
+ }
182
+ const res = await this.addTorrent(torrent, torrentOptions);
183
+ torrentHash = res.arguments['torrent-added'].hashString;
153
184
  }
154
- const res = await this.addTorrent(torrent, torrentOptions);
155
- const torrentId = res.arguments['torrent-added'].id;
156
185
  if (options.label) {
157
- await this.setTorrent(torrentId, { labels: [options.label] });
186
+ await this.setTorrent(torrentHash, { labels: [options.label] });
158
187
  }
159
- return this.getTorrent(torrentId);
188
+ return this.getTorrent(torrentHash);
160
189
  }
161
190
  async getTorrent(id) {
162
191
  const result = await this.listTorrents(id);
@@ -186,7 +215,7 @@ class Transmission {
186
215
  };
187
216
  return results;
188
217
  }
189
- async listTorrents(ids, additionalFields = []) {
218
+ async listTorrents(id, additionalFields = []) {
190
219
  const fields = [
191
220
  'id',
192
221
  'addedDate',
@@ -249,14 +278,14 @@ class Transmission {
249
278
  ...additionalFields,
250
279
  ];
251
280
  const args = { fields };
252
- if (ids) {
281
+ if (id) {
282
+ const ids = this._handleNormalizedIds(id);
253
283
  args.ids = ids;
254
284
  }
255
285
  const res = await this.request('torrent-get', args);
256
286
  return res.body;
257
287
  }
258
288
  async request(method, args = {}) {
259
- var _a, _b, _c;
260
289
  if (!this.sessionId && method !== 'session-get') {
261
290
  await this.getSession();
262
291
  }
@@ -264,27 +293,27 @@ class Transmission {
264
293
  'X-Transmission-Session-Id': this.sessionId,
265
294
  };
266
295
  if (this.config.username || this.config.password) {
267
- const str = `${(_a = this.config.username) !== null && _a !== void 0 ? _a : ''}:${(_b = this.config.password) !== null && _b !== void 0 ? _b : ''}`;
296
+ const str = `${this.config.username ?? ''}:${this.config.password ?? ''}`;
268
297
  headers.Authorization = 'Basic ' + Buffer.from(str).toString('base64');
269
298
  }
270
- const url = (0, url_join_1.urlJoin)(this.config.baseUrl, this.config.path);
299
+ const url = urlJoin(this.config.baseUrl, this.config.path);
271
300
  try {
272
- const res = await got_1.default.post(url, {
301
+ const res = await got.post(url, {
273
302
  json: {
274
303
  method,
275
304
  arguments: args,
276
305
  },
277
306
  headers,
278
- retry: 0,
307
+ retry: { limit: 0 },
279
308
  // allow proxy agent
280
- agent: this.config.agent,
281
- timeout: this.config.timeout,
309
+ timeout: { request: this.config.timeout },
282
310
  responseType: 'json',
311
+ ...(this.config.agent ? { agent: this.config.agent } : {}),
283
312
  });
284
313
  return res;
285
314
  }
286
315
  catch (error) {
287
- if (((_c = error === null || error === void 0 ? void 0 : error.response) === null || _c === void 0 ? void 0 : _c.statusCode) === 409) {
316
+ if (error?.response?.statusCode === 409) {
288
317
  this.sessionId = error.response.headers['x-transmission-session-id'];
289
318
  // eslint-disable-next-line no-return-await
290
319
  return await this.request(method, args);
@@ -293,31 +322,35 @@ class Transmission {
293
322
  throw error;
294
323
  }
295
324
  }
325
+ _handleNormalizedIds(ids) {
326
+ if (typeof ids === 'string' && ids !== 'recently-active') {
327
+ return [ids];
328
+ }
329
+ return ids;
330
+ }
296
331
  _normalizeTorrentData(torrent) {
297
- var _a;
298
332
  const dateAdded = new Date(torrent.addedDate * 1000).toISOString();
299
333
  const dateCompleted = new Date(torrent.doneDate * 1000).toISOString();
300
334
  // normalize state to enum
301
335
  // https://github.com/transmission/transmission/blob/c11f2870fd18ff781ca06ce84b6d43541f3293dd/web/javascript/torrent.js#L18
302
- let state = shared_torrent_1.TorrentState.unknown;
336
+ let state = TorrentState.unknown;
303
337
  if (torrent.status === 6) {
304
- state = shared_torrent_1.TorrentState.seeding;
338
+ state = TorrentState.seeding;
305
339
  }
306
340
  else if (torrent.status === 4) {
307
- state = shared_torrent_1.TorrentState.downloading;
341
+ state = TorrentState.downloading;
308
342
  }
309
343
  else if (torrent.status === 0) {
310
- state = shared_torrent_1.TorrentState.paused;
344
+ state = TorrentState.paused;
311
345
  }
312
346
  else if (torrent.status === 2) {
313
- state = shared_torrent_1.TorrentState.checking;
347
+ state = TorrentState.checking;
314
348
  }
315
349
  else if (torrent.status === 3 || torrent.status === 5) {
316
- state = shared_torrent_1.TorrentState.queued;
350
+ state = TorrentState.queued;
317
351
  }
318
352
  return {
319
- id: torrent.id,
320
- hash: torrent.hashString,
353
+ id: torrent.hashString,
321
354
  name: torrent.name,
322
355
  state,
323
356
  isCompleted: torrent.leftUntilDone < 1,
@@ -326,7 +359,7 @@ class Transmission {
326
359
  ratio: torrent.uploadRatio,
327
360
  dateAdded,
328
361
  dateCompleted,
329
- label: ((_a = torrent.labels) === null || _a === void 0 ? void 0 : _a.length) ? torrent.labels[0] : undefined,
362
+ label: torrent.labels?.length ? torrent.labels[0] : undefined,
330
363
  savePath: torrent.downloadDir,
331
364
  uploadSpeed: torrent.rateUpload,
332
365
  downloadSpeed: torrent.rateDownload,
@@ -343,4 +376,3 @@ class Transmission {
343
376
  };
344
377
  }
345
378
  }
346
- exports.Transmission = Transmission;
@@ -39,12 +39,17 @@ export interface FreeSpaceResponse extends DefaultResponse {
39
39
  /**
40
40
  * "ids", which specifies which torrents to use.
41
41
  * All torrents are used if the "ids" argument is omitted.
42
+ *
42
43
  * "ids" should be one of the following:
43
- * (1) an integer referring to a torrent id
44
- * (2) a list of torrent id numbers, sha1 hash strings, or both
45
- * (3) a string, "recently-active", for recently-active torrents
44
+ * 1. an integer referring to a torrent id
45
+ * 2. a list of torrent id numbers, sha1 hash strings, or both
46
+ * 3. a string, "recently-active", for recently-active torrents
46
47
  */
47
48
  export declare type TorrentIds = number | 'recently-active' | Array<number | string>;
49
+ /**
50
+ * Allows the user to pass a single hash, this will be converted to an array
51
+ */
52
+ export declare type NormalizedTorrentIds = TorrentIds | string;
48
53
  export interface GetTorrentRepsonse extends DefaultResponse {
49
54
  arguments: {
50
55
  removed: Torrent[];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,136 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import pWaitFor from 'p-wait-for';
4
+ import { afterEach, describe, expect, it } from 'vitest';
5
+ import { TorrentState } from '@ctrl/shared-torrent';
6
+ import { Transmission } from '../src/index.js';
7
+ const baseUrl = 'http://localhost:9091/';
8
+ const torrentName = 'ubuntu-18.04.1-desktop-amd64.iso';
9
+ const torrentFile = path.join(__dirname, '/ubuntu-18.04.1-desktop-amd64.iso.torrent');
10
+ async function setupTorrent(transmission) {
11
+ const res = await transmission.addTorrent(torrentFile);
12
+ await pWaitFor(async () => {
13
+ const r = await transmission.listTorrents(undefined, ['id']);
14
+ return r.arguments.torrents.length === 1;
15
+ }, { timeout: 10000, interval: 200 });
16
+ return res.arguments['torrent-added'].hashString;
17
+ }
18
+ describe('Transmission', () => {
19
+ afterEach(async () => {
20
+ const transmission = new Transmission({ baseUrl });
21
+ const res = await transmission.listTorrents();
22
+ // clean up all torrents
23
+ for (const torrent of res.arguments.torrents) {
24
+ // eslint-disable-next-line no-await-in-loop
25
+ await transmission.removeTorrent(torrent.id, false);
26
+ }
27
+ });
28
+ it('should be instantiable', () => {
29
+ const transmission = new Transmission({ baseUrl });
30
+ expect(transmission).toBeTruthy();
31
+ });
32
+ it('should add torrent from file path string', async () => {
33
+ const transmission = new Transmission({ baseUrl });
34
+ const res = await transmission.addTorrent(torrentFile);
35
+ expect(res.result).toBe('success');
36
+ });
37
+ it('should add magnet link', async () => {
38
+ const magnet = 'magnet:?xt=urn:btih:B0B81206633C42874173D22E564D293DAEFC45E2&dn=Ubuntu+11+10+Alternate+Amd64+Iso&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969%2Fannounce&tr=udp%3A%2F%2F9.rarbg.to%3A2710%2Fannounce&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.open-internet.nl%3A6969%2Fannounce&tr=udp%3A%2F%2Fopen.demonii.si%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.pirateparty.gr%3A6969%2Fannounce&tr=udp%3A%2F%2Fdenis.stalker.upeer.me%3A6969%2Fannounce&tr=udp%3A%2F%2Fp4p.arenabg.com%3A1337%2Fannounce&tr=udp%3A%2F%2Fexodus.desync.com%3A6969%2Fannounce';
39
+ const client = new Transmission({ baseUrl });
40
+ const res = await client.addMagnet(magnet);
41
+ expect(res.result).toBe('success');
42
+ });
43
+ it('should add normalized magnet link', async () => {
44
+ const magnet = 'magnet:?xt=urn:btih:B0B81206633C42874173D22E564D293DAEFC45E2&dn=Ubuntu+11+10+Alternate+Amd64+Iso&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969%2Fannounce&tr=udp%3A%2F%2F9.rarbg.to%3A2710%2Fannounce&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.open-internet.nl%3A6969%2Fannounce&tr=udp%3A%2F%2Fopen.demonii.si%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.pirateparty.gr%3A6969%2Fannounce&tr=udp%3A%2F%2Fdenis.stalker.upeer.me%3A6969%2Fannounce&tr=udp%3A%2F%2Fp4p.arenabg.com%3A1337%2Fannounce&tr=udp%3A%2F%2Fexodus.desync.com%3A6969%2Fannounce';
45
+ const client = new Transmission({ baseUrl });
46
+ const res = await client.normalizedAddTorrent(magnet);
47
+ expect(res.id).toBeTruthy();
48
+ });
49
+ it('should add torrent from file buffer', async () => {
50
+ const transmission = new Transmission({ baseUrl });
51
+ const res = await transmission.addTorrent(fs.readFileSync(torrentFile));
52
+ expect(res.result).toBe('success');
53
+ });
54
+ it('should add torrent from file contents base64', async () => {
55
+ const transmission = new Transmission({ baseUrl });
56
+ const contents = Buffer.from(fs.readFileSync(torrentFile)).toString('base64');
57
+ const res = await transmission.addTorrent(contents);
58
+ expect(res.result).toBe('success');
59
+ });
60
+ it('should get torrents', async () => {
61
+ const transmission = new Transmission({ baseUrl });
62
+ await setupTorrent(transmission);
63
+ const res = await transmission.listTorrents(undefined, ['id']);
64
+ expect(res.arguments.torrents).toHaveLength(1);
65
+ });
66
+ it('should get normalized all torrent data', async () => {
67
+ const transmission = new Transmission({ baseUrl });
68
+ await setupTorrent(transmission);
69
+ const res = await transmission.getAllData();
70
+ expect(res.torrents).toHaveLength(1);
71
+ expect(res.torrents[0].name).toBe(torrentName);
72
+ });
73
+ it('should get normalized torrent data', async () => {
74
+ const transmission = new Transmission({ baseUrl });
75
+ const id = await setupTorrent(transmission);
76
+ const res = await transmission.getTorrent(id);
77
+ expect(res.name).toBe(torrentName);
78
+ });
79
+ it('should remove torrent', async () => {
80
+ const transmission = new Transmission({ baseUrl });
81
+ const key = await setupTorrent(transmission);
82
+ await transmission.removeTorrent(key, false);
83
+ });
84
+ it('should verify torrent', async () => {
85
+ const transmission = new Transmission({ baseUrl });
86
+ const key = await setupTorrent(transmission);
87
+ await transmission.verifyTorrent(key);
88
+ });
89
+ it('should move in queue', async () => {
90
+ const transmission = new Transmission({ baseUrl });
91
+ const key = await setupTorrent(transmission);
92
+ await transmission.queueUp(key);
93
+ await transmission.queueDown(key);
94
+ await transmission.queueTop(key);
95
+ await transmission.queueBottom(key);
96
+ });
97
+ it('should report free space', async () => {
98
+ const transmission = new Transmission({ baseUrl });
99
+ const p = '/downloads';
100
+ const res = await transmission.freeSpace(p);
101
+ expect(res.result).toBe('success');
102
+ expect(res.arguments.path).toBe(p);
103
+ expect(typeof res.arguments['size-bytes']).toBe('number');
104
+ });
105
+ it('should add from url', async () => {
106
+ const transmission = new Transmission({ baseUrl });
107
+ const res = await transmission.addUrl('https://releases.ubuntu.com/20.10/ubuntu-20.10-desktop-amd64.iso.torrent');
108
+ expect(res.result).toBe('success');
109
+ });
110
+ it('should add torrent with normalized response', async () => {
111
+ const client = new Transmission({ baseUrl });
112
+ const torrent = await client.normalizedAddTorrent(fs.readFileSync(torrentFile), {
113
+ label: 'test',
114
+ });
115
+ expect(torrent.connectedPeers).toBe(0);
116
+ expect(torrent.connectedSeeds).toBe(0);
117
+ expect(torrent.downloadSpeed).toBe(0);
118
+ expect(torrent.eta).toBe(-1);
119
+ expect(torrent.isCompleted).toBe(false);
120
+ expect(torrent.label).toBe('test');
121
+ expect(torrent.name).toBe(torrentName);
122
+ expect(torrent.progress).toBeGreaterThanOrEqual(0);
123
+ expect(torrent.queuePosition).toBe(0);
124
+ // expect(torrent.ratio).toBe(0);
125
+ expect(torrent.savePath).toBe('/downloads');
126
+ expect(torrent.state).toBe(TorrentState.checking);
127
+ expect(torrent.stateMessage).toBe('');
128
+ expect(torrent.totalDownloaded).toBe(0);
129
+ expect(torrent.totalPeers).toBe(0);
130
+ expect(torrent.totalSeeds).toBe(0);
131
+ expect(torrent.totalSelected).toBe(1953349632);
132
+ // expect(torrent.totalSize).toBe(undefined);
133
+ expect(torrent.totalUploaded).toBe(0);
134
+ expect(torrent.uploadSpeed).toBe(0);
135
+ });
136
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -0,0 +1,7 @@
1
+ // @ts-expect-error
2
+ import { defineConfig } from 'vitest/config';
3
+ export default defineConfig({
4
+ test: {
5
+ threads: false,
6
+ },
7
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ctrl/transmission",
3
- "version": "2.5.0",
3
+ "version": "4.1.0",
4
4
  "description": "TypeScript api wrapper for transmission using got",
5
5
  "author": "Scott Cooper <scttcper@gmail.com>",
6
6
  "license": "MIT",
@@ -9,8 +9,9 @@
9
9
  "transmission",
10
10
  "typescript"
11
11
  ],
12
- "main": "dist/index.js",
13
- "typings": "dist/index.d.ts",
12
+ "type": "module",
13
+ "main": "./dist/src/index.js",
14
+ "typings": "./dist/src/index.d.ts",
14
15
  "files": [
15
16
  "dist"
16
17
  ],
@@ -19,48 +20,41 @@
19
20
  "lint": "eslint --ext .ts .",
20
21
  "lint:fix": "eslint --fix --ext .ts .",
21
22
  "prepare": "npm run build",
22
- "build": "tsc -p tsconfig.build.json",
23
+ "build": "tsc",
23
24
  "build:docs": "typedoc",
24
- "test": "jest --runInBand",
25
- "test:watch": "jest --watch --runInBand",
26
- "test:ci": "jest --ci --runInBand --reporters=default --reporters=jest-junit --coverage"
25
+ "test": "vitest run",
26
+ "test:watch": "vitest",
27
+ "test:ci": "vitest run --coverage"
27
28
  },
28
29
  "dependencies": {
29
- "@ctrl/shared-torrent": "^3.0.5",
30
- "got": "^11.8.3",
31
- "@ctrl/url-join": "^1.0.4"
30
+ "@ctrl/magnet-link": "^3.1.0",
31
+ "@ctrl/shared-torrent": "^4.1.1",
32
+ "@ctrl/url-join": "^2.0.0",
33
+ "got": "^12.1.0"
32
34
  },
33
35
  "devDependencies": {
34
- "@babel/plugin-transform-modules-commonjs": "7.16.8",
35
- "@babel/preset-typescript": "7.16.7",
36
- "@ctrl/eslint-config": "3.3.1",
37
- "@jest/globals": "27.4.6",
38
- "@types/node": "17.0.14",
39
- "jest": "27.4.7",
40
- "jest-junit": "13.0.0",
41
- "p-wait-for": "3.2.0",
42
- "typedoc": "0.22.11",
43
- "typescript": "4.5.5"
36
+ "@ctrl/eslint-config": "3.4.4",
37
+ "@sindresorhus/tsconfig": "3.0.1",
38
+ "@types/node": "17.0.38",
39
+ "c8": "7.11.3",
40
+ "p-wait-for": "4.1.0",
41
+ "typedoc": "0.22.17",
42
+ "typescript": "4.7.2",
43
+ "vitest": "0.13.1"
44
44
  },
45
45
  "jest": {
46
46
  "testEnvironment": "node",
47
47
  "coverageProvider": "v8"
48
48
  },
49
- "babel": {
50
- "presets": [
51
- "@babel/preset-typescript"
52
- ],
53
- "plugins": [
54
- "@babel/plugin-transform-modules-commonjs"
55
- ]
56
- },
57
49
  "publishConfig": {
58
50
  "access": "public"
59
51
  },
60
52
  "release": {
61
- "branch": "master"
53
+ "branches": [
54
+ "master"
55
+ ]
62
56
  },
63
57
  "engines": {
64
- "node": ">=10.19.0"
58
+ "node": ">=14.16"
65
59
  }
66
60
  }
package/dist/index.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export * from './transmission';
2
- export * from './types';
package/dist/index.js DELETED
@@ -1,14 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
- }) : (function(o, m, k, k2) {
6
- if (k2 === undefined) k2 = k;
7
- o[k2] = m[k];
8
- }));
9
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
- };
12
- Object.defineProperty(exports, "__esModule", { value: true });
13
- __exportStar(require("./transmission"), exports);
14
- __exportStar(require("./types"), exports);
package/dist/types.js DELETED
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });