diff --git a/package-lock.json b/package-lock.json index 36ab843..c22b043 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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": { diff --git a/package.json b/package.json index e341c24..7593264 100644 --- a/package.json +++ b/package.json @@ -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" diff --git a/services/autodownload.service.ts b/services/autodownload.service.ts index 4e5753a..102157a 100644 --- a/services/autodownload.service.ts +++ b/services/autodownload.service.ts @@ -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); + }); + }, }); } } diff --git a/services/prowlarr.service.ts b/services/prowlarr.service.ts index 0a1b7a9..b1adc01 100644 --- a/services/prowlarr.service.ts +++ b/services/prowlarr.service.ts @@ -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;