@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.
- package/dist/src/normalizeTorrentData.js +25 -11
- package/dist/src/qbittorrent.js +5 -5
- package/dist/src/types.d.ts +35 -0
- package/package.json +12 -12
|
@@ -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:
|
|
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:
|
|
32
|
+
case TorrentState.Downloading: {
|
|
33
|
+
// Torrent is being downloaded and data is being transferred
|
|
29
34
|
state = NormalizedTorrentState.downloading;
|
|
30
35
|
break;
|
|
31
|
-
|
|
36
|
+
}
|
|
37
|
+
case TorrentState.Allocating: {
|
|
32
38
|
// state = 'stalledDL';
|
|
33
39
|
state = NormalizedTorrentState.queued;
|
|
34
40
|
break;
|
|
35
|
-
|
|
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:
|
|
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
|
-
|
|
64
|
+
}
|
|
65
|
+
case TorrentState.Unknown: {
|
|
55
66
|
state = NormalizedTorrentState.error;
|
|
56
67
|
break;
|
|
57
|
-
|
|
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 = {
|
package/dist/src/qbittorrent.js
CHANGED
|
@@ -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
|
|
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
|
-
})
|
|
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
|
-
})
|
|
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() +
|
|
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() <
|
|
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');
|
package/dist/src/types.d.ts
CHANGED
|
@@ -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.
|
|
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.
|
|
44
|
-
"type-fest": "^5.0
|
|
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
|
|
50
|
-
"@sindresorhus/tsconfig": "8.0
|
|
51
|
-
"@trivago/prettier-plugin-sort-imports": "
|
|
52
|
-
"@types/node": "24.
|
|
53
|
-
"@vitest/coverage-v8": "
|
|
54
|
-
"oxlint": "1.
|
|
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.
|
|
57
|
+
"typedoc": "0.28.14",
|
|
58
58
|
"typescript": "5.9.3",
|
|
59
|
-
"vitest": "
|
|
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.
|
|
69
|
+
"packageManager": "pnpm@10.20.0",
|
|
70
70
|
"prettier": {
|
|
71
71
|
"singleQuote": true,
|
|
72
72
|
"trailingComma": "all",
|