Merge branch '2.0.0-ts' of https://github.com/MillenniumEarl/F95API into 2.0.0-ts

pull/74/head
MillenniumEarl 2021-03-04 10:47:40 +01:00
commit 8563be901f
17 changed files with 104 additions and 104 deletions

View File

@ -1,5 +1,5 @@
/* /*
to use this example, create an .env file to use this example, create an .env file
in the project root with the following values: in the project root with the following values:
F95_USERNAME = YOUR_USERNAME F95_USERNAME = YOUR_USERNAME
@ -12,12 +12,12 @@ F95_PASSWORD = YOUR_PASSWORD
import dotenv from "dotenv"; import dotenv from "dotenv";
// Modules from file // Modules from file
import { login, import { login,
getUserData, getUserData,
getLatestUpdates, getLatestUpdates,
LatestSearchQuery, LatestSearchQuery,
Game, Game,
searchHandiwork, searchHandiwork,
HandiworkSearchQuery HandiworkSearchQuery
} from "./index.js"; } from "./index.js";

View File

@ -59,7 +59,7 @@ export function isLogged(): boolean { return shared.isLogged; };
/** /**
* Log in to the F95Zone platform. * Log in to the F95Zone platform.
* *
* This **must** be the first operation performed before accessing any other script functions. * This **must** be the first operation performed before accessing any other script functions.
*/ */
export async function login(username: string, password: string): Promise<LoginResult> { export async function login(username: string, password: string): Promise<LoginResult> {
@ -102,7 +102,7 @@ export async function login(username: string, password: string): Promise<LoginRe
/** /**
* Chek if exists a new version of the handiwork. * Chek if exists a new version of the handiwork.
* *
* You **must** be logged in to the portal before calling this method. * You **must** be logged in to the portal before calling this method.
*/ */
export async function checkIfHandiworkHasUpdate(hw: HandiWork): Promise<boolean> { export async function checkIfHandiworkHasUpdate(hw: HandiWork): Promise<boolean> {
@ -127,9 +127,9 @@ export async function checkIfHandiworkHasUpdate(hw: HandiWork): Promise<boolean>
/** /**
* Search for one or more handiworks identified by a specific query. * Search for one or more handiworks identified by a specific query.
* *
* You **must** be logged in to the portal before calling this method. * You **must** be logged in to the portal before calling this method.
* *
* @param {HandiworkSearchQuery} query Parameters used for the search. * @param {HandiworkSearchQuery} query Parameters used for the search.
* @param {Number} limit Maximum number of results. Default: 10 * @param {Number} limit Maximum number of results. Default: 10
*/ */
@ -137,12 +137,12 @@ export async function searchHandiwork<T extends IBasic>(query: HandiworkSearchQu
// Check if the user is logged // Check if the user is logged
if (!shared.isLogged) throw new UserNotLogged(USER_NOT_LOGGED); if (!shared.isLogged) throw new UserNotLogged(USER_NOT_LOGGED);
return await search<T>(query, limit); return search<T>(query, limit);
}; };
/** /**
* Given the url, it gets all the information about the handiwork requested. * Given the url, it gets all the information about the handiwork requested.
* *
* You **must** be logged in to the portal before calling this method. * You **must** be logged in to the portal before calling this method.
*/ */
export async function getHandiworkFromURL<T extends IBasic>(url: string): Promise<T> { export async function getHandiworkFromURL<T extends IBasic>(url: string): Promise<T> {
@ -155,14 +155,14 @@ export async function getHandiworkFromURL<T extends IBasic>(url: string): Promis
if (!isF95URL(url)) throw new Error(`${url} is not a valid F95Zone URL`); if (!isF95URL(url)) throw new Error(`${url} is not a valid F95Zone URL`);
// Get game data // Get game data
return await getHandiworkInformation<T>(url); return getHandiworkInformation<T>(url);
}; };
/** /**
* Gets the data of the currently logged in user. * Gets the data of the currently logged in user.
* *
* You **must** be logged in to the portal before calling this method. * You **must** be logged in to the portal before calling this method.
* *
* @returns {Promise<UserProfile>} Data of the user currently logged in * @returns {Promise<UserProfile>} Data of the user currently logged in
*/ */
export async function getUserData(): Promise<UserProfile> { export async function getUserData(): Promise<UserProfile> {
@ -178,9 +178,9 @@ export async function getUserData(): Promise<UserProfile> {
/** /**
* Gets the latest updated games that match the specified parameters. * Gets the latest updated games that match the specified parameters.
* *
* You **must** be logged in to the portal before calling this method. * You **must** be logged in to the portal before calling this method.
* *
* @param {LatestSearchQuery} query Parameters used for the search. * @param {LatestSearchQuery} query Parameters used for the search.
* @param {Number} limit Maximum number of results. Default: 10 * @param {Number} limit Maximum number of results. Default: 10
*/ */
@ -196,7 +196,7 @@ export async function getLatestUpdates<T extends IBasic>(query: LatestSearchQuer
// Get the data from urls // Get the data from urls
const promiseList = urls.map((u: string) => getHandiworkInformation<T>(u)); const promiseList = urls.map((u: string) => getHandiworkInformation<T>(u));
return await Promise.all(promiseList); return Promise.all(promiseList);
}; };
//#endregion //#endregion

View File

@ -45,7 +45,7 @@ export default class Thread {
public get id() { return this._id; } public get id() { return this._id; }
/** /**
* URL of the thread. * URL of the thread.
* *
* It may vary depending on any versions of the contained product. * It may vary depending on any versions of the contained product.
*/ */
public get url() { return this._url; } public get url() { return this._url; }
@ -85,8 +85,8 @@ export default class Thread {
//#endregion Getters //#endregion Getters
/** /**
* Initializes an object for mapping a thread. * Initializes an object for mapping a thread.
* *
* The unique ID of the thread must be specified. * The unique ID of the thread must be specified.
*/ */
constructor(id: number) { this._id = id; } constructor(id: number) { this._id = id; }
@ -167,7 +167,7 @@ export default class Thread {
} }
/** /**
* It processes the rating of the thread * It processes the rating of the thread
* starting from the data contained in the JSON+LD tag. * starting from the data contained in the JSON+LD tag.
*/ */
private parseRating(data: TJsonLD): TRating { private parseRating(data: TJsonLD): TRating {
@ -241,7 +241,7 @@ export default class Thread {
/** /**
* Gets the post in the `index` position with respect to the posts in the thread. * Gets the post in the `index` position with respect to the posts in the thread.
* *
* `index` must be greater or equal to 1. * `index` must be greater or equal to 1.
* If the post is not found, `null` is returned. * If the post is not found, `null` is returned.
*/ */

View File

@ -149,7 +149,7 @@ export default class UserProfile extends PlatformUser {
} }
// Wait for the promises to resolve // Wait for the promises to resolve
return await Promise.all(responsePromiseList); return Promise.all(responsePromiseList);
} }
/** /**

View File

@ -11,7 +11,7 @@ export default class PrefixParser {
//#region Private methods //#region Private methods
/** /**
* Gets the key associated with a given value from a dictionary. * Gets the key associated with a given value from a dictionary.
* @param {Object} object Dictionary to search * @param {Object} object Dictionary to search
* @param {Any} value Value associated with the key * @param {Any} value Value associated with the key
* @returns {String|undefined} Key found or undefined * @returns {String|undefined} Key found or undefined
*/ */
@ -43,7 +43,7 @@ export default class PrefixParser {
} }
/** /**
* Search within the platform prefixes for the * Search within the platform prefixes for the
* desired element and return the dictionary that contains it. * desired element and return the dictionary that contains it.
* @param element Element to search in the prefixes as a key or as a value * @param element Element to search in the prefixes as a key or as a value
*/ */

View File

@ -13,21 +13,21 @@ import ThreadSearchQuery, { TThreadOrder } from './thread-search-query.js';
// Type definitions // Type definitions
/** /**
* Method of sorting results. Try to unify the two types of * Method of sorting results. Try to unify the two types of
* sorts in the "Latest" section and in the "Thread search" * sorts in the "Latest" section and in the "Thread search"
* section. Being dynamic research, if a sorting type is not * section. Being dynamic research, if a sorting type is not
* available, the replacement sort is chosen. * available, the replacement sort is chosen.
* *
* `date`: Order based on the latest update * `date`: Order based on the latest update
* *
* `likes`: Order based on the number of likes received. Replacement: `replies`. * `likes`: Order based on the number of likes received. Replacement: `replies`.
* *
* `relevance`: Order based on the relevance of the result (or rating). * `relevance`: Order based on the relevance of the result (or rating).
* *
* `replies`: Order based on the number of answers to the thread. Replacement: `views`. * `replies`: Order based on the number of answers to the thread. Replacement: `views`.
* *
* `title`: Order based on the growing alphabetical order of the titles. * `title`: Order based on the growing alphabetical order of the titles.
* *
* `views`: Order based on the number of visits. Replacement: `replies`. * `views`: Order based on the number of visits. Replacement: `replies`.
*/ */
type THandiworkOrder = "date" | "likes" | "relevance" | "replies" | "title" | "views"; type THandiworkOrder = "date" | "likes" | "relevance" | "replies" | "title" | "views";
@ -80,8 +80,8 @@ export default class HandiworkSearchQuery implements IQuery {
//#region Public methods //#region Public methods
/** /**
* Select what kind of search should be * Select what kind of search should be
* performed based on the properties of * performed based on the properties of
* the query. * the query.
*/ */
public selectSearchType(): "latest" | "thread" { public selectSearchType(): "latest" | "thread" {
@ -89,8 +89,8 @@ export default class HandiworkSearchQuery implements IQuery {
const MAX_TAGS_LATEST_SEARCH = 5; const MAX_TAGS_LATEST_SEARCH = 5;
const DEFAULT_SEARCH_TYPE = "latest"; const DEFAULT_SEARCH_TYPE = "latest";
// If the keywords are set or the number // If the keywords are set or the number
// of included tags is greather than 5, // of included tags is greather than 5,
// we must perform a thread search // we must perform a thread search
if (this.keywords || this.includedTags.length > MAX_TAGS_LATEST_SEARCH) return "thread"; if (this.keywords || this.includedTags.length > MAX_TAGS_LATEST_SEARCH) return "thread";
@ -156,7 +156,7 @@ export default class HandiworkSearchQuery implements IQuery {
private castToThread(): ThreadSearchQuery { private castToThread(): ThreadSearchQuery {
// Cast the basic query object and copy common values // Cast the basic query object and copy common values
const query: ThreadSearchQuery = new ThreadSearchQuery; const query: ThreadSearchQuery = new ThreadSearchQuery;
Object.keys(this).forEach(key => { Object.keys(this).forEach(key => {
if (query.hasOwnProperty(key)) { if (query.hasOwnProperty(key)) {
query[key] = this[key]; query[key] = this[key];
} }

View File

@ -29,15 +29,15 @@ export default class LatestSearchQuery implements IQuery {
public category: TCategory = 'games'; public category: TCategory = 'games';
/** /**
* Ordering type. * Ordering type.
* *
* Default: `date`. * Default: `date`.
*/ */
public order: TLatestOrder = 'date'; public order: TLatestOrder = 'date';
/** /**
* Date limit in days, to be understood as "less than". * Date limit in days, to be understood as "less than".
* Use `1` to indicate "today" or `null` to indicate "anytime". * Use `1` to indicate "today" or `null` to indicate "anytime".
* *
* Default: `null` * Default: `null`
*/ */
public date: TDate = null; public date: TDate = null;
@ -74,7 +74,7 @@ export default class LatestSearchQuery implements IQuery {
const decoded = decodeURIComponent(url.toString()); const decoded = decodeURIComponent(url.toString());
// Fetch the result // Fetch the result
return await fetchGETResponse(decoded); return fetchGETResponse(decoded);
} }
/** /**
@ -127,7 +127,7 @@ export default class LatestSearchQuery implements IQuery {
} }
/** /**
* *
*/ */
private dateDiffInDays(a: Date, b: Date) { private dateDiffInDays(a: Date, b: Date) {
const MS_PER_DAY = 1000 * 60 * 60 * 24; const MS_PER_DAY = 1000 * 60 * 60 * 24;

View File

@ -82,7 +82,7 @@ export default class ThreadSearchQuery implements IQuery {
const params = this.preparePOSTParameters(); const params = this.preparePOSTParameters();
// Return the POST response // Return the POST response
return await fetchPOSTResponse(urls.F95_SEARCH_URL, params); return fetchPOSTResponse(urls.F95_SEARCH_URL, params);
} }
//#endregion Public methods //#endregion Public methods

View File

@ -25,7 +25,7 @@ export const selectors = {
export const GENERIC = { export const GENERIC = {
/** /**
* The ID of the user currently logged into * The ID of the user currently logged into
* the platform in the attribute `data-user-id`. * the platform in the attribute `data-user-id`.
*/ */
CURRENT_USER_ID: "span.avatar[data-user-id]", CURRENT_USER_ID: "span.avatar[data-user-id]",
@ -41,17 +41,17 @@ export const WATCHED_THREAD = {
*/ */
BODIES: "div.structItem-cell--main", BODIES: "div.structItem-cell--main",
/** /**
* Link element containing the partial URL * Link element containing the partial URL
* of the thread in the `href` attribute. * of the thread in the `href` attribute.
* *
* It may be followed by the `/unread` segment. * It may be followed by the `/unread` segment.
* *
* For use within a `WATCHED_THREAD.BODIES` selector. * For use within a `WATCHED_THREAD.BODIES` selector.
*/ */
URL: "div > a[data-tp-primary]", URL: "div > a[data-tp-primary]",
/** /**
* Name of the forum to which the thread belongs as text. * Name of the forum to which the thread belongs as text.
* *
* For use within a `WATCHED_THREAD.BODIES` selector. * For use within a `WATCHED_THREAD.BODIES` selector.
*/ */
FORUM: "div.structItem-cell--main > div.structItem-minor > ul.structItem-parts > li:last-of-type > a", FORUM: "div.structItem-cell--main > div.structItem-minor > ul.structItem-parts > li:last-of-type > a",
@ -64,19 +64,19 @@ export const WATCHED_THREAD = {
export const THREAD = { export const THREAD = {
/** /**
* Number of pages in the thread (as text of the element). * Number of pages in the thread (as text of the element).
* *
* Two identical elements are identified. * Two identical elements are identified.
*/ */
LAST_PAGE: "ul.pageNav-main > li:last-child > a", LAST_PAGE: "ul.pageNav-main > li:last-child > a",
/** /**
* Identify the creator of the thread. * Identify the creator of the thread.
* *
* The ID is contained in the `data-user-id` attribute. * The ID is contained in the `data-user-id` attribute.
*/ */
OWNER_ID: "div.uix_headerInner > * a.username[data-user-id]", OWNER_ID: "div.uix_headerInner > * a.username[data-user-id]",
/** /**
* Contains the creation date of the thread. * Contains the creation date of the thread.
* *
* The date is contained in the `datetime` attribute as an ISO string. * The date is contained in the `datetime` attribute as an ISO string.
*/ */
CREATION: "div.uix_headerInner > * time", CREATION: "div.uix_headerInner > * time",
@ -94,7 +94,7 @@ export const THREAD = {
TITLE: "h1.p-title-value", TITLE: "h1.p-title-value",
/** /**
* JSON containing thread information. * JSON containing thread information.
* *
* Two different elements are found. * Two different elements are found.
*/ */
JSONLD: "script[type=\"application/ld+json\"]", JSONLD: "script[type=\"application/ld+json\"]",
@ -106,44 +106,44 @@ export const THREAD = {
export const POST = { export const POST = {
/** /**
* Unique post number for the current thread. * Unique post number for the current thread.
* *
* For use within a `THREAD.POSTS_IN_PAGE` selector. * For use within a `THREAD.POSTS_IN_PAGE` selector.
*/ */
NUMBER: "* ul.message-attribution-opposite > li > a:not([id])[rel=\"nofollow\"]", NUMBER: "* ul.message-attribution-opposite > li > a:not([id])[rel=\"nofollow\"]",
/** /**
* Unique ID of the post in the F95Zone platform in the `id` attribute. * Unique ID of the post in the F95Zone platform in the `id` attribute.
* *
* For use within a `THREAD.POSTS_IN_PAGE` selector. * For use within a `THREAD.POSTS_IN_PAGE` selector.
*/ */
ID: "span[id^=\"post\"]", ID: "span[id^=\"post\"]",
/** /**
* Unique ID of the post author in the `data-user-id` attribute. * Unique ID of the post author in the `data-user-id` attribute.
* *
* For use within a `THREAD.POSTS_IN_PAGE` selector. * For use within a `THREAD.POSTS_IN_PAGE` selector.
*/ */
OWNER_ID: "* div.message-cell--user > * a[data-user-id]", OWNER_ID: "* div.message-cell--user > * a[data-user-id]",
/** /**
* Main body of the post where the message written by the user is contained. * Main body of the post where the message written by the user is contained.
* *
* For use within a `THREAD.POSTS_IN_PAGE` selector. * For use within a `THREAD.POSTS_IN_PAGE` selector.
*/ */
BODY: "* article.message-body > div.bbWrapper", BODY: "* article.message-body > div.bbWrapper",
/** /**
* Publication date of the post contained in the `datetime` attribute as an ISO date. * Publication date of the post contained in the `datetime` attribute as an ISO date.
* *
* For use within a `THREAD.POSTS_IN_PAGE` selector. * For use within a `THREAD.POSTS_IN_PAGE` selector.
*/ */
PUBLISH_DATE: "* div.message-attribution-main > a > time", PUBLISH_DATE: "* div.message-attribution-main > a > time",
/** /**
* Last modified date of the post contained in the `datetime` attribute as the ISO date. * Last modified date of the post contained in the `datetime` attribute as the ISO date.
* *
* For use within a `THREAD.POSTS_IN_PAGE` selector. * For use within a `THREAD.POSTS_IN_PAGE` selector.
*/ */
LAST_EDIT: "* div.message-lastEdit > time", LAST_EDIT: "* div.message-lastEdit > time",
/** /**
* Gets the element only if the post has been bookmarked. * Gets the element only if the post has been bookmarked.
* *
* For use within a `THREAD.POSTS_IN_PAGE` selector. * For use within a `THREAD.POSTS_IN_PAGE` selector.
*/ */
BOOKMARKED: "* ul.message-attribution-opposite >li > a[title=\"Bookmark\"].is-bookmarked", BOOKMARKED: "* ul.message-attribution-opposite >li > a[title=\"Bookmark\"].is-bookmarked",
@ -152,37 +152,37 @@ export const POST = {
export const MEMBER = { export const MEMBER = {
/** /**
* Name of the user. * Name of the user.
* *
* It also contains the unique ID of the user in the `data-user-id` attribute. * It also contains the unique ID of the user in the `data-user-id` attribute.
*/ */
NAME: "span[class^=\"username\"]", NAME: "span[class^=\"username\"]",
/** /**
* Title of the user in the platform. * Title of the user in the platform.
* *
* i.e.: Member * i.e.: Member
*/ */
TITLE: "span.userTitle", TITLE: "span.userTitle",
/** /**
* Avatar used by the user. * Avatar used by the user.
* *
* Source in the attribute `src`. * Source in the attribute `src`.
*/ */
AVATAR: "span.avatarWrapper > a.avatar > img", AVATAR: "span.avatarWrapper > a.avatar > img",
/** /**
* User assigned banners. * User assigned banners.
* *
* The last element is always empty and can be ignored. * The last element is always empty and can be ignored.
*/ */
BANNERS: "em.userBanner > strong", BANNERS: "em.userBanner > strong",
/** /**
* Date the user joined the platform. * Date the user joined the platform.
* *
* The date is contained in the `datetime` attribute as an ISO string. * The date is contained in the `datetime` attribute as an ISO string.
*/ */
JOINED: "div.uix_memberHeader__extra > div.memberHeader-blurb:nth-child(1) > * time", JOINED: "div.uix_memberHeader__extra > div.memberHeader-blurb:nth-child(1) > * time",
/** /**
* Last time the user connected to the platform. * Last time the user connected to the platform.
* *
* The date is contained in the `datetime` attribute as an ISO string. * The date is contained in the `datetime` attribute as an ISO string.
*/ */
LAST_SEEN: "div.uix_memberHeader__extra > div.memberHeader-blurb:nth-child(2) > * time", LAST_SEEN: "div.uix_memberHeader__extra > div.memberHeader-blurb:nth-child(2) > * time",
@ -193,14 +193,14 @@ export const MEMBER = {
AMOUNT_DONATED: "div.pairJustifier > dl:nth-child(5) > dd", AMOUNT_DONATED: "div.pairJustifier > dl:nth-child(5) > dd",
/** /**
* Button used to follow/unfollow the user. * Button used to follow/unfollow the user.
* *
* If the text is `Unfollow` then the user is followed. * If the text is `Unfollow` then the user is followed.
* If the text is `Follow` then the user is not followed. * If the text is `Follow` then the user is not followed.
*/ */
FOLLOWED: "div.memberHeader-buttons > div.buttonGroup:first-child > a[data-sk-follow] > span", FOLLOWED: "div.memberHeader-buttons > div.buttonGroup:first-child > a[data-sk-follow] > span",
/** /**
* Button used to ignore/unignore the user. * Button used to ignore/unignore the user.
* *
* If the text is `Unignore` then the user is ignored. * If the text is `Unignore` then the user is ignored.
* If the text is `Ignore` then the user is not ignored. * If the text is `Ignore` then the user is not ignored.
*/ */

View File

@ -8,8 +8,8 @@ export const urls = {
F95_LATEST_PHP: "https://f95zone.to/new_latest.php", F95_LATEST_PHP: "https://f95zone.to/new_latest.php",
F95_BOOKMARKS: "https://f95zone.to/account/bookmarks", F95_BOOKMARKS: "https://f95zone.to/account/bookmarks",
/** /**
* Add the unique ID of the post to * Add the unique ID of the post to
* get the thread page where the post * get the thread page where the post
* is present. * is present.
*/ */
F95_POSTS: "https://f95zone.to/posts/", F95_POSTS: "https://f95zone.to/posts/",

View File

@ -9,7 +9,7 @@ import { urls as f95url } from "../constants/url.js";
* You *must* be logged. * You *must* be logged.
* @param {LatestSearchQuery} query * @param {LatestSearchQuery} query
* Query used for the search * Query used for the search
* @param {Number} limit * @param {Number} limit
* Maximum number of items to get. Default: 30 * Maximum number of items to get. Default: 30
* @returns {Promise<String[]>} URLs of the handiworks * @returns {Promise<String[]>} URLs of the handiworks
*/ */

View File

@ -43,7 +43,7 @@ interface ILatestResource {
//#region Public methods //#region Public methods
/** /**
* Gets the basic data used for game data processing * Gets the basic data used for game data processing
* (such as graphics engines and progress statuses) * (such as graphics engines and progress statuses)
*/ */
export default async function fetchPlatformData(): Promise<void> { export default async function fetchPlatformData(): Promise<void> {
@ -106,7 +106,7 @@ function saveCache(path: string): void {
/** /**
* @private * @private
* Given the HTML code of the response from the F95Zone, * Given the HTML code of the response from the F95Zone,
* parse it and return the result. * parse it and return the result.
*/ */
function parseLatestPlatformHTML(html: string): ILatestResource{ function parseLatestPlatformHTML(html: string): ILatestResource{

View File

@ -36,6 +36,6 @@ export default async function executeQuery(query: any, limit: number = 30): Prom
"handiwork"); "handiwork");
// Fetch and return the urls // Fetch and return the urls
return await searchMap[key](query, limit); return searchMap[key](query, limit);
} }
//#endregion //#endregion

View File

@ -26,7 +26,7 @@ export default async function fetchThreadHandiworkURLs(query: ThreadSearchQuery,
const response = await query.execute(); const response = await query.execute();
// Fetch the results from F95 and return the handiwork urls // Fetch the results from F95 and return the handiwork urls
if (response.isSuccess()) return await fetchResultURLs(response.value.data as string, limit); if (response.isSuccess()) return fetchResultURLs(response.value.data as string, limit);
else throw response.value else throw response.value
} }

View File

@ -15,7 +15,7 @@ import { failure, Result, success } from "./classes/result.js";
import { GenericAxiosError, InvalidF95Token, UnexpectedResponseContentType } from "./classes/errors.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) " +
"AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Safari/605.1.15"; "AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Safari/605.1.15";
// @ts-ignore // @ts-ignore
axiosCookieJarSupport.default(axios); axiosCookieJarSupport.default(axios);
@ -61,15 +61,15 @@ export async function fetchHTML(url: string): Promise<Result<GenericAxiosError |
error: null error: null
}); });
return isHTML ? return isHTML ?
success(response.value.data as string) : success(response.value.data as string) :
failure(unexpectedResponseError); failure(unexpectedResponseError);
} else return failure(response.value as GenericAxiosError); } else return failure(response.value as GenericAxiosError);
} }
/** /**
* It authenticates to the platform using the credentials * It authenticates to the platform using the credentials
* and token obtained previously. Save cookies on your * and token obtained previously. Save cookies on your
* device after authentication. * device after authentication.
* @param {module:./classes/credentials.ts:Credentials} credentials Platform access credentials * @param {module:./classes/credentials.ts:Credentials} credentials Platform access credentials
* @param {Boolean} force Specifies whether the request should be forced, ignoring any saved cookies * @param {Boolean} force Specifies whether the request should be forced, ignoring any saved cookies
@ -173,7 +173,7 @@ export function isF95URL(url: string): boolean {
}; };
/** /**
* Checks if the string passed by parameter has a * Checks if the string passed by parameter has a
* properly formatted and valid path to a URL (HTTP/HTTPS). * properly formatted and valid path to a URL (HTTP/HTTPS).
* @param {String} url String to check for correctness * @param {String} url String to check for correctness
*/ */
@ -187,7 +187,7 @@ export function isStringAValidURL(url: string): boolean {
/** /**
* Check if a particular URL is valid and reachable on the web. * Check if a particular URL is valid and reachable on the web.
* @param {string} url URL to check * @param {string} url URL to check
* @param {boolean} [checkRedirect] * @param {boolean} [checkRedirect]
* If true, the function will consider redirects a violation and return false. * If true, the function will consider redirects a violation and return false.
* Default: false * Default: false
* @returns {Promise<Boolean>} true if the URL exists, false otherwise * @returns {Promise<Boolean>} true if the URL exists, false otherwise

View File

@ -87,7 +87,7 @@ function toUpperCaseArray(a: string[]): string[] {
/** /**
* Check if the string `s` is in the dict `a`. * Check if the string `s` is in the dict `a`.
* *
* Case insensitive. * Case insensitive.
*/ */
function stringInDict(s: string, a: TPrefixDict): boolean { function stringInDict(s: string, a: TPrefixDict): boolean {
@ -99,7 +99,7 @@ function stringInDict(s: string, a: TPrefixDict): boolean {
/** /**
* Convert a string to a boolean. * Convert a string to a boolean.
* *
* Check also for `yes`/`no` and `1`/`0`. * Check also for `yes`/`no` and `1`/`0`.
*/ */
function stringToBoolean(s: string): boolean { function stringToBoolean(s: string): boolean {
@ -116,7 +116,7 @@ function stringToBoolean(s: string): boolean {
/** /**
* Gets the element with the given name or `undefined`. * Gets the element with the given name or `undefined`.
* *
* Case-insensitive. * Case-insensitive.
*/ */
function getPostElementByName(elements: IPostElement[], name: string): IPostElement | undefined { function getPostElementByName(elements: IPostElement[], name: string): IPostElement | undefined {
@ -127,7 +127,7 @@ function getPostElementByName(elements: IPostElement[], name: string): IPostElem
/** /**
* Parse the post prefixes. * Parse the post prefixes.
* *
* In particular, it elaborates the following prefixes for games: * In particular, it elaborates the following prefixes for games:
* `Engine`, `Status`, `Mod`. * `Engine`, `Status`, `Mod`.
*/ */
@ -174,7 +174,7 @@ function fillWithPrefixes(hw: HandiWork, prefixes: string[]) {
/** /**
* Compiles a HandiWork object with the data extracted * Compiles a HandiWork object with the data extracted
* from the main post of the HandiWork page. * from the main post of the HandiWork page.
* *
* The values that will be added are: * The values that will be added are:
* `Overview`, `OS`, `Language`, `Version`, `Installation`, * `Overview`, `OS`, `Language`, `Version`, `Installation`,
* `Pages`, `Resolution`, `Lenght`, `Genre`, `Censored`, * `Pages`, `Resolution`, `Lenght`, `Genre`, `Censored`,

View File

@ -21,11 +21,11 @@ export interface ILink extends IPostElement {
* Given a post of a thread page it extracts the information contained in the body. * Given a post of a thread page it extracts the information contained in the body.
*/ */
export function parseF95ThreadPost($: cheerio.Root, post: cheerio.Cheerio): IPostElement[] { export function parseF95ThreadPost($: cheerio.Root, post: cheerio.Cheerio): IPostElement[] {
// The data is divided between "tag" and "text" elements. // The data is divided between "tag" and "text" elements.
// Simple data is composed of a "tag" element followed // Simple data is composed of a "tag" element followed
// by a "text" element, while more complex data (contained // by a "text" element, while more complex data (contained
// in spoilers) is composed of a "tag" element, followed // in spoilers) is composed of a "tag" element, followed
// by a text containing only ":" and then by an additional // by a text containing only ":" and then by an additional
// "tag" element having as the first term "Spoiler" // "tag" element having as the first term "Spoiler"
// First fetch all the elements in the post // First fetch all the elements in the post
@ -44,13 +44,13 @@ export function parseF95ThreadPost($: cheerio.Root, post: cheerio.Cheerio): IPos
//#region Private methods //#region Private methods
/** /**
* Process a spoiler element by getting its text broken * Process a spoiler element by getting its text broken
* down by any other spoiler elements present. * down by any other spoiler elements present.
*/ */
function parseCheerioSpoilerNode($: cheerio.Root, spoiler: cheerio.Cheerio): IPostElement { function parseCheerioSpoilerNode($: cheerio.Root, spoiler: cheerio.Cheerio): IPostElement {
// A spoiler block is composed of a div with class "bbCodeSpoiler", // A spoiler block is composed of a div with class "bbCodeSpoiler",
// containing a div "bbCodeSpoiler-content" containing, in cascade, // containing a div "bbCodeSpoiler-content" containing, in cascade,
// a div with class "bbCodeBlock--spoiler" and a div with class "bbCodeBlock-content". // a div with class "bbCodeBlock--spoiler" and a div with class "bbCodeBlock-content".
// This last tag contains the required data. // This last tag contains the required data.
// Local variables // Local variables
@ -94,7 +94,7 @@ function parseCheerioSpoilerNode($: cheerio.Root, spoiler: cheerio.Cheerio): IPo
} }
/** /**
* Check if the node passed as a parameter is of text type. * Check if the node passed as a parameter is of text type.
* This also includes formatted nodes (i.e. `<b>`). * This also includes formatted nodes (i.e. `<b>`).
*/ */
function isTextNode(node: cheerio.Element): boolean { function isTextNode(node: cheerio.Element): boolean {
@ -106,7 +106,7 @@ function isTextNode(node: cheerio.Element): boolean {
} }
/** /**
* Gets the text of the node only, excluding child nodes. * Gets the text of the node only, excluding child nodes.
* Also includes formatted text elements (i.e. `<b>`). * Also includes formatted text elements (i.e. `<b>`).
*/ */
function getCheerioNonChildrenText(node: cheerio.Cheerio): string { function getCheerioNonChildrenText(node: cheerio.Cheerio): string {
@ -120,7 +120,7 @@ function getCheerioNonChildrenText(node: cheerio.Cheerio): string {
} }
/** /**
* Process a node and see if it contains a * Process a node and see if it contains a
* link or image. If not, it returns `null`. * link or image. If not, it returns `null`.
*/ */
function parseCheerioLinkNode(element: cheerio.Cheerio): ILink | null { function parseCheerioLinkNode(element: cheerio.Cheerio): ILink | null {
@ -149,7 +149,7 @@ function parseCheerioLinkNode(element: cheerio.Cheerio): ILink | null {
} }
/** /**
* Collapse an `IPostElement` element with a single subnode * Collapse an `IPostElement` element with a single subnode
* in the `Content` field in case it has no information. * in the `Content` field in case it has no information.
*/ */
function reducePostElement(element: IPostElement): IPostElement { function reducePostElement(element: IPostElement): IPostElement {
@ -234,7 +234,7 @@ function parseCheerioNode($: cheerio.Root, node: cheerio.Element, reduce = true)
} }
/** /**
* It simplifies the `IPostElement` elements by associating * It simplifies the `IPostElement` elements by associating
* the corresponding value to each characterizing element (i.e. author). * the corresponding value to each characterizing element (i.e. author).
*/ */
function parsePostElements(elements: IPostElement[]): IPostElement[] { function parsePostElements(elements: IPostElement[]): IPostElement[] {