Addes user data fetching
parent
49712b2337
commit
90100709ba
94
app/index.js
94
app/index.js
|
@ -2,11 +2,10 @@
|
|||
|
||||
// Modules from file
|
||||
const shared = require("./scripts/shared.js");
|
||||
const f95url = require("./scripts/constants/url.js");
|
||||
const f95selector = require("./scripts/constants/css-selector.js");
|
||||
const networkHelper = require("./scripts/network-helper.js");
|
||||
const scraper = require("./scripts/scraper.js");
|
||||
const searcher = require("./scripts/searcher.js");
|
||||
const uScraper = require("./scripts/user-scraper.js");
|
||||
|
||||
// Classes from file
|
||||
const Credentials = require("./scripts/classes/credentials.js");
|
||||
|
@ -163,95 +162,6 @@ module.exports.getUserData = async function () {
|
|||
return null;
|
||||
}
|
||||
|
||||
const threads = await getUserWatchedGameThreads(null);
|
||||
|
||||
const username = await page.evaluate(
|
||||
/* istanbul ignore next */ (selector) =>
|
||||
document.querySelector(selector).innerText,
|
||||
f95selector.USERNAME_ELEMENT
|
||||
);
|
||||
|
||||
const avatarSrc = await page.evaluate(
|
||||
/* istanbul ignore next */ (selector) =>
|
||||
document.querySelector(selector).getAttribute("src"),
|
||||
f95selector.AVATAR_PIC
|
||||
);
|
||||
|
||||
const ud = new UserData();
|
||||
ud.username = username;
|
||||
ud.avatarSrc = networkHelper.isStringAValidURL(avatarSrc) ? avatarSrc : null;
|
||||
ud.watchedThreads = threads;
|
||||
|
||||
return ud;
|
||||
return await uScraper.getUserData();
|
||||
};
|
||||
//#endregion
|
||||
|
||||
//#region Private methods
|
||||
|
||||
//#region User
|
||||
/**
|
||||
* @private
|
||||
* Gets the list of URLs of threads the user follows.
|
||||
* @param {puppeteer.Browser} browser Browser object used for navigation
|
||||
* @returns {Promise<String[]>} URL list
|
||||
*/
|
||||
async function getUserWatchedGameThreads() {
|
||||
const page = null;
|
||||
await page.goto(f95url.F95_WATCHED_THREADS); // Go to the thread page
|
||||
|
||||
// Explicitly wait for the required items to load
|
||||
await page.waitForSelector(f95selector.WATCHED_THREAD_FILTER_POPUP_BUTTON);
|
||||
|
||||
// Show the popup
|
||||
await Promise.all([
|
||||
page.click(f95selector.WATCHED_THREAD_FILTER_POPUP_BUTTON),
|
||||
page.waitForSelector(f95selector.UNREAD_THREAD_CHECKBOX),
|
||||
page.waitForSelector(f95selector.ONLY_GAMES_THREAD_OPTION),
|
||||
page.waitForSelector(f95selector.FILTER_THREADS_BUTTON),
|
||||
]);
|
||||
|
||||
// Set the filters
|
||||
await page.evaluate(
|
||||
/* istanbul ignore next */ (selector) =>
|
||||
document.querySelector(selector).removeAttribute("checked"),
|
||||
f95selector.UNREAD_THREAD_CHECKBOX
|
||||
); // Also read the threads already read
|
||||
|
||||
// Filter the threads
|
||||
await page.click(f95selector.ONLY_GAMES_THREAD_OPTION);
|
||||
await page.click(f95selector.FILTER_THREADS_BUTTON);
|
||||
await page.waitForSelector(f95selector.WATCHED_THREAD_URLS);
|
||||
|
||||
// Get the threads urls
|
||||
const urls = [];
|
||||
let nextPageExists = false;
|
||||
do {
|
||||
// Get all the URLs
|
||||
for (const handle of await page.$$(f95selector.WATCHED_THREAD_URLS)) {
|
||||
const src = await page.evaluate(
|
||||
/* istanbul ignore next */ (element) => element.href,
|
||||
handle
|
||||
);
|
||||
// If 'unread' is left, it will redirect to the last unread post
|
||||
const url = src.replace("/unread", "");
|
||||
urls.push(url);
|
||||
}
|
||||
|
||||
nextPageExists = await page.evaluate(
|
||||
/* istanbul ignore next */ (selector) => document.querySelector(selector),
|
||||
f95selector.WATCHED_THREAD_NEXT_PAGE
|
||||
);
|
||||
|
||||
// Click to next page
|
||||
if (nextPageExists) {
|
||||
await page.click(f95selector.WATCHED_THREAD_NEXT_PAGE);
|
||||
await page.waitForSelector(f95selector.WATCHED_THREAD_URLS);
|
||||
}
|
||||
} while (nextPageExists);
|
||||
|
||||
await page.close();
|
||||
return urls;
|
||||
}
|
||||
//#endregion User
|
||||
|
||||
//#endregion Private methods
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
module.exports = Object.freeze({
|
||||
BD_ENGINE_ID_SELECTOR: "div[id^=\"btn-prefix_1_\"]>span",
|
||||
BD_STATUS_ID_SELECTOR: "div[id^=\"btn-prefix_4_\"]>span",
|
||||
|
||||
GT_IMAGES: "img:not([title])[data-src^=\"https://attachments.f95zone.to\"][data-url=\"\"]",
|
||||
GT_TAGS: "a.tagItem",
|
||||
GT_TITLE: "h1.p-title-value",
|
||||
|
@ -16,13 +17,7 @@ module.exports = Object.freeze({
|
|||
GS_RESULT_BODY: "div.contentRow-main",
|
||||
GS_MEMBERSHIP: "li > a:not(.username)",
|
||||
GET_REQUEST_TOKEN: "input[name=\"_xfToken\"]",
|
||||
|
||||
LOGIN_BUTTON: "button.button--icon--login",
|
||||
UD_USERNAME_ELEMENT: "a[href=\"/account/\"] > span.p-navgroup-linkText",
|
||||
UD_AVATAR_PIC: "a[href=\"/account/\"] > span.avatar > img[class^=\"avatar\"]",
|
||||
LOGIN_MESSAGE_ERROR: "div.blockMessage.blockMessage--error.blockMessage--iconic",
|
||||
PASSWORD_INPUT: "input[name=\"password\"]",
|
||||
USERNAME_ELEMENT: "a[href=\"/account/\"] > span.p-navgroup-linkText",
|
||||
USERNAME_INPUT: "input[name=\"login\"]",
|
||||
AVATAR_INFO: "span.avatar",
|
||||
AVATAR_PIC: "a[href=\"/account/\"] > span.avatar > img[class^=\"avatar\"]",
|
||||
FILTER_THREADS_BUTTON: "button[class=\"button--primary button\"]",
|
||||
});
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
// Public modules from npm
|
||||
const axios = require("axios").default;
|
||||
const _ = require("lodash");
|
||||
const { isString } = require("lodash");
|
||||
const ky = require("ky-universal").create({
|
||||
throwHttpErrors: false,
|
||||
});
|
||||
|
@ -166,7 +166,7 @@ module.exports.fetchGETResponse = async function(url) {
|
|||
* @returns {String}
|
||||
*/
|
||||
module.exports.enforceHttpsUrl = function (url) {
|
||||
return _.isString(url) ? url.replace(/^(https?:)?\/\//, "https://") : null;
|
||||
return isString(url) ? url.replace(/^(https?:)?\/\//, "https://") : null;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -1 +1,97 @@
|
|||
"use strict";
|
||||
"use strict";
|
||||
|
||||
// Public modules from npm
|
||||
const cheerio = require("cheerio");
|
||||
|
||||
// Modules from file
|
||||
const networkHelper = require("./network-helper.js");
|
||||
const f95Selector = require("./constants/css-selector.js");
|
||||
const f95url = require("./constants/url.js");
|
||||
const UserData = require("./classes/user-data.js");
|
||||
|
||||
module.exports.getUserData = async function() {
|
||||
// Fetch data
|
||||
const data = await fetchUsernameAndAvatar();
|
||||
const urls = await fetchWatchedThreadURLs();
|
||||
|
||||
// Create object
|
||||
const ud = new UserData();
|
||||
ud.username = data.username;
|
||||
ud.avatarSrc = data.source;
|
||||
ud.watchedThreads = urls;
|
||||
|
||||
return ud;
|
||||
};
|
||||
|
||||
//#region Private methods
|
||||
async function fetchUsernameAndAvatar() {
|
||||
// Fetch page
|
||||
const html = await networkHelper.fetchHTML(f95url.F95_BASE_URL);
|
||||
|
||||
// Load HTML response
|
||||
const $ = cheerio.load(html);
|
||||
const body = $("body");
|
||||
|
||||
// Fetch username
|
||||
const username = body.find(f95Selector.UD_USERNAME_ELEMENT).first().text().trim();
|
||||
|
||||
// Fetch user avatar image source
|
||||
const source = body.find(f95Selector.UD_AVATAR_PIC).first().attr("src");
|
||||
|
||||
return {
|
||||
username,
|
||||
source
|
||||
};
|
||||
}
|
||||
|
||||
async function fetchWatchedThreadURLs() {
|
||||
// Local variables
|
||||
let currentURL = f95url.F95_WATCHED_THREADS;
|
||||
const wathcedThreadURLs = [];
|
||||
|
||||
do {
|
||||
// Fetch page
|
||||
const html = await networkHelper.fetchHTML(currentURL);
|
||||
|
||||
// Load HTML response
|
||||
const $ = cheerio.load(html);
|
||||
const body = $("body");
|
||||
|
||||
// Find the URLs
|
||||
const urls = fetchPageURLs(body);
|
||||
wathcedThreadURLs.push(...urls);
|
||||
|
||||
// Find the next page (if any)
|
||||
currentURL = fetchNextPageURL(body);
|
||||
}
|
||||
while (currentURL);
|
||||
|
||||
return wathcedThreadURLs;
|
||||
}
|
||||
|
||||
function fetchPageURLs(body) {
|
||||
const elements = body.find(f95Selector.WT_URLS);
|
||||
|
||||
return elements.map(function extractURLs(idx, e) {
|
||||
// Obtain the link (replace "unread" only for the unread threads)
|
||||
const partialLink = e.attribs.href.replace("unread", "");
|
||||
|
||||
// Compose and return the URL
|
||||
return new URL(partialLink, f95url.F95_BASE_URL).toString();
|
||||
}).get();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {cheerio.Cheerio} body
|
||||
*/
|
||||
function fetchNextPageURL(body) {
|
||||
const element = body.find(f95Selector.WT_NEXT_PAGE).first();
|
||||
|
||||
// No element found
|
||||
if(element.length === 0) return null;
|
||||
|
||||
// Compose and return the URL
|
||||
return new URL(element.attr("href"), f95url.F95_BASE_URL).toString();
|
||||
}
|
||||
//#endregion Private methods
|
|
@ -8,6 +8,7 @@ const searcher = require("../app/scripts/searcher.js");
|
|||
const scraper = require("../app/scripts/scraper.js");
|
||||
const Credentials = require("../app/scripts/classes/credentials.js");
|
||||
const networkHelper = require("../app/scripts/network-helper.js");
|
||||
const uScraper = require("../app/scripts/user-scraper.js");
|
||||
|
||||
// Configure the .env reader
|
||||
dotenv.config();
|
||||
|
@ -16,6 +17,10 @@ dotenv.config();
|
|||
auth().then(async function searchGames(result) {
|
||||
if(!result) return;
|
||||
|
||||
console.log("Fetching user data...");
|
||||
const userdata = await uScraper.getUserData();
|
||||
console.log(`${userdata.username} follows ${userdata.watchedThreads.length} threads`);
|
||||
|
||||
// Search for Kingdom Of Deception data
|
||||
await search("kingdom of deception");
|
||||
|
||||
|
|
Loading…
Reference in New Issue