🏗️ WIP for automatic downloads endpoint

This commit is contained in:
2024-05-09 13:45:18 -04:00
parent 17ed663823
commit 6fb1374ce9
4 changed files with 200 additions and 112 deletions

168
package-lock.json generated
View File

@@ -21,7 +21,6 @@
"@types/parse-torrent": "^5.8.7",
"@typescript-eslint/eslint-plugin": "^5.44.0",
"@typescript-eslint/parser": "^5.44.0",
"airdcpp-apisocket": "^2.4.4",
"axios": "^1.5.0",
"concurrently": "^7.6.0",
"cross-env": "^7.0.3",
@@ -35,10 +34,10 @@
"moleculer-repl": "^0.7.3",
"prettier": "^2.8.0",
"qbittorrent-api-v2": "^1.2.2",
"socket.io-client": "^4.7.5",
"ts-jest": "^29.0.3",
"ts-node": "^10.9.1",
"typescript": "^4.9.3",
"ws": "^8.16.0"
"typescript": "^4.9.3"
},
"engines": {
"node": ">= 16.x.x"
@@ -1361,6 +1360,12 @@
"@sinonjs/commons": "^3.0.0"
}
},
"node_modules/@socket.io/component-emitter": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
"dev": true
},
"node_modules/@tsconfig/node10": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
@@ -1761,19 +1766,6 @@
"node": ">=0.4.0"
}
},
"node_modules/airdcpp-apisocket": {
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/airdcpp-apisocket/-/airdcpp-apisocket-2.4.4.tgz",
"integrity": "sha512-Xn0kWSVdLJwPpOoHcdI2wzzfzZW2jTpuyZR2wCNs2UIlZhO+FTwMf3QQfNCt5gYTOld9LaiCEulxFuXDA8qrLA==",
"dev": true,
"dependencies": {
"chalk": "^4.1.2",
"events": "^3.3.0",
"invariant": "^2.2.4",
"is-in-browser": "^2.0.0",
"promise": "^8.1.0"
}
},
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -2076,12 +2068,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
"dev": true
},
"node_modules/astral-regex": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
@@ -3029,6 +3015,49 @@
"node": ">= 0.8"
}
},
"node_modules/engine.io-client": {
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz",
"integrity": "sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==",
"dev": true,
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1",
"engine.io-parser": "~5.2.1",
"ws": "~8.11.0",
"xmlhttprequest-ssl": "~2.0.0"
}
},
"node_modules/engine.io-client/node_modules/ws": {
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
"dev": true,
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/engine.io-parser": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz",
"integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==",
"dev": true,
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/error-ex": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
@@ -3715,15 +3744,6 @@
"resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz",
"integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg=="
},
"node_modules/events": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
"dev": true,
"engines": {
"node": ">=0.8.x"
}
},
"node_modules/execa": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
@@ -4417,15 +4437,6 @@
"node": ">= 0.4"
}
},
"node_modules/invariant": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
"dev": true,
"dependencies": {
"loose-envify": "^1.0.0"
}
},
"node_modules/ioredis": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.3.2.tgz",
@@ -4583,12 +4594,6 @@
"node": ">=0.10.0"
}
},
"node_modules/is-in-browser": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-2.0.0.tgz",
"integrity": "sha512-/NUv5pqj+krUJalhGpj0lyy+x7vrD9jt1PlAfkoIDEXqE+xZgFJ4FU8e9m99WuHbCqsBZVf+nzvAjNso+SO80A==",
"dev": true
},
"node_modules/is-interactive": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
@@ -5566,18 +5571,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"dev": true,
"dependencies": {
"js-tokens": "^3.0.0 || ^4.0.0"
},
"bin": {
"loose-envify": "cli.js"
}
},
"node_modules/lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@@ -6542,15 +6535,6 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/promise": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz",
"integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==",
"dev": true,
"dependencies": {
"asap": "~2.0.6"
}
},
"node_modules/prompts": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
@@ -7175,6 +7159,34 @@
"url": "https://github.com/chalk/slice-ansi?sponsor=1"
}
},
"node_modules/socket.io-client": {
"version": "4.7.5",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz",
"integrity": "sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==",
"dev": true,
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.2",
"engine.io-client": "~6.5.2",
"socket.io-parser": "~4.2.4"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/socket.io-parser": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
"dev": true,
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -8026,25 +8038,13 @@
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
}
},
"node_modules/ws": {
"version": "8.16.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz",
"integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==",
"node_modules/xmlhttprequest-ssl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
"integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==",
"dev": true,
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
"node": ">=0.4.0"
}
},
"node_modules/y18n": {

View File

@@ -40,6 +40,7 @@
"moleculer-repl": "^0.7.3",
"prettier": "^2.8.0",
"qbittorrent-api-v2": "^1.2.2",
"socket.io-client": "^4.7.5",
"ts-jest": "^29.0.3",
"ts-node": "^10.9.1",
"typescript": "^4.9.3"

View File

@@ -1,6 +1,6 @@
"use strict";
import { Context, Service, ServiceBroker, ServiceSchema, Errors } from "moleculer";
import axios from "axios";
import io from "socket.io-client";
export default class AutoDownloadService extends Service {
// @ts-ignore
@@ -25,12 +25,17 @@ export default class AutoDownloadService extends Service {
{},
);
// 2a. Get the list of hubs from AirDC++
const data: any = await this.broker.call("settings.getSettings", {
settingsKey: "directConnect",
});
const { hubs } = data?.client;
console.log("HUBZZZZZ", hubs);
// Iterate through the list of wanted comics
for (const comic of wantedComics) {
wantedComics.forEach(async (comic: any) => {
let issuesToSearch: any = [];
if (comic.wanted.markEntireVolumeAsWanted) {
// 1a. Fetch all issues from ComicVine if the entire volume is wanted
// Fetch all issues from ComicVine if the entire volume is wanted
issuesToSearch = await this.broker.call(
"comicvine.getIssuesForVolume",
{
@@ -39,12 +44,68 @@ export default class AutoDownloadService extends Service {
);
} else if (comic.wanted.issues && comic.wanted.issues.length > 0) {
// 1b. Just the issues in "wanted.issues[]"
issuesToSearch = comic.wanted.issues;
issuesToSearch = {
issues: comic.wanted.issues,
volumeName: comic.wanted.volume?.name,
};
}
for (const issue of issuesToSearch) {
// construct the search queries
for (const issue of issuesToSearch.issues) {
// 2. construct the search queries
// 2b. for AirDC++ search, with the volume name, issueId and cover_date
const { year } = this.parseStringDate(issue.coverDate);
const dcppSearchQuery = {
query: {
pattern: `${issuesToSearch.volumeName.replace(/#/g, "")} ${
issue.issueNumber
} ${year}`,
extensions: ["cbz", "cbr", "cb7"],
},
hub_urls: hubs.map((hub: any) => hub.value),
priority: 5,
};
// Perform the AirDC++ search
const dcppResults = await this.broker.call("socket.search", {
query: dcppSearchQuery,
config: {
hostname: "localhost:5600",
protocol: "http",
username: "user",
password: "pass",
},
namespace: "/automated",
});
this.socketIOInstance.on("searchResultUpdated", (data: any) => {
console.log("Hyaar we go", data);
});
// const dcppResults = await ctx.call("airdcpp.search", {
// dcppSearchQuery,
// });
// 2b. for Prowlarr search, with the volume name, issueId and cover_date
const prowlarrQuery = {
port: "9696",
apiKey: "c4f42e265fb044dc81f7e88bd41c3367",
offset: 0,
categories: [7030],
query: `${issuesToSearch.volumeName} ${issue.issueNumber} ${year}`,
host: "localhost",
limit: 100,
type: "search",
indexerIds: [2],
};
// Perform the Prowlarr search
const prowlarrResults = await this.broker.call("prowlarr.search", {
prowlarrQuery,
});
// Process results here or after the loop
console.log("DCPP Results: ", dcppResults);
console.log("Prowlarr Results: ", prowlarrResults);
}
}
});
},
},
determineDownloadChannel: {
@@ -62,7 +123,30 @@ export default class AutoDownloadService extends Service {
},
},
},
methods: {},
methods: {
parseStringDate: (dateString: string) => {
const date = new Date(dateString);
// Get the year, month, and day
const year = date.getFullYear(); // 2022
const month = date.getMonth() + 1; // December is 11 in Date object (0-indexed), so add 1 to make it human-readable
const day = date.getDate(); // 1
return { year, month, day };
},
},
async started() {
this.socketIOInstance = io("ws://localhost:3001/automated", {
transports: ["websocket"],
withCredentials: true,
});
this.socketIOInstance.on("connect", (data: any) => {
console.log("connected", data);
});
this.socketIOInstance.on("searchResultAdded", (data: any) => {
console.log("Received searchResultUpdated event:", data);
});
},
});
}
}

View File

@@ -54,28 +54,31 @@ export default class ProwlarrService extends Service {
rest: "GET /search",
handler: async (
ctx: Context<{
host: string;
port: string;
apiKey: string;
query: string;
type: string;
indexerIds: [number];
categories: [number];
limit: number;
offset: number;
prowlarrQuery: {
host: string;
port: string;
apiKey: string;
query: string;
type: string;
indexerIds: [number];
categories: [number];
limit: number;
offset: number;
};
}>,
) => {
console.log(JSON.stringify(ctx.params, null, 2));
const {
indexerIds,
categories,
host,
port,
apiKey,
query,
type,
limit,
offset,
prowlarrQuery: {
indexerIds,
categories,
host,
port,
apiKey,
query,
type,
limit,
offset,
},
} = ctx.params;
const indexer = indexerIds[0] ? indexerIds.length === 1 : indexerIds;
const category = categories[0] ? categories.length === 1 : categories;