cross-seed 6.0.0-3 → 6.0.0-30

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.
Files changed (67) hide show
  1. package/dist/Result.js +17 -11
  2. package/dist/Result.js.map +1 -1
  3. package/dist/action.js +158 -47
  4. package/dist/action.js.map +1 -1
  5. package/dist/arr.js +200 -0
  6. package/dist/arr.js.map +1 -0
  7. package/dist/clients/Deluge.js +129 -71
  8. package/dist/clients/Deluge.js.map +1 -1
  9. package/dist/clients/QBittorrent.js +74 -58
  10. package/dist/clients/QBittorrent.js.map +1 -1
  11. package/dist/clients/RTorrent.js +12 -10
  12. package/dist/clients/RTorrent.js.map +1 -1
  13. package/dist/clients/TorrentClient.js.map +1 -1
  14. package/dist/clients/Transmission.js +10 -10
  15. package/dist/clients/Transmission.js.map +1 -1
  16. package/dist/cmd.js +16 -16
  17. package/dist/cmd.js.map +1 -1
  18. package/dist/config.template.cjs +83 -46
  19. package/dist/config.template.cjs.map +1 -1
  20. package/dist/configSchema.js +97 -13
  21. package/dist/configSchema.js.map +1 -1
  22. package/dist/configuration.js +3 -0
  23. package/dist/configuration.js.map +1 -1
  24. package/dist/constants.js +100 -6
  25. package/dist/constants.js.map +1 -1
  26. package/dist/dataFiles.js +4 -5
  27. package/dist/dataFiles.js.map +1 -1
  28. package/dist/decide.js +263 -158
  29. package/dist/decide.js.map +1 -1
  30. package/dist/diff.js +12 -2
  31. package/dist/diff.js.map +1 -1
  32. package/dist/errors.js +5 -2
  33. package/dist/errors.js.map +1 -1
  34. package/dist/indexers.js +31 -4
  35. package/dist/indexers.js.map +1 -1
  36. package/dist/jobs.js +2 -0
  37. package/dist/jobs.js.map +1 -1
  38. package/dist/logger.js +19 -5
  39. package/dist/logger.js.map +1 -1
  40. package/dist/migrations/05-caps.js +16 -0
  41. package/dist/migrations/05-caps.js.map +1 -0
  42. package/dist/migrations/06-uniqueDecisions.js +29 -0
  43. package/dist/migrations/06-uniqueDecisions.js.map +1 -0
  44. package/dist/migrations/migrations.js +11 -1
  45. package/dist/migrations/migrations.js.map +1 -1
  46. package/dist/parseTorrent.js +5 -0
  47. package/dist/parseTorrent.js.map +1 -1
  48. package/dist/pipeline.js +181 -85
  49. package/dist/pipeline.js.map +1 -1
  50. package/dist/preFilter.js +130 -52
  51. package/dist/preFilter.js.map +1 -1
  52. package/dist/pushNotifier.js +4 -2
  53. package/dist/pushNotifier.js.map +1 -1
  54. package/dist/runtimeConfig.js.map +1 -1
  55. package/dist/searchee.js +203 -13
  56. package/dist/searchee.js.map +1 -1
  57. package/dist/server.js +22 -15
  58. package/dist/server.js.map +1 -1
  59. package/dist/startup.js +2 -0
  60. package/dist/startup.js.map +1 -1
  61. package/dist/torrent.js +84 -39
  62. package/dist/torrent.js.map +1 -1
  63. package/dist/torznab.js +285 -95
  64. package/dist/torznab.js.map +1 -1
  65. package/dist/utils.js +155 -31
  66. package/dist/utils.js.map +1 -1
  67. package/package.json +3 -1
@@ -1,10 +1,10 @@
1
+ import ms from "ms";
1
2
  import { InjectionResult, TORRENT_TAG, TORRENT_CATEGORY_SUFFIX, } from "../constants.js";
2
3
  import { CrossSeedError } from "../errors.js";
3
4
  import { Label, logger } from "../logger.js";
4
5
  import { getRuntimeConfig } from "../runtimeConfig.js";
5
- import { shouldRecheck, extractCredentialsFromUrl, wait } from "../utils.js";
6
+ import { shouldRecheck, extractCredentialsFromUrl, wait, getLogString, } from "../utils.js";
6
7
  import { resultOf, resultOfErr } from "../Result.js";
7
- import ms from "ms";
8
8
  var DelugeErrorCode;
9
9
  (function (DelugeErrorCode) {
10
10
  DelugeErrorCode[DelugeErrorCode["NO_AUTH"] = 1] = "NO_AUTH";
@@ -36,20 +36,20 @@ export default class Deluge {
36
36
  throw new CrossSeedError("You need to define a password in the delugeRpcUrl. (e.g. http://:<PASSWORD>@localhost:8112)");
37
37
  }
38
38
  try {
39
- const authResponse = await this.call("auth.login", [password], 0);
40
- if (!authResponse.result) {
39
+ const authResponse = (await this.call("auth.login", [password], 0)).unwrapOrThrow(new Error("failed to connect for authentication"));
40
+ if (!authResponse) {
41
41
  throw new CrossSeedError(`Reached Deluge, but failed to authenticate: ${href}`);
42
42
  }
43
43
  }
44
44
  catch (networkError) {
45
45
  throw new CrossSeedError(networkError);
46
46
  }
47
- const connectedResponse = await this.call("web.connected", [], 0);
48
- if (!connectedResponse.result) {
47
+ const isConnectedResponse = await this.call("web.connected", [], 0);
48
+ if (isConnectedResponse.isOk() && !isConnectedResponse.unwrap()) {
49
49
  logger.warn("Deluge WebUI disconnected from daemon...attempting to reconnect.");
50
- const webuiHostList = await this.call("web.get_hosts", [], 0);
51
- const connectResponse = await this.call("web.connect", [webuiHostList.result[0][0]], 0);
52
- if (!connectResponse.error) {
50
+ const webuiHostList = (await this.call("web.get_hosts", [], 0)).unwrapOrThrow(new Error("failed to get host-list for reconnect"));
51
+ const connectResponse = await this.call("web.connect", [webuiHostList[0][0]], 0);
52
+ if (connectResponse.isOk() && connectResponse.unwrap()) {
53
53
  logger.info("Deluge WebUI connected to the daemon.");
54
54
  }
55
55
  else {
@@ -59,16 +59,18 @@ export default class Deluge {
59
59
  }
60
60
  /**
61
61
  * ensures authentication and sends JSON-RPC calls to deluge
62
+ * @param method RPC method to send (usually prefaced with module name)
63
+ * @param params parameters for the method (usually in an array)
64
+ * @param retries specify a retry count (optional)
65
+ * @return a promised Result of the specified ResultType or an ErrorType
62
66
  */
63
67
  async call(method, params, retries = 1) {
64
68
  const { delugeRpcUrl } = getRuntimeConfig();
65
- const { href } = extractCredentialsFromUrl(delugeRpcUrl).unwrapOrThrow();
69
+ const { href } = extractCredentialsFromUrl(delugeRpcUrl).unwrapOrThrow(new CrossSeedError("delugeRpcUrl must be percent-encoded"));
66
70
  const headers = new Headers({ "Content-Type": "application/json" });
67
71
  if (this.delugeCookie)
68
72
  headers.set("Cookie", this.delugeCookie);
69
73
  let response, json;
70
- const abortController = new AbortController();
71
- setTimeout(() => void abortController.abort(), ms("10 seconds")).unref();
72
74
  try {
73
75
  response = await fetch(href, {
74
76
  body: JSON.stringify({
@@ -78,7 +80,7 @@ export default class Deluge {
78
80
  }),
79
81
  method: "POST",
80
82
  headers,
81
- signal: abortController.signal,
83
+ signal: AbortSignal.timeout(ms("10 seconds")),
82
84
  });
83
85
  }
84
86
  catch (networkError) {
@@ -106,10 +108,14 @@ export default class Deluge {
106
108
  }
107
109
  }
108
110
  this.handleResponseHeaders(response.headers);
109
- return json;
111
+ if (json.error) {
112
+ return resultOfErr(json.error);
113
+ }
114
+ return resultOf(json.result);
110
115
  }
111
116
  /**
112
117
  * parses the set-cookie header and updates stored value
118
+ * @param headers the headers from a request
113
119
  */
114
120
  handleResponseHeaders(headers) {
115
121
  if (headers.has("Set-Cookie")) {
@@ -118,15 +124,23 @@ export default class Deluge {
118
124
  }
119
125
  /**
120
126
  * checks enabled plugins for "Label"
121
- * returns true if successful.
127
+ * @return boolean declaring whether the "Label" plugin is enabled
122
128
  */
123
129
  async labelEnabled() {
124
130
  const enabledPlugins = await this.call("core.get_enabled_plugins", []);
125
- return enabledPlugins.error
126
- ? false
127
- : enabledPlugins.result.includes("Label");
131
+ if (enabledPlugins.isOk()) {
132
+ return enabledPlugins.unwrap().includes("Label");
133
+ }
134
+ else {
135
+ return false;
136
+ }
128
137
  }
129
- // generates the label (string) for injection based on searchee and torrentInfo
138
+ /**
139
+ * generates the label for injection based on searchee and torrentInfo
140
+ * @param searchee Searchee that contains the originating torrent
141
+ * @param torrentInfo TorrentInfo from the searchee
142
+ * @return string with the label for the newTorrent
143
+ */
130
144
  calculateLabel(searchee, torrentInfo) {
131
145
  const { linkCategory, duplicateCategories } = getRuntimeConfig();
132
146
  if (!searchee.infoHash || !torrentInfo.label) {
@@ -138,7 +152,7 @@ export default class Deluge {
138
152
  }
139
153
  const shouldSuffixLabel = !ogLabel.endsWith(this.delugeLabelSuffix) && // no .cross-seed
140
154
  ogLabel !== linkCategory; // not data
141
- return searchee.path
155
+ return !searchee.infoHash
142
156
  ? linkCategory
143
157
  : shouldSuffixLabel
144
158
  ? `${ogLabel}${this.delugeLabelSuffix}`
@@ -147,29 +161,52 @@ export default class Deluge {
147
161
  /**
148
162
  * if Label plugin is loaded, adds (if necessary)
149
163
  * and sets the label based on torrent hash.
164
+ * @param newTorrent the searchee of the newTorrent
165
+ * @param label the destination label for the newTorrent/searchee
150
166
  */
151
- async setLabel(name, infoHash, label) {
167
+ async setLabel(newTorrent, label) {
168
+ let setResult;
152
169
  if (!this.isLabelEnabled)
153
170
  return;
154
171
  try {
155
- const setResult = await this.call("label.set_torrent", [
156
- infoHash,
157
- label,
158
- ]);
159
- if (setResult.error?.code === DelugeErrorCode.RPC_FAIL) {
172
+ const getCurrentLabels = await this.call("label.get_labels", []);
173
+ if (getCurrentLabels.isErr()) {
174
+ this.isLabelEnabled = false;
175
+ throw new Error("Labels have been disabled.");
176
+ }
177
+ if (getCurrentLabels.unwrap().includes(label)) {
178
+ setResult = await this.call("label.set_torrent", [
179
+ newTorrent.infoHash,
180
+ label,
181
+ ]);
182
+ }
183
+ else {
160
184
  await this.call("label.add", [label]);
161
- await this.call("label.set_torrent", [infoHash, label]);
185
+ await wait(300);
186
+ setResult = await this.call("label.set_torrent", [
187
+ newTorrent.infoHash,
188
+ label,
189
+ ]);
190
+ }
191
+ if (setResult.isErr()) {
192
+ throw new Error(setResult.unwrapErr().message);
162
193
  }
163
194
  }
164
195
  catch (e) {
196
+ logger.debug(e);
165
197
  logger.warn({
166
198
  label: Label.DELUGE,
167
- message: `Failed to label ${name} (${infoHash}) as ${label}`,
199
+ message: `Failed to label ${getLogString(newTorrent)} as ${label}`,
168
200
  });
169
201
  }
170
202
  }
171
203
  /**
172
204
  * injects a torrent into deluge client
205
+ * @param newTorrent injected candidate torrent
206
+ * @param searchee originating torrent (searchee)
207
+ * @param decision decision by which the newTorrent was matched
208
+ * @param path location of the linked files (optional)
209
+ * @return InjectionResult of the newTorrent's injection
173
210
  */
174
211
  async inject(newTorrent, searchee, decision, path) {
175
212
  try {
@@ -183,21 +220,38 @@ export default class Deluge {
183
220
  if (!path && (!searchee.infoHash || !torrentInfo)) {
184
221
  logger.debug({
185
222
  label: Label.DELUGE,
186
- message: `Injection failure: ${newTorrent.name} was missing critical data.`,
223
+ message: `Injection failure: ${getLogString(searchee)} was missing critical data.`,
187
224
  });
188
225
  return InjectionResult.FAILURE;
189
226
  }
190
227
  const torrentFileName = `${newTorrent.getFileSystemSafeName()}.cross-seed.torrent`;
191
228
  const encodedTorrentData = newTorrent.encode().toString("base64");
192
229
  const torrentPath = path ? path : torrentInfo.save_path;
193
- const params = this.formatData(torrentFileName, encodedTorrentData, torrentPath, decision);
194
- const addResult = await this.call("core.add_torrent_file", params);
195
- const addResponse = typeof addResult.error?.message === "string"
196
- ? addResult.error
197
- : addResult.result;
198
- if (typeof addResponse === "string") {
199
- await this.setLabel(newTorrent.name, newTorrent.infoHash, this.calculateLabel(searchee, torrentInfo));
200
- if (shouldRecheck(decision)) {
230
+ const params = this.formatData(torrentFileName, encodedTorrentData, torrentPath, searchee, decision);
231
+ const addResponse = await this.call("core.add_torrent_file", params);
232
+ if (addResponse.isErr()) {
233
+ const addResponseError = addResponse.unwrapErr();
234
+ if (addResponseError.message.includes("already")) {
235
+ return InjectionResult.ALREADY_EXISTS;
236
+ }
237
+ else if (addResponseError) {
238
+ logger.debug({
239
+ label: Label.DELUGE,
240
+ message: `Injection failed: ${addResponseError.message}`,
241
+ });
242
+ return InjectionResult.FAILURE;
243
+ }
244
+ else {
245
+ logger.debug({
246
+ label: Label.DELUGE,
247
+ message: `Unknown injection failure: ${getLogString(newTorrent)}`,
248
+ });
249
+ return InjectionResult.FAILURE;
250
+ }
251
+ }
252
+ if (addResponse.isOk()) {
253
+ await this.setLabel(newTorrent, this.calculateLabel(searchee, torrentInfo));
254
+ if (shouldRecheck(searchee, decision)) {
201
255
  // when paused, libtorrent doesnt start rechecking
202
256
  // leaves torrent ready to download - ~99%
203
257
  await wait(1000);
@@ -205,24 +259,6 @@ export default class Deluge {
205
259
  [newTorrent.infoHash],
206
260
  ]);
207
261
  }
208
- return InjectionResult.SUCCESS;
209
- }
210
- else if (addResponse?.message.includes("already")) {
211
- return InjectionResult.ALREADY_EXISTS;
212
- }
213
- else if (addResponse) {
214
- logger.debug({
215
- label: Label.DELUGE,
216
- message: `Injection failed: ${addResponse}`,
217
- });
218
- return InjectionResult.FAILURE;
219
- }
220
- else {
221
- logger.debug({
222
- label: Label.DELUGE,
223
- message: `Unknown injection failure: ${newTorrent.name} (${newTorrent.infoHash})`,
224
- });
225
- return InjectionResult.FAILURE;
226
262
  }
227
263
  }
228
264
  catch (error) {
@@ -233,12 +269,17 @@ export default class Deluge {
233
269
  logger.debug(error);
234
270
  return InjectionResult.FAILURE;
235
271
  }
272
+ return InjectionResult.SUCCESS;
236
273
  }
237
274
  /**
238
275
  * formats the json for rpc calls to inject
276
+ * @param filename filename for the injecting torrent file
277
+ * @param filedump string with encoded torrent file
278
+ * @param path path to the torrent data
279
+ * @param decision decision by which the newTorrent was matched
239
280
  */
240
- formatData(filename, filedump, path, decision) {
241
- const toRecheck = shouldRecheck(decision);
281
+ formatData(filename, filedump, path, searchee, decision) {
282
+ const toRecheck = shouldRecheck(searchee, decision);
242
283
  return [
243
284
  filename,
244
285
  filedump,
@@ -251,32 +292,38 @@ export default class Deluge {
251
292
  }
252
293
  /**
253
294
  * returns directory of an infohash in deluge as a string
295
+ * @param searchee Searchee or Metafile for torrent to lookup in client
296
+ * @return Result containing either a string with path or reason it was not provided
254
297
  */
255
- async getDownloadDir(searchee) {
256
- let torrent, response;
257
- const params = [["save_path", "progress"], { hash: searchee.infoHash }];
298
+ async getDownloadDir(meta, options) {
299
+ let response;
300
+ const params = [["save_path", "progress"], { hash: meta.infoHash }];
258
301
  try {
259
302
  response = await this.call("web.update_ui", params);
260
303
  }
261
304
  catch (e) {
262
305
  return resultOfErr("UNKNOWN_ERROR");
263
306
  }
264
- if (response.result.torrents) {
265
- torrent = response.result.torrents?.[searchee.infoHash];
307
+ if (!response.isOk()) {
308
+ return resultOfErr("UNKNOWN_ERROR");
266
309
  }
267
- else {
310
+ const torrentResponse = response.unwrap().torrents;
311
+ if (!torrentResponse) {
268
312
  return resultOfErr("UNKNOWN_ERROR");
269
313
  }
270
- if (torrent === undefined) {
314
+ const torrent = torrentResponse[meta.infoHash];
315
+ if (!torrent) {
271
316
  return resultOfErr("NOT_FOUND");
272
317
  }
273
- else if (response.result.torrents?.[searchee.infoHash].progress !== 100) {
318
+ if (options.onlyCompleted && torrent.progress !== 100) {
274
319
  return resultOfErr("TORRENT_NOT_COMPLETE");
275
320
  }
276
321
  return resultOf(torrent.save_path);
277
322
  }
278
323
  /**
279
324
  * returns information needed to complete/validate injection
325
+ * @param searchee the Searchee for the torrent you are requesting TorrentInfo from
326
+ * @return Promise of TorrentInfo type
280
327
  */
281
328
  async getTorrentInfo(searchee) {
282
329
  if (!searchee.infoHash) {
@@ -285,12 +332,19 @@ export default class Deluge {
285
332
  let torrent;
286
333
  try {
287
334
  const params = [
288
- ["state", "progress", "save_path", "label"],
335
+ [
336
+ "name",
337
+ "state",
338
+ "progress",
339
+ "save_path",
340
+ "label",
341
+ "total_remaining",
342
+ ],
289
343
  { hash: searchee.infoHash },
290
344
  ];
291
- const response = await this.call("web.update_ui", params);
292
- if (response.result.torrents) {
293
- torrent = response.result.torrents?.[searchee.infoHash];
345
+ const response = (await this.call("web.update_ui", params)).unwrapOrThrow(new Error("failed to fetch the torrent list"));
346
+ if (response.torrents) {
347
+ torrent = response.torrents?.[searchee.infoHash];
294
348
  }
295
349
  else {
296
350
  throw new Error("Client returned unexpected response (object missing)");
@@ -298,7 +352,11 @@ export default class Deluge {
298
352
  if (torrent === undefined) {
299
353
  throw new Error(`Torrent not found in client (${searchee.infoHash})`);
300
354
  }
301
- const completedTorrent = torrent.state === "Seeding" || torrent.progress === 100;
355
+ const completedTorrent = (torrent.state === "Paused" &&
356
+ (torrent.progress === 100 || !torrent.total_remaining)) ||
357
+ torrent.state === "Seeding" ||
358
+ torrent.progress === 100 ||
359
+ !torrent.total_remaining;
302
360
  const torrentLabel = this.isLabelEnabled && torrent.label.length != 0
303
361
  ? torrent.label
304
362
  : undefined;
@@ -311,7 +369,7 @@ export default class Deluge {
311
369
  catch (e) {
312
370
  logger.error({
313
371
  label: Label.DELUGE,
314
- message: `Failed to fetch torrent data: ${searchee.name} - (${searchee.infoHash})`,
372
+ message: `Failed to fetch torrent data: ${getLogString(searchee)}`,
315
373
  });
316
374
  logger.debug(e);
317
375
  throw new Error("web.update_ui: failed to fetch data from client", {
@@ -1 +1 @@
1
- {"version":3,"file":"Deluge.js","sourceRoot":"","sources":["../../src/clients/Deluge.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Deluge.js","sourceRoot":"","sources":["../../src/clients/Deluge.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,10 @@
1
- import { dirname } from "path";
1
+ import { dirname, resolve } from "path";
2
2
  import { InjectionResult, TORRENT_TAG, TORRENT_CATEGORY_SUFFIX, } from "../constants.js";
3
3
  import { CrossSeedError } from "../errors.js";
4
4
  import { Label, logger } from "../logger.js";
5
+ import ms from "ms";
5
6
  import { getRuntimeConfig } from "../runtimeConfig.js";
6
- import { shouldRecheck, extractCredentialsFromUrl, wait } from "../utils.js";
7
+ import { shouldRecheck, extractCredentialsFromUrl, wait, getLogString, sanitizeInfoHash, } from "../utils.js";
7
8
  import { resultOf, resultOfErr } from "../Result.js";
8
9
  const X_WWW_FORM_URLENCODED = {
9
10
  "Content-Type": "application/x-www-form-urlencoded",
@@ -40,9 +41,12 @@ export default class QBittorrent {
40
41
  await this.createTag();
41
42
  }
42
43
  async request(path, body, headers = {}, retries = 3) {
44
+ const bodyStr = body instanceof FormData
45
+ ? JSON.stringify(Object.fromEntries(body))
46
+ : JSON.stringify(body).replace(/(?:hashes=)([a-z0-9]{40})/i, (match, hash) => match.replace(hash, sanitizeInfoHash(hash)));
43
47
  logger.verbose({
44
48
  label: Label.QBITTORRENT,
45
- message: `Making request (${retries}) to ${path} with body ${JSON.stringify(body)}`,
49
+ message: `Making request (${retries}) to ${path} with body ${bodyStr}`,
46
50
  });
47
51
  let response;
48
52
  try {
@@ -82,36 +86,32 @@ export default class QBittorrent {
82
86
  ? "Subfolder"
83
87
  : "Original";
84
88
  }
85
- getTagsForNewTorrent(searchee, searcheeInfo, category) {
89
+ getCategoryForNewTorrent(category) {
86
90
  const { duplicateCategories, linkCategory } = getRuntimeConfig();
87
- /* get the original category if torrent based - cuz otherwise we
88
- * use 'category'. this addresses path being truthy but still being
89
- * torrent searchee
90
- */
91
- const categoryForTagging = searcheeInfo
92
- ? searcheeInfo.category
93
- : category;
94
- if (!categoryForTagging?.length ||
95
- categoryForTagging === linkCategory) {
96
- return TORRENT_TAG;
91
+ if (!duplicateCategories) {
92
+ return category;
97
93
  }
98
- if (categoryForTagging.endsWith(TORRENT_CATEGORY_SUFFIX)) {
99
- if (duplicateCategories) {
100
- return `${TORRENT_TAG},${categoryForTagging}`;
101
- }
102
- else {
103
- return TORRENT_TAG;
104
- }
94
+ if (!category.length || category === linkCategory) {
95
+ return category; // Use tags for category duplication if linking
105
96
  }
106
- if (!searchee.infoHash) {
107
- return TORRENT_TAG;
97
+ if (category.endsWith(TORRENT_CATEGORY_SUFFIX)) {
98
+ return category;
108
99
  }
109
- else if (duplicateCategories) {
110
- return `${TORRENT_TAG},${categoryForTagging}${TORRENT_CATEGORY_SUFFIX}`;
100
+ return `${category}${TORRENT_CATEGORY_SUFFIX}`;
101
+ }
102
+ getTagsForNewTorrent(searcheeInfo, path) {
103
+ const { duplicateCategories, linkCategory } = getRuntimeConfig();
104
+ if (!duplicateCategories || !searcheeInfo || !path) {
105
+ return TORRENT_TAG; // Require path to duplicate category using tags
111
106
  }
112
- else {
107
+ const searcheeCategory = searcheeInfo.category;
108
+ if (!searcheeCategory.length || searcheeCategory === linkCategory) {
113
109
  return TORRENT_TAG;
114
110
  }
111
+ if (searcheeCategory.endsWith(TORRENT_CATEGORY_SUFFIX)) {
112
+ return `${TORRENT_TAG},${searcheeCategory}`;
113
+ }
114
+ return `${TORRENT_TAG},${searcheeCategory}${TORRENT_CATEGORY_SUFFIX}`;
115
115
  }
116
116
  async createTag() {
117
117
  await this.request("/torrents/createTags", `tags=${TORRENT_TAG}`, X_WWW_FORM_URLENCODED);
@@ -126,19 +126,21 @@ export default class QBittorrent {
126
126
  @param searchee the Searchee we are generating off (in client)
127
127
  @return either a string containing the path or a error mesage
128
128
  */
129
- async getDownloadDir(searchee) {
129
+ async getDownloadDir(meta, options) {
130
130
  try {
131
- const torrentInfo = await this.getTorrentInfo(searchee.infoHash);
131
+ const torrentInfo = await this.getTorrentInfo(meta.infoHash);
132
132
  if (!torrentInfo) {
133
133
  return resultOfErr("NOT_FOUND");
134
134
  }
135
- if (!this.isTorrentComplete(torrentInfo)) {
135
+ if (options.onlyCompleted &&
136
+ !this.isTorrentInfoComplete(torrentInfo)) {
136
137
  return resultOfErr("TORRENT_NOT_COMPLETE");
137
138
  }
138
- const savePath = this.getCorrectSavePath(searchee, torrentInfo);
139
+ const savePath = this.getCorrectSavePath(meta, torrentInfo);
139
140
  return resultOf(savePath);
140
141
  }
141
142
  catch (e) {
143
+ logger.debug(e);
142
144
  if (e.message.includes("retrieve")) {
143
145
  return resultOfErr("NOT_FOUND");
144
146
  }
@@ -171,26 +173,29 @@ export default class QBittorrent {
171
173
  @param hash the hash of the torrent
172
174
  @return the torrent if it exists
173
175
  */
174
- async getTorrentInfo(hash) {
176
+ async getTorrentInfo(hash, retries = 0) {
175
177
  if (!hash)
176
178
  return undefined;
177
- const responseText = await this.request("/torrents/info", `hashes=${hash}`, X_WWW_FORM_URLENCODED);
178
- if (responseText) {
179
- const torrents = JSON.parse(responseText);
180
- if (torrents.length > 0) {
181
- return torrents[0];
179
+ for (let i = 0; i <= retries; i++) {
180
+ const responseText = await this.request("/torrents/info", `hashes=${hash}`, X_WWW_FORM_URLENCODED);
181
+ if (responseText) {
182
+ const torrents = JSON.parse(responseText);
183
+ if (torrents.length > 0) {
184
+ return torrents[0];
185
+ }
182
186
  }
187
+ const torrents = await this.getAllTorrentInfo();
188
+ const torrentInfo = torrents.find((torrent) => hash === torrent.hash ||
189
+ hash === torrent.infohash_v1 ||
190
+ hash === torrent.infohash_v2);
191
+ if (torrentInfo) {
192
+ return torrentInfo;
193
+ }
194
+ await wait(ms("1 second") * 2 ** i);
183
195
  }
184
- logger.verbose({
185
- label: Label.QBITTORRENT,
186
- message: `Failed to retrieve torrent info using infohash_v1 ${hash}, checking all hashes`,
187
- });
188
- const torrents = await this.getAllTorrentInfo();
189
- return torrents.find((torrent) => hash === torrent.hash ||
190
- hash === torrent.infohash_v1 ||
191
- hash === torrent.infohash_v2);
196
+ return undefined;
192
197
  }
193
- isTorrentComplete(torrentInfo) {
198
+ isTorrentInfoComplete(torrentInfo) {
194
199
  return [
195
200
  "uploading",
196
201
  "pausedUP",
@@ -206,10 +211,11 @@ export default class QBittorrent {
206
211
  return false;
207
212
  if (dirname(searchee.files[0].path) !== ".")
208
213
  return false;
209
- return dirname(searcheeInfo.content_path) !== searcheeInfo.save_path;
214
+ return (resolve(dirname(searcheeInfo.content_path)) !==
215
+ resolve(searcheeInfo.save_path));
210
216
  }
211
217
  async inject(newTorrent, searchee, decision, path) {
212
- const { flatLinking, linkCategory } = getRuntimeConfig();
218
+ const { linkCategory } = getRuntimeConfig();
213
219
  try {
214
220
  if (await this.getTorrentInfo(newTorrent.infoHash)) {
215
221
  return InjectionResult.ALREADY_EXISTS;
@@ -218,12 +224,12 @@ export default class QBittorrent {
218
224
  if (!searcheeInfo) {
219
225
  if (!path) {
220
226
  // This is never possible, being made explicit here
221
- throw new Error(`Searchee torrent may have been deleted: ${searchee.name} [${searchee.infoHash}]`);
227
+ throw new Error(`Searchee torrent may have been deleted: ${getLogString(searchee)}`);
222
228
  }
223
229
  else if (searchee.infoHash) {
224
230
  logger.warning({
225
231
  label: Label.QBITTORRENT,
226
- message: `Searchee torrent may have been deleted, tagging may not meet expectations: ${searchee.name} [${searchee.infoHash}]`,
232
+ message: `Searchee torrent may have been deleted, tagging may not meet expectations: ${getLogString(searchee)}`,
227
233
  });
228
234
  }
229
235
  }
@@ -236,7 +242,7 @@ export default class QBittorrent {
236
242
  }
237
243
  : {
238
244
  savePath: searcheeInfo.save_path,
239
- isComplete: this.isTorrentComplete(searcheeInfo),
245
+ isComplete: this.isTorrentInfoComplete(searcheeInfo),
240
246
  autoTMM: searcheeInfo.auto_tmm,
241
247
  category: searcheeInfo.category,
242
248
  };
@@ -246,25 +252,34 @@ export default class QBittorrent {
246
252
  const buffer = new Blob([newTorrent.encode()], {
247
253
  type: "application/x-bittorrent",
248
254
  });
249
- const toRecheck = shouldRecheck(decision);
255
+ const toRecheck = shouldRecheck(searchee, decision);
250
256
  // ---------------------- Building form data ----------------------
251
257
  const formData = new FormData();
252
258
  formData.append("torrents", buffer, filename);
253
- if (path) {
259
+ if (!autoTMM) {
260
+ formData.append("downloadPath", savePath);
254
261
  formData.append("savepath", savePath);
255
262
  }
256
- formData.append("autoTMM", flatLinking && searchee.infoHash ? autoTMM.toString() : "false");
257
- formData.append("category", category);
258
- formData.append("tags", this.getTagsForNewTorrent(searchee, searcheeInfo, category));
263
+ formData.append("autoTMM", autoTMM.toString());
264
+ formData.append("category", this.getCategoryForNewTorrent(category));
265
+ formData.append("tags", this.getTagsForNewTorrent(searcheeInfo, path));
259
266
  formData.append("contentLayout", this.getLayoutForNewTorrent(searchee, searcheeInfo, path));
260
267
  formData.append("skip_checking", (!toRecheck).toString());
261
268
  formData.append("paused", toRecheck.toString());
262
269
  // for some reason the parser parses the last kv pair incorrectly
263
270
  // it concats the value and the sentinel
264
271
  formData.append("foo", "bar");
265
- await this.addTorrent(formData);
266
- await wait(1000);
267
- const newInfo = await this.getTorrentInfo(newTorrent.infoHash);
272
+ try {
273
+ await this.addTorrent(formData);
274
+ }
275
+ catch (e) {
276
+ logger.error({
277
+ label: Label.QBITTORRENT,
278
+ message: `Failed to add torrent (polling client to confirm): ${e.message}`,
279
+ });
280
+ logger.debug(e);
281
+ }
282
+ const newInfo = await this.getTorrentInfo(newTorrent.infoHash, 5);
268
283
  if (!newInfo) {
269
284
  throw new Error(`Failed to retrieve torrent after adding`);
270
285
  }
@@ -278,6 +293,7 @@ export default class QBittorrent {
278
293
  label: Label.QBITTORRENT,
279
294
  message: `Injection failed: ${e.message}`,
280
295
  });
296
+ logger.debug(e);
281
297
  return InjectionResult.FAILURE;
282
298
  }
283
299
  }