diff --git a/dist/main/hltbsearch.d.ts b/dist/main/hltbsearch.d.ts index b0536f6..68f7af6 100644 --- a/dist/main/hltbsearch.d.ts +++ b/dist/main/hltbsearch.d.ts @@ -6,7 +6,10 @@ export declare class HltbSearch { static DETAIL_URL: string; static SEARCH_URL: string; static IMAGE_URL: string; + private searchKey; + private static readonly SEARCH_KEY_PATTERN; payload: any; detailHtml(gameId: string, signal?: AbortSignal): Promise; search(query: Array, signal?: AbortSignal): Promise; + private getSearchKey; } diff --git a/dist/main/hltbsearch.js b/dist/main/hltbsearch.js index 16b1e47..96f3254 100644 --- a/dist/main/hltbsearch.js +++ b/dist/main/hltbsearch.js @@ -8,56 +8,61 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }); }; Object.defineProperty(exports, "__esModule", { value: true }); -const axios = require('axios'); -const UserAgent = require('user-agents'); +const axios = require("axios"); +const UserAgent = require("user-agents"); +const cheerio = require("cheerio"); /** * Takes care about the http connection and response handling */ class HltbSearch { constructor() { this.payload = { - "searchType": "games", - "searchTerms": [], - "searchPage": 1, - "size": 20, - "searchOptions": { - "games": { - "userId": 0, - "platform": "", - "sortCategory": "popular", - "rangeCategory": "main", - "rangeTime": { - "min": 0, - "max": 0 + searchType: "games", + searchTerms: [], + searchPage: 1, + size: 20, + searchOptions: { + games: { + userId: 0, + platform: "", + sortCategory: "popular", + rangeCategory: "main", + rangeTime: { + min: 0, + max: 0, }, - "gameplay": { - "perspective": "", - "flow": "", - "genre": "" + gameplay: { + perspective: "", + flow: "", + genre: "", }, - "modifier": "" + modifier: "", }, - "users": { - "sortCategory": "postcount" + users: { + sortCategory: "postcount", }, - "filter": "", - "sort": 0, - "randomizer": 0 - } + filter: "", + sort: 0, + randomizer: 0, + }, }; } detailHtml(gameId, signal) { return __awaiter(this, void 0, void 0, function* () { try { - let result = yield axios.get(`${HltbSearch.DETAIL_URL}${gameId}`, { + let result = yield axios + .get(`${HltbSearch.DETAIL_URL}${gameId}`, { headers: { - 'User-Agent': new UserAgent().toString(), - 'origin': 'https://howlongtobeat.com', - 'referer': 'https://howlongtobeat.com' + "User-Agent": new UserAgent().toString(), + origin: "https://howlongtobeat.com", + referer: "https://howlongtobeat.com", }, timeout: 20000, signal, - }).catch(e => { throw e; }); + }) + .catch((e) => { + throw e; + }); return result.data; } catch (error) { @@ -78,12 +83,16 @@ class HltbSearch { let search = Object.assign({}, this.payload); search.searchTerms = query; try { - let result = yield axios.post(HltbSearch.SEARCH_URL, search, { + if (!this.searchKey) { + this.searchKey = yield this.getSearchKey(); + } + const searchUrlWithKey = HltbSearch.SEARCH_URL + this.searchKey; + let result = yield axios.post(searchUrlWithKey, search, { headers: { - 'User-Agent': new UserAgent().toString(), - 'content-type': 'application/json', - 'origin': 'https://howlongtobeat.com/', - 'referer': 'https://howlongtobeat.com/' + "User-Agent": new UserAgent().toString(), + "content-type": "application/json", + origin: "https://howlongtobeat.com/", + referer: "https://howlongtobeat.com/", }, timeout: 20000, signal, @@ -103,10 +112,48 @@ class HltbSearch { } }); } + getSearchKey(checkAllScripts = false) { + return __awaiter(this, void 0, void 0, function* () { + const res = yield axios.get(HltbSearch.BASE_URL, { + headers: { + "User-Agent": new UserAgent().toString(), + origin: "https://howlongtobeat.com", + referer: "https://howlongtobeat.com", + }, + }); + const html = res.data; + const $ = cheerio.load(html); + const scripts = $("script[src]"); + for (const el of scripts) { + const src = $(el).attr("src"); + if (!checkAllScripts && !src.includes("_app-")) { + continue; + } + const scriptUrl = HltbSearch.BASE_URL + src; + try { + const res = yield axios.get(scriptUrl, { + headers: { + "User-Agent": new UserAgent().toString(), + origin: "https://howlongtobeat.com", + referer: "https://howlongtobeat.com", + }, + }); + const scriptText = res.data; + const matches = [...scriptText.matchAll(HltbSearch.SEARCH_KEY_PATTERN)]; + return matches[0][1]; + } + catch (error) { + continue; + } + } + throw new Error("Could not find search key"); + }); + } } -HltbSearch.BASE_URL = 'https://howlongtobeat.com/'; +HltbSearch.BASE_URL = "https://howlongtobeat.com/"; HltbSearch.DETAIL_URL = `${HltbSearch.BASE_URL}game?id=`; -HltbSearch.SEARCH_URL = `${HltbSearch.BASE_URL}api/search`; +HltbSearch.SEARCH_URL = `${HltbSearch.BASE_URL}api/search/`; HltbSearch.IMAGE_URL = `${HltbSearch.BASE_URL}games/`; +HltbSearch.SEARCH_KEY_PATTERN = /"\/api\/search\/".concat\("([a-zA-Z0-9]+)"\)/g; exports.HltbSearch = HltbSearch; //# sourceMappingURL=hltbsearch.js.map \ No newline at end of file diff --git a/dist/main/hltbsearch.js.map b/dist/main/hltbsearch.js.map index 404fc2d..0fdf66c 100644 --- a/dist/main/hltbsearch.js.map +++ b/dist/main/hltbsearch.js.map @@ -1 +1 @@ -{"version":3,"file":"hltbsearch.js","sourceRoot":"","sources":["../../src/main/hltbsearch.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"hltbsearch.js","sourceRoot":"","sources":["../../src/main/hltbsearch.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/main/howlongtobeat.js b/dist/main/howlongtobeat.js index 412d040..c4be795 100644 --- a/dist/main/howlongtobeat.js +++ b/dist/main/howlongtobeat.js @@ -8,8 +8,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }); }; Object.defineProperty(exports, "__esModule", { value: true }); -const cheerio = require('cheerio'); -const levenshtein = require('fast-levenshtein'); +const cheerio = require("cheerio"); +const levenshtein = require("fast-levenshtein"); const hltbsearch_1 = require("./hltbsearch"); class HowLongToBeatService { constructor() { @@ -29,14 +29,20 @@ class HowLongToBeatService { } search(query, signal) { return __awaiter(this, void 0, void 0, function* () { - let searchTerms = query.split(' '); + let searchTerms = query.split(" "); let search = yield this.hltb.search(searchTerms, signal); // console.log(`Found ${search.count} results`); let hltbEntries = new Array(); for (const resultEntry of search.data) { - hltbEntries.push(new HowLongToBeatEntry('' + resultEntry.game_id, // game id is now a number, but I want to keep the model stable - resultEntry.game_name, '', // no description - resultEntry.profile_platform ? resultEntry.profile_platform.split(', ') : [], hltbsearch_1.HltbSearch.IMAGE_URL + resultEntry.game_image, [["Main", "Main"], ["Main + Extra", "Main + Extra"], ["Completionist", "Completionist"]], Math.round(resultEntry.comp_main / 3600), Math.round(resultEntry.comp_plus / 3600), Math.round(resultEntry.comp_100 / 3600), HowLongToBeatService.calcDistancePercentage(resultEntry.game_name, query), query)); + hltbEntries.push(new HowLongToBeatEntry("" + resultEntry.game_id, // game id is now a number, but I want to keep the model stable + resultEntry.game_name, "", // no description + resultEntry.profile_platform + ? resultEntry.profile_platform.split(", ") + : [], hltbsearch_1.HltbSearch.IMAGE_URL + resultEntry.game_image, [ + ["Main", "Main"], + ["Main + Extra", "Main + Extra"], + ["Completionist", "Completionist"], + ], Math.round(resultEntry.comp_main / 3600), Math.round(resultEntry.comp_plus / 3600), Math.round(resultEntry.comp_100 / 3600), HowLongToBeatService.calcDistancePercentage(resultEntry.game_name, query), query)); } return hltbEntries; }); @@ -102,50 +108,47 @@ class HowLongToBeatParser { */ static parseDetails(html, id) { const $ = cheerio.load(html); - let gameName = ''; - let imageUrl = ''; + let gameName = ""; + let imageUrl = ""; let timeLabels = new Array(); let gameplayMain = 0; let gameplayMainExtra = 0; let gameplayComplete = 0; - gameName = $('div[class*=GameHeader_profile_header__]')[0].children[0].data.trim(); - imageUrl = $('div[class*=GameHeader_game_image__]')[0].children[0].attribs.src; - let liElements = $('div[class*=GameStats_game_times__] li'); - const gameDescription = $('.in.back_primary.shadow_box div[class*=GameSummary_large__]').text(); + gameName = $("div[class*=GameHeader_profile_header__]")[0].children[0].data.trim(); + imageUrl = $("div[class*=GameHeader_game_image__]")[0].children[0].attribs + .src; + let liElements = $("div[class*=GameStats_game_times__] li"); + const gameDescription = $(".in.back_primary.shadow_box div[class*=GameSummary_large__]").text(); let platforms = []; - $('div[class*=GameSummary_profile_info__]').each(function () { + $("div[class*=GameSummary_profile_info__]").each(function () { const metaData = $(this).text(); - if (metaData.includes('Platforms:')) { + if (metaData.includes("Platforms:")) { platforms = metaData - .replace(/\n/g, '') - .replace('Platforms:', '') - .split(',') - .map(data => data.trim()); + .replace(/\n/g, "") + .replace("Platforms:", "") + .split(",") + .map((data) => data.trim()); return; } }); // be backward compatible let playableOn = platforms; liElements.each(function () { - let type = $(this) - .find('h4') - .text(); - let time = HowLongToBeatParser.parseTime($(this) - .find('h5') - .text()); - if (type.startsWith('Main Story') || - type.startsWith('Single-Player') || - type.startsWith('Solo')) { + let type = $(this).find("h4").text(); + let time = HowLongToBeatParser.parseTime($(this).find("h5").text()); + if (type.startsWith("Main Story") || + type.startsWith("Single-Player") || + type.startsWith("Solo")) { gameplayMain = time; - timeLabels.push(['gameplayMain', type]); + timeLabels.push(["gameplayMain", type]); } - else if (type.startsWith('Main + Sides') || type.startsWith('Co-Op')) { + else if (type.startsWith("Main + Sides") || type.startsWith("Co-Op")) { gameplayMainExtra = time; - timeLabels.push(['gameplayMainExtra', type]); + timeLabels.push(["gameplayMainExtra", type]); } - else if (type.startsWith('Completionist') || type.startsWith('Vs.')) { + else if (type.startsWith("Completionist") || type.startsWith("Vs.")) { gameplayComplete = time; - timeLabels.push(['gameplayComplete', type]); + timeLabels.push(["gameplayComplete", type]); } }); return new HowLongToBeatEntry(id, gameName, gameDescription, platforms, imageUrl, timeLabels, gameplayMain, gameplayMainExtra, gameplayComplete, 1, gameName); @@ -161,10 +164,10 @@ class HowLongToBeatParser { */ static parseTime(text) { // '65½ Hours/Mins'; '--' if not known - if (text.startsWith('--')) { + if (text.startsWith("--")) { return 0; } - if (text.indexOf(' - ') > -1) { + if (text.indexOf(" - ") > -1) { return HowLongToBeatParser.handleRange(text); } return HowLongToBeatParser.getTime(text); @@ -176,7 +179,7 @@ class HowLongToBeatParser { * @return the arithmetic median of the range */ static handleRange(text) { - let range = text.split(' - '); + let range = text.split(" - "); let d = (HowLongToBeatParser.getTime(range[0]) + HowLongToBeatParser.getTime(range[1])) / 2; @@ -190,13 +193,13 @@ class HowLongToBeatParser { */ static getTime(text) { //check for Mins, then assume 1 hour at least - const timeUnit = text.substring(text.indexOf(' ') + 1).trim(); - if (timeUnit === 'Mins') { + const timeUnit = text.substring(text.indexOf(" ") + 1).trim(); + if (timeUnit === "Mins") { return 1; } - let time = text.substring(0, text.indexOf(' ')); - if (time.indexOf('½') > -1) { - return 0.5 + parseInt(time.substring(0, text.indexOf('½'))); + let time = text.substring(0, text.indexOf(" ")); + if (time.indexOf("½") > -1) { + return 0.5 + parseInt(time.substring(0, text.indexOf("½"))); } return parseInt(time); } diff --git a/dist/main/howlongtobeat.js.map b/dist/main/howlongtobeat.js.map index f815ff3..c8d9e66 100644 --- a/dist/main/howlongtobeat.js.map +++ b/dist/main/howlongtobeat.js.map @@ -1 +1 @@ -{"version":3,"file":"howlongtobeat.js","sourceRoot":"","sources":["../../src/main/howlongtobeat.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"howlongtobeat.js","sourceRoot":"","sources":["../../src/main/howlongtobeat.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/test/howlongtobeat.integration.test.js b/dist/test/howlongtobeat.integration.test.js index e4b20de..8c2aeb4 100644 --- a/dist/test/howlongtobeat.integration.test.js +++ b/dist/test/howlongtobeat.integration.test.js @@ -3,77 +3,90 @@ Object.defineProperty(exports, "__esModule", { value: true }); const chai = require("chai"); const howlongtobeat_1 = require("../main/howlongtobeat"); const assert = chai.assert; -describe('Integration-Testing HowLongToBeatService', () => { - describe('Test for detail()', () => { - it('should load entry for 2224 (Dark Souls)', () => { - return new howlongtobeat_1.HowLongToBeatService().detail('2224').then((entry) => { +describe("Integration-Testing HowLongToBeatService", () => { + describe("Test for detail()", () => { + it("should load entry for 2224 (Dark Souls)", () => { + return new howlongtobeat_1.HowLongToBeatService().detail("2224").then((entry) => { // console.log(entry); assert.isNotNull(entry); - assert.strictEqual(entry.id, '2224'); - assert.strictEqual(entry.name, 'Dark Souls'); - assert.strictEqual(entry.searchTerm, 'Dark Souls'); + assert.strictEqual(entry.id, "2224"); + assert.strictEqual(entry.name, "Dark Souls"); + assert.strictEqual(entry.searchTerm, "Dark Souls"); assert.isString(entry.imageUrl); assert.isArray(entry.platforms); - assert.strictEqual(entry.platforms.length, 4); + assert.strictEqual(entry.platforms.length, 3); // backward compatible test - assert.strictEqual(entry.playableOn.length, 4); - assert.isTrue(entry.description.includes('Live Through A Million Deaths & Earn Your Legacy.')); + assert.strictEqual(entry.playableOn.length, 3); + assert.isTrue(entry.description.includes("Live Through A Million Deaths & Earn Your Legacy.")); assert.isTrue(entry.gameplayMain > 40); assert.isTrue(entry.gameplayCompletionist > 100); }); }); - it('should abort loading entry for 2224 (Dark Souls)', () => { + it("should abort loading entry for 2224 (Dark Souls)", () => { const abortController = new AbortController(); abortController.abort(); - return new howlongtobeat_1.HowLongToBeatService().detail('2224', abortController.signal).then(() => { + return new howlongtobeat_1.HowLongToBeatService() + .detail("2224", abortController.signal) + .then(() => { assert.fail(); - }).catch(e => { - assert.include(e.message.toLowerCase(), 'cancel'); + }) + .catch((e) => { + assert.include(e.message.toLowerCase(), "cancel"); }); }); - it('should fail to load entry for 123 (404)', () => { - return new howlongtobeat_1.HowLongToBeatService().detail('123').then(() => { + it("should fail to load entry for 123 (404)", () => { + return new howlongtobeat_1.HowLongToBeatService() + .detail("123") + .then(() => { assert.fail(); - }).catch(e => { + }) + .catch((e) => { assert.isOk(e.message); }); }); }); - describe('Test for search()', () => { - it('should have no search results when searching for dorks', () => { - return new howlongtobeat_1.HowLongToBeatService().search('dorks').then((result) => { + describe("Test for search()", () => { + it("should have no search results when searching for dorks", () => { + return new howlongtobeat_1.HowLongToBeatService().search("dorks").then((result) => { assert.isNotNull(result); assert.strictEqual(result.length, 0); }); }); - it('should have at least 3 search results when searching for dark souls III', () => { - return new howlongtobeat_1.HowLongToBeatService().search('dark souls III').then((result) => { + it("should have at least 3 search results when searching for dark souls III", () => { + return new howlongtobeat_1.HowLongToBeatService() + .search("dark souls III") + .then((result) => { assert.isNotNull(result); assert.isTrue(result.length >= 3); - assert.strictEqual(result[0].id, '26803'); - assert.strictEqual(result[0].name, 'Dark Souls III'); + assert.strictEqual(result[0].id, "26803"); + assert.strictEqual(result[0].name, "Dark Souls III"); assert.isTrue(result[0].gameplayMain > 30); assert.isTrue(result[0].gameplayCompletionist > 80); }); }); - it('should abort searching for dark souls III', () => { + it("should abort searching for dark souls III", () => { const abortController = new AbortController(); abortController.abort(); - return new howlongtobeat_1.HowLongToBeatService().search('dark souls III', abortController.signal).then(() => { + return new howlongtobeat_1.HowLongToBeatService() + .search("dark souls III", abortController.signal) + .then(() => { assert.fail(); - }).catch(e => { - assert.include(e.message.toLowerCase(), 'cancel'); + }) + .catch((e) => { + assert.include(e.message.toLowerCase(), "cancel"); }); }); - it('should have 1 search results with 100% similarity when searching for Persona 4: Golden', () => { - return new howlongtobeat_1.HowLongToBeatService().search('Persona 4 Golden').then((result) => { + it("should have 1 search results with 100% similarity when searching for Persona 4: Golden", () => { + return new howlongtobeat_1.HowLongToBeatService() + .search("Persona 4 Golden") + .then((result) => { assert.isNotNull(result); assert.strictEqual(result.length, 1); //assert.strictEqual(result[0].similarity, 1); }); }); it('Entries without any time settings (e.g. "Surge") should have a zero hour result', () => { - return new howlongtobeat_1.HowLongToBeatService().search('Surge').then((result) => { + return new howlongtobeat_1.HowLongToBeatService().search("Surge").then((result) => { // console.log(result); assert.isNotNull(result); assert.isTrue(result.length > 1); diff --git a/dist/test/howlongtobeat.integration.test.js.map b/dist/test/howlongtobeat.integration.test.js.map index b5de261..31a192b 100644 --- a/dist/test/howlongtobeat.integration.test.js.map +++ b/dist/test/howlongtobeat.integration.test.js.map @@ -1 +1 @@ -{"version":3,"file":"howlongtobeat.integration.test.js","sourceRoot":"","sources":["../../src/test/howlongtobeat.integration.test.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"howlongtobeat.integration.test.js","sourceRoot":"","sources":["../../src/test/howlongtobeat.integration.test.ts"],"names":[],"mappings":";;AAAA,6BAA6B;AAE7B,yDAA6D;AAE7D,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;AAE3B,QAAQ,CAAC,0CAA0C,EAAE,GAAG,EAAE;IACxD,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;QACjC,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;YACjD,OAAO,IAAI,oCAAoB,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;gBAC9D,sBAAsB;gBACtB,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;gBACxB,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;gBACrC,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;gBAC7C,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;gBACnD,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;gBAChC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;gBAChC,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;gBAC9C,2BAA2B;gBAC3B,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;gBAC/C,MAAM,CAAC,MAAM,CACX,KAAK,CAAC,WAAW,CAAC,QAAQ,CACxB,mDAAmD,CACpD,CACF,CAAC;gBACF,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,GAAG,EAAE,CAAC,CAAC;gBACvC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,qBAAqB,GAAG,GAAG,CAAC,CAAC;YACnD,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;YAC1D,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;YAC9C,eAAe,CAAC,KAAK,EAAE,CAAC;YACxB,OAAO,IAAI,oCAAoB,EAAE;iBAC9B,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC;iBACtC,IAAI,CAAC,GAAG,EAAE;gBACT,MAAM,CAAC,IAAI,EAAE,CAAC;YAChB,CAAC,CAAC;iBACD,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;gBACX,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,QAAQ,CAAC,CAAC;YACpD,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;YACjD,OAAO,IAAI,oCAAoB,EAAE;iBAC9B,MAAM,CAAC,KAAK,CAAC;iBACb,IAAI,CAAC,GAAG,EAAE;gBACT,MAAM,CAAC,IAAI,EAAE,CAAC;YAChB,CAAC,CAAC;iBACD,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;gBACX,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;QACjC,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;YAChE,OAAO,IAAI,oCAAoB,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;gBAChE,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;gBACzB,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YACvC,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yEAAyE,EAAE,GAAG,EAAE;YACjF,OAAO,IAAI,oCAAoB,EAAE;iBAC9B,MAAM,CAAC,gBAAgB,CAAC;iBACxB,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;gBACf,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;gBACzB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;gBAClC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;gBAC1C,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;gBACrD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,GAAG,EAAE,CAAC,CAAC;gBAC3C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;YACtD,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;YACnD,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;YAC9C,eAAe,CAAC,KAAK,EAAE,CAAC;YACxB,OAAO,IAAI,oCAAoB,EAAE;iBAC9B,MAAM,CAAC,gBAAgB,EAAE,eAAe,CAAC,MAAM,CAAC;iBAChD,IAAI,CAAC,GAAG,EAAE;gBACT,MAAM,CAAC,IAAI,EAAE,CAAC;YAChB,CAAC,CAAC;iBACD,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;gBACX,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,QAAQ,CAAC,CAAC;YACpD,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wFAAwF,EAAE,GAAG,EAAE;YAChG,OAAO,IAAI,oCAAoB,EAAE;iBAC9B,MAAM,CAAC,kBAAkB,CAAC;iBAC1B,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;gBACf,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;gBACzB,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;gBACrC,8CAA8C;YAChD,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iFAAiF,EAAE,GAAG,EAAE;YACzF,OAAO,IAAI,oCAAoB,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;gBAChE,uBAAuB;gBACvB,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;gBACzB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;gBACjC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;YAChD,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/src/main/hltbsearch.ts b/src/main/hltbsearch.ts index a9bf05a..74fa4f3 100644 --- a/src/main/hltbsearch.ts +++ b/src/main/hltbsearch.ts @@ -1,67 +1,75 @@ -const axios: any = require('axios'); -const UserAgent: any = require('user-agents'); - +const axios: any = require("axios"); +const UserAgent: any = require("user-agents"); +const cheerio: any = require("cheerio"); /** * Takes care about the http connection and response handling */ export class HltbSearch { - public static BASE_URL: string = 'https://howlongtobeat.com/'; + public static BASE_URL: string = "https://howlongtobeat.com/"; public static DETAIL_URL: string = `${HltbSearch.BASE_URL}game?id=`; - public static SEARCH_URL: string = `${HltbSearch.BASE_URL}api/search`; + public static SEARCH_URL: string = `${HltbSearch.BASE_URL}api/search/`; public static IMAGE_URL: string = `${HltbSearch.BASE_URL}games/`; + private searchKey: string; + + private static readonly SEARCH_KEY_PATTERN = + /"\/api\/search\/".concat\("([a-zA-Z0-9]+)"\)/g; + payload: any = { - "searchType": "games", - "searchTerms": [ - - ], - "searchPage": 1, - "size": 20, - "searchOptions": { - "games": { - "userId": 0, - "platform": "", - "sortCategory": "popular", - "rangeCategory": "main", - "rangeTime": { - "min": 0, - "max": 0 + searchType: "games", + searchTerms: [], + searchPage: 1, + size: 20, + searchOptions: { + games: { + userId: 0, + platform: "", + sortCategory: "popular", + rangeCategory: "main", + rangeTime: { + min: 0, + max: 0, }, - "gameplay": { - "perspective": "", - "flow": "", - "genre": "" + gameplay: { + perspective: "", + flow: "", + genre: "", }, - "modifier": "" + modifier: "", }, - "users": { - "sortCategory": "postcount" + users: { + sortCategory: "postcount", }, - "filter": "", - "sort": 0, - "randomizer": 0 - } - } + filter: "", + sort: 0, + randomizer: 0, + }, + }; async detailHtml(gameId: string, signal?: AbortSignal): Promise { try { - let result = - await axios.get(`${HltbSearch.DETAIL_URL}${gameId}`, { + let result = await axios + .get(`${HltbSearch.DETAIL_URL}${gameId}`, { headers: { - 'User-Agent': new UserAgent().toString(), - 'origin': 'https://howlongtobeat.com', - 'referer': 'https://howlongtobeat.com' + "User-Agent": new UserAgent().toString(), + origin: "https://howlongtobeat.com", + referer: "https://howlongtobeat.com", }, timeout: 20000, signal, - }).catch(e => { throw e; }); + }) + .catch((e) => { + throw e; + }); return result.data; } catch (error) { if (error) { throw new Error(error); } else if (error.response.status !== 200) { - throw new Error(`Got non-200 status code from howlongtobeat.com [${error.response.status}] + throw new Error(`Got non-200 status code from howlongtobeat.com [${ + error.response.status + }] ${JSON.stringify(error.response)} `); } @@ -73,27 +81,79 @@ export class HltbSearch { let search = { ...this.payload }; search.searchTerms = query; try { - let result = - await axios.post(HltbSearch.SEARCH_URL, search, { - headers: { - 'User-Agent': new UserAgent().toString(), - 'content-type': 'application/json', - 'origin': 'https://howlongtobeat.com/', - 'referer': 'https://howlongtobeat.com/' - }, - timeout: 20000, - signal, - }); + if (!this.searchKey) { + this.searchKey = await this.getSearchKey(); + } + + const searchUrlWithKey = HltbSearch.SEARCH_URL + this.searchKey; + + let result = await axios.post(searchUrlWithKey, search, { + headers: { + "User-Agent": new UserAgent().toString(), + "content-type": "application/json", + origin: "https://howlongtobeat.com/", + referer: "https://howlongtobeat.com/", + }, + timeout: 20000, + signal, + }); // console.log('Result', JSON.stringify(result.data)); return result.data; } catch (error) { if (error) { throw new Error(error); } else if (error.response.status !== 200) { - throw new Error(`Got non-200 status code from howlongtobeat.com [${error.response.status}] + throw new Error(`Got non-200 status code from howlongtobeat.com [${ + error.response.status + }] ${JSON.stringify(error.response)} `); } } } + + private async getSearchKey( + checkAllScripts: boolean = false + ): Promise { + const res = await axios.get(HltbSearch.BASE_URL, { + headers: { + "User-Agent": new UserAgent().toString(), + origin: "https://howlongtobeat.com", + referer: "https://howlongtobeat.com", + }, + }); + + const html = res.data; + const $ = cheerio.load(html); + + const scripts = $("script[src]"); + + for (const el of scripts) { + const src = $(el).attr("src") as string; + + if (!checkAllScripts && !src.includes("_app-")) { + continue; + } + + const scriptUrl = HltbSearch.BASE_URL + src; + + try { + const res = await axios.get(scriptUrl, { + headers: { + "User-Agent": new UserAgent().toString(), + origin: "https://howlongtobeat.com", + referer: "https://howlongtobeat.com", + }, + }); + + const scriptText = res.data; + const matches = [...scriptText.matchAll(HltbSearch.SEARCH_KEY_PATTERN)]; + return matches[0][1]; + } catch (error) { + continue; + } + } + + throw new Error("Could not find search key"); + } } diff --git a/src/main/howlongtobeat.ts b/src/main/howlongtobeat.ts index f42b055..40929b5 100644 --- a/src/main/howlongtobeat.ts +++ b/src/main/howlongtobeat.ts @@ -1,49 +1,60 @@ -const cheerio = require('cheerio'); -const levenshtein = require('fast-levenshtein'); +const cheerio = require("cheerio"); +const levenshtein = require("fast-levenshtein"); -import { HltbSearch } from './hltbsearch'; +import { HltbSearch } from "./hltbsearch"; export class HowLongToBeatService { private hltb: HltbSearch = new HltbSearch(); - constructor() { } + constructor() {} /** * Get HowLongToBeatEntry from game id, by fetching the detail page like https://howlongtobeat.com/game.php?id=6974 and parsing it. * @param gameId the hltb internal gameid * @return Promise the promise that, when fullfilled, returns the game */ - async detail(gameId: string, signal?: AbortSignal): Promise { - let detailPage = await this.hltb.detailHtml( - gameId, - signal - ); + async detail( + gameId: string, + signal?: AbortSignal + ): Promise { + let detailPage = await this.hltb.detailHtml(gameId, signal); let entry = HowLongToBeatParser.parseDetails(detailPage, gameId); return entry; } - async search(query: string, signal?: AbortSignal): Promise> { - let searchTerms = query.split(' '); - let search = await this.hltb.search( - searchTerms, - signal - ); + async search( + query: string, + signal?: AbortSignal + ): Promise> { + let searchTerms = query.split(" "); + let search = await this.hltb.search(searchTerms, signal); // console.log(`Found ${search.count} results`); let hltbEntries = new Array(); for (const resultEntry of search.data) { - hltbEntries.push(new HowLongToBeatEntry( - '' + resultEntry.game_id, // game id is now a number, but I want to keep the model stable - resultEntry.game_name, - '', // no description - resultEntry.profile_platform ? resultEntry.profile_platform.split(', ') : [], - HltbSearch.IMAGE_URL + resultEntry.game_image, - [["Main", "Main"] , ["Main + Extra", "Main + Extra"], ["Completionist", "Completionist"]], - Math.round(resultEntry.comp_main / 3600), - Math.round(resultEntry.comp_plus / 3600), - Math.round(resultEntry.comp_100 / 3600), - HowLongToBeatService.calcDistancePercentage(resultEntry.game_name, query), - query - )); + hltbEntries.push( + new HowLongToBeatEntry( + "" + resultEntry.game_id, // game id is now a number, but I want to keep the model stable + resultEntry.game_name, + "", // no description + resultEntry.profile_platform + ? resultEntry.profile_platform.split(", ") + : [], + HltbSearch.IMAGE_URL + resultEntry.game_image, + [ + ["Main", "Main"], + ["Main + Extra", "Main + Extra"], + ["Completionist", "Completionist"], + ], + Math.round(resultEntry.comp_main / 3600), + Math.round(resultEntry.comp_plus / 3600), + Math.round(resultEntry.comp_100 / 3600), + HowLongToBeatService.calcDistancePercentage( + resultEntry.game_name, + query + ), + query + ) + ); } return hltbEntries; } @@ -112,30 +123,33 @@ export class HowLongToBeatParser { */ static parseDetails(html: string, id: string): HowLongToBeatEntry { const $ = cheerio.load(html); - let gameName = ''; - let imageUrl = ''; + let gameName = ""; + let imageUrl = ""; let timeLabels: Array = new Array(); let gameplayMain = 0; let gameplayMainExtra = 0; let gameplayComplete = 0; - gameName = $('div[class*=GameHeader_profile_header__]')[0].children[0].data.trim(); - imageUrl = $('div[class*=GameHeader_game_image__]')[0].children[0].attribs.src; + gameName = $( + "div[class*=GameHeader_profile_header__]" + )[0].children[0].data.trim(); + imageUrl = $("div[class*=GameHeader_game_image__]")[0].children[0].attribs + .src; - let liElements = $('div[class*=GameStats_game_times__] li'); + let liElements = $("div[class*=GameStats_game_times__] li"); const gameDescription = $( - '.in.back_primary.shadow_box div[class*=GameSummary_large__]' + ".in.back_primary.shadow_box div[class*=GameSummary_large__]" ).text(); let platforms = []; - $('div[class*=GameSummary_profile_info__]').each(function () { + $("div[class*=GameSummary_profile_info__]").each(function () { const metaData = $(this).text(); - if (metaData.includes('Platforms:')) { + if (metaData.includes("Platforms:")) { platforms = metaData - .replace(/\n/g, '') - .replace('Platforms:', '') - .split(',') - .map(data => data.trim()); + .replace(/\n/g, "") + .replace("Platforms:", "") + .split(",") + .map((data) => data.trim()); return; } }); @@ -143,27 +157,23 @@ export class HowLongToBeatParser { let playableOn = platforms; liElements.each(function () { - let type: string = $(this) - .find('h4') - .text(); + let type: string = $(this).find("h4").text(); let time: number = HowLongToBeatParser.parseTime( - $(this) - .find('h5') - .text() + $(this).find("h5").text() ); if ( - type.startsWith('Main Story') || - type.startsWith('Single-Player') || - type.startsWith('Solo') + type.startsWith("Main Story") || + type.startsWith("Single-Player") || + type.startsWith("Solo") ) { gameplayMain = time; - timeLabels.push(['gameplayMain', type]); - } else if (type.startsWith('Main + Sides') || type.startsWith('Co-Op')) { + timeLabels.push(["gameplayMain", type]); + } else if (type.startsWith("Main + Sides") || type.startsWith("Co-Op")) { gameplayMainExtra = time; - timeLabels.push(['gameplayMainExtra', type]); - } else if (type.startsWith('Completionist') || type.startsWith('Vs.')) { + timeLabels.push(["gameplayMainExtra", type]); + } else if (type.startsWith("Completionist") || type.startsWith("Vs.")) { gameplayComplete = time; - timeLabels.push(['gameplayComplete', type]); + timeLabels.push(["gameplayComplete", type]); } }); @@ -193,10 +203,10 @@ export class HowLongToBeatParser { */ private static parseTime(text: string): number { // '65½ Hours/Mins'; '--' if not known - if (text.startsWith('--')) { + if (text.startsWith("--")) { return 0; } - if (text.indexOf(' - ') > -1) { + if (text.indexOf(" - ") > -1) { return HowLongToBeatParser.handleRange(text); } return HowLongToBeatParser.getTime(text); @@ -209,7 +219,7 @@ export class HowLongToBeatParser { * @return the arithmetic median of the range */ private static handleRange(text: string): number { - let range: Array = text.split(' - '); + let range: Array = text.split(" - "); let d: number = (HowLongToBeatParser.getTime(range[0]) + HowLongToBeatParser.getTime(range[1])) / @@ -225,16 +235,14 @@ export class HowLongToBeatParser { */ private static getTime(text: string): number { //check for Mins, then assume 1 hour at least - const timeUnit = text.substring(text.indexOf(' ') + 1).trim(); - if (timeUnit === 'Mins') { + const timeUnit = text.substring(text.indexOf(" ") + 1).trim(); + if (timeUnit === "Mins") { return 1; } - let time: string = text.substring(0, text.indexOf(' ')); - if (time.indexOf('½') > -1) { - return 0.5 + parseInt(time.substring(0, text.indexOf('½'))); + let time: string = text.substring(0, text.indexOf(" ")); + if (time.indexOf("½") > -1) { + return 0.5 + parseInt(time.substring(0, text.indexOf("½"))); } return parseInt(time); } - - } diff --git a/src/test/howlongtobeat.integration.test.ts b/src/test/howlongtobeat.integration.test.ts index fd89ebb..012c3ca 100644 --- a/src/test/howlongtobeat.integration.test.ts +++ b/src/test/howlongtobeat.integration.test.ts @@ -1,90 +1,104 @@ -import * as chai from 'chai'; +import * as chai from "chai"; -import { HowLongToBeatService } from '../main/howlongtobeat'; +import { HowLongToBeatService } from "../main/howlongtobeat"; const assert = chai.assert; -describe('Integration-Testing HowLongToBeatService', () => { - - describe('Test for detail()', () => { - - it('should load entry for 2224 (Dark Souls)', () => { - return new HowLongToBeatService().detail('2224').then((entry) => { +describe("Integration-Testing HowLongToBeatService", () => { + describe("Test for detail()", () => { + it("should load entry for 2224 (Dark Souls)", () => { + return new HowLongToBeatService().detail("2224").then((entry) => { // console.log(entry); assert.isNotNull(entry); - assert.strictEqual(entry.id, '2224'); - assert.strictEqual(entry.name, 'Dark Souls'); - assert.strictEqual(entry.searchTerm, 'Dark Souls'); + assert.strictEqual(entry.id, "2224"); + assert.strictEqual(entry.name, "Dark Souls"); + assert.strictEqual(entry.searchTerm, "Dark Souls"); assert.isString(entry.imageUrl); assert.isArray(entry.platforms); - assert.strictEqual(entry.platforms.length, 4); + assert.strictEqual(entry.platforms.length, 3); // backward compatible test - assert.strictEqual(entry.playableOn.length, 4); - assert.isTrue(entry.description.includes('Live Through A Million Deaths & Earn Your Legacy.')) + assert.strictEqual(entry.playableOn.length, 3); + assert.isTrue( + entry.description.includes( + "Live Through A Million Deaths & Earn Your Legacy." + ) + ); assert.isTrue(entry.gameplayMain > 40); assert.isTrue(entry.gameplayCompletionist > 100); }); }); - it('should abort loading entry for 2224 (Dark Souls)', () => { - const abortController = new AbortController() - abortController.abort() - return new HowLongToBeatService().detail('2224', abortController.signal).then(() => { - assert.fail() - }).catch(e => { - assert.include(e.message.toLowerCase(), 'cancel') - }) + it("should abort loading entry for 2224 (Dark Souls)", () => { + const abortController = new AbortController(); + abortController.abort(); + return new HowLongToBeatService() + .detail("2224", abortController.signal) + .then(() => { + assert.fail(); + }) + .catch((e) => { + assert.include(e.message.toLowerCase(), "cancel"); + }); }); - it('should fail to load entry for 123 (404)', () => { - return new HowLongToBeatService().detail('123').then(() => { - assert.fail() - }).catch(e => { - assert.isOk(e.message) - }); + it("should fail to load entry for 123 (404)", () => { + return new HowLongToBeatService() + .detail("123") + .then(() => { + assert.fail(); + }) + .catch((e) => { + assert.isOk(e.message); + }); }); }); - - describe('Test for search()', () => { - it('should have no search results when searching for dorks', () => { - return new HowLongToBeatService().search('dorks').then((result) => { + describe("Test for search()", () => { + it("should have no search results when searching for dorks", () => { + return new HowLongToBeatService().search("dorks").then((result) => { assert.isNotNull(result); assert.strictEqual(result.length, 0); }); }); - it('should have at least 3 search results when searching for dark souls III', () => { - return new HowLongToBeatService().search('dark souls III').then((result) => { - assert.isNotNull(result); - assert.isTrue(result.length >= 3); - assert.strictEqual(result[0].id, '26803'); - assert.strictEqual(result[0].name, 'Dark Souls III'); - assert.isTrue(result[0].gameplayMain > 30); - assert.isTrue(result[0].gameplayCompletionist > 80); - }); + it("should have at least 3 search results when searching for dark souls III", () => { + return new HowLongToBeatService() + .search("dark souls III") + .then((result) => { + assert.isNotNull(result); + assert.isTrue(result.length >= 3); + assert.strictEqual(result[0].id, "26803"); + assert.strictEqual(result[0].name, "Dark Souls III"); + assert.isTrue(result[0].gameplayMain > 30); + assert.isTrue(result[0].gameplayCompletionist > 80); + }); }); - it('should abort searching for dark souls III', () => { - const abortController = new AbortController() - abortController.abort() - return new HowLongToBeatService().search('dark souls III', abortController.signal).then(() => { - assert.fail() - }).catch(e => { - assert.include(e.message.toLowerCase(), 'cancel') - }) + it("should abort searching for dark souls III", () => { + const abortController = new AbortController(); + abortController.abort(); + return new HowLongToBeatService() + .search("dark souls III", abortController.signal) + .then(() => { + assert.fail(); + }) + .catch((e) => { + assert.include(e.message.toLowerCase(), "cancel"); + }); }); - it('should have 1 search results with 100% similarity when searching for Persona 4: Golden', () => { - return new HowLongToBeatService().search('Persona 4 Golden').then((result) => { - assert.isNotNull(result); - assert.strictEqual(result.length, 1); - //assert.strictEqual(result[0].similarity, 1); - }); + it("should have 1 search results with 100% similarity when searching for Persona 4: Golden", () => { + return new HowLongToBeatService() + .search("Persona 4 Golden") + .then((result) => { + assert.isNotNull(result); + assert.strictEqual(result.length, 1); + //assert.strictEqual(result[0].similarity, 1); + }); }); it('Entries without any time settings (e.g. "Surge") should have a zero hour result', () => { - return new HowLongToBeatService().search('Surge').then((result) => { + return new HowLongToBeatService().search("Surge").then((result) => { // console.log(result); assert.isNotNull(result); assert.isTrue(result.length > 1); @@ -92,6 +106,4 @@ describe('Integration-Testing HowLongToBeatService', () => { }); }); }); - - });