@ctrl/qbittorrent 6.0.0 → 7.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.
- package/README.md +1 -1
- package/dist/src/normalizeTorrentData.d.ts +3 -0
- package/dist/src/normalizeTorrentData.js +91 -0
- package/dist/src/qbittorrent.d.ts +8 -9
- package/dist/src/qbittorrent.js +144 -266
- package/dist/src/types.d.ts +24 -0
- package/dist/src/types.js +4 -4
- package/package.json +19 -19
package/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# qBittorrent [](https://www.npmjs.com/package/@ctrl/qbittorrent) [](https://www.npmjs.com/package/@ctrl/qbittorrent) [](https://codecov.io/gh/scttcper/qbittorrent)
|
2
2
|
|
3
3
|
> TypeScript api wrapper for [qBittorrent](https://www.qbittorrent.org/) using [got](https://github.com/sindresorhus/got)
|
4
4
|
|
@@ -0,0 +1,91 @@
|
|
1
|
+
import { TorrentState as NormalizedTorrentState } from '@ctrl/shared-torrent';
|
2
|
+
import { TorrentState } from './types.js';
|
3
|
+
export function normalizeTorrentData(torrent) {
|
4
|
+
let state = NormalizedTorrentState.unknown;
|
5
|
+
let stateMessage = '';
|
6
|
+
let { eta } = torrent;
|
7
|
+
/**
|
8
|
+
* Good references https://github.com/qbittorrent/qBittorrent/blob/master/src/webui/www/private/scripts/dynamicTable.js#L933
|
9
|
+
* https://github.com/Radarr/Radarr/blob/develop/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrent.cs#L242
|
10
|
+
*/
|
11
|
+
switch (torrent.state) {
|
12
|
+
case TorrentState.Error:
|
13
|
+
state = NormalizedTorrentState.warning;
|
14
|
+
stateMessage = 'qBittorrent is reporting an error';
|
15
|
+
break;
|
16
|
+
case TorrentState.PausedDL:
|
17
|
+
state = NormalizedTorrentState.paused;
|
18
|
+
break;
|
19
|
+
case TorrentState.QueuedDL: // queuing is enabled and torrent is queued for download
|
20
|
+
case TorrentState.CheckingDL: // same as checkingUP, but torrent has NOT finished downloading
|
21
|
+
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.
|
22
|
+
state = NormalizedTorrentState.queued;
|
23
|
+
break;
|
24
|
+
case TorrentState.MetaDL: // Metadl could be an error if DHT is not enabled
|
25
|
+
case TorrentState.ForcedDL: // torrent is being downloaded, and was forced started
|
26
|
+
case TorrentState.ForcedMetaDL: // torrent metadata is being forcibly downloaded
|
27
|
+
case TorrentState.Downloading: // torrent is being downloaded and data is being transferred
|
28
|
+
state = NormalizedTorrentState.downloading;
|
29
|
+
break;
|
30
|
+
case TorrentState.Allocating:
|
31
|
+
// state = 'stalledDL';
|
32
|
+
state = NormalizedTorrentState.queued;
|
33
|
+
break;
|
34
|
+
case TorrentState.StalledDL:
|
35
|
+
state = NormalizedTorrentState.warning;
|
36
|
+
stateMessage = 'The download is stalled with no connection';
|
37
|
+
break;
|
38
|
+
case TorrentState.PausedUP: // torrent is paused and has finished downloading:
|
39
|
+
case TorrentState.Uploading: // torrent is being seeded and data is being transferred
|
40
|
+
case TorrentState.StalledUP: // torrent is being seeded, but no connection were made
|
41
|
+
case TorrentState.QueuedUP: // queuing is enabled and torrent is queued for upload
|
42
|
+
case TorrentState.ForcedUP: // torrent has finished downloading and is being forcibly seeded
|
43
|
+
// state = 'completed';
|
44
|
+
state = NormalizedTorrentState.seeding;
|
45
|
+
eta = 0; // qBittorrent sends eta=8640000 for completed torrents
|
46
|
+
break;
|
47
|
+
case TorrentState.Moving: // torrent is being moved from a folder
|
48
|
+
case TorrentState.QueuedForChecking:
|
49
|
+
case TorrentState.CheckingResumeData:
|
50
|
+
state = NormalizedTorrentState.checking;
|
51
|
+
break;
|
52
|
+
case TorrentState.Unknown:
|
53
|
+
state = NormalizedTorrentState.error;
|
54
|
+
break;
|
55
|
+
case TorrentState.MissingFiles:
|
56
|
+
state = NormalizedTorrentState.error;
|
57
|
+
stateMessage = 'The download is missing files';
|
58
|
+
break;
|
59
|
+
default:
|
60
|
+
break;
|
61
|
+
}
|
62
|
+
const isCompleted = torrent.progress === 1;
|
63
|
+
const result = {
|
64
|
+
id: torrent.hash,
|
65
|
+
name: torrent.name,
|
66
|
+
stateMessage,
|
67
|
+
state,
|
68
|
+
eta,
|
69
|
+
dateAdded: new Date(torrent.added_on * 1000).toISOString(),
|
70
|
+
isCompleted,
|
71
|
+
progress: torrent.progress,
|
72
|
+
label: torrent.category,
|
73
|
+
tags: torrent.tags.split(', '),
|
74
|
+
dateCompleted: new Date(torrent.completion_on * 1000).toISOString(),
|
75
|
+
savePath: torrent.save_path,
|
76
|
+
uploadSpeed: torrent.upspeed,
|
77
|
+
downloadSpeed: torrent.dlspeed,
|
78
|
+
queuePosition: torrent.priority,
|
79
|
+
connectedPeers: torrent.num_leechs,
|
80
|
+
connectedSeeds: torrent.num_seeds,
|
81
|
+
totalPeers: torrent.num_incomplete,
|
82
|
+
totalSeeds: torrent.num_complete,
|
83
|
+
totalSelected: torrent.size,
|
84
|
+
totalSize: torrent.total_size,
|
85
|
+
totalUploaded: torrent.uploaded,
|
86
|
+
totalDownloaded: torrent.downloaded,
|
87
|
+
ratio: torrent.ratio,
|
88
|
+
raw: torrent,
|
89
|
+
};
|
90
|
+
return result;
|
91
|
+
}
|
@@ -1,7 +1,6 @@
|
|
1
1
|
/// <reference types="node" resolution-mode="require"/>
|
2
|
-
import type { Options as GotOptions, Response } from 'got';
|
3
2
|
import type { AddTorrentOptions as NormalizedAddTorrentOptions, AllClientData, NormalizedTorrent, TorrentClient, TorrentSettings } from '@ctrl/shared-torrent';
|
4
|
-
import type { AddMagnetOptions, AddTorrentOptions, BuildInfo, Preferences, Torrent, TorrentCategories, TorrentFile, TorrentFilePriority, TorrentFilters, TorrentPieceState, TorrentProperties, TorrentTrackers, WebSeed } from './types.js';
|
3
|
+
import type { AddMagnetOptions, AddTorrentOptions, BuildInfo, Preferences, Torrent, TorrentCategories, TorrentFile, TorrentFilePriority, TorrentFilters, TorrentPeersResponse, TorrentPieceState, TorrentProperties, TorrentTrackers, WebSeed } from './types.js';
|
5
4
|
export declare class QBittorrent implements TorrentClient {
|
6
5
|
config: TorrentSettings;
|
7
6
|
/**
|
@@ -197,16 +196,16 @@ export declare class QBittorrent implements TorrentClient {
|
|
197
196
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#minimal-torrent-priority}
|
198
197
|
*/
|
199
198
|
bottomPriority(hashes: string | string[] | 'all'): Promise<boolean>;
|
199
|
+
/**
|
200
|
+
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#get-torrent-peers-data}
|
201
|
+
* @param rid - Response ID. If not provided, rid=0 will be assumed. If the given rid is
|
202
|
+
* different from the one of last server reply, full_update will be true (see the server reply details for more info)
|
203
|
+
*/
|
204
|
+
torrentPeers(hash: string, rid?: number): Promise<TorrentPeersResponse>;
|
200
205
|
/**
|
201
206
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#login}
|
202
207
|
*/
|
203
208
|
login(): Promise<boolean>;
|
204
209
|
logout(): boolean;
|
205
|
-
request<T
|
206
|
-
/**
|
207
|
-
* Normalizes hashes
|
208
|
-
* @returns hashes as string seperated by `|`
|
209
|
-
*/
|
210
|
-
private _normalizeHashes;
|
211
|
-
private _normalizeTorrentData;
|
210
|
+
request<T>(path: string, method: 'GET' | 'POST', params?: Record<string, string | number>, body?: URLSearchParams | FormData, headers?: any, json?: boolean): Promise<T>;
|
212
211
|
}
|
package/dist/src/qbittorrent.js
CHANGED
@@ -1,16 +1,10 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
import { existsSync } from 'fs';
|
4
|
-
import { URLSearchParams } from 'url';
|
5
|
-
import { File, FormData } from 'formdata-node';
|
6
|
-
import { fileFromPath } from 'formdata-node/file-from-path';
|
7
|
-
import got from 'got';
|
1
|
+
import { FormData } from 'node-fetch-native';
|
2
|
+
import { ofetch } from 'ofetch';
|
8
3
|
import { Cookie } from 'tough-cookie';
|
4
|
+
import { joinURL } from 'ufo';
|
9
5
|
import { magnetDecode } from '@ctrl/magnet-link';
|
10
|
-
import { TorrentState as NormalizedTorrentState } from '@ctrl/shared-torrent';
|
11
6
|
import { hash } from '@ctrl/torrent-file';
|
12
|
-
import {
|
13
|
-
import { TorrentState } from './types.js';
|
7
|
+
import { normalizeTorrentData } from './normalizeTorrentData.js';
|
14
8
|
const defaults = {
|
15
9
|
baseUrl: 'http://localhost:9091/',
|
16
10
|
path: '/api/v2',
|
@@ -19,31 +13,16 @@ const defaults = {
|
|
19
13
|
timeout: 5000,
|
20
14
|
};
|
21
15
|
export class QBittorrent {
|
16
|
+
config;
|
17
|
+
/**
|
18
|
+
* auth cookie
|
19
|
+
*/
|
20
|
+
_sid;
|
21
|
+
/**
|
22
|
+
* cookie expiration
|
23
|
+
*/
|
24
|
+
_exp;
|
22
25
|
constructor(options = {}) {
|
23
|
-
Object.defineProperty(this, "config", {
|
24
|
-
enumerable: true,
|
25
|
-
configurable: true,
|
26
|
-
writable: true,
|
27
|
-
value: void 0
|
28
|
-
});
|
29
|
-
/**
|
30
|
-
* auth cookie
|
31
|
-
*/
|
32
|
-
Object.defineProperty(this, "_sid", {
|
33
|
-
enumerable: true,
|
34
|
-
configurable: true,
|
35
|
-
writable: true,
|
36
|
-
value: void 0
|
37
|
-
});
|
38
|
-
/**
|
39
|
-
* cookie expiration
|
40
|
-
*/
|
41
|
-
Object.defineProperty(this, "_exp", {
|
42
|
-
enumerable: true,
|
43
|
-
configurable: true,
|
44
|
-
writable: true,
|
45
|
-
value: void 0
|
46
|
-
});
|
47
26
|
this.config = { ...defaults, ...options };
|
48
27
|
}
|
49
28
|
/**
|
@@ -57,19 +36,19 @@ export class QBittorrent {
|
|
57
36
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#get-application-version}
|
58
37
|
*/
|
59
38
|
async getAppVersion() {
|
60
|
-
const res = await this.request('/app/version', 'GET', undefined, undefined, undefined,
|
61
|
-
return res
|
39
|
+
const res = await this.request('/app/version', 'GET', undefined, undefined, undefined, false);
|
40
|
+
return res;
|
62
41
|
}
|
63
42
|
async getApiVersion() {
|
64
|
-
const res = await this.request('/app/webapiVersion', 'GET', undefined, undefined, undefined,
|
65
|
-
return res
|
43
|
+
const res = await this.request('/app/webapiVersion', 'GET', undefined, undefined, undefined, false);
|
44
|
+
return res;
|
66
45
|
}
|
67
46
|
/**
|
68
47
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#get-build-info}
|
69
48
|
*/
|
70
49
|
async getBuildInfo() {
|
71
50
|
const res = await this.request('/app/buildInfo', 'GET');
|
72
|
-
return res
|
51
|
+
return res;
|
73
52
|
}
|
74
53
|
async getTorrent(hash) {
|
75
54
|
const torrentsResponse = await this.listTorrents({ hashes: hash });
|
@@ -77,22 +56,22 @@ export class QBittorrent {
|
|
77
56
|
if (!torrentData) {
|
78
57
|
throw new Error('Torrent not found');
|
79
58
|
}
|
80
|
-
return
|
59
|
+
return normalizeTorrentData(torrentData);
|
81
60
|
}
|
82
61
|
/**
|
83
62
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#get-application-preferences}
|
84
63
|
*/
|
85
64
|
async getPreferences() {
|
86
65
|
const res = await this.request('/app/preferences', 'GET');
|
87
|
-
return res
|
66
|
+
return res;
|
88
67
|
}
|
89
68
|
/**
|
90
69
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#set-application-preferences}
|
91
70
|
*/
|
92
71
|
async setPreferences(preferences) {
|
93
|
-
await this.request('/app/setPreferences', 'POST', undefined,
|
72
|
+
await this.request('/app/setPreferences', 'POST', undefined, objToUrlSearchParams({
|
94
73
|
json: JSON.stringify(preferences),
|
95
|
-
});
|
74
|
+
}));
|
96
75
|
return true;
|
97
76
|
}
|
98
77
|
/**
|
@@ -105,7 +84,7 @@ export class QBittorrent {
|
|
105
84
|
async listTorrents({ hashes, filter, category, sort, offset, reverse, tag, } = {}) {
|
106
85
|
const params = {};
|
107
86
|
if (hashes) {
|
108
|
-
params.hashes =
|
87
|
+
params.hashes = normalizeHashes(hashes);
|
109
88
|
}
|
110
89
|
if (filter) {
|
111
90
|
params.filter = filter;
|
@@ -126,7 +105,7 @@ export class QBittorrent {
|
|
126
105
|
params.reverse = JSON.stringify(reverse);
|
127
106
|
}
|
128
107
|
const res = await this.request('/torrents/info', 'GET', params);
|
129
|
-
return res
|
108
|
+
return res;
|
130
109
|
}
|
131
110
|
async getAllData() {
|
132
111
|
const listTorrents = await this.listTorrents();
|
@@ -137,7 +116,7 @@ export class QBittorrent {
|
|
137
116
|
};
|
138
117
|
const labels = {};
|
139
118
|
for (const torrent of listTorrents) {
|
140
|
-
const torrentData =
|
119
|
+
const torrentData = normalizeTorrentData(torrent);
|
141
120
|
results.torrents.push(torrentData);
|
142
121
|
// setup label
|
143
122
|
if (torrentData.label) {
|
@@ -160,40 +139,40 @@ export class QBittorrent {
|
|
160
139
|
*/
|
161
140
|
async torrentProperties(hash) {
|
162
141
|
const res = await this.request('/torrents/properties', 'GET', { hash });
|
163
|
-
return res
|
142
|
+
return res;
|
164
143
|
}
|
165
144
|
/**
|
166
145
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#get-torrent-trackers}
|
167
146
|
*/
|
168
147
|
async torrentTrackers(hash) {
|
169
148
|
const res = await this.request('/torrents/trackers', 'GET', { hash });
|
170
|
-
return res
|
149
|
+
return res;
|
171
150
|
}
|
172
151
|
/**
|
173
152
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#get-torrent-web-seeds}
|
174
153
|
*/
|
175
154
|
async torrentWebSeeds(hash) {
|
176
155
|
const res = await this.request('/torrents/webseeds', 'GET', { hash });
|
177
|
-
return res
|
156
|
+
return res;
|
178
157
|
}
|
179
158
|
async torrentFiles(hash) {
|
180
159
|
const res = await this.request('/torrents/files', 'GET', { hash });
|
181
|
-
return res
|
160
|
+
return res;
|
182
161
|
}
|
183
162
|
async setFilePriority(hash, fileIds, priority) {
|
184
163
|
const res = await this.request('/torrents/filePrio', 'GET', {
|
185
164
|
hash,
|
186
|
-
id:
|
165
|
+
id: normalizeHashes(fileIds),
|
187
166
|
priority,
|
188
167
|
});
|
189
|
-
return res
|
168
|
+
return res;
|
190
169
|
}
|
191
170
|
/**
|
192
171
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#get-torrent-pieces-states}
|
193
172
|
*/
|
194
173
|
async torrentPieceStates(hash) {
|
195
174
|
const res = await this.request('/torrents/pieceStates', 'GET', { hash });
|
196
|
-
return res
|
175
|
+
return res;
|
197
176
|
}
|
198
177
|
/**
|
199
178
|
* Torrents piece hashes
|
@@ -202,7 +181,7 @@ export class QBittorrent {
|
|
202
181
|
*/
|
203
182
|
async torrentPieceHashes(hash) {
|
204
183
|
const res = await this.request('/torrents/pieceHashes', 'GET', { hash });
|
205
|
-
return res
|
184
|
+
return res;
|
206
185
|
}
|
207
186
|
/**
|
208
187
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#set-torrent-location}
|
@@ -210,7 +189,7 @@ export class QBittorrent {
|
|
210
189
|
async setTorrentLocation(hashes, location) {
|
211
190
|
await this.request('/torrents/setLocation', 'POST', undefined, undefined, {
|
212
191
|
location,
|
213
|
-
hashes:
|
192
|
+
hashes: normalizeHashes(hashes),
|
214
193
|
});
|
215
194
|
return true;
|
216
195
|
}
|
@@ -218,27 +197,24 @@ export class QBittorrent {
|
|
218
197
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#set-torrent-name}
|
219
198
|
*/
|
220
199
|
async setTorrentName(hash, name) {
|
221
|
-
|
222
|
-
|
223
|
-
name,
|
224
|
-
});
|
200
|
+
const data = { hash, name };
|
201
|
+
await this.request('/torrents/rename', 'POST', undefined, objToUrlSearchParams(data));
|
225
202
|
return true;
|
226
203
|
}
|
227
204
|
/**
|
228
205
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#get-all-tags}
|
229
206
|
*/
|
230
207
|
async getTags() {
|
231
|
-
const res = await this.request('/torrents/tags', '
|
232
|
-
return res
|
208
|
+
const res = await this.request('/torrents/tags', 'GET');
|
209
|
+
return res;
|
233
210
|
}
|
234
211
|
/**
|
235
212
|
* @param tags comma separated list
|
236
213
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#create-tags}
|
237
214
|
*/
|
238
215
|
async createTags(tags) {
|
239
|
-
|
240
|
-
|
241
|
-
}, undefined, false);
|
216
|
+
const data = { tags };
|
217
|
+
await this.request('/torrents/createTags', 'POST', undefined, objToUrlSearchParams(data), undefined, false);
|
242
218
|
return true;
|
243
219
|
}
|
244
220
|
/**
|
@@ -246,53 +222,47 @@ export class QBittorrent {
|
|
246
222
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#delete-tags}
|
247
223
|
*/
|
248
224
|
async deleteTags(tags) {
|
249
|
-
|
225
|
+
const data = { tags };
|
226
|
+
await this.request('/torrents/deleteTags', 'POST', undefined, objToUrlSearchParams(data), undefined, false);
|
250
227
|
return true;
|
251
228
|
}
|
252
229
|
/**
|
253
230
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#get-all-categories}
|
254
231
|
*/
|
255
232
|
async getCategories() {
|
256
|
-
const res = await this.request('/torrents/categories', '
|
257
|
-
return res
|
233
|
+
const res = await this.request('/torrents/categories', 'GET');
|
234
|
+
return res;
|
258
235
|
}
|
259
236
|
/**
|
260
237
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#add-new-category}
|
261
238
|
*/
|
262
239
|
async createCategory(category, savePath = '') {
|
263
|
-
|
264
|
-
|
265
|
-
savePath,
|
266
|
-
}, undefined, false);
|
240
|
+
const data = { category, savePath };
|
241
|
+
await this.request('/torrents/createCategory', 'POST', undefined, objToUrlSearchParams(data), undefined, false);
|
267
242
|
return true;
|
268
243
|
}
|
269
244
|
/**
|
270
245
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#edit-category}
|
271
246
|
*/
|
272
247
|
async editCategory(category, savePath = '') {
|
273
|
-
|
274
|
-
|
275
|
-
savePath,
|
276
|
-
}, undefined, false);
|
248
|
+
const data = { category, savePath };
|
249
|
+
await this.request('/torrents/editCategory', 'POST', undefined, objToUrlSearchParams(data), undefined, false);
|
277
250
|
return true;
|
278
251
|
}
|
279
252
|
/**
|
280
253
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#remove-categories}
|
281
254
|
*/
|
282
255
|
async removeCategory(categories) {
|
283
|
-
|
284
|
-
|
285
|
-
}, undefined, false);
|
256
|
+
const data = { categories };
|
257
|
+
await this.request('/torrents/removeCategories', 'POST', undefined, objToUrlSearchParams(data), undefined, false);
|
286
258
|
return true;
|
287
259
|
}
|
288
260
|
/**
|
289
261
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#add-torrent-tags}
|
290
262
|
*/
|
291
263
|
async addTorrentTags(hashes, tags) {
|
292
|
-
|
293
|
-
|
294
|
-
tags,
|
295
|
-
}, undefined, false);
|
264
|
+
const data = { hashes: normalizeHashes(hashes), tags };
|
265
|
+
await this.request('/torrents/addTags', 'POST', undefined, objToUrlSearchParams(data), undefined, false);
|
296
266
|
return true;
|
297
267
|
}
|
298
268
|
/**
|
@@ -300,11 +270,11 @@ export class QBittorrent {
|
|
300
270
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#remove-torrent-tags}
|
301
271
|
*/
|
302
272
|
async removeTorrentTags(hashes, tags) {
|
303
|
-
const
|
273
|
+
const data = { hashes: normalizeHashes(hashes) };
|
304
274
|
if (tags) {
|
305
|
-
|
275
|
+
data.tags = tags;
|
306
276
|
}
|
307
|
-
await this.request('/torrents/removeTags', 'POST', undefined,
|
277
|
+
await this.request('/torrents/removeTags', 'POST', undefined, objToUrlSearchParams(data), undefined, false);
|
308
278
|
return true;
|
309
279
|
}
|
310
280
|
/**
|
@@ -317,61 +287,54 @@ export class QBittorrent {
|
|
317
287
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#set-torrent-category}
|
318
288
|
*/
|
319
289
|
async setTorrentCategory(hashes, category = '') {
|
320
|
-
|
321
|
-
hashes:
|
290
|
+
const data = {
|
291
|
+
hashes: normalizeHashes(hashes),
|
322
292
|
category,
|
323
|
-
}
|
293
|
+
};
|
294
|
+
await this.request('/torrents/setCategory', 'POST', undefined, objToUrlSearchParams(data));
|
324
295
|
return true;
|
325
296
|
}
|
326
297
|
/**
|
327
298
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#pause-torrents}
|
328
299
|
*/
|
329
300
|
async pauseTorrent(hashes) {
|
330
|
-
const
|
331
|
-
|
332
|
-
};
|
333
|
-
await this.request('/torrents/pause', 'POST', undefined, undefined, params);
|
301
|
+
const data = { hashes: normalizeHashes(hashes) };
|
302
|
+
await this.request('/torrents/pause', 'POST', undefined, objToUrlSearchParams(data));
|
334
303
|
return true;
|
335
304
|
}
|
336
305
|
/**
|
337
306
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#resume-torrents}
|
338
307
|
*/
|
339
308
|
async resumeTorrent(hashes) {
|
340
|
-
const
|
341
|
-
|
342
|
-
};
|
343
|
-
await this.request('/torrents/resume', 'POST', undefined, undefined, params);
|
309
|
+
const data = { hashes: normalizeHashes(hashes) };
|
310
|
+
await this.request('/torrents/resume', 'POST', undefined, objToUrlSearchParams(data));
|
344
311
|
return true;
|
345
312
|
}
|
346
313
|
/**
|
347
314
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#delete-torrents}
|
348
315
|
*/
|
349
316
|
async removeTorrent(hashes, deleteFiles = true) {
|
350
|
-
const
|
351
|
-
hashes:
|
317
|
+
const data = {
|
318
|
+
hashes: normalizeHashes(hashes),
|
352
319
|
deleteFiles,
|
353
320
|
};
|
354
|
-
await this.request('/torrents/delete', 'POST', undefined,
|
321
|
+
await this.request('/torrents/delete', 'POST', undefined, objToUrlSearchParams(data));
|
355
322
|
return true;
|
356
323
|
}
|
357
324
|
/**
|
358
325
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#recheck-torrents}
|
359
326
|
*/
|
360
327
|
async recheckTorrent(hashes) {
|
361
|
-
const
|
362
|
-
|
363
|
-
};
|
364
|
-
await this.request('/torrents/recheck', 'POST', undefined, undefined, params);
|
328
|
+
const data = { hashes: normalizeHashes(hashes) };
|
329
|
+
await this.request('/torrents/recheck', 'POST', undefined, objToUrlSearchParams(data));
|
365
330
|
return true;
|
366
331
|
}
|
367
332
|
/**
|
368
333
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#reannounce-torrents}
|
369
334
|
*/
|
370
335
|
async reannounceTorrent(hashes) {
|
371
|
-
const
|
372
|
-
|
373
|
-
};
|
374
|
-
await this.request('/torrents/reannounce', 'POST', undefined, undefined, params);
|
336
|
+
const data = { hashes: normalizeHashes(hashes) };
|
337
|
+
await this.request('/torrents/reannounce', 'POST', undefined, objToUrlSearchParams(data));
|
375
338
|
return true;
|
376
339
|
}
|
377
340
|
async addTorrent(torrent, options = {}) {
|
@@ -382,13 +345,7 @@ export class QBittorrent {
|
|
382
345
|
}
|
383
346
|
const type = { type: 'application/x-bittorrent' };
|
384
347
|
if (typeof torrent === 'string') {
|
385
|
-
|
386
|
-
const file = await fileFromPath(torrent, options.filename ?? 'torrent', type);
|
387
|
-
form.set('file', file);
|
388
|
-
}
|
389
|
-
else {
|
390
|
-
form.set('file', new File([Buffer.from(torrent, 'base64')], 'file.torrent', type));
|
391
|
-
}
|
348
|
+
form.set('file', new File([Buffer.from(torrent, 'base64')], 'file.torrent', type));
|
392
349
|
}
|
393
350
|
else {
|
394
351
|
const file = new File([torrent], options.filename ?? 'torrent', type);
|
@@ -403,11 +360,11 @@ export class QBittorrent {
|
|
403
360
|
options.useAutoTMM = 'false';
|
404
361
|
}
|
405
362
|
for (const [key, value] of Object.entries(options)) {
|
406
|
-
form.append(key, value);
|
363
|
+
form.append(key, `${value}`);
|
407
364
|
}
|
408
365
|
}
|
409
|
-
const res = await this.request('/torrents/add', 'POST', undefined, form, undefined,
|
410
|
-
if (res
|
366
|
+
const res = await this.request('/torrents/add', 'POST', undefined, form, undefined, false);
|
367
|
+
if (res === 'Fails.') {
|
411
368
|
throw new Error('Failed to add torrent');
|
412
369
|
}
|
413
370
|
return true;
|
@@ -445,9 +402,9 @@ export class QBittorrent {
|
|
445
402
|
async renameFile(hash, id, name) {
|
446
403
|
const form = new FormData();
|
447
404
|
form.append('hash', hash);
|
448
|
-
form.append('id', id);
|
405
|
+
form.append('id', id.toString());
|
449
406
|
form.append('name', name);
|
450
|
-
await this.request('/torrents/renameFile', 'POST', undefined,
|
407
|
+
await this.request('/torrents/renameFile', 'POST', undefined, undefined, form, false);
|
451
408
|
return true;
|
452
409
|
}
|
453
410
|
/**
|
@@ -458,7 +415,7 @@ export class QBittorrent {
|
|
458
415
|
form.append('hash', hash);
|
459
416
|
form.append('oldPath', oldPath);
|
460
417
|
form.append('newPath', newPath);
|
461
|
-
await this.request('/torrents/renameFolder', 'POST', undefined,
|
418
|
+
await this.request('/torrents/renameFolder', 'POST', undefined, undefined, form, false);
|
462
419
|
return true;
|
463
420
|
}
|
464
421
|
/**
|
@@ -477,11 +434,11 @@ export class QBittorrent {
|
|
477
434
|
options.useAutoTMM = 'false';
|
478
435
|
}
|
479
436
|
for (const [key, value] of Object.entries(options)) {
|
480
|
-
form.append(key, value);
|
437
|
+
form.append(key, `${value}`);
|
481
438
|
}
|
482
439
|
}
|
483
|
-
const res = await this.request('/torrents/add', 'POST', undefined, form, undefined,
|
484
|
-
if (res
|
440
|
+
const res = await this.request('/torrents/add', 'POST', undefined, form, undefined, false);
|
441
|
+
if (res === 'Fails.') {
|
485
442
|
throw new Error('Failed to add torrent');
|
486
443
|
}
|
487
444
|
return true;
|
@@ -490,89 +447,94 @@ export class QBittorrent {
|
|
490
447
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#add-trackers-to-torrent}
|
491
448
|
*/
|
492
449
|
async addTrackers(hash, urls) {
|
493
|
-
const
|
494
|
-
await this.request('/torrents/addTrackers', 'POST', undefined,
|
450
|
+
const data = { hash, urls };
|
451
|
+
await this.request('/torrents/addTrackers', 'POST', undefined, objToUrlSearchParams(data));
|
495
452
|
return true;
|
496
453
|
}
|
497
454
|
/**
|
498
455
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#edit-trackers}
|
499
456
|
*/
|
500
457
|
async editTrackers(hash, origUrl, newUrl) {
|
501
|
-
const
|
502
|
-
await this.request('/torrents/editTrackers', 'POST', undefined,
|
458
|
+
const data = { hash, origUrl, newUrl };
|
459
|
+
await this.request('/torrents/editTrackers', 'POST', undefined, objToUrlSearchParams(data));
|
503
460
|
return true;
|
504
461
|
}
|
505
462
|
/**
|
506
463
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#remove-trackers}
|
507
464
|
*/
|
508
465
|
async removeTrackers(hash, urls) {
|
509
|
-
const
|
510
|
-
await this.request('/torrents/removeTrackers', 'POST', undefined,
|
466
|
+
const data = { hash, urls };
|
467
|
+
await this.request('/torrents/removeTrackers', 'POST', undefined, objToUrlSearchParams(data));
|
511
468
|
return true;
|
512
469
|
}
|
513
470
|
/**
|
514
471
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#increase-torrent-priority}
|
515
472
|
*/
|
516
473
|
async queueUp(hashes) {
|
517
|
-
const
|
518
|
-
|
519
|
-
};
|
520
|
-
await this.request('/torrents/increasePrio', 'POST', undefined, undefined, params);
|
474
|
+
const data = { hashes: normalizeHashes(hashes) };
|
475
|
+
await this.request('/torrents/increasePrio', 'POST', undefined, objToUrlSearchParams(data));
|
521
476
|
return true;
|
522
477
|
}
|
523
478
|
/**
|
524
479
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#decrease-torrent-priority}
|
525
480
|
*/
|
526
481
|
async queueDown(hashes) {
|
527
|
-
const
|
528
|
-
|
529
|
-
};
|
530
|
-
await this.request('/torrents/decreasePrio', 'POST', undefined, undefined, params);
|
482
|
+
const data = { hashes: normalizeHashes(hashes) };
|
483
|
+
await this.request('/torrents/decreasePrio', 'POST', undefined, objToUrlSearchParams(data));
|
531
484
|
return true;
|
532
485
|
}
|
533
486
|
/**
|
534
487
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#maximal-torrent-priority}
|
535
488
|
*/
|
536
489
|
async topPriority(hashes) {
|
537
|
-
const
|
538
|
-
|
539
|
-
};
|
540
|
-
await this.request('/torrents/topPrio', 'POST', undefined, undefined, params);
|
490
|
+
const data = { hashes: normalizeHashes(hashes) };
|
491
|
+
await this.request('/torrents/topPrio', 'POST', undefined, objToUrlSearchParams(data));
|
541
492
|
return true;
|
542
493
|
}
|
543
494
|
/**
|
544
495
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#minimal-torrent-priority}
|
545
496
|
*/
|
546
497
|
async bottomPriority(hashes) {
|
547
|
-
const
|
548
|
-
|
549
|
-
};
|
550
|
-
await this.request('/torrents/bottomPrio', 'POST', undefined, undefined, params);
|
498
|
+
const data = { hashes: normalizeHashes(hashes) };
|
499
|
+
await this.request('/torrents/bottomPrio', 'POST', undefined, objToUrlSearchParams(data));
|
551
500
|
return true;
|
552
501
|
}
|
502
|
+
/**
|
503
|
+
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#get-torrent-peers-data}
|
504
|
+
* @param rid - Response ID. If not provided, rid=0 will be assumed. If the given rid is
|
505
|
+
* different from the one of last server reply, full_update will be true (see the server reply details for more info)
|
506
|
+
*/
|
507
|
+
async torrentPeers(hash, rid) {
|
508
|
+
const params = { hash };
|
509
|
+
if (rid) {
|
510
|
+
params.rid = rid;
|
511
|
+
}
|
512
|
+
const res = await this.request('/sync/torrentPeers', 'GET', params);
|
513
|
+
return res;
|
514
|
+
}
|
553
515
|
/**
|
554
516
|
* {@link https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#login}
|
555
517
|
*/
|
556
518
|
async login() {
|
557
|
-
const url =
|
558
|
-
const res = await
|
559
|
-
url,
|
519
|
+
const url = joinURL(this.config.baseUrl, this.config.path, '/auth/login');
|
520
|
+
const res = await ofetch.raw(url, {
|
560
521
|
method: 'POST',
|
561
|
-
|
522
|
+
headers: {
|
523
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
524
|
+
},
|
525
|
+
body: new URLSearchParams({
|
562
526
|
username: this.config.username ?? '',
|
563
527
|
password: this.config.password ?? '',
|
564
|
-
},
|
565
|
-
|
566
|
-
retry:
|
567
|
-
timeout:
|
568
|
-
//
|
569
|
-
...(this.config.agent ? { agent: this.config.agent } : {}),
|
528
|
+
}),
|
529
|
+
redirect: 'manual',
|
530
|
+
retry: false,
|
531
|
+
timeout: this.config.timeout,
|
532
|
+
// ...(this.config.agent ? { agent: this.config.agent } : {}),
|
570
533
|
});
|
571
|
-
|
572
|
-
if (!res.headers['set-cookie'] || !res.headers['set-cookie'].length) {
|
534
|
+
if (!res.headers.get('set-cookie')?.length) {
|
573
535
|
throw new Error('Cookie not found. Auth Failed.');
|
574
536
|
}
|
575
|
-
const cookie = Cookie.parse(res.headers
|
537
|
+
const cookie = Cookie.parse(res.headers.get('set-cookie'));
|
576
538
|
if (!cookie || cookie.key !== 'SID') {
|
577
539
|
throw new Error('Invalid cookie');
|
578
540
|
}
|
@@ -586,130 +548,46 @@ export class QBittorrent {
|
|
586
548
|
return true;
|
587
549
|
}
|
588
550
|
// eslint-disable-next-line max-params
|
589
|
-
async request(path, method, params
|
551
|
+
async request(path, method, params, body, headers = {}, json = true) {
|
590
552
|
if (!this._sid || !this._exp || this._exp.getTime() < new Date().getTime()) {
|
591
553
|
const authed = await this.login();
|
592
554
|
if (!authed) {
|
593
555
|
throw new Error('Auth Failed');
|
594
556
|
}
|
595
557
|
}
|
596
|
-
const url =
|
597
|
-
const res = await
|
598
|
-
isStream: false,
|
599
|
-
resolveBodyOnly: false,
|
558
|
+
const url = joinURL(this.config.baseUrl, this.config.path, path);
|
559
|
+
const res = await ofetch(url, {
|
600
560
|
method,
|
601
561
|
headers: {
|
602
562
|
Cookie: `SID=${this._sid ?? ''}`,
|
603
563
|
...headers,
|
604
564
|
},
|
605
|
-
retry: { limit: 0 },
|
606
565
|
body,
|
607
|
-
|
608
|
-
searchParams: new URLSearchParams(params),
|
566
|
+
params,
|
609
567
|
// allow proxy agent
|
610
|
-
|
568
|
+
retry: 0,
|
569
|
+
timeout: this.config.timeout,
|
611
570
|
responseType: json ? 'json' : 'text',
|
612
|
-
|
571
|
+
// @ts-expect-error for some reason agent is not in the type
|
572
|
+
agent: this.config.agent,
|
613
573
|
});
|
614
574
|
return res;
|
615
575
|
}
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
* Good references https://github.com/qbittorrent/qBittorrent/blob/master/src/webui/www/private/scripts/dynamicTable.js#L933
|
632
|
-
* https://github.com/Radarr/Radarr/blob/develop/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrent.cs#L242
|
633
|
-
*/
|
634
|
-
switch (torrent.state) {
|
635
|
-
case TorrentState.Error:
|
636
|
-
state = NormalizedTorrentState.warning;
|
637
|
-
stateMessage = 'qBittorrent is reporting an error';
|
638
|
-
break;
|
639
|
-
case TorrentState.PausedDL:
|
640
|
-
state = NormalizedTorrentState.paused;
|
641
|
-
break;
|
642
|
-
case TorrentState.QueuedDL: // queuing is enabled and torrent is queued for download
|
643
|
-
case TorrentState.CheckingDL: // same as checkingUP, but torrent has NOT finished downloading
|
644
|
-
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.
|
645
|
-
state = NormalizedTorrentState.queued;
|
646
|
-
break;
|
647
|
-
case TorrentState.MetaDL: // Metadl could be an error if DHT is not enabled
|
648
|
-
case TorrentState.ForcedDL: // torrent is being downloaded, and was forced started
|
649
|
-
case TorrentState.ForcedMetaDL: // torrent metadata is being forcibly downloaded
|
650
|
-
case TorrentState.Downloading: // torrent is being downloaded and data is being transferred
|
651
|
-
state = NormalizedTorrentState.downloading;
|
652
|
-
break;
|
653
|
-
case TorrentState.Allocating:
|
654
|
-
// state = 'stalledDL';
|
655
|
-
state = NormalizedTorrentState.queued;
|
656
|
-
break;
|
657
|
-
case TorrentState.StalledDL:
|
658
|
-
state = NormalizedTorrentState.warning;
|
659
|
-
stateMessage = 'The download is stalled with no connection';
|
660
|
-
break;
|
661
|
-
case TorrentState.PausedUP: // torrent is paused and has finished downloading:
|
662
|
-
case TorrentState.Uploading: // torrent is being seeded and data is being transferred
|
663
|
-
case TorrentState.StalledUP: // torrent is being seeded, but no connection were made
|
664
|
-
case TorrentState.QueuedUP: // queuing is enabled and torrent is queued for upload
|
665
|
-
case TorrentState.ForcedUP: // torrent has finished downloading and is being forcibly seeded
|
666
|
-
// state = 'completed';
|
667
|
-
state = NormalizedTorrentState.seeding;
|
668
|
-
eta = 0; // qBittorrent sends eta=8640000 for completed torrents
|
669
|
-
break;
|
670
|
-
case TorrentState.Moving: // torrent is being moved from a folder
|
671
|
-
case TorrentState.QueuedForChecking:
|
672
|
-
case TorrentState.CheckingResumeData:
|
673
|
-
state = NormalizedTorrentState.checking;
|
674
|
-
break;
|
675
|
-
case TorrentState.Unknown:
|
676
|
-
state = NormalizedTorrentState.error;
|
677
|
-
break;
|
678
|
-
case TorrentState.MissingFiles:
|
679
|
-
state = NormalizedTorrentState.error;
|
680
|
-
stateMessage = 'The download is missing files';
|
681
|
-
break;
|
682
|
-
default:
|
683
|
-
break;
|
684
|
-
}
|
685
|
-
const isCompleted = torrent.progress === 1;
|
686
|
-
const result = {
|
687
|
-
id: torrent.hash,
|
688
|
-
name: torrent.name,
|
689
|
-
stateMessage,
|
690
|
-
state,
|
691
|
-
eta,
|
692
|
-
dateAdded: new Date(torrent.added_on * 1000).toISOString(),
|
693
|
-
isCompleted,
|
694
|
-
progress: torrent.progress,
|
695
|
-
label: torrent.category,
|
696
|
-
tags: torrent.tags.split(', '),
|
697
|
-
dateCompleted: new Date(torrent.completion_on * 1000).toISOString(),
|
698
|
-
savePath: torrent.save_path,
|
699
|
-
uploadSpeed: torrent.upspeed,
|
700
|
-
downloadSpeed: torrent.dlspeed,
|
701
|
-
queuePosition: torrent.priority,
|
702
|
-
connectedPeers: torrent.num_leechs,
|
703
|
-
connectedSeeds: torrent.num_seeds,
|
704
|
-
totalPeers: torrent.num_incomplete,
|
705
|
-
totalSeeds: torrent.num_complete,
|
706
|
-
totalSelected: torrent.size,
|
707
|
-
totalSize: torrent.total_size,
|
708
|
-
totalUploaded: torrent.uploaded,
|
709
|
-
totalDownloaded: torrent.downloaded,
|
710
|
-
ratio: torrent.ratio,
|
711
|
-
raw: torrent,
|
712
|
-
};
|
713
|
-
return result;
|
576
|
+
}
|
577
|
+
/**
|
578
|
+
* Normalizes hashes
|
579
|
+
* @returns hashes as string seperated by `|`
|
580
|
+
*/
|
581
|
+
function normalizeHashes(hashes) {
|
582
|
+
if (Array.isArray(hashes)) {
|
583
|
+
return hashes.join('|');
|
584
|
+
}
|
585
|
+
return hashes;
|
586
|
+
}
|
587
|
+
function objToUrlSearchParams(obj) {
|
588
|
+
const params = new URLSearchParams();
|
589
|
+
for (const [key, value] of Object.entries(obj)) {
|
590
|
+
params.append(key, value.toString());
|
714
591
|
}
|
592
|
+
return params;
|
715
593
|
}
|
package/dist/src/types.d.ts
CHANGED
@@ -1234,4 +1234,28 @@ export interface Preferences {
|
|
1234
1234
|
*/
|
1235
1235
|
utp_tcp_mixed_mode: number;
|
1236
1236
|
}
|
1237
|
+
export interface TorrentPeersResponse {
|
1238
|
+
full_update: boolean;
|
1239
|
+
peers: Peers;
|
1240
|
+
rid: number;
|
1241
|
+
show_flags: boolean;
|
1242
|
+
}
|
1243
|
+
type Peers = Record<string, TorrentPeer>;
|
1244
|
+
export interface TorrentPeer {
|
1245
|
+
client?: string;
|
1246
|
+
connection?: string;
|
1247
|
+
country?: string;
|
1248
|
+
country_code?: string;
|
1249
|
+
dl_speed?: number;
|
1250
|
+
downloaded?: number;
|
1251
|
+
files?: string;
|
1252
|
+
flags?: string;
|
1253
|
+
flags_desc?: string;
|
1254
|
+
ip?: string;
|
1255
|
+
port?: number;
|
1256
|
+
progress?: number;
|
1257
|
+
relevance?: number;
|
1258
|
+
up_speed?: number;
|
1259
|
+
uploaded?: number;
|
1260
|
+
}
|
1237
1261
|
export {};
|
package/dist/src/types.js
CHANGED
@@ -81,7 +81,7 @@ export var TorrentState;
|
|
81
81
|
* Torrent data files is missing
|
82
82
|
*/
|
83
83
|
TorrentState["MissingFiles"] = "missingFiles";
|
84
|
-
})(TorrentState
|
84
|
+
})(TorrentState || (TorrentState = {}));
|
85
85
|
export var TorrentTrackerStatus;
|
86
86
|
(function (TorrentTrackerStatus) {
|
87
87
|
/**
|
@@ -104,7 +104,7 @@ export var TorrentTrackerStatus;
|
|
104
104
|
* Tracker has been contacted, but it is not working (or doesn't send proper replies)
|
105
105
|
*/
|
106
106
|
TorrentTrackerStatus[TorrentTrackerStatus["Errored"] = 4] = "Errored";
|
107
|
-
})(TorrentTrackerStatus
|
107
|
+
})(TorrentTrackerStatus || (TorrentTrackerStatus = {}));
|
108
108
|
export var TorrentFilePriority;
|
109
109
|
(function (TorrentFilePriority) {
|
110
110
|
/**
|
@@ -123,7 +123,7 @@ export var TorrentFilePriority;
|
|
123
123
|
* Maximal priority
|
124
124
|
*/
|
125
125
|
TorrentFilePriority[TorrentFilePriority["MaxPriority"] = 7] = "MaxPriority";
|
126
|
-
})(TorrentFilePriority
|
126
|
+
})(TorrentFilePriority || (TorrentFilePriority = {}));
|
127
127
|
export var TorrentPieceState;
|
128
128
|
(function (TorrentPieceState) {
|
129
129
|
/**
|
@@ -138,4 +138,4 @@ export var TorrentPieceState;
|
|
138
138
|
* Already downloaded
|
139
139
|
*/
|
140
140
|
TorrentPieceState[TorrentPieceState["Downloaded"] = 2] = "Downloaded";
|
141
|
-
})(TorrentPieceState
|
141
|
+
})(TorrentPieceState || (TorrentPieceState = {}));
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@ctrl/qbittorrent",
|
3
|
-
"version": "
|
3
|
+
"version": "7.0.0",
|
4
4
|
"description": "TypeScript api wrapper for qbittorrent using got",
|
5
5
|
"author": "Scott Cooper <scttcper@gmail.com>",
|
6
6
|
"license": "MIT",
|
@@ -14,7 +14,8 @@
|
|
14
14
|
],
|
15
15
|
"sideEffects": false,
|
16
16
|
"publishConfig": {
|
17
|
-
"access": "public"
|
17
|
+
"access": "public",
|
18
|
+
"provenance": true
|
18
19
|
},
|
19
20
|
"keywords": [
|
20
21
|
"typescript",
|
@@ -31,25 +32,24 @@
|
|
31
32
|
"test:ci": "vitest run --coverage --reporter=default --reporter=junit --outputFile=./junit.xml"
|
32
33
|
},
|
33
34
|
"dependencies": {
|
34
|
-
"@ctrl/magnet-link": "^3.1.
|
35
|
-
"@ctrl/shared-torrent": "^
|
36
|
-
"@ctrl/torrent-file": "^
|
37
|
-
"
|
38
|
-
"
|
39
|
-
"
|
40
|
-
"
|
35
|
+
"@ctrl/magnet-link": "^3.1.2",
|
36
|
+
"@ctrl/shared-torrent": "^5.0.0",
|
37
|
+
"@ctrl/torrent-file": "^3.0.0",
|
38
|
+
"node-fetch-native": "^1.4.0",
|
39
|
+
"ofetch": "^1.3.3",
|
40
|
+
"tough-cookie": "^4.1.3",
|
41
|
+
"ufo": "^1.3.0"
|
41
42
|
},
|
42
43
|
"devDependencies": {
|
43
|
-
"@ctrl/eslint-config": "
|
44
|
-
"@sindresorhus/tsconfig": "
|
45
|
-
"@types/node": "
|
46
|
-
"@types/tough-cookie": "4.0.
|
47
|
-
"@vitest/coverage-
|
48
|
-
"c8": "7.13.0",
|
44
|
+
"@ctrl/eslint-config": "4.0.7",
|
45
|
+
"@sindresorhus/tsconfig": "4.0.0",
|
46
|
+
"@types/node": "20.6.5",
|
47
|
+
"@types/tough-cookie": "4.0.3",
|
48
|
+
"@vitest/coverage-v8": "0.34.5",
|
49
49
|
"p-wait-for": "5.0.2",
|
50
|
-
"typedoc": "0.
|
51
|
-
"typescript": "5.
|
52
|
-
"vitest": "0.
|
50
|
+
"typedoc": "0.25.1",
|
51
|
+
"typescript": "5.2.2",
|
52
|
+
"vitest": "0.34.5"
|
53
53
|
},
|
54
54
|
"release": {
|
55
55
|
"branches": [
|
@@ -57,6 +57,6 @@
|
|
57
57
|
]
|
58
58
|
},
|
59
59
|
"engines": {
|
60
|
-
"node": ">=
|
60
|
+
"node": ">=18"
|
61
61
|
}
|
62
62
|
}
|