Adapt to new Result class

pull/73/head
MillenniumEarl 2021-02-25 19:07:36 +01:00
parent 20e3d863ed
commit 138a112e96
5 changed files with 93 additions and 88 deletions

View File

@ -53,13 +53,15 @@ export default async function fetchPlatformData(): Promise<void> {
const html = await fetchHTML(f95url.F95_LATEST_UPDATES); const html = await fetchHTML(f95url.F95_LATEST_UPDATES);
// Parse data // Parse data
const data = parseLatestPlatformHTML(html); if (html.isSuccess()) {
const data = parseLatestPlatformHTML(html.value);
// Assign data // Assign data
assignLatestPlatformData(data); assignLatestPlatformData(data);
// Cache data // Cache data
saveCache(shared.cachePath); saveCache(shared.cachePath);
} else throw html.value;
} }
} }
//#endregion Public methods //#endregion Public methods

View File

@ -42,7 +42,9 @@ async function fetchResultURLs(url: string, limit: number = 30): Promise<string[
// Fetch HTML and prepare Cheerio // Fetch HTML and prepare Cheerio
const html = await fetchHTML(url); const html = await fetchHTML(url);
const $ = cheerio.load(html);
if (html.isSuccess()) {
const $ = cheerio.load(html.value);
// Here we get all the DIV that are the body of the various query results // Here we get all the DIV that are the body of the various query results
const results = $("body").find(f95Selector.GS_RESULT_BODY); const results = $("body").find(f95Selector.GS_RESULT_BODY);
@ -54,6 +56,7 @@ async function fetchResultURLs(url: string, limit: number = 30): Promise<string[
}).get(); }).get();
return urls; return urls;
} else throw html.value;
} }
/** /**

View File

@ -12,6 +12,8 @@ import { urls as f95url } from "./constants/url.js";
import { selectors as f95selector } from "./constants/css-selector.js"; import { selectors as f95selector } from "./constants/css-selector.js";
import LoginResult from "./classes/login-result.js"; import LoginResult from "./classes/login-result.js";
import credentials from "./classes/credentials.js"; import credentials from "./classes/credentials.js";
import { failure, Result, success } from "./classes/result.js";
import { GenericAxiosError, InvalidF95Token, UnexpectedResponseContentType } from "./classes/errors.js";
// Global variables // Global variables
const userAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) " + const userAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) " +
@ -31,26 +33,23 @@ const commonConfig = {
/** /**
* Gets the HTML code of a page. * Gets the HTML code of a page.
*/ */
export async function fetchHTML(url: string): Promise<string|null> { export async function fetchHTML(url: string): Promise<Result<GenericAxiosError | UnexpectedResponseContentType, string>> {
// Local variables
let returnValue = null;
// Fetch the response of the platform // Fetch the response of the platform
const response = await fetchGETResponse(url); const response = await fetchGETResponse(url);
// Manage response if (response.isSuccess()) {
/* istambul ignore next */ const isHTML = response.value["content-type"].includes("text/html");
if (!response) {
shared.logger.warn(`Unable to fetch HTML for ${url}`);
}
/* istambul ignore next */
else if (!response.headers["content-type"].includes("text/html")) {
// The response is not a HTML page
shared.logger.warn(`The ${url} returned a ${response.headers["content-type"]} response`);
}
returnValue = response.data; const unexpectedResponseError = new UnexpectedResponseContentType({
return returnValue; id: 2,
message: `Expected HTML but received ${response.value["content-type"]}`,
error: null
});
return isHTML ?
success(response.value.data as string) :
failure(unexpectedResponseError);
} else return failure(response.value as GenericAxiosError);
} }
/** /**
@ -63,7 +62,7 @@ export async function fetchHTML(url: string): Promise<string|null> {
*/ */
export async function authenticate(credentials: credentials, force: boolean = false): Promise<LoginResult> { export async function authenticate(credentials: credentials, force: boolean = false): Promise<LoginResult> {
shared.logger.info(`Authenticating with user ${credentials.username}`); shared.logger.info(`Authenticating with user ${credentials.username}`);
if (!credentials.token) throw new Error(`Invalid token for auth: ${credentials.token}`); if (!credentials.token) throw new InvalidF95Token(`Invalid token for auth: ${credentials.token}`);
// Secure the URL // Secure the URL
const secureURL = enforceHttpsUrl(f95url.F95_LOGIN_URL); const secureURL = enforceHttpsUrl(f95url.F95_LOGIN_URL);
@ -104,43 +103,43 @@ export async function authenticate(credentials: credentials, force: boolean = fa
/** /**
* Obtain the token used to authenticate the user to the platform. * Obtain the token used to authenticate the user to the platform.
* @returns {Promise<String>} Token or `null` if an error arise
*/ */
export async function getF95Token(): Promise<string|null> { export async function getF95Token() {
// Fetch the response of the platform // Fetch the response of the platform
const response = await fetchGETResponse(f95url.F95_LOGIN_URL); const response = await fetchGETResponse(f95url.F95_LOGIN_URL);
/* istambul ignore next */
if (!response) {
shared.logger.warn("Unable to get the token for the session");
return null;
}
if (response.isSuccess()) {
// The response is a HTML page, we need to find the <input> with name "_xfToken" // The response is a HTML page, we need to find the <input> with name "_xfToken"
const $ = cheerio.load(response.data as string); const $ = cheerio.load(response.value.data as string);
return $("body").find(f95selector.GET_REQUEST_TOKEN).attr("value"); return $("body").find(f95selector.GET_REQUEST_TOKEN).attr("value");
} else throw response.value;
} }
//#region Utility methods //#region Utility methods
/** /**
* Performs a GET request to a specific URL and returns the response. * Performs a GET request to a specific URL and returns the response.
* If the request generates an error (for example 400) `null` is returned.
*/ */
export async function fetchGETResponse(url: string): Promise<AxiosResponse<unknown>> { export async function fetchGETResponse(url: string): Promise<Result<GenericAxiosError, AxiosResponse<any>>>{
// Secure the URL // Secure the URL
const secureURL = enforceHttpsUrl(url); const secureURL = enforceHttpsUrl(url);
try { try {
// Fetch and return the response // Fetch and return the response
return await axios.get(secureURL, commonConfig); const response = await axios.get(secureURL, commonConfig);
return success(response);
} catch (e) { } catch (e) {
shared.logger.error(`Error ${e.message} occurred while trying to fetch ${secureURL}`); shared.logger.error(`Error ${e.message} occurred while trying to fetch ${secureURL}`);
return null; const genericError = new GenericAxiosError({
id: 1,
message:`Error ${e.message} occurred while trying to fetch ${secureURL}`,
error: e
});
return failure(genericError);
} }
} }
/** /**
* Enforces the scheme of the URL is https and returns the new URL. * Enforces the scheme of the URL is https and returns the new URL.
* @param {String} url
* @returns {String} Secure URL or `null` if the argument is not a string * @returns {String} Secure URL or `null` if the argument is not a string
*/ */
export function enforceHttpsUrl(url: string): string { export function enforceHttpsUrl(url: string): string {
@ -149,12 +148,9 @@ export function enforceHttpsUrl(url: string): string {
/** /**
* Check if the url belongs to the domain of the F95 platform. * Check if the url belongs to the domain of the F95 platform.
* @param {String} url URL to check
* @returns {Boolean} true if the url belongs to the domain, false otherwise
*/ */
export function isF95URL(url: string): boolean { export function isF95URL(url: string): boolean {
if (url.toString().startsWith(f95url.F95_BASE_URL)) return true; return url.toString().startsWith(f95url.F95_BASE_URL);
else return false;
}; };
/** /**
@ -167,8 +163,7 @@ export function isStringAValidURL(url: string): boolean {
// Many thanks to Daveo at StackOverflow (https://preview.tinyurl.com/y2f2e2pc) // Many thanks to Daveo at StackOverflow (https://preview.tinyurl.com/y2f2e2pc)
const expression = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/; const expression = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
const regex = new RegExp(expression); const regex = new RegExp(expression);
if (url.match(regex)) return true; return url.match(regex).length > 0;
else return false;
}; };
/** /**

View File

@ -24,9 +24,9 @@ export async function getPostInformation<T extends IBasic>(url: string): Promise
// Fetch HTML and prepare Cheerio // Fetch HTML and prepare Cheerio
const html = await fetchHTML(url); const html = await fetchHTML(url);
if (!html) return null;
const $ = cheerio.load(html); if (html.isSuccess()) {
const $ = cheerio.load(html.value);
const body = $("body"); const body = $("body");
const mainPost = $(f95Selector.GS_POSTS).first(); const mainPost = $(f95Selector.GS_POSTS).first();
@ -43,6 +43,7 @@ export async function getPostInformation<T extends IBasic>(url: string): Promise
shared.logger.info(`Founded data for ${hw.name}`); shared.logger.info(`Founded data for ${hw.name}`);
return <T><unknown>hw; return <T><unknown>hw;
} else throw html.value;
}; };
//#endregion Public methods //#endregion Public methods

View File

@ -36,8 +36,9 @@ async function fetchUsernameAndAvatar(): Promise<{ [s: string]: string; }> {
// Fetch page // Fetch page
const html = await fetchHTML(f95url.F95_BASE_URL); const html = await fetchHTML(f95url.F95_BASE_URL);
if (html.isSuccess()) {
// Load HTML response // Load HTML response
const $ = cheerio.load(html); const $ = cheerio.load(html.value);
const body = $("body"); const body = $("body");
// Fetch username // Fetch username
@ -50,6 +51,7 @@ async function fetchUsernameAndAvatar(): Promise<{ [s: string]: string; }> {
username, username,
source source
}; };
} else throw html.value;
} }
/** /**
@ -73,8 +75,9 @@ async function fetchWatchedGameThreadURLs(): Promise<string[]> {
// Fetch page // Fetch page
const html = await fetchHTML(currentURL); const html = await fetchHTML(currentURL);
if (html.isSuccess()) {
// Load HTML response // Load HTML response
const $ = cheerio.load(html); const $ = cheerio.load(html.value);
const body = $("body"); const body = $("body");
// Find the URLs // Find the URLs
@ -83,6 +86,7 @@ async function fetchWatchedGameThreadURLs(): Promise<string[]> {
// Find the next page (if any) // Find the next page (if any)
currentURL = fetchNextPageURL(body); currentURL = fetchNextPageURL(body);
} else throw html.value;
} }
while (currentURL); while (currentURL);