cross-seed 2.9.1 → 3.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 (91) hide show
  1. package/README.md +2 -1
  2. package/dist/{src/clients → clients}/QBittorrent.js +31 -37
  3. package/dist/clients/QBittorrent.js.map +1 -0
  4. package/dist/{src/clients → clients}/RTorrent.js +52 -48
  5. package/dist/clients/RTorrent.js.map +1 -0
  6. package/dist/clients/TorrentClient.js +20 -0
  7. package/dist/clients/TorrentClient.js.map +1 -0
  8. package/dist/cmd.js +148 -0
  9. package/dist/cmd.js.map +1 -0
  10. package/dist/{src/config.template.js → config.template.cjs} +4 -2
  11. package/dist/config.template.cjs.map +1 -0
  12. package/dist/{src/config.template.docker.js → config.template.docker.cjs} +4 -3
  13. package/dist/config.template.docker.cjs.map +1 -0
  14. package/dist/configuration.js +39 -0
  15. package/dist/configuration.js.map +1 -0
  16. package/dist/constants.js +33 -0
  17. package/dist/constants.js.map +1 -0
  18. package/dist/db.js +29 -0
  19. package/dist/db.js.map +1 -0
  20. package/dist/decide.js +134 -0
  21. package/dist/decide.js.map +1 -0
  22. package/dist/diff.js +23 -0
  23. package/dist/diff.js.map +1 -0
  24. package/dist/errors.js +11 -0
  25. package/dist/errors.js.map +1 -0
  26. package/dist/jackett.js +68 -0
  27. package/dist/jackett.js.map +1 -0
  28. package/dist/logger.js +88 -0
  29. package/dist/logger.js.map +1 -0
  30. package/dist/pipeline.js +134 -0
  31. package/dist/pipeline.js.map +1 -0
  32. package/dist/preFilter.js +66 -0
  33. package/dist/preFilter.js.map +1 -0
  34. package/dist/pushNotifier.js +27 -0
  35. package/dist/pushNotifier.js.map +1 -0
  36. package/dist/runtimeConfig.js +12 -0
  37. package/dist/runtimeConfig.js.map +1 -0
  38. package/dist/searchee.js +52 -0
  39. package/dist/searchee.js.map +1 -0
  40. package/dist/{src/server.js → server.js} +23 -30
  41. package/dist/server.js.map +1 -0
  42. package/dist/{src/signalHandlers.js → signalHandlers.js} +0 -0
  43. package/dist/signalHandlers.js.map +1 -0
  44. package/dist/startup.js +24 -0
  45. package/dist/startup.js.map +1 -0
  46. package/dist/torrent.js +128 -0
  47. package/dist/torrent.js.map +1 -0
  48. package/dist/utils.js +28 -0
  49. package/dist/utils.js.map +1 -0
  50. package/package.json +22 -25
  51. package/dist/package.json +0 -68
  52. package/dist/src/clients/QBittorrent.js.map +0 -1
  53. package/dist/src/clients/RTorrent.js.map +0 -1
  54. package/dist/src/clients/TorrentClient.js +0 -27
  55. package/dist/src/clients/TorrentClient.js.map +0 -1
  56. package/dist/src/cmd.js +0 -136
  57. package/dist/src/cmd.js.map +0 -1
  58. package/dist/src/config.template.docker.js.map +0 -1
  59. package/dist/src/config.template.js.map +0 -1
  60. package/dist/src/configuration.js +0 -66
  61. package/dist/src/configuration.js.map +0 -1
  62. package/dist/src/constants.js +0 -39
  63. package/dist/src/constants.js.map +0 -1
  64. package/dist/src/db.js +0 -34
  65. package/dist/src/db.js.map +0 -1
  66. package/dist/src/decide.js +0 -140
  67. package/dist/src/decide.js.map +0 -1
  68. package/dist/src/errors.js +0 -15
  69. package/dist/src/errors.js.map +0 -1
  70. package/dist/src/jackett.js +0 -76
  71. package/dist/src/jackett.js.map +0 -1
  72. package/dist/src/logger.js +0 -78
  73. package/dist/src/logger.js.map +0 -1
  74. package/dist/src/pipeline.js +0 -140
  75. package/dist/src/pipeline.js.map +0 -1
  76. package/dist/src/preFilter.js +0 -77
  77. package/dist/src/preFilter.js.map +0 -1
  78. package/dist/src/pushNotifier.js +0 -35
  79. package/dist/src/pushNotifier.js.map +0 -1
  80. package/dist/src/runtimeConfig.js +0 -17
  81. package/dist/src/runtimeConfig.js.map +0 -1
  82. package/dist/src/searchee.js +0 -72
  83. package/dist/src/searchee.js.map +0 -1
  84. package/dist/src/server.js.map +0 -1
  85. package/dist/src/signalHandlers.js.map +0 -1
  86. package/dist/src/startup.js +0 -28
  87. package/dist/src/startup.js.map +0 -1
  88. package/dist/src/torrent.js +0 -169
  89. package/dist/src/torrent.js.map +0 -1
  90. package/dist/src/utils.js +0 -39
  91. package/dist/src/utils.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configuration.js","sourceRoot":"","sources":["../src/configuration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,IAAI,MAAM,MAAM,CAAC;AAGxB,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,cAAc,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;AA0BlD,MAAM,UAAU,MAAM;IACrB,OAAO,CACN,OAAO,CAAC,GAAG,CAAC,UAAU;QACtB,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO;YAC5B,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,cAAc,CAAC,IAAI,CAAC;YAC7D,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,CAC7D,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY;IAC3B,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,eAAe,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,EAC9B,KAAK,GAAG,KAAK,EACb,MAAM,GAAG,KAAK,GACQ;IACtB,YAAY,EAAE,CAAC;IACf,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,WAAW,CAAC,CAAC;IAC9C,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAC7B,oBAAoB,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,CACjD,CAAC;IACF,IAAI,CAAC,KAAK,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE;QAC/B,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;QAClD,OAAO;KACP;IACD,YAAY,CAAC,IAAI,GAAG,CAAC,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;IAC3D,OAAO,CAAC,GAAG,CAAC,+BAA+B,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa;IAClC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,WAAW,CAAC,CAAC;IAEpD,IAAI;QACH,OAAO,CAAC,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC;KAC1C;IAAC,OAAO,CAAC,EAAE;QACX,IAAI,CAAC,CAAC,IAAI,KAAK,sBAAsB;YAAE,MAAM,CAAC,CAAC;QAC/C,OAAO,EAAE,CAAC;KACV;AACF,CAAC"}
@@ -0,0 +1,33 @@
1
+ export const EP_REGEX = /^(?<title>.+)[. ](?<season>S\d+)(?<episode>E\d+)/i;
2
+ export const SEASON_REGEX = /^(?<title>.+)[. ](?<season>S\d+)(?:\s?-\s?(?<seasonmax>S?\d+))?(?!E\d+)/i;
3
+ export const MOVIE_REGEX = /^(?<title>.+)[. ][[(]?(?<year>\d{4})[)\]]?(?![pi])/i;
4
+ export const EXTENSIONS = ["mkv", "mp4", "avi"];
5
+ export const CONFIG_TEMPLATE_URL = "https://github.com/mmgoodnow/cross-seed/blob/master/src/config.template.js";
6
+ export const TORRENT_CACHE_FOLDER = "torrent_cache";
7
+ export var Action;
8
+ (function (Action) {
9
+ Action["SAVE"] = "save";
10
+ Action["INJECT"] = "inject";
11
+ })(Action = Action || (Action = {}));
12
+ export var InjectionResult;
13
+ (function (InjectionResult) {
14
+ InjectionResult[InjectionResult["SUCCESS"] = 0] = "SUCCESS";
15
+ InjectionResult[InjectionResult["FAILURE"] = 1] = "FAILURE";
16
+ InjectionResult[InjectionResult["ALREADY_EXISTS"] = 2] = "ALREADY_EXISTS";
17
+ InjectionResult[InjectionResult["TORRENT_NOT_COMPLETE"] = 3] = "TORRENT_NOT_COMPLETE";
18
+ })(InjectionResult = InjectionResult || (InjectionResult = {}));
19
+ export var Decision;
20
+ (function (Decision) {
21
+ Decision["MATCH"] = "MATCH";
22
+ Decision["SIZE_MISMATCH"] = "SIZE_MISMATCH";
23
+ Decision["NO_DOWNLOAD_LINK"] = "NO_DOWNLOAD_LINK";
24
+ Decision["DOWNLOAD_FAILED"] = "DOWNLOAD_FAILED";
25
+ Decision["INFO_HASH_ALREADY_EXISTS"] = "INFO_HASH_ALREADY_EXISTS";
26
+ Decision["FILE_TREE_MISMATCH"] = "FILE_TREE_MISMATCH";
27
+ })(Decision = Decision || (Decision = {}));
28
+ export const PermanentDecisions = [
29
+ Decision.SIZE_MISMATCH,
30
+ Decision.NO_DOWNLOAD_LINK,
31
+ Decision.FILE_TREE_MISMATCH,
32
+ ];
33
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAG,mDAAmD,CAAC;AAC5E,MAAM,CAAC,MAAM,YAAY,GACxB,0EAA0E,CAAC;AAC5E,MAAM,CAAC,MAAM,WAAW,GACvB,qDAAqD,CAAC;AAEvD,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;AAEhD,MAAM,CAAC,MAAM,mBAAmB,GAC/B,4EAA4E,CAAC;AAE9E,MAAM,CAAC,MAAM,oBAAoB,GAAG,eAAe,CAAC;AAEpD,MAAM,CAAN,IAAY,MAGX;AAHD,WAAY,MAAM;IACjB,uBAAa,CAAA;IACb,2BAAiB,CAAA;AAClB,CAAC,EAHW,MAAM,GAAN,MAAM,KAAN,MAAM,QAGjB;AAED,MAAM,CAAN,IAAY,eAKX;AALD,WAAY,eAAe;IAC1B,2DAAO,CAAA;IACP,2DAAO,CAAA;IACP,yEAAc,CAAA;IACd,qFAAoB,CAAA;AACrB,CAAC,EALW,eAAe,GAAf,eAAe,KAAf,eAAe,QAK1B;AAED,MAAM,CAAN,IAAY,QAOX;AAPD,WAAY,QAAQ;IACnB,2BAAe,CAAA;IACf,2CAA+B,CAAA;IAC/B,iDAAqC,CAAA;IACrC,+CAAmC,CAAA;IACnC,iEAAqD,CAAA;IACrD,qDAAyC,CAAA;AAC1C,CAAC,EAPW,QAAQ,GAAR,QAAQ,KAAR,QAAQ,QAOnB;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAe;IAC7C,QAAQ,CAAC,aAAa;IACtB,QAAQ,CAAC,gBAAgB;IACzB,QAAQ,CAAC,kBAAkB;CAC3B,CAAC"}
package/dist/db.js ADDED
@@ -0,0 +1,29 @@
1
+ var _a;
2
+ import { unlinkSync } from "fs";
3
+ import { JSONFileSync, LowSync } from "lowdb";
4
+ import path from "path";
5
+ import rimraf from "rimraf";
6
+ import { appDir, createAppDir } from "./configuration.js";
7
+ createAppDir();
8
+ const emptyDatabase = {
9
+ searchees: {},
10
+ decisions: {},
11
+ indexedTorrents: [],
12
+ dbVersion: 3,
13
+ };
14
+ const db = new LowSync(new JSONFileSync(path.join(appDir(), "cache.json")));
15
+ db.read();
16
+ (_a = db.data) !== null && _a !== void 0 ? _a : (db.data = emptyDatabase);
17
+ const dbVersion = db.data.dbVersion;
18
+ if (!dbVersion || dbVersion < emptyDatabase.dbVersion) {
19
+ db.data = emptyDatabase;
20
+ }
21
+ db.write();
22
+ export function dropDatabase() {
23
+ db.data = emptyDatabase;
24
+ db.write();
25
+ unlinkSync(path.join(appDir(), "cache.json"));
26
+ rimraf.sync(path.join(appDir(), "torrent_cache"));
27
+ }
28
+ export default db;
29
+ //# sourceMappingURL=db.js.map
package/dist/db.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAC9C,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAG1D,YAAY,EAAE,CAAC;AA4Bf,MAAM,aAAa,GAAG;IACrB,SAAS,EAAE,EAAE;IACb,SAAS,EAAE,EAAE;IACb,eAAe,EAAE,EAAE;IACnB,SAAS,EAAE,CAAC;CACZ,CAAC;AAEF,MAAM,EAAE,GAAG,IAAI,OAAO,CACrB,IAAI,YAAY,CAAS,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,YAAY,CAAC,CAAC,CAC3D,CAAC;AAEF,EAAE,CAAC,IAAI,EAAE,CAAC;AAEV,MAAA,EAAE,CAAC,IAAI,oCAAP,EAAE,CAAC,IAAI,GAAK,aAAa,EAAC;AAE1B,MAAM,SAAS,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC;AAEpC,IAAI,CAAC,SAAS,IAAI,SAAS,GAAG,aAAa,CAAC,SAAS,EAAE;IACtD,EAAE,CAAC,IAAI,GAAG,aAAa,CAAC;CACxB;AAED,EAAE,CAAC,KAAK,EAAE,CAAC;AAEX,MAAM,UAAU,YAAY;IAC3B,EAAE,CAAC,IAAI,GAAG,aAAa,CAAC;IACxB,EAAE,CAAC,KAAK,EAAE,CAAC;IACX,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,YAAY,CAAC,CAAC,CAAC;IAC9C,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC;AACnD,CAAC;AAED,eAAe,EAAE,CAAC"}
package/dist/decide.js ADDED
@@ -0,0 +1,134 @@
1
+ import { existsSync, writeFileSync } from "fs";
2
+ import parseTorrent from "parse-torrent";
3
+ import path from "path";
4
+ import { appDir } from "./configuration.js";
5
+ import { Decision, TORRENT_CACHE_FOLDER } from "./constants.js";
6
+ import db from "./db.js";
7
+ import { Label, logger } from "./logger.js";
8
+ import { parseTorrentFromFilename, parseTorrentFromURL } from "./torrent.js";
9
+ import { getRuntimeConfig } from "./runtimeConfig.js";
10
+ const createReasonLogger = (Title, tracker, name) => (decision, cached) => {
11
+ function logReason(reason) {
12
+ logger.verbose({
13
+ label: Label.DECIDE,
14
+ message: `${name} - no match for ${tracker} torrent ${Title} - ${reason}`,
15
+ });
16
+ }
17
+ let reason;
18
+ switch (decision) {
19
+ case Decision.MATCH:
20
+ return;
21
+ case Decision.SIZE_MISMATCH:
22
+ reason = "its size does not match";
23
+ break;
24
+ case Decision.NO_DOWNLOAD_LINK:
25
+ reason = "it doesn't have a download link";
26
+ break;
27
+ case Decision.DOWNLOAD_FAILED:
28
+ reason = "the torrent file failed to download";
29
+ break;
30
+ case Decision.INFO_HASH_ALREADY_EXISTS:
31
+ reason = "the info hash matches a torrent you already have";
32
+ break;
33
+ case Decision.FILE_TREE_MISMATCH:
34
+ reason = "it has a different file tree";
35
+ break;
36
+ default:
37
+ reason = decision;
38
+ break;
39
+ }
40
+ if (cached)
41
+ logReason(`${reason} (cached)`);
42
+ else
43
+ logReason(reason);
44
+ };
45
+ export function compareFileTrees(candidate, searchee) {
46
+ const cmp = (elOfA, elOfB) => {
47
+ const lengthsAreEqual = elOfB.length === elOfA.length;
48
+ const pathsAreEqual = elOfB.path === elOfA.path;
49
+ return lengthsAreEqual && pathsAreEqual;
50
+ };
51
+ return candidate.files.every((elOfA) => searchee.files.some((elOfB) => cmp(elOfA, elOfB)));
52
+ }
53
+ function sizeDoesMatch(resultSize, searchee) {
54
+ const { fuzzySizeThreshold } = getRuntimeConfig();
55
+ const { length } = searchee;
56
+ const lowerBound = length - fuzzySizeThreshold * length;
57
+ const upperBound = length + fuzzySizeThreshold * length;
58
+ return resultSize >= lowerBound && resultSize <= upperBound;
59
+ }
60
+ async function assessResultHelper({ Link, Size }, searchee, hashesToExclude) {
61
+ if (!sizeDoesMatch(Size, searchee)) {
62
+ return { decision: Decision.SIZE_MISMATCH };
63
+ }
64
+ if (!Link)
65
+ return { decision: Decision.NO_DOWNLOAD_LINK };
66
+ const info = await parseTorrentFromURL(Link);
67
+ if (!info)
68
+ return { decision: Decision.DOWNLOAD_FAILED };
69
+ if (hashesToExclude.includes(info.infoHash)) {
70
+ return { decision: Decision.INFO_HASH_ALREADY_EXISTS };
71
+ }
72
+ if (!compareFileTrees(info, searchee)) {
73
+ return { decision: Decision.FILE_TREE_MISMATCH };
74
+ }
75
+ return { decision: Decision.MATCH, info };
76
+ }
77
+ function existsInTorrentCache(infoHash) {
78
+ return existsSync(path.join(appDir(), TORRENT_CACHE_FOLDER, `${infoHash}.cached.torrent`));
79
+ }
80
+ async function getCachedTorrentFile(infoHash) {
81
+ return parseTorrentFromFilename(path.join(appDir(), TORRENT_CACHE_FOLDER, `${infoHash}.cached.torrent`));
82
+ }
83
+ function cacheTorrentFile(meta) {
84
+ writeFileSync(path.join(appDir(), TORRENT_CACHE_FOLDER, `${meta.infoHash}.cached.torrent`), parseTorrent.toTorrentFile(meta));
85
+ }
86
+ async function assessResultCaching(result, searchee, infoHashesToExclude) {
87
+ var _a;
88
+ var _b, _c;
89
+ const { Guid, Title, TrackerId: tracker } = result;
90
+ const logReason = createReasonLogger(Title, tracker, searchee.name);
91
+ (_a = (_b = db.data.decisions)[_c = searchee.name]) !== null && _a !== void 0 ? _a : (_b[_c] = {});
92
+ const cacheEntry = db.data.decisions[searchee.name][Guid];
93
+ let assessment;
94
+ if (cacheEntry && cacheEntry.decision !== Decision.MATCH) {
95
+ // cached rejection
96
+ assessment = { decision: cacheEntry.decision };
97
+ logReason(cacheEntry.decision, true);
98
+ }
99
+ else if (cacheEntry && existsInTorrentCache(cacheEntry.infoHash)) {
100
+ // cached match
101
+ if (infoHashesToExclude.includes(cacheEntry.infoHash)) {
102
+ // has been added since the last run
103
+ assessment = { decision: Decision.INFO_HASH_ALREADY_EXISTS };
104
+ db.data.decisions[searchee.name][Guid].decision =
105
+ assessment.decision;
106
+ }
107
+ else {
108
+ assessment = {
109
+ decision: cacheEntry.decision,
110
+ info: await getCachedTorrentFile(cacheEntry.infoHash),
111
+ };
112
+ }
113
+ }
114
+ else {
115
+ // uncached case, send it
116
+ assessment = await assessResultHelper(result, searchee, infoHashesToExclude);
117
+ db.data.decisions[searchee.name][Guid] = {
118
+ decision: assessment.decision,
119
+ lastSeen: Date.now(),
120
+ firstSeen: Date.now(),
121
+ };
122
+ if (assessment.decision === Decision.MATCH) {
123
+ db.data.decisions[searchee.name][Guid].infoHash =
124
+ assessment.info.infoHash;
125
+ cacheTorrentFile(assessment.info);
126
+ }
127
+ logReason(assessment.decision, false);
128
+ }
129
+ db.data.decisions[searchee.name][Guid].lastSeen = Date.now();
130
+ db.write();
131
+ return assessment;
132
+ }
133
+ export { assessResultCaching as assessResult };
134
+ //# sourceMappingURL=decide.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decide.js","sourceRoot":"","sources":["../src/decide.ts"],"names":[],"mappings":"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"}
package/dist/diff.js ADDED
@@ -0,0 +1,23 @@
1
+ import { createSearcheeFromMetafile } from "./searchee.js";
2
+ import { parseTorrentFromFilename } from "./torrent.js";
3
+ import { deepStrictEqual } from "assert";
4
+ function diff(thing1, thing2) {
5
+ try {
6
+ deepStrictEqual(thing1, thing2);
7
+ console.log(thing1);
8
+ console.log("Torrents are equal");
9
+ }
10
+ catch (e) {
11
+ console.log(e);
12
+ }
13
+ }
14
+ export async function diffCmd(first, second) {
15
+ const firstMeta = await parseTorrentFromFilename(first);
16
+ const secondMeta = await parseTorrentFromFilename(second);
17
+ const firstSearchee = createSearcheeFromMetafile(firstMeta);
18
+ const secondSearchee = createSearcheeFromMetafile(secondMeta);
19
+ delete firstSearchee.infoHash;
20
+ delete secondSearchee.infoHash;
21
+ diff(firstSearchee, secondSearchee);
22
+ }
23
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAEzC,SAAS,IAAI,CAAC,MAAM,EAAE,MAAM;IAC3B,IAAI;QACH,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpB,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;KAClC;IAAC,OAAO,CAAC,EAAE;QACX,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;KACf;AACF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,KAAa,EAAE,MAAc;IAC1D,MAAM,SAAS,GAAG,MAAM,wBAAwB,CAAC,KAAK,CAAC,CAAC;IACxD,MAAM,UAAU,GAAG,MAAM,wBAAwB,CAAC,MAAM,CAAC,CAAC;IAC1D,MAAM,aAAa,GAAG,0BAA0B,CAAC,SAAS,CAAC,CAAC;IAC5D,MAAM,cAAc,GAAG,0BAA0B,CAAC,UAAU,CAAC,CAAC;IAC9D,OAAO,aAAa,CAAC,QAAQ,CAAC;IAC9B,OAAO,cAAc,CAAC,QAAQ,CAAC;IAC/B,IAAI,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC;AACrC,CAAC"}
package/dist/errors.js ADDED
@@ -0,0 +1,11 @@
1
+ import { logger } from "./logger.js";
2
+ export class CrossSeedError extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ delete this.stack;
6
+ }
7
+ print() {
8
+ logger.error(this.message);
9
+ }
10
+ }
11
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,OAAO,cAAe,SAAQ,KAAK;IACxC,YAAY,OAAe;QAC1B,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,OAAO,IAAI,CAAC,KAAK,CAAC;IACnB,CAAC;IAED,KAAK;QACJ,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC;CACD"}
@@ -0,0 +1,68 @@
1
+ import querystring from "querystring";
2
+ import get from "simple-get";
3
+ import { EP_REGEX, MOVIE_REGEX, SEASON_REGEX } from "./constants.js";
4
+ import { CrossSeedError } from "./errors.js";
5
+ import { Label, logger } from "./logger.js";
6
+ import { EmptyNonceOptions, getRuntimeConfig, } from "./runtimeConfig.js";
7
+ function reformatTitleForSearching(name) {
8
+ const seasonMatch = name.match(SEASON_REGEX);
9
+ const movieMatch = name.match(MOVIE_REGEX);
10
+ const episodeMatch = name.match(EP_REGEX);
11
+ const fullMatch = episodeMatch
12
+ ? episodeMatch[0]
13
+ : seasonMatch
14
+ ? seasonMatch[0]
15
+ : movieMatch
16
+ ? movieMatch[0]
17
+ : name;
18
+ return fullMatch
19
+ .replace(/[.()[\]]/g, " ")
20
+ .replace(/\s+/g, " ")
21
+ .trim();
22
+ }
23
+ function fullJackettUrl(jackettServerUrl, params) {
24
+ const jackettPath = `/api/v2.0/indexers/all/results`;
25
+ return `${jackettServerUrl}${jackettPath}?${querystring.encode(params)}`;
26
+ }
27
+ export async function validateJackettApi() {
28
+ const { jackettServerUrl, jackettApiKey: apikey } = getRuntimeConfig();
29
+ if (/\/$/.test(jackettServerUrl)) {
30
+ logger.warn("Warning: Jackett server url should not end with '/'");
31
+ }
32
+ // search for gibberish so the results will be empty
33
+ const gibberish = "bscdjpstabgdspjdasmomdsenqciadsnocdpsikncaodsnimcdqsanc";
34
+ try {
35
+ await makeJackettRequest(gibberish);
36
+ }
37
+ catch (e) {
38
+ const dummyUrl = fullJackettUrl(jackettServerUrl, { apikey });
39
+ throw new CrossSeedError(`Could not reach Jackett at ${dummyUrl}`);
40
+ }
41
+ }
42
+ export function makeJackettRequest(name, nonceOptions = EmptyNonceOptions) {
43
+ const { jackettApiKey, trackers: runtimeConfigTrackers, jackettServerUrl, } = getRuntimeConfig();
44
+ const { trackers = runtimeConfigTrackers } = nonceOptions;
45
+ const params = {
46
+ apikey: jackettApiKey,
47
+ Query: reformatTitleForSearching(name),
48
+ "Tracker[]": trackers,
49
+ };
50
+ const opts = {
51
+ method: "GET",
52
+ url: fullJackettUrl(jackettServerUrl, params),
53
+ json: true,
54
+ };
55
+ logger.verbose({
56
+ label: Label.JACKETT,
57
+ message: `making search with query "${params.Query}"`,
58
+ });
59
+ return new Promise((resolve, reject) => {
60
+ get.concat(opts, (err, res, data) => {
61
+ if (err)
62
+ reject(err);
63
+ else
64
+ resolve(data);
65
+ });
66
+ });
67
+ }
68
+ //# sourceMappingURL=jackett.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jackett.js","sourceRoot":"","sources":["../src/jackett.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,aAAa,CAAC;AACtC,OAAO,GAAG,MAAM,YAAY,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EACN,iBAAiB,EACjB,gBAAgB,GAEhB,MAAM,oBAAoB,CAAC;AAiD5B,SAAS,yBAAyB,CAAC,IAAY;IAC9C,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IAC7C,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAC3C,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC1C,MAAM,SAAS,GAAG,YAAY;QAC7B,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;QACjB,CAAC,CAAC,WAAW;YACb,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;YAChB,CAAC,CAAC,UAAU;gBACZ,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;gBACf,CAAC,CAAC,IAAI,CAAC;IACR,OAAO,SAAS;SACd,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC;SACzB,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE,CAAC;AACV,CAAC;AAED,SAAS,cAAc,CAAC,gBAAwB,EAAE,MAAM;IACvD,MAAM,WAAW,GAAG,gCAAgC,CAAC;IACrD,OAAO,GAAG,gBAAgB,GAAG,WAAW,IAAI,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;AAC1E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACvC,MAAM,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,gBAAgB,EAAE,CAAC;IAEvE,IAAI,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAAE;QACjC,MAAM,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC;KACnE;IAED,oDAAoD;IACpD,MAAM,SAAS,GAAG,yDAAyD,CAAC;IAC5E,IAAI;QACH,MAAM,kBAAkB,CAAC,SAAS,CAAC,CAAC;KACpC;IAAC,OAAO,CAAC,EAAE;QACX,MAAM,QAAQ,GAAG,cAAc,CAAC,gBAAgB,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;QAC9D,MAAM,IAAI,cAAc,CAAC,8BAA8B,QAAQ,EAAE,CAAC,CAAC;KACnE;AACF,CAAC;AAED,MAAM,UAAU,kBAAkB,CACjC,IAAY,EACZ,eAA6B,iBAAiB;IAE9C,MAAM,EACL,aAAa,EACb,QAAQ,EAAE,qBAAqB,EAC/B,gBAAgB,GAChB,GAAG,gBAAgB,EAAE,CAAC;IACvB,MAAM,EAAE,QAAQ,GAAG,qBAAqB,EAAE,GAAG,YAAY,CAAC;IAC1D,MAAM,MAAM,GAAG;QACd,MAAM,EAAE,aAAa;QACrB,KAAK,EAAE,yBAAyB,CAAC,IAAI,CAAC;QACtC,WAAW,EAAE,QAAQ;KACrB,CAAC;IAEF,MAAM,IAAI,GAAG;QACZ,MAAM,EAAE,KAAK;QACb,GAAG,EAAE,cAAc,CAAC,gBAAgB,EAAE,MAAM,CAAC;QAC7C,IAAI,EAAE,IAAI;KACV,CAAC;IAEF,MAAM,CAAC,OAAO,CAAC;QACd,KAAK,EAAE,KAAK,CAAC,OAAO;QACpB,OAAO,EAAE,6BAA6B,MAAM,CAAC,KAAK,GAAG;KACrD,CAAC,CAAC;IAEH,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACtC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;YACnC,IAAI,GAAG;gBAAE,MAAM,CAAC,GAAG,CAAC,CAAC;;gBAChB,OAAO,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;AACJ,CAAC"}
package/dist/logger.js ADDED
@@ -0,0 +1,88 @@
1
+ import { join } from "path";
2
+ import winston from "winston";
3
+ import { appDir, createAppDir } from "./configuration.js";
4
+ import { getRuntimeConfig } from "./runtimeConfig.js";
5
+ import DailyRotateFile from "winston-daily-rotate-file";
6
+ export var Label;
7
+ (function (Label) {
8
+ Label["QBITTORRENT"] = "qbittorrent";
9
+ Label["RTORRENT"] = "rtorrent";
10
+ Label["DECIDE"] = "decide";
11
+ Label["PREFILTER"] = "prefilter";
12
+ Label["CONFIGDUMP"] = "configdump";
13
+ Label["JACKETT"] = "jackett";
14
+ Label["SERVER"] = "server";
15
+ Label["STARTUP"] = "startup";
16
+ })(Label = Label || (Label = {}));
17
+ export let logger;
18
+ const redactionMsg = "[REDACTED]";
19
+ function redactUrlPassword(message, urlStr) {
20
+ let url;
21
+ try {
22
+ url = new URL(urlStr);
23
+ if (url.password) {
24
+ const urlDecodedPassword = decodeURIComponent(url.password);
25
+ const urlEncodedPassword = encodeURIComponent(url.password);
26
+ message = message.split(url.password).join(redactionMsg);
27
+ message = message.split(urlDecodedPassword).join(redactionMsg);
28
+ message = message.split(urlEncodedPassword).join(redactionMsg);
29
+ }
30
+ }
31
+ catch (e) {
32
+ // do nothing
33
+ }
34
+ return message;
35
+ }
36
+ function redactMessage(message) {
37
+ const runtimeConfig = getRuntimeConfig();
38
+ message = message.split(runtimeConfig.jackettApiKey).join(redactionMsg);
39
+ for (const [key, urlStr] of Object.entries(runtimeConfig)) {
40
+ if (key.endsWith("Url") && urlStr) {
41
+ message = redactUrlPassword(message, urlStr);
42
+ }
43
+ }
44
+ return message;
45
+ }
46
+ export function initializeLogger() {
47
+ createAppDir();
48
+ logger = winston.createLogger({
49
+ level: "info",
50
+ format: winston.format.combine(winston.format.timestamp({
51
+ format: "YYYY-MM-DD HH:mm:ss",
52
+ }), winston.format.errors({ stack: true }), winston.format.splat(), winston.format.colorize(), winston.format.printf(({ level, message, label, timestamp }) => {
53
+ return `${timestamp} ${level}: ${label ? `[${label}] ` : ""}${redactMessage(message)}`;
54
+ })),
55
+ transports: [
56
+ new DailyRotateFile({
57
+ filename: "error.%DATE%.log",
58
+ createSymlink: true,
59
+ symlinkName: "error.current.log",
60
+ dirname: join(appDir(), "logs"),
61
+ maxFiles: "14d",
62
+ level: "error",
63
+ }),
64
+ new DailyRotateFile({
65
+ filename: "info.%DATE%.log",
66
+ createSymlink: true,
67
+ symlinkName: "info.current.log",
68
+ dirname: join(appDir(), "logs"),
69
+ maxFiles: "14d",
70
+ }),
71
+ new DailyRotateFile({
72
+ filename: "verbose.%DATE%.log",
73
+ createSymlink: true,
74
+ symlinkName: "verbose.current.log",
75
+ dirname: join(appDir(), "logs"),
76
+ maxFiles: "14d",
77
+ level: "silly",
78
+ }),
79
+ new winston.transports.Console({
80
+ level: getRuntimeConfig().verbose ? "silly" : "info",
81
+ format: winston.format.combine(winston.format.errors({ stack: true }), winston.format.splat(), winston.format.colorize(), winston.format.printf(({ level, message, label }) => {
82
+ return `${level}: ${label ? `[${label}] ` : ""}${redactMessage(message)}`;
83
+ })),
84
+ }),
85
+ ],
86
+ });
87
+ }
88
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,134 @@
1
+ import chalk from "chalk";
2
+ import fs from "fs";
3
+ import { getClient } from "./clients/TorrentClient.js";
4
+ import { Action, Decision, InjectionResult } from "./constants.js";
5
+ import db from "./db.js";
6
+ import { assessResult } from "./decide.js";
7
+ import { makeJackettRequest, } from "./jackett.js";
8
+ import { logger } from "./logger.js";
9
+ import { filterByContent, filterDupes, filterTimestamps } from "./preFilter.js";
10
+ import { pushNotifier } from "./pushNotifier.js";
11
+ import { EmptyNonceOptions, getRuntimeConfig, } from "./runtimeConfig.js";
12
+ import { getInfoHashesToExclude, getTorrentByCriteria, loadTorrentDirLight, saveTorrentFile, } from "./torrent.js";
13
+ import { getTag, stripExtension } from "./utils.js";
14
+ async function findOnOtherSites(searchee, hashesToExclude, nonceOptions = EmptyNonceOptions) {
15
+ const { action } = getRuntimeConfig();
16
+ const assessEach = async (result) => ({
17
+ assessment: await assessResult(result, searchee, hashesToExclude),
18
+ tracker: result.TrackerId,
19
+ });
20
+ const tag = getTag(searchee.name);
21
+ const query = stripExtension(searchee.name);
22
+ let response;
23
+ try {
24
+ response = await makeJackettRequest(query, nonceOptions);
25
+ }
26
+ catch (e) {
27
+ logger.error(`error querying Jackett for ${query}`);
28
+ return 0;
29
+ }
30
+ const results = response.Results;
31
+ const loaded = await Promise.all(results.map(assessEach));
32
+ const successful = loaded.filter((e) => e.assessment.decision === Decision.MATCH);
33
+ pushNotifier.notify({
34
+ body: `Found ${searchee.name} on ${successful.length} trackers${successful.length &&
35
+ // @ts-expect-error ListFormat totally exists in node 12
36
+ `: ${new Intl.ListFormat("en", {
37
+ style: "long",
38
+ type: "conjunction",
39
+ }).format(successful.map((s) => s.tracker))}`}`,
40
+ extra: {
41
+ infoHashes: successful.map((s) => s.assessment.info.infoHash),
42
+ trackers: successful.map((s) => s.tracker),
43
+ },
44
+ });
45
+ let isTorrentIncomplete;
46
+ for (const { tracker, assessment: { info: newInfo }, } of successful) {
47
+ const styledName = chalk.green.bold(newInfo.name);
48
+ const styledTracker = chalk.bold(tracker);
49
+ if (action === Action.INJECT) {
50
+ const result = await getClient().inject(newInfo, searchee, nonceOptions);
51
+ switch (result) {
52
+ case InjectionResult.SUCCESS:
53
+ logger.info(`Found ${styledName} on ${styledTracker} - injected`);
54
+ break;
55
+ case InjectionResult.ALREADY_EXISTS:
56
+ logger.info(`Found ${styledName} on ${styledTracker} - exists`);
57
+ break;
58
+ case InjectionResult.TORRENT_NOT_COMPLETE:
59
+ logger.warn(`Found ${styledName} on ${styledTracker} - skipping incomplete torrent`);
60
+ isTorrentIncomplete = true;
61
+ break;
62
+ case InjectionResult.FAILURE:
63
+ default:
64
+ logger.error(`Found ${styledName} on ${styledTracker} - failed to inject, saving instead`);
65
+ saveTorrentFile(tracker, tag, newInfo, nonceOptions);
66
+ break;
67
+ }
68
+ }
69
+ else {
70
+ saveTorrentFile(tracker, tag, newInfo, nonceOptions);
71
+ logger.info(`Found ${styledName} on ${styledTracker}`);
72
+ }
73
+ }
74
+ if (!isTorrentIncomplete) {
75
+ updateSearchTimestamps(searchee.name);
76
+ }
77
+ return successful.length;
78
+ }
79
+ function updateSearchTimestamps(name) {
80
+ if (db.data.searchees[name]) {
81
+ db.data.searchees[name].lastSearched = Date.now();
82
+ }
83
+ else {
84
+ db.data.searchees[name] = {
85
+ firstSearched: Date.now(),
86
+ lastSearched: Date.now(),
87
+ };
88
+ }
89
+ db.write();
90
+ }
91
+ async function findMatchesBatch(samples, hashesToExclude) {
92
+ const { delay, offset } = getRuntimeConfig();
93
+ let totalFound = 0;
94
+ for (const [i, sample] of samples.entries()) {
95
+ const sleep = new Promise((r) => setTimeout(r, delay * 1000));
96
+ const progress = chalk.blue(`[${i + 1 + offset}/${samples.length + offset}]`);
97
+ const name = stripExtension(sample.name);
98
+ logger.info("%s %s %s", progress, chalk.dim("Searching for"), name);
99
+ const numFoundPromise = findOnOtherSites(sample, hashesToExclude);
100
+ const [numFound] = await Promise.all([numFoundPromise, sleep]);
101
+ totalFound += numFound;
102
+ }
103
+ return totalFound;
104
+ }
105
+ export async function searchForLocalTorrentByCriteria(criteria, nonceOptions) {
106
+ const meta = await getTorrentByCriteria(criteria);
107
+ const hashesToExclude = getInfoHashesToExclude();
108
+ if (!filterByContent(meta))
109
+ return null;
110
+ return findOnOtherSites(meta, hashesToExclude, nonceOptions);
111
+ }
112
+ async function findSearchableTorrents() {
113
+ const { offset } = getRuntimeConfig();
114
+ const parsedTorrents = await loadTorrentDirLight();
115
+ const hashesToExclude = parsedTorrents
116
+ .map((t) => t.infoHash)
117
+ .filter(Boolean);
118
+ const filteredTorrents = filterDupes(parsedTorrents)
119
+ .filter(filterByContent)
120
+ .filter(filterTimestamps);
121
+ const samples = filteredTorrents.slice(offset);
122
+ logger.info("Found %d torrents, %d suitable to search for matches", parsedTorrents.length, filteredTorrents.length);
123
+ return { samples, hashesToExclude };
124
+ }
125
+ export async function main() {
126
+ const { offset, outputDir } = getRuntimeConfig();
127
+ const { samples, hashesToExclude } = await findSearchableTorrents();
128
+ if (offset > 0)
129
+ logger.info(`Starting at offset ${offset}`);
130
+ fs.mkdirSync(outputDir, { recursive: true });
131
+ const totalFound = await findMatchesBatch(samples, hashesToExclude);
132
+ logger.info(chalk.cyan("Done! Found %s cross seeds from %s original torrents"), chalk.bold.white(totalFound), chalk.bold.white(samples.length));
133
+ }
134
+ //# sourceMappingURL=pipeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"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"}