2020-10-16 08:06:03 +00:00
|
|
|
"use strict";
|
2020-10-12 08:27:48 +00:00
|
|
|
|
|
|
|
// Public modules from npm
|
2020-10-16 08:06:03 +00:00
|
|
|
const puppeteer = require("puppeteer"); // skipcq: JS-0128
|
2020-10-12 08:27:48 +00:00
|
|
|
|
|
|
|
// Modules from file
|
2020-10-16 08:06:03 +00:00
|
|
|
const shared = require("./shared.js");
|
|
|
|
const constURLs = require("./constants/urls.js");
|
|
|
|
const selectors = require("./constants/css-selectors.js");
|
|
|
|
const { preparePage } = require("./puppeteer-helper.js");
|
|
|
|
const { isF95URL } = require("./urls-helper.js");
|
2020-10-12 08:27:48 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @protected
|
|
|
|
* Search the F95Zone portal to find possible conversations regarding the game you are looking for.
|
|
|
|
* @param {puppeteer.Browser} browser Browser object used for navigation
|
|
|
|
* @param {String} gamename Name of the game to search for
|
2020-10-20 20:47:36 +00:00
|
|
|
* @returns {Promise<String[]>} List of URL of possible games obtained from the preliminary research on the F95 portal
|
2020-10-12 08:27:48 +00:00
|
|
|
*/
|
2020-10-12 12:12:29 +00:00
|
|
|
module.exports.getSearchGameResults = async function (browser, gamename) {
|
2020-10-16 08:06:03 +00:00
|
|
|
if (shared.debug) console.log("Searching " + gamename + " on F95Zone");
|
2020-10-12 12:12:29 +00:00
|
|
|
|
2020-10-16 07:21:19 +00:00
|
|
|
const page = await preparePage(browser); // Set new isolated page
|
2020-10-12 12:12:29 +00:00
|
|
|
await page.setCookie(...shared.cookies); // Set cookies to avoid login
|
|
|
|
await page.goto(constURLs.F95_SEARCH_URL, {
|
2020-10-16 08:06:03 +00:00
|
|
|
waitUntil: shared.WAIT_STATEMENT,
|
2020-10-12 12:12:29 +00:00
|
|
|
}); // Go to the search form and wait for it
|
|
|
|
|
|
|
|
// Explicitly wait for the required items to load
|
2020-10-20 20:47:36 +00:00
|
|
|
await Promise.all([
|
|
|
|
page.waitForSelector(selectors.SEARCH_FORM_TEXTBOX),
|
|
|
|
page.waitForSelector(selectors.TITLE_ONLY_CHECKBOX),
|
|
|
|
page.waitForSelector(selectors.SEARCH_BUTTON)
|
|
|
|
]);
|
2020-10-12 12:12:29 +00:00
|
|
|
|
|
|
|
await page.type(selectors.SEARCH_FORM_TEXTBOX, gamename); // Type the game we desire
|
2020-10-14 13:12:35 +00:00
|
|
|
await Promise.all([
|
2020-10-20 20:47:36 +00:00
|
|
|
page.click(selectors.TITLE_ONLY_CHECKBOX), // Select only the thread with the game in the titles
|
2020-10-14 13:12:35 +00:00
|
|
|
page.click(selectors.SEARCH_BUTTON), // Execute search
|
|
|
|
page.waitForNavigation({
|
2020-10-16 08:06:03 +00:00
|
|
|
waitUntil: shared.WAIT_STATEMENT,
|
2020-10-14 13:15:34 +00:00
|
|
|
}), // Wait for page to load
|
2020-10-14 13:12:35 +00:00
|
|
|
]);
|
2020-10-14 13:15:34 +00:00
|
|
|
|
2020-10-12 12:12:29 +00:00
|
|
|
// Select all conversation titles
|
2020-10-16 07:21:19 +00:00
|
|
|
const resultsThread = await page.$$(selectors.SEARCH_THREADS_RESULTS_BODY);
|
2020-10-12 12:12:29 +00:00
|
|
|
|
|
|
|
// For each element found extract the info about the conversation
|
2020-10-16 08:06:03 +00:00
|
|
|
if (shared.debug) console.log("Extracting info from conversations");
|
2020-10-16 07:21:19 +00:00
|
|
|
const results = [];
|
|
|
|
for (const element of resultsThread) {
|
|
|
|
const gameUrl = await getOnlyGameThreads(page, element);
|
2020-10-12 12:12:29 +00:00
|
|
|
if (gameUrl !== null) results.push(gameUrl);
|
|
|
|
}
|
2020-10-16 08:06:03 +00:00
|
|
|
if (shared.debug) console.log("Find " + results.length + " conversations");
|
2020-10-12 12:12:29 +00:00
|
|
|
await page.close(); // Close the page
|
|
|
|
|
|
|
|
return results;
|
|
|
|
};
|
2020-10-12 08:27:48 +00:00
|
|
|
|
|
|
|
//#region Private methods
|
|
|
|
/**
|
|
|
|
* @private
|
|
|
|
* Return the link of a conversation if it is a game or a mod.
|
|
|
|
* @param {puppeteer.Page} page Page containing the conversation to be analyzed
|
|
|
|
* @param {puppeteer.ElementHandle} divHandle Element of the conversation to be analyzed
|
|
|
|
* @return {Promise<String>} URL of the game/mod or null if the URL is not of a game
|
|
|
|
*/
|
|
|
|
async function getOnlyGameThreads(page, divHandle) {
|
2020-10-12 12:12:29 +00:00
|
|
|
// Obtain the elements containing the basic information
|
2020-10-16 07:21:19 +00:00
|
|
|
const titleHandle = await divHandle.$(selectors.THREAD_TITLE);
|
|
|
|
const forumHandle = await divHandle.$(selectors.SEARCH_THREADS_MEMBERSHIP);
|
2020-10-12 12:12:29 +00:00
|
|
|
|
|
|
|
// Get the forum where the thread was posted
|
2020-10-16 07:21:19 +00:00
|
|
|
const forum = await getMembershipForum(page, forumHandle);
|
2020-10-16 08:06:03 +00:00
|
|
|
if (forum !== "GAMES" && forum !== "MODS") return null;
|
2020-10-12 12:12:29 +00:00
|
|
|
|
|
|
|
// Get the URL of the thread from the title
|
|
|
|
return await getThreadURL(page, titleHandle);
|
2020-10-12 08:27:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @private
|
2020-10-16 07:58:08 +00:00
|
|
|
* Obtain the membership forum of the thread passed throught 'handle'.
|
2020-10-12 08:27:48 +00:00
|
|
|
* @param {puppeteer.Page} page Page containing the conversation to be analyzed
|
|
|
|
* @param {puppeteer.ElementHandle} handle Handle containing the forum membership
|
2020-10-12 12:12:29 +00:00
|
|
|
* @returns {Promise<String>} Uppercase membership category
|
2020-10-12 08:27:48 +00:00
|
|
|
*/
|
|
|
|
async function getMembershipForum(page, handle) {
|
2020-10-12 12:12:29 +00:00
|
|
|
// The link can be something like:
|
|
|
|
// + /forums/request.NUMBER/
|
|
|
|
// + /forums/game-recommendations-identification.NUMBER/
|
|
|
|
// + /forums/games.NUMBER/ <-- We need this
|
|
|
|
|
|
|
|
let link = await page.evaluate(
|
|
|
|
/* istanbul ignore next */
|
2020-10-16 08:06:03 +00:00
|
|
|
(e) => e.getAttribute("href"),
|
2020-10-12 12:12:29 +00:00
|
|
|
handle
|
|
|
|
);
|
|
|
|
|
|
|
|
// Parse link
|
2020-10-16 08:06:03 +00:00
|
|
|
link = link.replace("/forums/", "");
|
|
|
|
const endIndex = link.indexOf(".");
|
2020-10-16 07:21:19 +00:00
|
|
|
const forum = link.substring(0, endIndex);
|
2020-10-12 12:12:29 +00:00
|
|
|
|
|
|
|
return forum.toUpperCase();
|
2020-10-12 08:27:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @private
|
2020-10-16 07:58:08 +00:00
|
|
|
* Obtain the URL of the thread passed through 'handle'.
|
2020-10-12 08:27:48 +00:00
|
|
|
* @param {puppeteer.Page} page Page containing the conversation to be analyzed
|
|
|
|
* @param {puppeteer.ElementHandle} handle Handle containing the thread title
|
|
|
|
* @returns {Promise<String>} URL of the thread
|
|
|
|
*/
|
|
|
|
async function getThreadURL(page, handle) {
|
2020-10-16 07:21:19 +00:00
|
|
|
const relativeURLThread = await page.evaluate(
|
2020-10-12 12:12:29 +00:00
|
|
|
/* istanbul ignore next */
|
2020-10-16 08:06:03 +00:00
|
|
|
(e) => e.querySelector("a").href,
|
2020-10-12 12:12:29 +00:00
|
|
|
handle
|
|
|
|
);
|
2020-10-14 14:04:50 +00:00
|
|
|
|
|
|
|
// Some game already have a full URL
|
|
|
|
if (isF95URL(relativeURLThread)) return relativeURLThread;
|
|
|
|
|
2020-10-16 07:21:31 +00:00
|
|
|
const urlThread = new URL(
|
|
|
|
relativeURLThread,
|
|
|
|
constURLs.F95_BASE_URL
|
|
|
|
).toString();
|
2020-10-12 12:12:29 +00:00
|
|
|
return urlThread;
|
2020-10-12 08:27:48 +00:00
|
|
|
}
|
|
|
|
//#endregion Private methods
|