cross-seed 6.0.0-2 → 6.0.0-20

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 (60) hide show
  1. package/dist/Result.js +17 -11
  2. package/dist/Result.js.map +1 -1
  3. package/dist/action.js +141 -45
  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 +121 -61
  8. package/dist/clients/Deluge.js.map +1 -1
  9. package/dist/clients/QBittorrent.js +70 -64
  10. package/dist/clients/QBittorrent.js.map +1 -1
  11. package/dist/clients/RTorrent.js +9 -9
  12. package/dist/clients/RTorrent.js.map +1 -1
  13. package/dist/clients/TorrentClient.js.map +1 -1
  14. package/dist/clients/Transmission.js +9 -9
  15. package/dist/clients/Transmission.js.map +1 -1
  16. package/dist/cmd.js +11 -7
  17. package/dist/cmd.js.map +1 -1
  18. package/dist/config.template.cjs +68 -36
  19. package/dist/config.template.cjs.map +1 -1
  20. package/dist/configSchema.js +42 -8
  21. package/dist/configSchema.js.map +1 -1
  22. package/dist/configuration.js.map +1 -1
  23. package/dist/constants.js +89 -6
  24. package/dist/constants.js.map +1 -1
  25. package/dist/dataFiles.js +4 -5
  26. package/dist/dataFiles.js.map +1 -1
  27. package/dist/decide.js +128 -90
  28. package/dist/decide.js.map +1 -1
  29. package/dist/errors.js +5 -2
  30. package/dist/errors.js.map +1 -1
  31. package/dist/indexers.js +31 -4
  32. package/dist/indexers.js.map +1 -1
  33. package/dist/jobs.js +2 -0
  34. package/dist/jobs.js.map +1 -1
  35. package/dist/logger.js +18 -5
  36. package/dist/logger.js.map +1 -1
  37. package/dist/migrations/05-caps.js +16 -0
  38. package/dist/migrations/05-caps.js.map +1 -0
  39. package/dist/migrations/migrations.js +9 -1
  40. package/dist/migrations/migrations.js.map +1 -1
  41. package/dist/pipeline.js +165 -81
  42. package/dist/pipeline.js.map +1 -1
  43. package/dist/preFilter.js +89 -36
  44. package/dist/preFilter.js.map +1 -1
  45. package/dist/pushNotifier.js +2 -1
  46. package/dist/pushNotifier.js.map +1 -1
  47. package/dist/runtimeConfig.js.map +1 -1
  48. package/dist/searchee.js +149 -10
  49. package/dist/searchee.js.map +1 -1
  50. package/dist/server.js +10 -10
  51. package/dist/server.js.map +1 -1
  52. package/dist/startup.js +2 -0
  53. package/dist/startup.js.map +1 -1
  54. package/dist/torrent.js +86 -28
  55. package/dist/torrent.js.map +1 -1
  56. package/dist/torznab.js +250 -88
  57. package/dist/torznab.js.map +1 -1
  58. package/dist/utils.js +84 -21
  59. package/dist/utils.js.map +1 -1
  60. package/package.json +3 -1
@@ -3,8 +3,16 @@ import jobs from "./01-jobs.js";
3
3
  import timestamps from "./02-timestamps.js";
4
4
  import rateLimits from "./03-rateLimits.js";
5
5
  import auth from "./04-auth.js";
6
+ import caps from "./05-caps.js";
6
7
  export const migrations = {
7
- getMigrations: () => Promise.resolve([initialSchema, jobs, timestamps, rateLimits, auth]),
8
+ getMigrations: () => Promise.resolve([
9
+ initialSchema,
10
+ jobs,
11
+ timestamps,
12
+ rateLimits,
13
+ auth,
14
+ caps,
15
+ ]),
8
16
  getMigrationName: (migration) => migration.name,
9
17
  getMigration: (migration) => migration,
10
18
  };
@@ -1 +1 @@
1
- {"version":3,"file":"migrations.js","sourceRoot":"","sources":["../../src/migrations/migrations.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,uBAAuB,CAAC;AAClD,OAAO,IAAI,MAAM,cAAc,CAAC;AAChC,OAAO,UAAU,MAAM,oBAAoB,CAAC;AAC5C,OAAO,UAAU,MAAM,oBAAoB,CAAC;AAC5C,OAAO,IAAI,MAAM,cAAc,CAAC;AAEhC,MAAM,CAAC,MAAM,UAAU,GAAG;IACzB,aAAa,EAAE,GAAG,EAAE,CACnB,OAAO,CAAC,OAAO,CAAC,CAAC,aAAa,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC;IACrE,gBAAgB,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI;IAC/C,YAAY,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS;CACtC,CAAC"}
1
+ {"version":3,"file":"migrations.js","sourceRoot":"","sources":["../../src/migrations/migrations.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,uBAAuB,CAAC;AAClD,OAAO,IAAI,MAAM,cAAc,CAAC;AAChC,OAAO,UAAU,MAAM,oBAAoB,CAAC;AAC5C,OAAO,UAAU,MAAM,oBAAoB,CAAC;AAC5C,OAAO,IAAI,MAAM,cAAc,CAAC;AAChC,OAAO,IAAI,MAAM,cAAc,CAAC;AAEhC,MAAM,CAAC,MAAM,UAAU,GAAG;IACzB,aAAa,EAAE,GAAG,EAAE,CACnB,OAAO,CAAC,OAAO,CAAC;QACf,aAAa;QACb,IAAI;QACJ,UAAU;QACV,UAAU;QACV,IAAI;QACJ,IAAI;KACJ,CAAC;IACH,gBAAgB,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI;IAC/C,YAAY,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS;CACtC,CAAC"}
package/dist/pipeline.js CHANGED
@@ -3,19 +3,20 @@ import fs from "fs";
3
3
  import { zip } from "lodash-es";
4
4
  import ms from "ms";
5
5
  import { performAction, performActions } from "./action.js";
6
- import { Decision, InjectionResult, } from "./constants.js";
6
+ import { Decision, InjectionResult, isAnyMatchedDecision, SaveResult, } from "./constants.js";
7
7
  import { findPotentialNestedRoots, findSearcheesFromAllDataDirs, } from "./dataFiles.js";
8
8
  import { db } from "./db.js";
9
9
  import { assessCandidate } from "./decide.js";
10
10
  import { IndexerStatus, updateIndexerStatus, updateSearchTimestamps, } from "./indexers.js";
11
11
  import { Label, logger } from "./logger.js";
12
- import { filterByContent, filterDupes, filterTimestamps } from "./preFilter.js";
12
+ import { filterByContent, filterDupesFromSimilar, filterTimestamps, } from "./preFilter.js";
13
13
  import { sendResultsNotification } from "./pushNotifier.js";
14
+ import { isOk } from "./Result.js";
14
15
  import { getRuntimeConfig } from "./runtimeConfig.js";
15
16
  import { createSearcheeFromMetafile, createSearcheeFromPath, createSearcheeFromTorrentFile, } from "./searchee.js";
16
- import { getInfoHashesToExclude, getTorrentByCriteria, getTorrentByFuzzyName, indexNewTorrents, loadTorrentDirLight, } from "./torrent.js";
17
- import { queryRssFeeds, searchTorznab } from "./torznab.js";
18
- import { filterAsync, isTruthy, stripExtension } from "./utils.js";
17
+ import { getInfoHashesToExclude, getTorrentByCriteria, getSimilarTorrentsByName, indexNewTorrents, loadTorrentDirLight, } from "./torrent.js";
18
+ import { getSearchString, queryRssFeeds, searchTorznab, } from "./torznab.js";
19
+ import { getLogString, isTruthy, wait } from "./utils.js";
19
20
  async function assessCandidates(candidates, searchee, hashesToExclude) {
20
21
  const assessments = [];
21
22
  for (const result of candidates) {
@@ -24,21 +25,15 @@ async function assessCandidates(candidates, searchee, hashesToExclude) {
24
25
  }
25
26
  return assessments;
26
27
  }
27
- async function findOnOtherSites(searchee, hashesToExclude) {
28
+ async function findOnOtherSites(searchee, hashesToExclude, cachedSearch, progress) {
28
29
  // make sure searchee is in database
29
30
  await db("searchee")
30
31
  .insert({ name: searchee.name })
31
32
  .onConflict("name")
32
33
  .ignore();
33
- let response;
34
- try {
35
- response = await searchTorznab(searchee);
36
- }
37
- catch (e) {
38
- logger.error(`error searching for ${searchee.name}`);
39
- logger.debug(e);
40
- return { searchedIndexers: 0, matches: 0 };
41
- }
34
+ const response = await searchTorznab(searchee, cachedSearch, progress);
35
+ const searchedIndexers = response.length - cachedSearch.indexerCandidates.length;
36
+ cachedSearch.indexerCandidates = response;
42
37
  const results = response.flatMap((e) => e.candidates.map((candidate) => ({
43
38
  ...candidate,
44
39
  indexerId: e.indexerId,
@@ -55,141 +50,230 @@ async function findOnOtherSites(searchee, hashesToExclude) {
55
50
  rateLimited: new Set(),
56
51
  notRateLimited: new Set(response.map((r) => r.indexerId)),
57
52
  });
58
- const matches = assessments.filter((e) => e.assessment.decision === Decision.MATCH ||
59
- e.assessment.decision === Decision.MATCH_SIZE_ONLY ||
60
- e.assessment.decision === Decision.MATCH_PARTIAL);
53
+ const matches = assessments.filter((e) => isAnyMatchedDecision(e.assessment.decision));
61
54
  const actionResults = await performActions(searchee, matches);
62
55
  if (actionResults.includes(InjectionResult.TORRENT_NOT_COMPLETE)) {
63
56
  // If the torrent is not complete, "cancel the search"
64
- return { matches: 0, searchedIndexers: 0 };
57
+ return { searchedIndexers: 0, matches: 0 };
65
58
  }
66
59
  await updateSearchTimestamps(searchee.name, Array.from(notRateLimited));
67
60
  await updateIndexerStatus(IndexerStatus.RATE_LIMITED, Date.now() + ms("1 hour"), Array.from(rateLimited));
68
61
  const zipped = zip(matches.map((m) => m.assessment), matches.map((m) => m.tracker), actionResults);
69
- sendResultsNotification(searchee, zipped, Label.SEARCH);
70
- return { matches: matches.length, searchedIndexers: response.length };
62
+ sendResultsNotification(searchee, zipped);
63
+ return { searchedIndexers, matches: matches.length };
71
64
  }
72
- async function findMatchesBatch(samples, hashesToExclude) {
65
+ async function findMatchesBatch(searchees, hashesToExclude) {
73
66
  const { delay } = getRuntimeConfig();
74
67
  let totalFound = 0;
75
- for (const [i, sample] of samples.entries()) {
68
+ let prevSearchTime = 0;
69
+ const cachedSearch = { q: null, indexerCandidates: [] };
70
+ for (const [i, searchee] of searchees.entries()) {
71
+ const progress = chalk.blue(`(${i + 1}/${searchees.length}) `);
76
72
  try {
77
- const sleep = new Promise((r) => setTimeout(r, delay * 1000));
78
- const progress = chalk.blue(`[${i + 1}/${samples.length}]`);
79
- const name = stripExtension(sample.name);
80
- logger.info("%s %s %s", progress, chalk.dim("Searching for"), name);
81
- const { matches, searchedIndexers } = await findOnOtherSites(sample, hashesToExclude);
73
+ const sleepTime = delay * 1000 - (Date.now() - prevSearchTime);
74
+ if (sleepTime > 0) {
75
+ await new Promise((r) => setTimeout(r, sleepTime));
76
+ }
77
+ const searchTime = Date.now();
78
+ const { searchedIndexers, matches } = await findOnOtherSites(searchee, hashesToExclude, cachedSearch, progress);
82
79
  totalFound += matches;
83
- // if all indexers were rate limited, don't sleep
80
+ // if all indexers were rate limited or cached, don't sleep
84
81
  if (searchedIndexers === 0)
85
82
  continue;
86
- await sleep;
83
+ prevSearchTime = searchTime;
87
84
  }
88
85
  catch (e) {
89
- logger.error(`error searching for ${sample.name}`);
86
+ const searcheeLog = getLogString(searchee, chalk.bold.white);
87
+ logger.error({
88
+ label: searchee.label,
89
+ message: `${progress}Error searching for ${searcheeLog}`,
90
+ });
90
91
  logger.debug(e);
91
92
  }
92
93
  }
93
94
  return totalFound;
94
95
  }
95
96
  export async function searchForLocalTorrentByCriteria(criteria) {
96
- const { maxDataDepth } = getRuntimeConfig();
97
- let searchees;
97
+ const { delay, maxDataDepth } = getRuntimeConfig();
98
+ let rawSearchees;
98
99
  if (criteria.path) {
99
100
  const searcheeResults = await Promise.all(findPotentialNestedRoots(criteria.path, maxDataDepth).map(createSearcheeFromPath));
100
- searchees = searcheeResults.map((t) => t.unwrapOrThrow());
101
+ rawSearchees = searcheeResults.filter(isOk).map((t) => t.unwrap());
101
102
  }
102
103
  else {
103
- searchees = [await getTorrentByCriteria(criteria)];
104
+ rawSearchees = [await getTorrentByCriteria(criteria)];
104
105
  }
106
+ const searchees = rawSearchees.map((searchee) => ({
107
+ ...searchee,
108
+ label: Label.WEBHOOK,
109
+ }));
105
110
  const hashesToExclude = await getInfoHashesToExclude();
106
- let matches = 0;
107
- for (let i = 0; i < searchees.length; i++) {
108
- if (!filterByContent(searchees[i]))
109
- return null;
110
- const foundOnOtherSites = await findOnOtherSites(searchees[i], hashesToExclude);
111
- matches += foundOnOtherSites.matches;
112
- }
113
- return matches;
111
+ let totalFound = 0;
112
+ let filtered = 0;
113
+ const cachedSearch = { q: null, indexerCandidates: [] };
114
+ for (const [i, searchee] of searchees.entries()) {
115
+ const progress = chalk.blue(`(${i + 1}/${searchees.length}) `);
116
+ try {
117
+ if (!filterByContent(searchee)) {
118
+ filtered++;
119
+ continue;
120
+ }
121
+ const sleep = wait(delay * 1000);
122
+ const { matches, searchedIndexers } = await findOnOtherSites(searchee, hashesToExclude, cachedSearch, progress);
123
+ totalFound += matches;
124
+ // if all indexers were rate limited, don't sleep
125
+ if (searchedIndexers === 0 || i === searchees.length - 1)
126
+ continue;
127
+ await sleep;
128
+ }
129
+ catch (e) {
130
+ const searcheeLog = getLogString(searchee, chalk.bold.white);
131
+ logger.error({
132
+ label: searchee.label,
133
+ message: `${progress}Error searching for ${searcheeLog}`,
134
+ });
135
+ logger.debug(e);
136
+ }
137
+ }
138
+ if (filtered === searchees.length)
139
+ return null;
140
+ return totalFound;
114
141
  }
115
- export async function checkNewCandidateMatch(candidate) {
116
- const meta = await getTorrentByFuzzyName(candidate.name);
117
- if (meta === null) {
142
+ export async function checkNewCandidateMatch(candidate, searcheeLabel) {
143
+ const candidateLog = `${candidate.name} from ${candidate.tracker}`;
144
+ const { keys, metas } = await getSimilarTorrentsByName(candidate.name);
145
+ const method = keys.length ? `[${keys}]` : "Fuse fallback";
146
+ if (!metas.length) {
118
147
  logger.verbose({
119
- label: Label.REVERSE_LOOKUP,
120
- message: `Did not find an existing entry for ${candidate.name}`,
148
+ label: searcheeLabel,
149
+ message: `Did not find an existing entry using ${method} for ${candidateLog}`,
121
150
  });
122
151
  return null;
123
152
  }
124
- const hashesToExclude = await getInfoHashesToExclude();
125
- if (!filterByContent(meta))
126
- return null;
127
- const searchee = createSearcheeFromMetafile(meta);
128
- // make sure searchee is in database
129
- await db("searchee")
130
- .insert({ name: searchee.name })
131
- .onConflict("name")
132
- .ignore();
133
- const assessment = await assessCandidate(candidate, searchee, hashesToExclude);
134
- if (assessment.decision !== Decision.MATCH &&
135
- assessment.decision !== Decision.MATCH_SIZE_ONLY &&
136
- assessment.decision !== Decision.MATCH_PARTIAL) {
153
+ const searchees = filterDupesFromSimilar(metas
154
+ .map(createSearcheeFromMetafile)
155
+ .map((searchee) => ({ ...searchee, label: searcheeLabel }))
156
+ .filter(filterByContent));
157
+ if (!searchees.length) {
158
+ logger.verbose({
159
+ label: searcheeLabel,
160
+ message: `No valid entries found using ${method} for ${candidateLog}`,
161
+ });
137
162
  return null;
138
163
  }
139
- const result = await performAction(assessment.metafile, assessment.decision, searchee, candidate.tracker);
140
- await sendResultsNotification(searchee, [[assessment, candidate.tracker, result]], Label.REVERSE_LOOKUP);
164
+ logger.verbose({
165
+ label: searcheeLabel,
166
+ message: `Unique entries [${searchees.map((m) => m.name)}] using ${method} for ${candidateLog}`,
167
+ });
168
+ const hashesToExclude = await getInfoHashesToExclude();
169
+ let result = null;
170
+ searchees.sort((a, b) => b.files.length - a.files.length);
171
+ for (const searchee of searchees) {
172
+ await db("searchee")
173
+ .insert({ name: searchee.name })
174
+ .onConflict("name")
175
+ .ignore();
176
+ const assessment = await assessCandidate(candidate, searchee, hashesToExclude);
177
+ if (!isAnyMatchedDecision(assessment.decision)) {
178
+ continue;
179
+ }
180
+ result = await performAction(assessment.metafile, assessment.decision, searchee, candidate.tracker);
181
+ sendResultsNotification(searchee, [
182
+ [assessment, candidate.tracker, result],
183
+ ]);
184
+ if (result === SaveResult.SAVED ||
185
+ result === InjectionResult.SUCCESS ||
186
+ result === InjectionResult.ALREADY_EXISTS) {
187
+ break;
188
+ }
189
+ }
141
190
  return result;
142
191
  }
143
- async function findSearchableTorrents() {
192
+ async function findSearchableTorrents(searcheeLabel) {
144
193
  const { torrents, dataDirs, torrentDir, searchLimit } = getRuntimeConfig();
145
- let allSearchees = [];
194
+ const rawSearchees = [];
146
195
  if (Array.isArray(torrents)) {
147
196
  const searcheeResults = await Promise.all(torrents.map(createSearcheeFromTorrentFile));
148
- allSearchees = searcheeResults
149
- .filter((t) => t.isOk())
150
- .map((t) => t.unwrapOrThrow());
197
+ rawSearchees.push(...searcheeResults.filter(isOk).map((r) => r.unwrap()));
151
198
  }
152
199
  else {
153
200
  if (typeof torrentDir === "string") {
154
- allSearchees.push(...(await loadTorrentDirLight(torrentDir)));
201
+ rawSearchees.push(...(await loadTorrentDirLight(torrentDir)));
155
202
  }
156
203
  if (Array.isArray(dataDirs)) {
157
204
  const searcheeResults = await Promise.all(findSearcheesFromAllDataDirs().map(createSearcheeFromPath));
158
- allSearchees.push(...searcheeResults
159
- .filter((t) => t.isOk())
160
- .map((t) => t.unwrapOrThrow()));
205
+ rawSearchees.push(...searcheeResults.filter(isOk).map((r) => r.unwrap()));
161
206
  }
162
207
  }
208
+ const allSearchees = rawSearchees.map((searchee) => ({
209
+ ...searchee,
210
+ label: searcheeLabel,
211
+ }));
163
212
  const hashesToExclude = allSearchees
164
213
  .map((t) => t.infoHash)
165
214
  .filter(isTruthy);
166
- let filteredTorrents = await filterAsync(filterDupes(allSearchees).filter(filterByContent), filterTimestamps);
215
+ // Group the exact same search queries together for easy cache use later
216
+ const grouping = new Map();
217
+ for (const searchee of allSearchees.filter(filterByContent)) {
218
+ const key = await getSearchString(searchee);
219
+ if (!grouping.has(key)) {
220
+ grouping.set(key, []);
221
+ }
222
+ grouping.get(key).push(searchee);
223
+ }
224
+ const keysToDelete = [];
225
+ for (const [key, groupedSearchees] of grouping) {
226
+ // If one searchee needs to be searched, use the candidates for all
227
+ const searchees = filterDupesFromSimilar(groupedSearchees);
228
+ const results = await Promise.all(searchees.map(filterTimestamps));
229
+ if (!results.some(isTruthy)) {
230
+ keysToDelete.push(key);
231
+ continue;
232
+ }
233
+ // Prefer infoHash
234
+ searchees.sort((a, b) => {
235
+ if (a.infoHash && !b.infoHash)
236
+ return -1;
237
+ if (!a.infoHash && b.infoHash)
238
+ return 1;
239
+ return 0;
240
+ });
241
+ // Sort by most number files (less chance of partial)
242
+ searchees.sort((a, b) => {
243
+ return b.files.length - a.files.length;
244
+ });
245
+ grouping.set(key, searchees);
246
+ }
247
+ for (const key of keysToDelete) {
248
+ grouping.delete(key);
249
+ }
250
+ let finalSearchees = Array.from(grouping.values()).flat();
167
251
  logger.info({
168
252
  label: Label.SEARCH,
169
- message: `Found ${allSearchees.length} torrents, ${filteredTorrents.length} suitable to search for matches`,
253
+ message: `Found ${allSearchees.length} torrents, ${finalSearchees.length} suitable to search for matches using ${grouping.size} unique queries`,
170
254
  });
171
- if (searchLimit && filteredTorrents.length > searchLimit) {
255
+ if (searchLimit && finalSearchees.length > searchLimit) {
172
256
  logger.info({
173
257
  label: Label.SEARCH,
174
258
  message: `Limited to ${searchLimit} searches`,
175
259
  });
176
- filteredTorrents = filteredTorrents.slice(0, searchLimit);
260
+ finalSearchees = finalSearchees.slice(0, searchLimit);
177
261
  }
178
- return { samples: filteredTorrents, hashesToExclude };
262
+ return { searchees: finalSearchees, hashesToExclude };
179
263
  }
180
264
  export async function main() {
181
265
  const { outputDir, linkDir } = getRuntimeConfig();
182
- const { samples, hashesToExclude } = await findSearchableTorrents();
266
+ const { searchees, hashesToExclude } = await findSearchableTorrents(Label.SEARCH);
183
267
  if (!fs.existsSync(outputDir)) {
184
268
  fs.mkdirSync(outputDir, { recursive: true });
185
269
  }
186
270
  if (linkDir && !fs.existsSync(linkDir)) {
187
271
  fs.mkdirSync(linkDir, { recursive: true });
188
272
  }
189
- const totalFound = await findMatchesBatch(samples, hashesToExclude);
273
+ const totalFound = await findMatchesBatch(searchees, hashesToExclude);
190
274
  logger.info({
191
275
  label: Label.SEARCH,
192
- message: chalk.cyan(`Found ${chalk.bold.white(totalFound)} cross seeds from ${chalk.bold.white(samples.length)} original torrents`),
276
+ message: chalk.cyan(`Found ${chalk.bold.white(totalFound)} cross seeds from ${chalk.bold.white(searchees.length)} original torrents`),
193
277
  });
194
278
  }
195
279
  export async function scanRssFeeds() {
@@ -215,7 +299,7 @@ export async function scanRssFeeds() {
215
299
  label: Label.RSS,
216
300
  message: `Processing release ${i + 1}/${candidatesSinceLastTime.length}`,
217
301
  });
218
- await checkNewCandidateMatch(candidate);
302
+ await checkNewCandidateMatch(candidate, Label.RSS);
219
303
  }
220
304
  logger.info({ label: Label.RSS, message: "Scan complete" });
221
305
  }
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAChC,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAEN,QAAQ,EACR,eAAe,EACf,oBAAoB,EACpB,UAAU,GACV,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACN,wBAAwB,EACxB,4BAA4B,GAC5B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAoB,MAAM,aAAa,CAAC;AAChE,OAAO,EACN,aAAa,EACb,mBAAmB,EACnB,sBAAsB,GACtB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EACN,eAAe,EACf,sBAAsB,EACtB,gBAAgB,GAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EACN,0BAA0B,EAC1B,sBAAsB,EACtB,6BAA6B,GAI7B,MAAM,eAAe,CAAC;AACvB,OAAO,EACN,sBAAsB,EACtB,oBAAoB,EACpB,wBAAwB,EACxB,gBAAgB,EAChB,mBAAmB,GAEnB,MAAM,cAAc,CAAC;AACtB,OAAO,EAEN,eAAe,EACf,aAAa,EACb,aAAa,GACb,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAsB1D,KAAK,UAAU,gBAAgB,CAC9B,UAAuB,EACvB,QAAkB,EAClB,eAAyB;IAEzB,MAAM,WAAW,GAA4B,EAAE,CAAC;IAChD,KAAK,MAAM,MAAM,IAAI,UAAU,EAAE,CAAC;QACjC,MAAM,UAAU,GAAG,MAAM,eAAe,CACvC,MAAM,EACN,QAAQ,EACR,eAAe,CACf,CAAC;QACF,WAAW,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,WAAW,CAAC;AACpB,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC9B,QAA2B,EAC3B,eAAyB,EACzB,YAA0B,EAC1B,QAAgB;IAEhB,oCAAoC;IACpC,MAAM,EAAE,CAAC,UAAU,CAAC;SAClB,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC;SAC/B,UAAU,CAAC,MAAM,CAAC;SAClB,MAAM,EAAE,CAAC;IAEX,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,QAAQ,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;IACvE,MAAM,gBAAgB,GACrB,QAAQ,CAAC,MAAM,GAAG,YAAY,CAAC,iBAAiB,CAAC,MAAM,CAAC;IACzD,YAAY,CAAC,iBAAiB,GAAG,QAAQ,CAAC;IAE1C,MAAM,OAAO,GAAgB,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CACnD,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QAChC,GAAG,SAAS;QACZ,SAAS,EAAE,CAAC,CAAC,SAAS;KACtB,CAAC,CAAC,CACH,CAAC;IAEF,MAAM,WAAW,GAAG,MAAM,gBAAgB,CACzC,OAAO,EACP,QAAQ,EACR,eAAe,CACf,CAAC;IAEF,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,GAAG,WAAW,CAAC,MAAM,CACzD,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QACjB,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,GAAG,CAAC,UAAU,CAAC,QAAQ,KAAK,QAAQ,CAAC,YAAY,EAAE,CAAC;YACvD,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,SAAU,CAAC,CAAC;YAC1C,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC,SAAU,CAAC,CAAC;QACjD,CAAC;QACD,OAAO,GAAG,CAAC;IACZ,CAAC,EACD;QACC,WAAW,EAAE,IAAI,GAAG,EAAU;QAC9B,cAAc,EAAE,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;KACzD,CACD,CAAC;IAEF,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACxC,oBAAoB,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAC3C,CAAC;IACF,MAAM,aAAa,GAAG,MAAM,cAAc,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC9D,IAAI,aAAa,CAAC,QAAQ,CAAC,eAAe,CAAC,oBAAoB,CAAC,EAAE,CAAC;QAClE,sDAAsD;QACtD,OAAO,EAAE,gBAAgB,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IAC5C,CAAC;IAED,MAAM,sBAAsB,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;IAExE,MAAM,mBAAmB,CACxB,aAAa,CAAC,YAAY,EAC1B,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,EACzB,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CACvB,CAAC;IAEF,MAAM,MAAM,GAA+C,GAAG,CAC7D,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,EAChC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAC7B,aAAa,CACb,CAAC;IACF,uBAAuB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAE1C,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;AACtD,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC9B,SAA8B,EAC9B,eAAyB;IAEzB,MAAM,EAAE,KAAK,EAAE,GAAG,gBAAgB,EAAE,CAAC;IAErC,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,MAAM,YAAY,GAAiB,EAAE,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,EAAE,EAAE,CAAC;IACtE,KAAK,MAAM,CAAC,CAAC,EAAE,QAAQ,CAAC,IAAI,SAAS,CAAC,OAAO,EAAE,EAAE,CAAC;QACjD,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC,MAAM,IAAI,CAAC,CAAC;QAC/D,IAAI,CAAC;YACJ,MAAM,SAAS,GAAG,KAAK,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,cAAc,CAAC,CAAC;YAC/D,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;gBACnB,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;YACpD,CAAC;YACD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAE9B,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,GAAG,MAAM,gBAAgB,CAC3D,QAAQ,EACR,eAAe,EACf,YAAY,EACZ,QAAQ,CACR,CAAC;YACF,UAAU,IAAI,OAAO,CAAC;YAEtB,2DAA2D;YAC3D,IAAI,gBAAgB,KAAK,CAAC;gBAAE,SAAS;YACrC,cAAc,GAAG,UAAU,CAAC;QAC7B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACZ,MAAM,WAAW,GAAG,YAAY,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC7D,MAAM,CAAC,KAAK,CAAC;gBACZ,KAAK,EAAE,QAAQ,CAAC,KAAK;gBACrB,OAAO,EAAE,GAAG,QAAQ,uBAAuB,WAAW,EAAE;aACxD,CAAC,CAAC;YACH,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACjB,CAAC;IACF,CAAC;IACD,OAAO,UAAU,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,+BAA+B,CACpD,QAAwB;IAExB,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,gBAAgB,EAAE,CAAC;IAEnD,IAAI,YAAwB,CAAC;IAC7B,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnB,MAAM,eAAe,GAAG,MAAM,OAAO,CAAC,GAAG,CACxC,wBAAwB,CAAC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,GAAG,CACxD,sBAAsB,CACtB,CACD,CAAC;QACF,YAAY,GAAG,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;IACpE,CAAC;SAAM,CAAC;QACP,YAAY,GAAG,CAAC,MAAM,oBAAoB,CAAC,QAAQ,CAAC,CAAC,CAAC;IACvD,CAAC;IACD,MAAM,SAAS,GAAwB,YAAY,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACtE,GAAG,QAAQ;QACX,KAAK,EAAE,KAAK,CAAC,OAAO;KACpB,CAAC,CAAC,CAAC;IACJ,MAAM,eAAe,GAAG,MAAM,sBAAsB,EAAE,CAAC;IACvD,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,MAAM,YAAY,GAAiB,EAAE,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,EAAE,EAAE,CAAC;IACtE,KAAK,MAAM,CAAC,CAAC,EAAE,QAAQ,CAAC,IAAI,SAAS,CAAC,OAAO,EAAE,EAAE,CAAC;QACjD,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC,MAAM,IAAI,CAAC,CAAC;QAC/D,IAAI,CAAC;YACJ,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAChC,QAAQ,EAAE,CAAC;gBACX,SAAS;YACV,CAAC;YACD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;YAEjC,MAAM,EAAE,OAAO,EAAE,gBAAgB,EAAE,GAAG,MAAM,gBAAgB,CAC3D,QAAQ,EACR,eAAe,EACf,YAAY,EACZ,QAAQ,CACR,CAAC;YACF,UAAU,IAAI,OAAO,CAAC;YAEtB,iDAAiD;YACjD,IAAI,gBAAgB,KAAK,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC,MAAM,GAAG,CAAC;gBAAE,SAAS;YACnE,MAAM,KAAK,CAAC;QACb,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACZ,MAAM,WAAW,GAAG,YAAY,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC7D,MAAM,CAAC,KAAK,CAAC;gBACZ,KAAK,EAAE,QAAQ,CAAC,KAAK;gBACrB,OAAO,EAAE,GAAG,QAAQ,uBAAuB,WAAW,EAAE;aACxD,CAAC,CAAC;YACH,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACjB,CAAC;IACF,CAAC;IACD,IAAI,QAAQ,KAAK,SAAS,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAC/C,OAAO,UAAU,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC3C,SAAoB,EACpB,aAA4B;IAE5B,MAAM,YAAY,GAAG,GAAG,SAAS,CAAC,IAAI,SAAS,SAAS,CAAC,OAAO,EAAE,CAAC;IACnE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,wBAAwB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,eAAe,CAAC;IAC3D,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,CAAC,OAAO,CAAC;YACd,KAAK,EAAE,aAAa;YACpB,OAAO,EAAE,wCAAwC,MAAM,QAAQ,YAAY,EAAE;SAC7E,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACb,CAAC;IACD,MAAM,SAAS,GAAwB,sBAAsB,CAC5D,KAAK;SACH,GAAG,CAAC,0BAA0B,CAAC;SAC/B,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,QAAQ,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC;SAC1D,MAAM,CAAC,eAAe,CAAC,CACzB,CAAC;IACF,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;QACvB,MAAM,CAAC,OAAO,CAAC;YACd,KAAK,EAAE,aAAa;YACpB,OAAO,EAAE,gCAAgC,MAAM,QAAQ,YAAY,EAAE;SACrE,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACb,CAAC;IACD,MAAM,CAAC,OAAO,CAAC;QACd,KAAK,EAAE,aAAa;QACpB,OAAO,EAAE,mBAAmB,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,MAAM,QAAQ,YAAY,EAAE;KAC/F,CAAC,CAAC;IAEH,MAAM,eAAe,GAAG,MAAM,sBAAsB,EAAE,CAAC;IAEvD,IAAI,MAAM,GAAwC,IAAI,CAAC;IACvD,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC1D,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QAClC,MAAM,EAAE,CAAC,UAAU,CAAC;aAClB,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC;aAC/B,UAAU,CAAC,MAAM,CAAC;aAClB,MAAM,EAAE,CAAC;QAEX,MAAM,UAAU,GAAqB,MAAM,eAAe,CACzD,SAAS,EACT,QAAQ,EACR,eAAe,CACf,CAAC;QAEF,IAAI,CAAC,oBAAoB,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAChD,SAAS;QACV,CAAC;QAED,MAAM,GAAG,MAAM,aAAa,CAC3B,UAAU,CAAC,QAAS,EACpB,UAAU,CAAC,QAAQ,EACnB,QAAQ,EACR,SAAS,CAAC,OAAO,CACjB,CAAC;QACF,uBAAuB,CAAC,QAAQ,EAAE;YACjC,CAAC,UAAU,EAAE,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;SACvC,CAAC,CAAC;QACH,IACC,MAAM,KAAK,UAAU,CAAC,KAAK;YAC3B,MAAM,KAAK,eAAe,CAAC,OAAO;YAClC,MAAM,KAAK,eAAe,CAAC,cAAc,EACxC,CAAC;YACF,MAAM;QACP,CAAC;IACF,CAAC;IACD,OAAO,MAAM,CAAC;AACf,CAAC;AAED,KAAK,UAAU,sBAAsB,CAAC,aAA4B;IAIjE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,gBAAgB,EAAE,CAAC;IAC3E,MAAM,YAAY,GAAe,EAAE,CAAC;IACpC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,MAAM,eAAe,GAAG,MAAM,OAAO,CAAC,GAAG,CACxC,QAAQ,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAC3C,CAAC;QACF,YAAY,CAAC,IAAI,CAChB,GAAG,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CACtD,CAAC;IACH,CAAC;SAAM,CAAC;QACP,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE,CAAC;YACpC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,mBAAmB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAC/D,CAAC;QACD,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,MAAM,eAAe,GAAG,MAAM,OAAO,CAAC,GAAG,CACxC,4BAA4B,EAAE,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAC1D,CAAC;YACF,YAAY,CAAC,IAAI,CAChB,GAAG,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CACtD,CAAC;QACH,CAAC;IACF,CAAC;IACD,MAAM,YAAY,GAAwB,YAAY,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACzE,GAAG,QAAQ;QACX,KAAK,EAAE,aAAa;KACpB,CAAC,CAAC,CAAC;IAEJ,MAAM,eAAe,GAAG,YAAY;SAClC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;SACtB,MAAM,CAAC,QAAQ,CAAC,CAAC;IAEnB,wEAAwE;IACxE,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA+B,CAAC;IACxD,KAAK,MAAM,QAAQ,IAAI,YAAY,CAAC,MAAM,CAAC,eAAe,CAAC,EAAE,CAAC;QAC7D,MAAM,GAAG,GAAG,MAAM,eAAe,CAAC,QAAQ,CAAC,CAAC;QAC5C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACvB,CAAC;QACD,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACnC,CAAC;IACD,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,KAAK,MAAM,CAAC,GAAG,EAAE,gBAAgB,CAAC,IAAI,QAAQ,EAAE,CAAC;QAChD,mEAAmE;QACnE,MAAM,SAAS,GAAG,sBAAsB,CAAC,gBAAgB,CAAC,CAAC;QAC3D,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC;QACnE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACvB,SAAS;QACV,CAAC;QACD,kBAAkB;QAClB,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACvB,IAAI,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,QAAQ;gBAAE,OAAO,CAAC,CAAC,CAAC;YACzC,IAAI,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,QAAQ;gBAAE,OAAO,CAAC,CAAC;YACxC,OAAO,CAAC,CAAC;QACV,CAAC,CAAC,CAAC;QACH,qDAAqD;QACrD,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACvB,OAAO,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;QACxC,CAAC,CAAC,CAAC;QACH,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IAC9B,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;QAChC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACtB,CAAC;IACD,IAAI,cAAc,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAE1D,MAAM,CAAC,IAAI,CAAC;QACX,KAAK,EAAE,KAAK,CAAC,MAAM;QACnB,OAAO,EAAE,SAAS,YAAY,CAAC,MAAM,cAAc,cAAc,CAAC,MAAM,yCAAyC,QAAQ,CAAC,IAAI,iBAAiB;KAC/I,CAAC,CAAC;IAEH,IAAI,WAAW,IAAI,cAAc,CAAC,MAAM,GAAG,WAAW,EAAE,CAAC;QACxD,MAAM,CAAC,IAAI,CAAC;YACX,KAAK,EAAE,KAAK,CAAC,MAAM;YACnB,OAAO,EAAE,cAAc,WAAW,WAAW;SAC7C,CAAC,CAAC;QAEH,cAAc,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;IACvD,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,eAAe,EAAE,CAAC;AACvD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,IAAI;IACzB,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,gBAAgB,EAAE,CAAC;IAClD,MAAM,EAAE,SAAS,EAAE,eAAe,EAAE,GAAG,MAAM,sBAAsB,CAClE,KAAK,CAAC,MAAM,CACZ,CAAC;IAEF,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC/B,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,CAAC;IACD,IAAI,OAAO,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACxC,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,gBAAgB,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;IAEtE,MAAM,CAAC,IAAI,CAAC;QACX,KAAK,EAAE,KAAK,CAAC,MAAM;QACnB,OAAO,EAAE,KAAK,CAAC,IAAI,CAClB,SAAS,KAAK,CAAC,IAAI,CAAC,KAAK,CACxB,UAAU,CACV,qBAAqB,KAAK,CAAC,IAAI,CAAC,KAAK,CACrC,SAAS,CAAC,MAAM,CAChB,oBAAoB,CACrB;KACD,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY;IACjC,MAAM,EAAE,OAAO,EAAE,GAAG,gBAAgB,EAAE,CAAC;IACvC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,UAAU,GAAG,MAAM,aAAa,EAAE,CAAC;QACzC,MAAM,OAAO,GACZ,CACC,MAAM,EAAE,CAAC,SAAS,CAAC;aACjB,MAAM,CAAC,UAAU,CAAC;aAClB,KAAK,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;aACtB,KAAK,EAAE,CACT,EAAE,QAAQ,IAAI,CAAC,CAAC;QAClB,MAAM,uBAAuB,GAAG,UAAU,CAAC,MAAM,CAChD,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,OAAO,CAC1B,CAAC;QACF,MAAM,CAAC,OAAO,CAAC;YACd,KAAK,EAAE,KAAK,CAAC,GAAG;YAChB,OAAO,EAAE,iBACR,uBAAuB,CAAC,MACzB,0BACC,UAAU,CAAC,MAAM,GAAG,uBAAuB,CAAC,MAC7C,eAAe;SACf,CAAC,CAAC;QACH,MAAM,CAAC,OAAO,CAAC;YACd,KAAK,EAAE,KAAK,CAAC,GAAG;YAChB,OAAO,EAAE,0BAA0B;SACnC,CAAC,CAAC;QACH,MAAM,gBAAgB,EAAE,CAAC;QACzB,KAAK,MAAM,CAAC,CAAC,EAAE,SAAS,CAAC,IAAI,uBAAuB,CAAC,OAAO,EAAE,EAAE,CAAC;YAChE,MAAM,CAAC,OAAO,CAAC;gBACd,KAAK,EAAE,KAAK,CAAC,GAAG;gBAChB,OAAO,EAAE,sBAAsB,CAAC,GAAG,CAAC,IACnC,uBAAuB,CAAC,MACzB,EAAE;aACF,CAAC,CAAC;YACH,MAAM,sBAAsB,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QACpD,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,eAAe,EAAE,CAAC,CAAC;IAC7D,CAAC;AACF,CAAC"}
package/dist/preFilter.js CHANGED
@@ -1,43 +1,56 @@
1
1
  import ms from "ms";
2
- import { extname } from "path";
3
- import { EP_REGEX, SEASON_REGEX, VIDEO_EXTENSIONS } from "./constants.js";
2
+ import { extname, basename, dirname } from "path";
3
+ import { statSync } from "fs";
4
+ import { ARR_DIR_REGEX, EP_REGEX, SONARR_SUBFOLDERS_REGEX, SEASON_REGEX, VIDEO_EXTENSIONS, } from "./constants.js";
4
5
  import { db } from "./db.js";
5
6
  import { getEnabledIndexers } from "./indexers.js";
6
7
  import { Label, logger } from "./logger.js";
7
8
  import { getRuntimeConfig } from "./runtimeConfig.js";
8
- import { humanReadableDate, nMsAgo } from "./utils.js";
9
- import path from "path";
9
+ import { indexerDoesSupportMediaType } from "./torznab.js";
10
+ import { getLogString, getMediaType, humanReadableDate, nMsAgo, } from "./utils.js";
11
+ import chalk from "chalk";
12
+ function logReason(reason, searchee) {
13
+ logger.verbose({
14
+ label: Label.PREFILTER,
15
+ message: `${getLogString(searchee, chalk.reset)} was not selected for searching because ${reason}`,
16
+ });
17
+ }
10
18
  export function filterByContent(searchee) {
11
- const { includeEpisodes, includeNonVideos, includeSingleEpisodes, blockList, } = getRuntimeConfig();
12
- function logReason(reason) {
13
- logger.verbose({
14
- label: Label.PREFILTER,
15
- message: `Torrent ${searchee.name} was not selected for searching because ${reason}`,
16
- });
17
- }
19
+ const { fuzzySizeThreshold, includeNonVideos, includeSingleEpisodes, blockList, } = getRuntimeConfig();
18
20
  const blockedNote = findBlockedStringInReleaseMaybe(searchee, blockList);
19
21
  if (blockedNote) {
20
- logReason(`it matched the blocklist - ("${blockedNote}")`);
22
+ logReason(`it matched the blocklist - ("${blockedNote}")`, searchee);
21
23
  return false;
22
24
  }
23
- const isSingleEpisodeTorrent = searchee.files.length === 1 && EP_REGEX.test(searchee.name);
24
- const isSeasonPackEpisode = searchee.path &&
25
+ if (searchee.path &&
25
26
  searchee.files.length === 1 &&
26
- SEASON_REGEX.test(path.basename(path.dirname(searchee.path)));
27
- if (!includeEpisodes &&
28
- !includeSingleEpisodes &&
29
- isSingleEpisodeTorrent &&
30
- !isSeasonPackEpisode) {
31
- logReason("it is a single episode");
27
+ (SEASON_REGEX.test(basename(dirname(searchee.path))) ||
28
+ SONARR_SUBFOLDERS_REGEX.test(basename(dirname(searchee.path))))) {
29
+ logReason("it is a season pack episode", searchee);
32
30
  return false;
33
31
  }
34
- if (!includeEpisodes && isSeasonPackEpisode) {
35
- logReason("it is a season pack episode");
32
+ if (!includeSingleEpisodes &&
33
+ ![Label.ANNOUNCE, Label.RSS].includes(searchee.label) &&
34
+ EP_REGEX.test(searchee.name)) {
35
+ logReason("it is a single episode", searchee);
36
36
  return false;
37
37
  }
38
- const allFilesAreVideos = searchee.files.every((file) => VIDEO_EXTENSIONS.includes(extname(file.name)));
39
- if (!includeNonVideos && !allFilesAreVideos) {
40
- logReason("not all files are videos");
38
+ const nonVideoSizeRatio = searchee.files.reduce((acc, cur) => {
39
+ if (!VIDEO_EXTENSIONS.includes(extname(cur.name))) {
40
+ return acc + cur.length;
41
+ }
42
+ return acc;
43
+ }, 0) / searchee.length;
44
+ if (!includeNonVideos && nonVideoSizeRatio > fuzzySizeThreshold) {
45
+ logReason(`nonVideoSizeRatio ${nonVideoSizeRatio} > ${fuzzySizeThreshold} fuzzySizeThreshold`, searchee);
46
+ return false;
47
+ }
48
+ if (searchee.path &&
49
+ statSync(searchee.path).isDirectory() &&
50
+ ARR_DIR_REGEX.test(basename(searchee.path)) &&
51
+ !(searchee.files.length > 1 &&
52
+ SONARR_SUBFOLDERS_REGEX.test(basename(searchee.path)))) {
53
+ logReason("it looks like an arr movie/series directory", searchee);
41
54
  return false;
42
55
  }
43
56
  return true;
@@ -48,13 +61,27 @@ export function findBlockedStringInReleaseMaybe(searchee, blockList) {
48
61
  blockedStr === searchee.infoHash);
49
62
  });
50
63
  }
51
- export function filterDupes(searchees) {
64
+ /**
65
+ * Filters duplicates from searchees that should be for different candidates,
66
+ * e.g. all searchees created by cross-seed.
67
+ * @param searchees - An array of searchees to filter duplicates from.
68
+ * @returns An array of searchees with duplicates removed, preferring infoHash.
69
+ */
70
+ export function filterDupesByName(searchees) {
52
71
  const duplicateMap = searchees.reduce((acc, cur) => {
53
72
  const entry = acc.get(cur.name);
54
73
  if (entry === undefined) {
55
74
  acc.set(cur.name, cur);
75
+ return acc;
56
76
  }
57
- else if (cur.infoHash && !entry.infoHash) {
77
+ if (cur.files.length > entry.files.length) {
78
+ acc.set(cur.name, cur);
79
+ return acc;
80
+ }
81
+ if (cur.files.length < entry.files.length) {
82
+ return acc;
83
+ }
84
+ if (cur.infoHash && !entry.infoHash) {
58
85
  acc.set(cur.name, cur);
59
86
  }
60
87
  return acc;
@@ -69,9 +96,39 @@ export function filterDupes(searchees) {
69
96
  }
70
97
  return filtered;
71
98
  }
99
+ /**
100
+ * Filters duplicates from searchees that are for the same candidates,
101
+ * e.g. searchees for the same media but different resolutions.
102
+ * @param searchees - An array of searchees for a specific media.
103
+ * @returns An array of searchees that are unique from a matching perspective.
104
+ */
105
+ export function filterDupesFromSimilar(searchees) {
106
+ const filteredSearchees = [];
107
+ for (const searchee of searchees) {
108
+ const isDupe = filteredSearchees.some((s) => {
109
+ if (searchee.length !== s.length)
110
+ return false;
111
+ if (searchee.files.length !== s.files.length)
112
+ return false;
113
+ const potentialFiles = s.files.map((f) => f.length);
114
+ return searchee.files.every((file) => {
115
+ const index = potentialFiles.indexOf(file.length);
116
+ if (index === -1)
117
+ return false;
118
+ potentialFiles.splice(index, 1);
119
+ return true;
120
+ });
121
+ });
122
+ if (!isDupe) {
123
+ filteredSearchees.push(searchee);
124
+ }
125
+ }
126
+ return filteredSearchees;
127
+ }
72
128
  export async function filterTimestamps(searchee) {
73
129
  const { excludeOlder, excludeRecentSearch } = getRuntimeConfig();
74
130
  const enabledIndexers = await getEnabledIndexers();
131
+ const mediaType = getMediaType(searchee);
75
132
  const timestampDataSql = (await db("searchee")
76
133
  // @ts-expect-error crossJoin supports string
77
134
  .crossJoin("indexer")
@@ -80,7 +137,9 @@ export async function filterTimestamps(searchee) {
80
137
  "timestamp.searchee_id": "searchee.id",
81
138
  })
82
139
  .where("searchee.name", searchee.name)
83
- .whereIn("indexer.id", enabledIndexers.map((i) => i.id))
140
+ .whereIn("indexer.id", enabledIndexers
141
+ .filter((indexer) => indexerDoesSupportMediaType(mediaType, JSON.parse(indexer.categories)))
142
+ .map((indexer) => indexer.id))
84
143
  .min({
85
144
  first_searched_any: db.raw("coalesce(timestamp.first_searched, 9223372036854775807)"),
86
145
  })
@@ -89,22 +148,16 @@ export async function filterTimestamps(searchee) {
89
148
  })
90
149
  .first());
91
150
  const { first_searched_any, last_searched_all } = timestampDataSql;
92
- function logReason(reason) {
93
- logger.verbose({
94
- label: Label.PREFILTER,
95
- message: `Torrent ${searchee.name} was not selected for searching because ${reason}`,
96
- });
97
- }
98
151
  if (typeof excludeOlder === "number" &&
99
152
  first_searched_any &&
100
153
  first_searched_any < nMsAgo(excludeOlder)) {
101
- logReason(`its first search timestamp ${humanReadableDate(first_searched_any)} is older than ${ms(excludeOlder, { long: true })} ago`);
154
+ logReason(`its first search timestamp ${humanReadableDate(first_searched_any)} is older than ${ms(excludeOlder, { long: true })} ago`, searchee);
102
155
  return false;
103
156
  }
104
157
  if (typeof excludeRecentSearch === "number" &&
105
158
  last_searched_all &&
106
159
  last_searched_all > nMsAgo(excludeRecentSearch)) {
107
- logReason(`its last search timestamp ${humanReadableDate(last_searched_all)} is newer than ${ms(excludeRecentSearch, { long: true })} ago`);
160
+ logReason(`its last search timestamp ${humanReadableDate(last_searched_all)} is newer than ${ms(excludeRecentSearch, { long: true })} ago`, searchee);
108
161
  return false;
109
162
  }
110
163
  return true;