diff --git a/src/example.ts b/src/example.ts index 4948d00..a6737c2 100644 --- a/src/example.ts +++ b/src/example.ts @@ -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: F95_USERNAME = YOUR_USERNAME @@ -12,12 +12,12 @@ F95_PASSWORD = YOUR_PASSWORD import dotenv from "dotenv"; // Modules from file -import { login, - getUserData, - getLatestUpdates, - LatestSearchQuery, - Game, - searchHandiwork, +import { login, + getUserData, + getLatestUpdates, + LatestSearchQuery, + Game, + searchHandiwork, HandiworkSearchQuery } from "./index.js"; diff --git a/src/index.ts b/src/index.ts index 30ef426..a669332 100644 --- a/src/index.ts +++ b/src/index.ts @@ -59,7 +59,7 @@ export function isLogged(): boolean { return shared.isLogged; }; /** * Log in to the F95Zone platform. - * + * * This **must** be the first operation performed before accessing any other script functions. */ export async function login(username: string, password: string): Promise { @@ -102,7 +102,7 @@ export async function login(username: string, password: string): Promise { @@ -127,9 +127,9 @@ export async function checkIfHandiworkHasUpdate(hw: HandiWork): Promise /** * Search for one or more handiworks identified by a specific query. - * + * * You **must** be logged in to the portal before calling this method. - * + * * @param {HandiworkSearchQuery} query Parameters used for the search. * @param {Number} limit Maximum number of results. Default: 10 */ @@ -137,12 +137,12 @@ export async function searchHandiwork(query: HandiworkSearchQu // Check if the user is logged if (!shared.isLogged) throw new UserNotLogged(USER_NOT_LOGGED); - return await search(query, limit); + return search(query, limit); }; /** * Given the url, it gets all the information about the handiwork requested. - * + * * You **must** be logged in to the portal before calling this method. */ export async function getHandiworkFromURL(url: string): Promise { @@ -155,14 +155,14 @@ export async function getHandiworkFromURL(url: string): Promis if (!isF95URL(url)) throw new Error(`${url} is not a valid F95Zone URL`); // Get game data - return await getHandiworkInformation(url); + return getHandiworkInformation(url); }; /** * Gets the data of the currently logged in user. - * + * * You **must** be logged in to the portal before calling this method. - * + * * @returns {Promise} Data of the user currently logged in */ export async function getUserData(): Promise { @@ -178,9 +178,9 @@ export async function getUserData(): Promise { /** * Gets the latest updated games that match the specified parameters. - * + * * You **must** be logged in to the portal before calling this method. - * + * * @param {LatestSearchQuery} query Parameters used for the search. * @param {Number} limit Maximum number of results. Default: 10 */ @@ -196,7 +196,7 @@ export async function getLatestUpdates(query: LatestSearchQuer // Get the data from urls const promiseList = urls.map((u: string) => getHandiworkInformation(u)); - return await Promise.all(promiseList); + return Promise.all(promiseList); }; //#endregion diff --git a/src/scripts/classes/mapping/thread.ts b/src/scripts/classes/mapping/thread.ts index 1b87d55..6803cff 100644 --- a/src/scripts/classes/mapping/thread.ts +++ b/src/scripts/classes/mapping/thread.ts @@ -45,7 +45,7 @@ export default class Thread { public get id() { return this._id; } /** * URL of the thread. - * + * * It may vary depending on any versions of the contained product. */ public get url() { return this._url; } @@ -85,8 +85,8 @@ export default class Thread { //#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. */ 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. */ 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. - * + * * `index` must be greater or equal to 1. * If the post is not found, `null` is returned. */ diff --git a/src/scripts/classes/mapping/user-profile.ts b/src/scripts/classes/mapping/user-profile.ts index 9a1b5b2..c75e85f 100644 --- a/src/scripts/classes/mapping/user-profile.ts +++ b/src/scripts/classes/mapping/user-profile.ts @@ -149,7 +149,7 @@ export default class UserProfile extends PlatformUser { } // Wait for the promises to resolve - return await Promise.all(responsePromiseList); + return Promise.all(responsePromiseList); } /** diff --git a/src/scripts/classes/prefix-parser.ts b/src/scripts/classes/prefix-parser.ts index db9c9d0..15c8e25 100644 --- a/src/scripts/classes/prefix-parser.ts +++ b/src/scripts/classes/prefix-parser.ts @@ -11,7 +11,7 @@ export default class PrefixParser { //#region Private methods /** * 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 * @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. * @param element Element to search in the prefixes as a key or as a value */ diff --git a/src/scripts/classes/query/handiwork-search-query.ts b/src/scripts/classes/query/handiwork-search-query.ts index 89fa43d..d0419bb 100644 --- a/src/scripts/classes/query/handiwork-search-query.ts +++ b/src/scripts/classes/query/handiwork-search-query.ts @@ -13,21 +13,21 @@ import ThreadSearchQuery, { TThreadOrder } from './thread-search-query.js'; // Type definitions /** - * Method of sorting results. Try to unify the two types of - * sorts in the "Latest" section and in the "Thread search" - * section. Being dynamic research, if a sorting type is not + * Method of sorting results. Try to unify the two types of + * sorts in the "Latest" section and in the "Thread search" + * section. Being dynamic research, if a sorting type is not * available, the replacement sort is chosen. - * + * * `date`: Order based on the latest update * * `likes`: Order based on the number of likes received. Replacement: `replies`. - * + * * `relevance`: Order based on the relevance of the result (or rating). - * + * * `replies`: Order based on the number of answers to the thread. Replacement: `views`. - * + * * `title`: Order based on the growing alphabetical order of the titles. - * + * * `views`: Order based on the number of visits. Replacement: `replies`. */ type THandiworkOrder = "date" | "likes" | "relevance" | "replies" | "title" | "views"; @@ -80,8 +80,8 @@ export default class HandiworkSearchQuery implements IQuery { //#region Public methods /** - * Select what kind of search should be - * performed based on the properties of + * Select what kind of search should be + * performed based on the properties of * the query. */ public selectSearchType(): "latest" | "thread" { @@ -89,8 +89,8 @@ export default class HandiworkSearchQuery implements IQuery { const MAX_TAGS_LATEST_SEARCH = 5; const DEFAULT_SEARCH_TYPE = "latest"; - // If the keywords are set or the number - // of included tags is greather than 5, + // If the keywords are set or the number + // of included tags is greather than 5, // we must perform a thread search 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 { // Cast the basic query object and copy common values const query: ThreadSearchQuery = new ThreadSearchQuery; - Object.keys(this).forEach(key => { + Object.keys(this).forEach(key => { if (query.hasOwnProperty(key)) { query[key] = this[key]; } diff --git a/src/scripts/classes/query/latest-search-query.ts b/src/scripts/classes/query/latest-search-query.ts index 87b428d..3259db6 100644 --- a/src/scripts/classes/query/latest-search-query.ts +++ b/src/scripts/classes/query/latest-search-query.ts @@ -29,15 +29,15 @@ export default class LatestSearchQuery implements IQuery { public category: TCategory = 'games'; /** - * Ordering type. - * + * Ordering type. + * * Default: `date`. */ public order: TLatestOrder = 'date'; /** * Date limit in days, to be understood as "less than". * Use `1` to indicate "today" or `null` to indicate "anytime". - * + * * Default: `null` */ public date: TDate = null; @@ -74,7 +74,7 @@ export default class LatestSearchQuery implements IQuery { const decoded = decodeURIComponent(url.toString()); // 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) { const MS_PER_DAY = 1000 * 60 * 60 * 24; diff --git a/src/scripts/classes/query/thread-search-query.ts b/src/scripts/classes/query/thread-search-query.ts index 0b14929..1894792 100644 --- a/src/scripts/classes/query/thread-search-query.ts +++ b/src/scripts/classes/query/thread-search-query.ts @@ -82,7 +82,7 @@ export default class ThreadSearchQuery implements IQuery { const params = this.preparePOSTParameters(); // Return the POST response - return await fetchPOSTResponse(urls.F95_SEARCH_URL, params); + return fetchPOSTResponse(urls.F95_SEARCH_URL, params); } //#endregion Public methods diff --git a/src/scripts/constants/css-selector.ts b/src/scripts/constants/css-selector.ts index ee9da31..670232e 100644 --- a/src/scripts/constants/css-selector.ts +++ b/src/scripts/constants/css-selector.ts @@ -25,7 +25,7 @@ export const selectors = { 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`. */ CURRENT_USER_ID: "span.avatar[data-user-id]", @@ -41,17 +41,17 @@ export const WATCHED_THREAD = { */ BODIES: "div.structItem-cell--main", /** - * Link element containing the partial URL + * Link element containing the partial URL * of the thread in the `href` attribute. - * + * * It may be followed by the `/unread` segment. - * + * * For use within a `WATCHED_THREAD.BODIES` selector. */ URL: "div > a[data-tp-primary]", /** * Name of the forum to which the thread belongs as text. - * + * * For use within a `WATCHED_THREAD.BODIES` selector. */ 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 = { /** * Number of pages in the thread (as text of the element). - * + * * Two identical elements are identified. */ LAST_PAGE: "ul.pageNav-main > li:last-child > a", /** * Identify the creator of the thread. - * + * * The ID is contained in the `data-user-id` attribute. */ OWNER_ID: "div.uix_headerInner > * a.username[data-user-id]", /** * Contains the creation date of the thread. - * + * * The date is contained in the `datetime` attribute as an ISO string. */ CREATION: "div.uix_headerInner > * time", @@ -94,7 +94,7 @@ export const THREAD = { TITLE: "h1.p-title-value", /** * JSON containing thread information. - * + * * Two different elements are found. */ JSONLD: "script[type=\"application/ld+json\"]", @@ -106,44 +106,44 @@ export const THREAD = { 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. */ NUMBER: "* ul.message-attribution-opposite > li > a:not([id])[rel=\"nofollow\"]", /** * Unique ID of the post in the F95Zone platform in the `id` attribute. - * + * * For use within a `THREAD.POSTS_IN_PAGE` selector. */ ID: "span[id^=\"post\"]", /** * Unique ID of the post author in the `data-user-id` attribute. - * + * * For use within a `THREAD.POSTS_IN_PAGE` selector. */ OWNER_ID: "* div.message-cell--user > * a[data-user-id]", /** * Main body of the post where the message written by the user is contained. - * + * * For use within a `THREAD.POSTS_IN_PAGE` selector. */ BODY: "* article.message-body > div.bbWrapper", /** * Publication date of the post contained in the `datetime` attribute as an ISO date. - * + * * For use within a `THREAD.POSTS_IN_PAGE` selector. */ PUBLISH_DATE: "* div.message-attribution-main > a > time", /** * Last modified date of the post contained in the `datetime` attribute as the ISO date. - * + * * For use within a `THREAD.POSTS_IN_PAGE` selector. */ LAST_EDIT: "* div.message-lastEdit > time", /** * Gets the element only if the post has been bookmarked. - * + * * For use within a `THREAD.POSTS_IN_PAGE` selector. */ BOOKMARKED: "* ul.message-attribution-opposite >li > a[title=\"Bookmark\"].is-bookmarked", @@ -152,37 +152,37 @@ export const POST = { export const MEMBER = { /** * Name of the user. - * + * * It also contains the unique ID of the user in the `data-user-id` attribute. */ NAME: "span[class^=\"username\"]", /** * Title of the user in the platform. - * + * * i.e.: Member */ TITLE: "span.userTitle", /** * Avatar used by the user. - * + * * Source in the attribute `src`. */ AVATAR: "span.avatarWrapper > a.avatar > img", /** * User assigned banners. - * + * * The last element is always empty and can be ignored. */ BANNERS: "em.userBanner > strong", /** * Date the user joined the platform. - * + * * The date is contained in the `datetime` attribute as an ISO string. */ JOINED: "div.uix_memberHeader__extra > div.memberHeader-blurb:nth-child(1) > * time", /** * Last time the user connected to the platform. - * + * * 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", @@ -193,14 +193,14 @@ export const MEMBER = { AMOUNT_DONATED: "div.pairJustifier > dl:nth-child(5) > dd", /** * Button used to follow/unfollow the user. - * + * * If the text is `Unfollow` then the user is 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", /** * Button used to ignore/unignore the user. - * + * * If the text is `Unignore` then the user is ignored. * If the text is `Ignore` then the user is not ignored. */ diff --git a/src/scripts/constants/url.ts b/src/scripts/constants/url.ts index 94e121f..88c2de9 100644 --- a/src/scripts/constants/url.ts +++ b/src/scripts/constants/url.ts @@ -8,8 +8,8 @@ export const urls = { F95_LATEST_PHP: "https://f95zone.to/new_latest.php", F95_BOOKMARKS: "https://f95zone.to/account/bookmarks", /** - * Add the unique ID of the post to - * get the thread page where the post + * Add the unique ID of the post to + * get the thread page where the post * is present. */ F95_POSTS: "https://f95zone.to/posts/", diff --git a/src/scripts/fetch-data/fetch-latest.ts b/src/scripts/fetch-data/fetch-latest.ts index d9dcdc5..d12434a 100644 --- a/src/scripts/fetch-data/fetch-latest.ts +++ b/src/scripts/fetch-data/fetch-latest.ts @@ -9,7 +9,7 @@ import { urls as f95url } from "../constants/url.js"; * You *must* be logged. * @param {LatestSearchQuery} query * Query used for the search - * @param {Number} limit + * @param {Number} limit * Maximum number of items to get. Default: 30 * @returns {Promise} URLs of the handiworks */ diff --git a/src/scripts/fetch-data/fetch-platform-data.ts b/src/scripts/fetch-data/fetch-platform-data.ts index 9d2c25f..701958c 100644 --- a/src/scripts/fetch-data/fetch-platform-data.ts +++ b/src/scripts/fetch-data/fetch-platform-data.ts @@ -43,7 +43,7 @@ interface ILatestResource { //#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) */ export default async function fetchPlatformData(): Promise { @@ -106,7 +106,7 @@ function saveCache(path: string): void { /** * @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. */ function parseLatestPlatformHTML(html: string): ILatestResource{ diff --git a/src/scripts/fetch-data/fetch-query.ts b/src/scripts/fetch-data/fetch-query.ts index 91e1fda..cf5cdea 100644 --- a/src/scripts/fetch-data/fetch-query.ts +++ b/src/scripts/fetch-data/fetch-query.ts @@ -36,6 +36,6 @@ export default async function executeQuery(query: any, limit: number = 30): Prom "handiwork"); // Fetch and return the urls - return await searchMap[key](query, limit); + return searchMap[key](query, limit); } //#endregion \ No newline at end of file diff --git a/src/scripts/fetch-data/fetch-thread.ts b/src/scripts/fetch-data/fetch-thread.ts index 8a8967c..ee89163 100644 --- a/src/scripts/fetch-data/fetch-thread.ts +++ b/src/scripts/fetch-data/fetch-thread.ts @@ -26,7 +26,7 @@ export default async function fetchThreadHandiworkURLs(query: ThreadSearchQuery, const response = await query.execute(); // 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 } diff --git a/src/scripts/network-helper.ts b/src/scripts/network-helper.ts index 8a6272c..5b63ef0 100644 --- a/src/scripts/network-helper.ts +++ b/src/scripts/network-helper.ts @@ -15,7 +15,7 @@ import { failure, Result, success } from "./classes/result.js"; import { GenericAxiosError, InvalidF95Token, UnexpectedResponseContentType } from "./classes/errors.js"; // 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"; // @ts-ignore axiosCookieJarSupport.default(axios); @@ -61,15 +61,15 @@ export async function fetchHTML(url: string): Promise} true if the URL exists, false otherwise diff --git a/src/scripts/scrape-data/handiwork-parse.ts b/src/scripts/scrape-data/handiwork-parse.ts index ea38527..a333cb4 100644 --- a/src/scripts/scrape-data/handiwork-parse.ts +++ b/src/scripts/scrape-data/handiwork-parse.ts @@ -87,7 +87,7 @@ function toUpperCaseArray(a: string[]): string[] { /** * Check if the string `s` is in the dict `a`. - * + * * Case insensitive. */ function stringInDict(s: string, a: TPrefixDict): boolean { @@ -99,7 +99,7 @@ function stringInDict(s: string, a: TPrefixDict): boolean { /** * Convert a string to a boolean. - * + * * Check also for `yes`/`no` and `1`/`0`. */ function stringToBoolean(s: string): boolean { @@ -116,7 +116,7 @@ function stringToBoolean(s: string): boolean { /** * Gets the element with the given name or `undefined`. - * + * * Case-insensitive. */ function getPostElementByName(elements: IPostElement[], name: string): IPostElement | undefined { @@ -127,7 +127,7 @@ function getPostElementByName(elements: IPostElement[], name: string): IPostElem /** * Parse the post prefixes. - * + * * In particular, it elaborates the following prefixes for games: * `Engine`, `Status`, `Mod`. */ @@ -174,7 +174,7 @@ function fillWithPrefixes(hw: HandiWork, prefixes: string[]) { /** * Compiles a HandiWork object with the data extracted * from the main post of the HandiWork page. - * + * * The values that will be added are: * `Overview`, `OS`, `Language`, `Version`, `Installation`, * `Pages`, `Resolution`, `Lenght`, `Genre`, `Censored`, diff --git a/src/scripts/scrape-data/post-parse.ts b/src/scripts/scrape-data/post-parse.ts index 95f3395..52aaf80 100644 --- a/src/scripts/scrape-data/post-parse.ts +++ b/src/scripts/scrape-data/post-parse.ts @@ -21,11 +21,11 @@ export interface ILink extends IPostElement { * Given a post of a thread page it extracts the information contained in the body. */ export function parseF95ThreadPost($: cheerio.Root, post: cheerio.Cheerio): IPostElement[] { - // The data is divided between "tag" and "text" elements. - // Simple data is composed of a "tag" element followed - // by a "text" element, while more complex data (contained - // in spoilers) is composed of a "tag" element, followed - // by a text containing only ":" and then by an additional + // The data is divided between "tag" and "text" elements. + // Simple data is composed of a "tag" element followed + // by a "text" element, while more complex data (contained + // in spoilers) is composed of a "tag" element, followed + // by a text containing only ":" and then by an additional // "tag" element having as the first term "Spoiler" // First fetch all the elements in the post @@ -44,13 +44,13 @@ export function parseF95ThreadPost($: cheerio.Root, post: cheerio.Cheerio): IPos //#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. */ function parseCheerioSpoilerNode($: cheerio.Root, spoiler: cheerio.Cheerio): IPostElement { - // A spoiler block is composed of a div with class "bbCodeSpoiler", - // containing a div "bbCodeSpoiler-content" containing, in cascade, - // a div with class "bbCodeBlock--spoiler" and a div with class "bbCodeBlock-content". + // A spoiler block is composed of a div with class "bbCodeSpoiler", + // containing a div "bbCodeSpoiler-content" containing, in cascade, + // a div with class "bbCodeBlock--spoiler" and a div with class "bbCodeBlock-content". // This last tag contains the required data. // 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. ``). */ 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. ``). */ 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`. */ 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. */ 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). */ function parsePostElements(elements: IPostElement[]): IPostElement[] {