cross-seed 6.13.6 → 7.0.0-1

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 (147) hide show
  1. package/README.md +12 -13
  2. package/dist/webui/assets/FieldInfo-Bxj_j8SJ.js +1 -0
  3. package/dist/webui/assets/Page-C3rteCZt.js +1 -0
  4. package/dist/webui/assets/array-field-DVSC6nHP.js +1 -0
  5. package/dist/webui/assets/badge-DTZMtS0e.js +1 -0
  6. package/dist/webui/assets/check-Bu3ldi63.js +1 -0
  7. package/dist/webui/assets/chevron-down-CRy8M0kJ.js +1 -0
  8. package/dist/webui/assets/clients-CW8oEZoQ.js +1 -0
  9. package/dist/webui/assets/connect-YBNsnjWT.js +1 -0
  10. package/dist/webui/assets/debug-mz8-WYZj.js +1 -0
  11. package/dist/webui/assets/directories-BSK28RgR.js +1 -0
  12. package/dist/webui/assets/duration-field-C6xoSlJg.js +1 -0
  13. package/dist/webui/assets/general-lJJxZhH7.js +1 -0
  14. package/dist/webui/assets/health-CXbsVrie.js +1 -0
  15. package/dist/webui/assets/index-Bi48hI2z.js +54 -0
  16. package/dist/webui/assets/index-C-Ul7GNg.css +1 -0
  17. package/dist/webui/assets/index-C2cH1Gst.js +1 -0
  18. package/dist/webui/assets/index-Cc5bDmJr.js +1 -0
  19. package/dist/webui/assets/jobs-CxmNab9w.js +1 -0
  20. package/dist/webui/assets/library-vaj2W8sE.js +1 -0
  21. package/dist/webui/assets/loader-circle-M0gu1gZ-.js +1 -0
  22. package/dist/webui/assets/logs-Cu9RyKS0.js +1 -0
  23. package/dist/webui/assets/search-2R5sIdT8.js +1 -0
  24. package/dist/webui/assets/select-field-BCqNLDrJ.js +1 -0
  25. package/dist/webui/assets/select-zHgqMzLj.js +1 -0
  26. package/dist/webui/assets/settings-CMYjpTbZ.js +1 -0
  27. package/dist/webui/assets/submit-button-BtcnyggQ.js +1 -0
  28. package/dist/webui/assets/switch-G0W3uJVN.js +1 -0
  29. package/dist/webui/assets/switch-field-IBd9ORNq.js +1 -0
  30. package/dist/webui/assets/table-DvgJU7Gh.js +1 -0
  31. package/dist/webui/assets/test-tube-BIwmoM45.js +1 -0
  32. package/dist/webui/assets/text-field-DruSbGhy.js +1 -0
  33. package/dist/webui/assets/time-BSMZjmyW.js +1 -0
  34. package/dist/webui/assets/trackers-D-OpAe63.js +7 -0
  35. package/dist/webui/assets/use-form-validation-context-BkAfWAh0.js +1 -0
  36. package/dist/webui/assets/use-settings-form-submit-CDRh-E9U.js +2 -0
  37. package/dist/webui/assets/useQuery-A4Hv_4uX.js +1 -0
  38. package/dist/webui/index.html +13 -0
  39. package/node_modules/@cross-seed/shared/dist/configSchema.d.ts +261 -0
  40. package/node_modules/@cross-seed/shared/dist/configSchema.d.ts.map +1 -0
  41. package/node_modules/@cross-seed/shared/dist/configSchema.js +53 -0
  42. package/node_modules/@cross-seed/shared/dist/configSchema.js.map +1 -0
  43. package/node_modules/@cross-seed/shared/dist/constants.d.ts +122 -0
  44. package/node_modules/@cross-seed/shared/dist/constants.d.ts.map +1 -0
  45. package/node_modules/@cross-seed/shared/dist/constants.js +127 -0
  46. package/node_modules/@cross-seed/shared/dist/constants.js.map +1 -0
  47. package/node_modules/@cross-seed/shared/dist/tsconfig.tsbuildinfo +1 -0
  48. package/node_modules/@cross-seed/shared/dist/utils.d.ts +6 -0
  49. package/node_modules/@cross-seed/shared/dist/utils.d.ts.map +1 -0
  50. package/node_modules/@cross-seed/shared/dist/utils.js +9 -0
  51. package/node_modules/@cross-seed/shared/dist/utils.js.map +1 -0
  52. package/node_modules/@cross-seed/shared/package.json +22 -0
  53. package/package.json +35 -11
  54. package/dist/Result.js +0 -64
  55. package/dist/Result.js.map +0 -1
  56. package/dist/action.js +0 -693
  57. package/dist/action.js.map +0 -1
  58. package/dist/arr.js +0 -199
  59. package/dist/arr.js.map +0 -1
  60. package/dist/auth.js +0 -25
  61. package/dist/auth.js.map +0 -1
  62. package/dist/clients/Deluge.js +0 -698
  63. package/dist/clients/Deluge.js.map +0 -1
  64. package/dist/clients/QBittorrent.js +0 -785
  65. package/dist/clients/QBittorrent.js.map +0 -1
  66. package/dist/clients/RTorrent.js +0 -654
  67. package/dist/clients/RTorrent.js.map +0 -1
  68. package/dist/clients/TorrentClient.js +0 -272
  69. package/dist/clients/TorrentClient.js.map +0 -1
  70. package/dist/clients/Transmission.js +0 -404
  71. package/dist/clients/Transmission.js.map +0 -1
  72. package/dist/cmd.js +0 -196
  73. package/dist/cmd.js.map +0 -1
  74. package/dist/config.template.cjs +0 -353
  75. package/dist/config.template.cjs.map +0 -1
  76. package/dist/configSchema.js +0 -667
  77. package/dist/configSchema.js.map +0 -1
  78. package/dist/configuration.js +0 -82
  79. package/dist/configuration.js.map +0 -1
  80. package/dist/constants.js +0 -281
  81. package/dist/constants.js.map +0 -1
  82. package/dist/dataFiles.js +0 -208
  83. package/dist/dataFiles.js.map +0 -1
  84. package/dist/db.js +0 -216
  85. package/dist/db.js.map +0 -1
  86. package/dist/decide.js +0 -553
  87. package/dist/decide.js.map +0 -1
  88. package/dist/diff.js +0 -24
  89. package/dist/diff.js.map +0 -1
  90. package/dist/errors.js +0 -16
  91. package/dist/errors.js.map +0 -1
  92. package/dist/indexers.js +0 -180
  93. package/dist/indexers.js.map +0 -1
  94. package/dist/inject.js +0 -594
  95. package/dist/inject.js.map +0 -1
  96. package/dist/jobs.js +0 -146
  97. package/dist/jobs.js.map +0 -1
  98. package/dist/logger.js +0 -143
  99. package/dist/logger.js.map +0 -1
  100. package/dist/migrations/00-initialSchema.js +0 -30
  101. package/dist/migrations/00-initialSchema.js.map +0 -1
  102. package/dist/migrations/01-jobs.js +0 -12
  103. package/dist/migrations/01-jobs.js.map +0 -1
  104. package/dist/migrations/02-timestamps.js +0 -21
  105. package/dist/migrations/02-timestamps.js.map +0 -1
  106. package/dist/migrations/03-rateLimits.js +0 -14
  107. package/dist/migrations/03-rateLimits.js.map +0 -1
  108. package/dist/migrations/04-auth.js +0 -13
  109. package/dist/migrations/04-auth.js.map +0 -1
  110. package/dist/migrations/05-caps.js +0 -16
  111. package/dist/migrations/05-caps.js.map +0 -1
  112. package/dist/migrations/06-uniqueDecisions.js +0 -29
  113. package/dist/migrations/06-uniqueDecisions.js.map +0 -1
  114. package/dist/migrations/07-limits.js +0 -12
  115. package/dist/migrations/07-limits.js.map +0 -1
  116. package/dist/migrations/08-rss.js +0 -15
  117. package/dist/migrations/08-rss.js.map +0 -1
  118. package/dist/migrations/09-clientAndDataSearchees.js +0 -34
  119. package/dist/migrations/09-clientAndDataSearchees.js.map +0 -1
  120. package/dist/migrations/10-indexerNameAudioBookCaps.js +0 -18
  121. package/dist/migrations/10-indexerNameAudioBookCaps.js.map +0 -1
  122. package/dist/migrations/11-trackers.js +0 -38
  123. package/dist/migrations/11-trackers.js.map +0 -1
  124. package/dist/migrations/migrations.js +0 -31
  125. package/dist/migrations/migrations.js.map +0 -1
  126. package/dist/parseTorrent.js +0 -128
  127. package/dist/parseTorrent.js.map +0 -1
  128. package/dist/pipeline.js +0 -527
  129. package/dist/pipeline.js.map +0 -1
  130. package/dist/preFilter.js +0 -250
  131. package/dist/preFilter.js.map +0 -1
  132. package/dist/pushNotifier.js +0 -137
  133. package/dist/pushNotifier.js.map +0 -1
  134. package/dist/runtimeConfig.js +0 -11
  135. package/dist/runtimeConfig.js.map +0 -1
  136. package/dist/searchee.js +0 -658
  137. package/dist/searchee.js.map +0 -1
  138. package/dist/server.js +0 -456
  139. package/dist/server.js.map +0 -1
  140. package/dist/startup.js +0 -203
  141. package/dist/startup.js.map +0 -1
  142. package/dist/torrent.js +0 -637
  143. package/dist/torrent.js.map +0 -1
  144. package/dist/torznab.js +0 -786
  145. package/dist/torznab.js.map +0 -1
  146. package/dist/utils.js +0 -637
  147. package/dist/utils.js.map +0 -1
package/dist/inject.js DELETED
@@ -1,594 +0,0 @@
1
- import chalk from "chalk";
2
- import { stat, unlink } from "fs/promises";
3
- import ms from "ms";
4
- import { copyFile } from "fs/promises";
5
- import path, { basename } from "path";
6
- import { performActionWithoutMutex } from "./action.js";
7
- import { byClientHostPriority, waitForTorrentToComplete, } from "./clients/TorrentClient.js";
8
- import { appDir } from "./configuration.js";
9
- import { Decision, InjectionResult, isAnyMatchedDecision, MediaType, SaveResult, TORRENT_CACHE_FOLDER, UNKNOWN_TRACKER, VIDEO_DISC_EXTENSIONS, } from "./constants.js";
10
- import { assessCandidate } from "./decide.js";
11
- import { getHostToNameMap } from "./indexers.js";
12
- import { Label, logger } from "./logger.js";
13
- import { findAllSearchees } from "./pipeline.js";
14
- import { findBlockedStringInReleaseMaybe, logFilterReason, } from "./preFilter.js";
15
- import { sendResultsNotification } from "./pushNotifier.js";
16
- import { resultOf, resultOfErr } from "./Result.js";
17
- import { getRuntimeConfig } from "./runtimeConfig.js";
18
- import { createEnsembleSearchees, createSearcheeFromMetafile, getMediaType, } from "./searchee.js";
19
- import { findAllTorrentFilesInDir, getTorrentSavePath, parseMetadataFromFilename, parseTorrentFromPath, } from "./torrent.js";
20
- import { areMediaTitlesSimilar, comparing, exists, findFallback, formatAsList, getLogString, hasExt, humanReadableDate, isTruthy, Mutex, sanitizeInfoHash, withMutex, } from "./utils.js";
21
- function getTorrentFilePathLog(torrentFilePath) {
22
- const { infoHash } = parseMetadataFromFilename(basename(torrentFilePath));
23
- return infoHash
24
- ? chalk.bold.magenta(torrentFilePath.replace(infoHash, sanitizeInfoHash(infoHash)))
25
- : chalk.bold.magenta(torrentFilePath);
26
- }
27
- async function deleteTorrentFileIfSafe(torrentFilePath) {
28
- const filePathLog = getTorrentFilePathLog(torrentFilePath);
29
- const { tracker, name, mediaType } = parseMetadataFromFilename(basename(torrentFilePath));
30
- // we are confident cross-seed created the torrent,
31
- // or it is intended for use with cross-seed
32
- const isSafeToDelete = tracker && name && mediaType;
33
- if (!isSafeToDelete) {
34
- logger.warn({
35
- label: Label.INJECT,
36
- message: `Will not delete ${filePathLog}: missing metadata from filename`,
37
- });
38
- return;
39
- }
40
- logger.verbose({
41
- label: Label.INJECT,
42
- message: `Deleting ${filePathLog}`,
43
- });
44
- try {
45
- await unlink(torrentFilePath);
46
- }
47
- catch (e) {
48
- if (e.code !== "ENOENT") {
49
- logger.error({
50
- label: Label.INJECT,
51
- message: `Failed to delete ${filePathLog}: ${e.message}`,
52
- });
53
- logger.debug(e);
54
- }
55
- }
56
- }
57
- async function deleteTorrentFileIfComplete(torrentFilePath, client, infoHash) {
58
- if (await waitForTorrentToComplete(client, infoHash)) {
59
- await deleteTorrentFileIfSafe(torrentFilePath);
60
- }
61
- else {
62
- logger.warn({
63
- label: Label.INJECT,
64
- message: `Will not delete ${getTorrentFilePathLog(torrentFilePath)}: torrent is incomplete`,
65
- });
66
- }
67
- }
68
- async function whichSearcheesMatchTorrent(meta, searchees, blockList, ignoreTitles) {
69
- const isSimilar = (searchee, meta) => areMediaTitlesSimilar(searchee.title, meta.title) ||
70
- areMediaTitlesSimilar(searchee.title, meta.name) ||
71
- areMediaTitlesSimilar(searchee.name, meta.name) ||
72
- areMediaTitlesSimilar(searchee.name, meta.title);
73
- let foundBlocked = false;
74
- let fuzzyFail = false;
75
- const matches = [];
76
- for (const searchee of searchees) {
77
- const { decision } = await assessCandidate(meta, searchee, new Set(), []);
78
- if (!isAnyMatchedDecision(decision))
79
- continue;
80
- const blockedNote = findBlockedStringInReleaseMaybe(searchee, blockList);
81
- if (blockedNote) {
82
- logFilterReason(`it matches the blocklist: ${blockedNote}`, searchee, getMediaType(searchee));
83
- foundBlocked = true;
84
- continue;
85
- }
86
- if (!isSimilar(searchee, meta)) {
87
- if (ignoreTitles) {
88
- logger.warn({
89
- label: Label.INJECT,
90
- message: `Ignoring title mismatch for ${getLogString(meta, chalk.bold.white)} with ${getLogString(searchee, chalk.bold.white)}`,
91
- });
92
- }
93
- else {
94
- logger.warn({
95
- label: Label.INJECT,
96
- message: `Skipping match for ${getLogString(meta, chalk.bold.white)} with ${getLogString(searchee, chalk.bold.white)} due to title mismatch (use "${chalk.bold.white("cross-seed inject --ignore-titles")}" if this is an erroneous rejection)`,
97
- });
98
- fuzzyFail = true;
99
- continue;
100
- }
101
- }
102
- matches.push({ searchee, decision });
103
- }
104
- /**
105
- * sort by client priority first for consistency, then
106
- * full matches, then size only matches, then partial matches
107
- * torrent, then data, then virtual
108
- * prefer more files for partials
109
- */
110
- matches.sort(comparing((match) => byClientHostPriority(match.searchee.clientHost), (match) =>
111
- // indexOf returns -1 for not found
112
- -[Decision.MATCH_SIZE_ONLY, Decision.MATCH].indexOf(match.decision), (match) => !match.searchee.infoHash, (match) => !match.searchee.path, (match) => -match.searchee.files.length));
113
- return { matches, foundBlocked, fuzzyFail };
114
- }
115
- async function injectInitialAction(meta, matches, tracker) {
116
- let client;
117
- const clientMatches = [];
118
- let injectionResult = InjectionResult.FAILURE;
119
- let matchedSearchee;
120
- let matchedDecision;
121
- let destinationDir;
122
- let linkedNewFiles = false;
123
- for (const { searchee, decision } of matches) {
124
- const res = await performActionWithoutMutex(meta, decision, searchee, tracker, client);
125
- const actionResult = res.actionResult;
126
- clientMatches.push({ searchee, decision, actionResult });
127
- if (actionResult === InjectionResult.FAILURE) {
128
- if (res.linkedNewFiles)
129
- break; // Since we couldn't unlink, process with the next job
130
- continue;
131
- }
132
- if (actionResult === SaveResult.SAVED || !res.client)
133
- continue;
134
- if (res.linkedNewFiles)
135
- linkedNewFiles = true;
136
- if (injectionResult === InjectionResult.SUCCESS)
137
- continue;
138
- if (actionResult === InjectionResult.ALREADY_EXISTS) {
139
- client = res.client;
140
- destinationDir = res.destinationDir;
141
- injectionResult = actionResult;
142
- continue;
143
- }
144
- if (actionResult === InjectionResult.TORRENT_NOT_COMPLETE) {
145
- if (injectionResult === InjectionResult.ALREADY_EXISTS)
146
- continue;
147
- client = res.client;
148
- injectionResult = actionResult;
149
- continue;
150
- }
151
- client = res.client;
152
- destinationDir = res.destinationDir;
153
- injectionResult = InjectionResult.SUCCESS;
154
- matchedSearchee = searchee;
155
- matchedDecision = decision;
156
- }
157
- return {
158
- client,
159
- clientMatches,
160
- injectionResult,
161
- matchedSearchee,
162
- matchedDecision,
163
- destinationDir,
164
- linkedNewFiles,
165
- };
166
- }
167
- function injectionFailed({ progress, injectionResult, summary, filePathLog, }) {
168
- logger.error({
169
- label: Label.INJECT,
170
- message: `${progress} Failed to inject ${filePathLog} - ${chalk.red(injectionResult)}`,
171
- });
172
- summary.FAILED++;
173
- }
174
- async function injectFromStalledTorrent({ meta, client, clientMatches, tracker, injectionResult, progress, filePathLog, }) {
175
- let injected = false;
176
- let linkedNewFiles = false;
177
- const stalledDecision = Decision.MATCH_PARTIAL; // Should always be considered partial
178
- for (const { searchee } of clientMatches) {
179
- const searcheeLog = getLogString(searchee, chalk.bold.white);
180
- const res = await performActionWithoutMutex(meta, stalledDecision, searchee, tracker, client, { onlyCompleted: false });
181
- if (res.actionResult === SaveResult.SAVED ||
182
- res.actionResult === InjectionResult.TORRENT_NOT_COMPLETE) {
183
- continue; // Not possible
184
- }
185
- linkedNewFiles = res.linkedNewFiles;
186
- if (res.actionResult === InjectionResult.FAILURE) {
187
- logger.error({
188
- label: Label.INJECT,
189
- message: `${progress} Failed to inject ${filePathLog} using stalled source ${searcheeLog} - ${chalk.yellow(injectionResult)}`,
190
- });
191
- continue;
192
- }
193
- if (res.actionResult === InjectionResult.ALREADY_EXISTS)
194
- continue;
195
- logger.warn({
196
- label: Label.INJECT,
197
- message: `${progress} Injected ${filePathLog} using stalled source ${searcheeLog}, you will need to resume or remove from client - ${chalk.green(injectionResult)}`,
198
- });
199
- injected = true;
200
- }
201
- if (injected)
202
- return;
203
- if (!(await client.isTorrentInClient(meta.infoHash)).orElse(false))
204
- return;
205
- if (linkedNewFiles) {
206
- logger.info({
207
- label: Label.INJECT,
208
- message: `${progress} Rechecking ${filePathLog} as new files were linked - ${chalk.green(injectionResult)}`,
209
- });
210
- }
211
- else {
212
- logger.warn({
213
- label: Label.INJECT,
214
- message: `${progress} No new files linked for ${filePathLog}, resume or remove from client - ${chalk.yellow(injectionResult)}`,
215
- });
216
- }
217
- }
218
- async function injectionTorrentNotComplete(injectionAftermath) {
219
- const { progress, torrentFilePath, injectionResult, summary, filePathLog } = injectionAftermath;
220
- const { linkDirs } = getRuntimeConfig();
221
- if (!linkDirs.length ||
222
- (await stat(torrentFilePath)).mtimeMs >= Date.now() - ms("1 day")) {
223
- // Normal case where source is likely still downloading
224
- logger.warn({
225
- label: Label.INJECT,
226
- message: `${progress} Unable to inject ${filePathLog} - ${chalk.yellow(injectionResult)}`,
227
- });
228
- }
229
- else {
230
- // Since source is stalled, add to client paused so user can resume later if desired
231
- // Try linking all possible matches as they may have different files
232
- await injectFromStalledTorrent(injectionAftermath);
233
- }
234
- summary.INCOMPLETE_SEARCHEES++;
235
- }
236
- async function injectionAlreadyExists({ progress, torrentFilePath, client, clientMatches, injectionResult, summary, linkedNewFiles, meta, filePathLog, }) {
237
- const isChecking = (await client.isTorrentChecking(meta.infoHash)).orElse(false);
238
- let isComplete = (await client.isTorrentComplete(meta.infoHash)).orElse(false);
239
- const decision = findFallback(clientMatches, [Decision.MATCH, Decision.MATCH_SIZE_ONLY], (match, decision) => match.decision === decision &&
240
- match.actionResult === InjectionResult.ALREADY_EXISTS)?.decision ?? Decision.MATCH_PARTIAL;
241
- if (linkedNewFiles) {
242
- logger.info({
243
- label: Label.INJECT,
244
- message: `${progress} Rechecking ${filePathLog} as new files were linked - ${chalk.green(injectionResult)}`,
245
- });
246
- }
247
- else if (isChecking) {
248
- logger.info({
249
- label: Label.INJECT,
250
- message: `${progress} ${filePathLog} is being checked by client - ${chalk.green(injectionResult)}`,
251
- });
252
- summary.PROMISES.push(client.resumeInjection(meta, decision, {
253
- checkOnce: false,
254
- }));
255
- }
256
- else if (!isComplete && decision !== Decision.MATCH_PARTIAL) {
257
- const finalCheckTime = (await stat(torrentFilePath)).mtimeMs + ms("1 day");
258
- if (hasExt(meta.files, VIDEO_DISC_EXTENSIONS)) {
259
- logger.warn({
260
- label: Label.INJECT,
261
- message: `${progress} Skipping recheck for ${filePathLog}: VIDEO_DISC_EXTENSIONS - ${chalk.yellow(injectionResult)}`,
262
- });
263
- }
264
- else {
265
- logger.info({
266
- label: Label.INJECT,
267
- message: `${progress} Rechecking ${filePathLog} as it's not complete but has all files (final check at ${humanReadableDate(finalCheckTime)}) - ${chalk.yellow(injectionResult)}`,
268
- });
269
- await client.recheckTorrent(meta.infoHash);
270
- }
271
- summary.PROMISES.push(client.resumeInjection(meta, decision, {
272
- checkOnce: false,
273
- }));
274
- if (Date.now() >= finalCheckTime) {
275
- isComplete = true; // Prevent infinite recheck in rare case of corrupted cross seed
276
- }
277
- }
278
- else {
279
- if (isComplete) {
280
- logger.info({
281
- label: Label.INJECT,
282
- message: `${progress} ${filePathLog} - ${chalk.yellow(injectionResult)}`,
283
- });
284
- }
285
- else {
286
- logger.warn({
287
- label: Label.INJECT,
288
- message: `${progress} ${filePathLog} - ${chalk.yellow(injectionResult)} (incomplete)`,
289
- });
290
- summary.PROMISES.push(client.resumeInjection(meta, decision, {
291
- checkOnce: true,
292
- }));
293
- }
294
- }
295
- summary.ALREADY_EXISTS++;
296
- summary.INCOMPLETE_CANDIDATES += isComplete ? 0 : 1;
297
- if (isComplete) {
298
- await deleteTorrentFileIfSafe(torrentFilePath);
299
- }
300
- else {
301
- summary.PROMISES.push(deleteTorrentFileIfComplete(torrentFilePath, client, meta.infoHash));
302
- }
303
- }
304
- function injectionSuccess({ progress, torrentFilePath, client, injectionResult, summary, matchedSearchee, matchedDecision, meta, tracker, filePathLog, destinationDir, }, searchees) {
305
- const { useClientTorrents } = getRuntimeConfig();
306
- logger.info({
307
- label: Label.INJECT,
308
- message: `${progress} Injected ${filePathLog} - ${chalk.green(injectionResult)}`,
309
- });
310
- sendResultsNotification(matchedSearchee, [
311
- [
312
- { decision: matchedDecision, metafile: meta },
313
- tracker,
314
- injectionResult,
315
- ],
316
- ]);
317
- summary.INJECTED++;
318
- if (matchedDecision === Decision.MATCH_PARTIAL) {
319
- summary.PARTIAL_MATCHES++;
320
- }
321
- else {
322
- summary.FULL_MATCHES++;
323
- }
324
- summary.PROMISES.push(deleteTorrentFileIfComplete(torrentFilePath, client, meta.infoHash));
325
- const res = createSearcheeFromMetafile(meta);
326
- if (res.isOk()) {
327
- searchees.push(useClientTorrents
328
- ? {
329
- ...res.unwrap(),
330
- label: Label.INJECT,
331
- clientHost: client.clientHost,
332
- savePath: destinationDir,
333
- }
334
- : { ...res.unwrap(), label: Label.INJECT });
335
- }
336
- }
337
- async function loadMetafile(torrentFilePath, progress, summary) {
338
- const filePathLog = getTorrentFilePathLog(torrentFilePath);
339
- let meta;
340
- try {
341
- meta = await parseTorrentFromPath(torrentFilePath);
342
- }
343
- catch (e) {
344
- logger.error({
345
- label: Label.INJECT,
346
- message: `${progress} Failed to parse ${filePathLog}: ${e.message}`,
347
- });
348
- logger.debug(e);
349
- return resultOfErr("FAILED_TO_PARSE");
350
- }
351
- const { tracker: trackerFromFilename } = parseMetadataFromFilename(basename(torrentFilePath));
352
- if (trackerFromFilename) {
353
- return resultOf({ meta, tracker: trackerFromFilename });
354
- }
355
- summary.FOUND_BAD_FORMAT = true;
356
- const hostToName = await getHostToNameMap();
357
- const trackerHost = meta.trackers.find((h) => hostToName.has(h));
358
- if (trackerHost) {
359
- return resultOf({ meta, tracker: hostToName.get(trackerHost) });
360
- }
361
- return resultOf({ meta, tracker: UNKNOWN_TRACKER });
362
- }
363
- async function injectSavedTorrent(progress, torrentFilePath, summary, searchees, ignoreTitles) {
364
- const { blockList } = getRuntimeConfig();
365
- const metafileResult = await loadMetafile(torrentFilePath, progress, summary);
366
- if (metafileResult.isErr())
367
- return;
368
- const { meta, tracker } = metafileResult.unwrap();
369
- const filePathLog = getTorrentFilePathLog(torrentFilePath);
370
- const metaBlockedString = findBlockedStringInReleaseMaybe(meta, blockList);
371
- if (metaBlockedString) {
372
- logger.warn({
373
- label: Label.INJECT,
374
- message: `${progress} ${filePathLog} ${chalk.yellow(`is in the blockList: ${metaBlockedString}`)}`,
375
- });
376
- summary.BLOCKED++;
377
- return;
378
- }
379
- const { matches, foundBlocked, fuzzyFail } = await whichSearcheesMatchTorrent(meta, searchees, blockList, ignoreTitles);
380
- if (!matches.length) {
381
- if (foundBlocked) {
382
- logger.warn({
383
- label: Label.INJECT,
384
- message: `${progress} ${filePathLog} ${chalk.yellow(`has all matches in the blockList`)}`,
385
- });
386
- summary.BLOCKED++;
387
- }
388
- else {
389
- logger.error({
390
- label: Label.INJECT,
391
- message: `${progress} ${filePathLog} ${chalk.red("has no matches")}`,
392
- });
393
- summary.UNMATCHED++;
394
- }
395
- if (fuzzyFail) {
396
- logger.warn({
397
- label: Label.INJECT,
398
- message: `Will not delete ${filePathLog}: is has no matches due to title mismatch`,
399
- });
400
- }
401
- else {
402
- await deleteTorrentFileIfSafe(torrentFilePath);
403
- }
404
- return;
405
- }
406
- const { client, clientMatches, injectionResult, matchedSearchee, matchedDecision, destinationDir, linkedNewFiles, } = await injectInitialAction(meta, matches, tracker);
407
- const injectionAftermath = {
408
- progress,
409
- torrentFilePath,
410
- client,
411
- injectionResult,
412
- summary,
413
- meta,
414
- tracker,
415
- clientMatches,
416
- matchedSearchee,
417
- matchedDecision,
418
- destinationDir,
419
- linkedNewFiles,
420
- filePathLog,
421
- };
422
- switch (injectionResult) {
423
- case InjectionResult.SUCCESS:
424
- injectionSuccess(injectionAftermath, searchees);
425
- break;
426
- case InjectionResult.FAILURE:
427
- injectionFailed(injectionAftermath);
428
- break;
429
- case InjectionResult.ALREADY_EXISTS:
430
- await injectionAlreadyExists(injectionAftermath);
431
- break;
432
- case InjectionResult.TORRENT_NOT_COMPLETE:
433
- await injectionTorrentNotComplete(injectionAftermath);
434
- break;
435
- }
436
- }
437
- function logInjectSummary(summary, flatLinking) {
438
- const incompleteMsg = `${chalk.bold.yellow(summary.ALREADY_EXISTS)} existed in client${summary.INCOMPLETE_CANDIDATES
439
- ? chalk.dim(` (${summary.INCOMPLETE_CANDIDATES} were incomplete)`)
440
- : ""}`;
441
- const resultMsg = formatAsList([
442
- `Injected ${chalk.bold.green(summary.INJECTED)}/${chalk.bold.white(summary.TOTAL)} torrents`,
443
- summary.FULL_MATCHES &&
444
- `${chalk.bold.green(summary.FULL_MATCHES)} were full matches`,
445
- summary.PARTIAL_MATCHES &&
446
- `${chalk.bold.yellow(summary.PARTIAL_MATCHES)} were partial matches`,
447
- summary.INCOMPLETE_SEARCHEES &&
448
- `${chalk.bold.yellow(summary.INCOMPLETE_SEARCHEES)} had incomplete sources`,
449
- summary.ALREADY_EXISTS && incompleteMsg,
450
- summary.BLOCKED &&
451
- `${chalk.bold.yellow(summary.BLOCKED)} were possibly blocklisted`,
452
- summary.FAILED &&
453
- `${chalk.bold.red(summary.FAILED)} failed to inject`,
454
- summary.UNMATCHED &&
455
- `${chalk.bold.red(summary.UNMATCHED)} had no matches`,
456
- ].filter(isTruthy), { sort: false, type: "unit" });
457
- logger.info({ label: Label.INJECT, message: chalk.cyan(resultMsg) });
458
- if (summary.UNMATCHED > 0) {
459
- logger.info({
460
- label: Label.INJECT,
461
- message: `Use "${chalk.bold.white("cross-seed diff")}" to get the reasons two torrents are not considered matches`,
462
- });
463
- }
464
- if (summary.FOUND_BAD_FORMAT && !flatLinking) {
465
- logger.warn({
466
- label: Label.INJECT,
467
- message: `Some torrents could be linked to linkDir/${UNKNOWN_TRACKER} - follow .torrent naming format in the docs to avoid this`,
468
- });
469
- }
470
- }
471
- function createSummary(total) {
472
- return {
473
- TOTAL: total,
474
- INJECTED: 0,
475
- FULL_MATCHES: 0,
476
- PARTIAL_MATCHES: 0,
477
- BLOCKED: 0,
478
- ALREADY_EXISTS: 0,
479
- INCOMPLETE_CANDIDATES: 0,
480
- INCOMPLETE_SEARCHEES: 0,
481
- FAILED: 0,
482
- UNMATCHED: 0,
483
- FOUND_BAD_FORMAT: false,
484
- PROMISES: [],
485
- };
486
- }
487
- export async function injectSavedTorrents() {
488
- const { flatLinking, ignoreTitles, injectDir, outputDir } = getRuntimeConfig();
489
- const targetDir = injectDir ?? outputDir;
490
- const targetDirLog = chalk.bold.magenta(targetDir);
491
- if (injectDir !== undefined) {
492
- logger.warn({
493
- label: Label.INJECT,
494
- message: `Manually injecting torrents performs minimal filtering which slightly increases chances of false positives, see the docs for more info`,
495
- });
496
- }
497
- if (ignoreTitles) {
498
- logger.warn({
499
- label: Label.INJECT,
500
- message: `Ignoring torrent titles when looking for matches, this may result in false positives`,
501
- });
502
- }
503
- const torrentFilePaths = await findAllTorrentFilesInDir(targetDir);
504
- if (torrentFilePaths.length === 0) {
505
- logger.info({
506
- label: Label.INJECT,
507
- message: `No torrent files are awaiting injection in ${targetDirLog}`,
508
- });
509
- return;
510
- }
511
- logger.info({
512
- label: Label.INJECT,
513
- message: `Found ${chalk.bold.white(torrentFilePaths.length)} torrent file(s) to inject in ${targetDirLog}`,
514
- });
515
- const summary = createSummary(torrentFilePaths.length);
516
- const realSearchees = await findAllSearchees(Label.INJECT);
517
- const ensembleSearchees = await createEnsembleSearchees(realSearchees, {
518
- useFilters: false,
519
- });
520
- const searchees = [...realSearchees, ...ensembleSearchees];
521
- for (const [i, torrentFilePath] of torrentFilePaths.entries()) {
522
- const progress = chalk.blue(`(${i + 1}/${torrentFilePaths.length})`);
523
- await withMutex(Mutex.CLIENT_INJECTION, { useQueue: true }, async () => {
524
- return injectSavedTorrent(progress, torrentFilePath, summary, searchees, ignoreTitles ?? false);
525
- });
526
- }
527
- logInjectSummary(summary, flatLinking);
528
- if (injectDir !== undefined) {
529
- logger.info({
530
- label: Label.INJECT,
531
- message: `Waiting on post-injection tasks to complete...`,
532
- });
533
- await Promise.all(summary.PROMISES);
534
- }
535
- }
536
- export async function restoreFromTorrentCache() {
537
- const { outputDir } = getRuntimeConfig();
538
- const torrentFilePaths = await findAllTorrentFilesInDir(path.join(appDir(), TORRENT_CACHE_FOLDER));
539
- if (torrentFilePaths.length === 0) {
540
- logger.info("No .torrent files found to restore from cache");
541
- return;
542
- }
543
- logger.info(`Found ${chalk.bold.white(torrentFilePaths.length)} .torrent files to restore from cache`);
544
- let copied = 0;
545
- const copyFromTorrentCache = async (torrentFilePath, destPath, infoHash) => {
546
- if (await exists(destPath))
547
- return;
548
- await copyFile(torrentFilePath, destPath);
549
- copied++;
550
- if (copied % 1000 === 0) {
551
- const destPathLog = infoHash
552
- ? destPath.replace(infoHash, sanitizeInfoHash(infoHash))
553
- : destPath;
554
- logger.info(`${chalk.blue(`(${copied}/${torrentFilePaths.length})`)} ${chalk.bold.magenta(destPathLog)}`);
555
- }
556
- };
557
- const hostToName = await getHostToNameMap();
558
- let numMissingMetadata = 0;
559
- for (const torrentFilePath of torrentFilePaths) {
560
- try {
561
- try {
562
- const meta = await parseTorrentFromPath(torrentFilePath);
563
- const infoHash = meta.infoHash;
564
- const trackerHost = meta.trackers.find((h) => hostToName.has(h));
565
- const destPath = getTorrentSavePath(meta, getMediaType(meta), trackerHost
566
- ? hostToName.get(trackerHost)
567
- : UNKNOWN_TRACKER, outputDir, { cached: true });
568
- await copyFromTorrentCache(torrentFilePath, destPath, infoHash);
569
- if (!trackerHost)
570
- numMissingMetadata++;
571
- }
572
- catch (e) {
573
- logger.error(chalk.bold.red(`Failure when processing ${torrentFilePath}, filename metadata will be unknown: ${e.message}`));
574
- logger.error(e);
575
- const baseName = basename(torrentFilePath);
576
- const infoHash = baseName.split(".")[0];
577
- const destFileName = `[${MediaType.OTHER}][${UNKNOWN_TRACKER}]${baseName}`;
578
- const destPath = path.join(outputDir, destFileName);
579
- await copyFromTorrentCache(torrentFilePath, destPath, infoHash);
580
- numMissingMetadata++;
581
- }
582
- }
583
- catch (e) {
584
- logger.error(chalk.bold.red(`Failed to copy ${torrentFilePath}: ${e.message}`));
585
- logger.error(e);
586
- }
587
- }
588
- logger.info(`Copied ${chalk.bold.green(copied)}/${chalk.bold.white(torrentFilePaths.length)} .torrent files from cache to outputDir, run "${chalk.bold.white("cross-seed inject")}" to inject into client using your dataDirs`);
589
- if (numMissingMetadata) {
590
- logger.info(`Copied ${chalk.bold.yellow(numMissingMetadata)} .torrent files without filename metadata`);
591
- }
592
- logger.info(chalk.bold.yellow("Some of the restored torrents may be unregistered, you will need to remove them from your client after injecting"));
593
- }
594
- //# sourceMappingURL=inject.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"inject.js","sourceRoot":"","sources":["../src/inject.ts"],"names":[],"mappings":"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"}