@ctrl/qbittorrent 9.9.1 → 9.11.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.
@@ -9,58 +9,72 @@ export function normalizeTorrentData(torrent) {
9
9
  * https://github.com/Radarr/Radarr/blob/develop/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrent.cs#L242
10
10
  */
11
11
  switch (torrent.state) {
12
- case TorrentState.Error:
12
+ case TorrentState.Error: {
13
13
  state = NormalizedTorrentState.warning;
14
14
  stateMessage = 'qBittorrent is reporting an error';
15
15
  break;
16
+ }
16
17
  case TorrentState.PausedDL:
17
- case TorrentState.StoppedDL:
18
+ case TorrentState.StoppedDL: {
18
19
  state = NormalizedTorrentState.paused;
19
20
  break;
21
+ }
20
22
  case TorrentState.QueuedDL: // queuing is enabled and torrent is queued for download
21
23
  case TorrentState.CheckingDL: // same as checkingUP, but torrent has NOT finished downloading
22
- case TorrentState.CheckingUP: // torrent has finished downloading and is being checked. Set when `recheck torrent on completion` is enabled. In the event the check fails we shouldn't treat it as completed.
24
+ case TorrentState.CheckingUP: {
25
+ // Torrent has finished downloading and is being checked. Set when `recheck torrent on completion` is enabled. In the event the check fails we shouldn't treat it as completed.
23
26
  state = NormalizedTorrentState.queued;
24
27
  break;
28
+ }
25
29
  case TorrentState.MetaDL: // Metadl could be an error if DHT is not enabled
26
30
  case TorrentState.ForcedDL: // torrent is being downloaded, and was forced started
27
31
  case TorrentState.ForcedMetaDL: // torrent metadata is being forcibly downloaded
28
- case TorrentState.Downloading: // torrent is being downloaded and data is being transferred
32
+ case TorrentState.Downloading: {
33
+ // Torrent is being downloaded and data is being transferred
29
34
  state = NormalizedTorrentState.downloading;
30
35
  break;
31
- case TorrentState.Allocating:
36
+ }
37
+ case TorrentState.Allocating: {
32
38
  // state = 'stalledDL';
33
39
  state = NormalizedTorrentState.queued;
34
40
  break;
35
- case TorrentState.StalledDL:
41
+ }
42
+ case TorrentState.StalledDL: {
36
43
  state = NormalizedTorrentState.warning;
37
44
  stateMessage = 'The download is stalled with no connection';
38
45
  break;
46
+ }
39
47
  case TorrentState.StoppedUP: // torrent is paused and has finished downloading
40
48
  case TorrentState.PausedUP: // torrent is paused and has finished downloading
41
49
  case TorrentState.Uploading: // torrent is being seeded and data is being transferred
42
50
  case TorrentState.StalledUP: // torrent is being seeded, but no connection were made
43
51
  case TorrentState.QueuedUP: // queuing is enabled and torrent is queued for upload
44
- case TorrentState.ForcedUP: // torrent has finished downloading and is being forcibly seeded
52
+ case TorrentState.ForcedUP: {
53
+ // Torrent has finished downloading and is being forcibly seeded
45
54
  // state = 'completed';
46
55
  state = NormalizedTorrentState.seeding;
47
56
  eta = 0; // qBittorrent sends eta=8640000 for completed torrents
48
57
  break;
58
+ }
49
59
  case TorrentState.Moving: // torrent is being moved from a folder
50
60
  case TorrentState.QueuedForChecking:
51
- case TorrentState.CheckingResumeData:
61
+ case TorrentState.CheckingResumeData: {
52
62
  state = NormalizedTorrentState.checking;
53
63
  break;
54
- case TorrentState.Unknown:
64
+ }
65
+ case TorrentState.Unknown: {
55
66
  state = NormalizedTorrentState.error;
56
67
  break;
57
- case TorrentState.MissingFiles:
68
+ }
69
+ case TorrentState.MissingFiles: {
58
70
  state = NormalizedTorrentState.error;
59
71
  stateMessage = 'The download is missing files';
60
72
  break;
73
+ }
61
74
  // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
62
- default:
75
+ default: {
63
76
  break;
77
+ }
64
78
  }
65
79
  const isCompleted = torrent.progress === 1;
66
80
  const result = {
@@ -70,7 +70,7 @@ export class QBittorrent {
70
70
  }
71
71
  async getTorrent(hash) {
72
72
  const torrentsResponse = await this.listTorrents({ hashes: hash });
73
- const torrentData = torrentsResponse[0];
73
+ const [torrentData] = torrentsResponse;
74
74
  if (!torrentData) {
75
75
  throw new Error('Torrent not found');
76
76
  }
@@ -82,7 +82,7 @@ export class QBittorrent {
82
82
  async getTorrentDownloadLimit(hash) {
83
83
  const downloadLimit = await this.request('/torrents/downloadLimit', 'POST', undefined, objToUrlSearchParams({
84
84
  hashes: normalizeHashes(hash),
85
- }), undefined);
85
+ }));
86
86
  return downloadLimit;
87
87
  }
88
88
  /**
@@ -102,7 +102,7 @@ export class QBittorrent {
102
102
  async getTorrentUploadLimit(hash) {
103
103
  const UploadLimit = await this.request('/torrents/uploadLimit', 'POST', undefined, objToUrlSearchParams({
104
104
  hashes: normalizeHashes(hash),
105
- }), undefined);
105
+ }));
106
106
  return UploadLimit;
107
107
  }
108
108
  /**
@@ -657,7 +657,7 @@ export class QBittorrent {
657
657
  ? new Date(expires)
658
658
  : maxAge
659
659
  ? new Date(Number(maxAge) * 1000)
660
- : new Date(Date.now() + 3600000),
660
+ : new Date(Date.now() + 3_600_000),
661
661
  };
662
662
  // Check version after successful login
663
663
  await this.checkVersion();
@@ -671,7 +671,7 @@ export class QBittorrent {
671
671
  async request(path, method, params, body, headers = {}, isJson = true) {
672
672
  if (!this.state.auth?.sid ||
673
673
  !this.state.auth.expires ||
674
- this.state.auth.expires.getTime() < new Date().getTime()) {
674
+ this.state.auth.expires.getTime() < Date.now()) {
675
675
  const authed = await this.login();
676
676
  if (!authed) {
677
677
  throw new Error('Auth Failed');
@@ -182,6 +182,41 @@ export interface Torrent {
182
182
  * Comma-concatenated tag list of the torrent e.g. - "abc, 123"
183
183
  */
184
184
  tags: string;
185
+ /**
186
+ * Absolute path of torrent content (root path for multifile torrents,
187
+ * absolute file path for singlefile torrents)
188
+ * Added in qBittorrent WebUI API v2.6.1
189
+ */
190
+ content_path: string;
191
+ /**
192
+ * Whether this torrent is managed by Automatic Torrent Management
193
+ */
194
+ auto_tmm: boolean;
195
+ /**
196
+ * Percentage of file pieces currently available
197
+ * Added in qBittorrent WebUI API v2.2.0
198
+ */
199
+ availability: number;
200
+ /**
201
+ * True if force start is enabled for this torrent
202
+ */
203
+ force_start: boolean;
204
+ /**
205
+ * True if torrent is from a private tracker
206
+ * Added in qBittorrent v5.0.0
207
+ * Might be able to make not optional once qb v5 is more widely used
208
+ */
209
+ isPrivate?: boolean;
210
+ /**
211
+ * Time until the next tracker reannounce
212
+ * Added in qBittorrent WebUI API v2.9.3 (qb v5.0.0)
213
+ */
214
+ reannounce?: number;
215
+ /**
216
+ * Torrent elapsed time while complete (seconds)
217
+ * Added in qBittorrent WebUI API v2.8.1
218
+ */
219
+ seeding_time: number;
185
220
  }
186
221
  export type TorrentCategories = Record<string, Category>;
187
222
  interface Category {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ctrl/qbittorrent",
3
- "version": "9.9.1",
3
+ "version": "9.11.0",
4
4
  "description": "TypeScript api wrapper for qbittorrent using ofetch",
5
5
  "author": "Scott Cooper <scttcper@gmail.com>",
6
6
  "license": "MIT",
@@ -40,23 +40,23 @@
40
40
  "@ctrl/torrent-file": "^4.4.0",
41
41
  "cookie": "^1.0.2",
42
42
  "node-fetch-native": "^1.6.7",
43
- "ofetch": "^1.4.1",
44
- "type-fest": "^5.0.1",
43
+ "ofetch": "^1.5.1",
44
+ "type-fest": "^5.2.0",
45
45
  "ufo": "^1.6.1",
46
46
  "uint8array-extras": "^1.5.0"
47
47
  },
48
48
  "devDependencies": {
49
- "@ctrl/oxlint-config": "1.2.7",
50
- "@sindresorhus/tsconfig": "8.0.1",
51
- "@trivago/prettier-plugin-sort-imports": "5.2.2",
52
- "@types/node": "24.6.2",
53
- "@vitest/coverage-v8": "3.2.4",
54
- "oxlint": "1.19.0",
49
+ "@ctrl/oxlint-config": "1.3.2",
50
+ "@sindresorhus/tsconfig": "8.1.0",
51
+ "@trivago/prettier-plugin-sort-imports": "6.0.0",
52
+ "@types/node": "24.10.0",
53
+ "@vitest/coverage-v8": "4.0.7",
54
+ "oxlint": "1.26.0",
55
55
  "p-wait-for": "6.0.0",
56
56
  "prettier": "3.6.2",
57
- "typedoc": "0.28.13",
57
+ "typedoc": "0.28.14",
58
58
  "typescript": "5.9.3",
59
- "vitest": "3.2.4"
59
+ "vitest": "4.0.7"
60
60
  },
61
61
  "release": {
62
62
  "branches": [
@@ -66,7 +66,7 @@
66
66
  "engines": {
67
67
  "node": ">=18"
68
68
  },
69
- "packageManager": "pnpm@10.18.0",
69
+ "packageManager": "pnpm@10.20.0",
70
70
  "prettier": {
71
71
  "singleQuote": true,
72
72
  "trailingComma": "all",