Clena css-selectors
							parent
							
								
									cb3370c212
								
							
						
					
					
						commit
						0a57d2b2ec
					
				| 
						 | 
					@ -3,31 +3,6 @@
 | 
				
			||||||
// This software is released under the MIT License.
 | 
					// This software is released under the MIT License.
 | 
				
			||||||
// https://opensource.org/licenses/MIT
 | 
					// https://opensource.org/licenses/MIT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const selectors = {
 | 
					 | 
				
			||||||
  WT_FILTER_POPUP_BUTTON: "a.filterBar-menuTrigger",
 | 
					 | 
				
			||||||
  WT_NEXT_PAGE: "a.pageNav-jump--next",
 | 
					 | 
				
			||||||
  WT_URLS: 'a[href^="/threads/"][data-tp-primary]',
 | 
					 | 
				
			||||||
  WT_UNREAD_THREAD_CHECKBOX: 'input[type="checkbox"][name="unread"]',
 | 
					 | 
				
			||||||
  GS_POSTS: "article.message-body:first-child > div.bbWrapper:first-of-type",
 | 
					 | 
				
			||||||
  GS_RESULT_THREAD_TITLE: "h3.contentRow-title > a",
 | 
					 | 
				
			||||||
  GS_RESULT_BODY: "div.contentRow-main",
 | 
					 | 
				
			||||||
  GS_MEMBERSHIP: "li > a:not(.username)",
 | 
					 | 
				
			||||||
  GET_REQUEST_TOKEN: 'input[name="_xfToken"]',
 | 
					 | 
				
			||||||
  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",
 | 
					 | 
				
			||||||
  LU_TAGS_SCRIPT: "script:contains('latestUpdates')",
 | 
					 | 
				
			||||||
  BK_RESULTS: "ol.listPlain > *  div.contentRow-main",
 | 
					 | 
				
			||||||
  BK_POST_URL: "div.contentRow-title > a",
 | 
					 | 
				
			||||||
  BK_DESCRIPTION: "div.contentRow-snippet",
 | 
					 | 
				
			||||||
  BK_POST_OWNER: "div.contentRow-minor > * a.username",
 | 
					 | 
				
			||||||
  BK_TAGS: "div.contentRow-minor > * a.tagItem",
 | 
					 | 
				
			||||||
  /**
 | 
					 | 
				
			||||||
   * Attribute `datetime` contains an ISO date.
 | 
					 | 
				
			||||||
   */
 | 
					 | 
				
			||||||
  BK_TIME: "div.contentRow-minor > * time"
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const GENERIC = {
 | 
					export const GENERIC = {
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * The ID of the user currently logged into
 | 
					   * The ID of the user currently logged into
 | 
				
			||||||
| 
						 | 
					@ -37,7 +12,19 @@ export const GENERIC = {
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Banner containing any error messages as text.
 | 
					   * Banner containing any error messages as text.
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  ERROR_BANNER: "div.p-body-pageContent > div.blockMessage"
 | 
					  ERROR_BANNER: "div.p-body-pageContent > div.blockMessage",
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Locate the token used for the session.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  GET_REQUEST_TOKEN: 'input[name="_xfToken"]',
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Block containing the text of any errors that occurred during the login.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  LOGIN_MESSAGE_ERROR: "div.blockMessage.blockMessage--error.blockMessage--iconic",
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Locate the script containing the tags and prefixes of the platform content in JSON format.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  LATEST_UPDATES_TAGS_SCRIPT: "script:contains('latestUpdates')"
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const WATCHED_THREAD = {
 | 
					export const WATCHED_THREAD = {
 | 
				
			||||||
| 
						 | 
					@ -110,6 +97,17 @@ export const THREAD = {
 | 
				
			||||||
  POSTS_IN_PAGE: "article.message"
 | 
					  POSTS_IN_PAGE: "article.message"
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const THREAD_SEARCH = {
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Thread title resulting from research.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  THREAD_TITLE: "h3.contentRow-title > a",
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   *Thread body resulting from research.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  BODY: "div.contentRow-main"
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const POST = {
 | 
					export const POST = {
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Unique post number for the current thread.
 | 
					   * Unique post number for the current thread.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,10 +14,11 @@ import cheerio from "cheerio";
 | 
				
			||||||
// Modules from file
 | 
					// Modules from file
 | 
				
			||||||
import shared, { TPrefixDict } from "../shared.js";
 | 
					import shared, { TPrefixDict } from "../shared.js";
 | 
				
			||||||
import { urls as f95url } from "../constants/url.js";
 | 
					import { urls as f95url } from "../constants/url.js";
 | 
				
			||||||
import { selectors as f95selector } from "../constants/css-selector.js";
 | 
					import { GENERIC } from "../constants/css-selector.js";
 | 
				
			||||||
import { fetchHTML } from "../network-helper.js";
 | 
					import { fetchHTML } from "../network-helper.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//#region Interface definitions
 | 
					//#region Interface definitions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Represents the single element contained in the data categories.
 | 
					 * Represents the single element contained in the data categories.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -44,9 +45,11 @@ interface ILatestResource {
 | 
				
			||||||
  tags: TPrefixDict;
 | 
					  tags: TPrefixDict;
 | 
				
			||||||
  options: string;
 | 
					  options: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//#endregion Interface definitions
 | 
					//#endregion Interface definitions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//#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)
 | 
				
			||||||
| 
						 | 
					@ -69,12 +72,13 @@ export default async function fetchPlatformData(): Promise<void> {
 | 
				
			||||||
    } else throw html.value;
 | 
					    } else throw html.value;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//#endregion Public methods
 | 
					//#endregion Public methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//#region Private methods
 | 
					//#region Private methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @private
 | 
					 * Read the platform cache (if available).
 | 
				
			||||||
 * Read the platform cache (if available)
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function readCache(path: string) {
 | 
					function readCache(path: string) {
 | 
				
			||||||
  // Local variables
 | 
					  // Local variables
 | 
				
			||||||
| 
						 | 
					@ -95,7 +99,6 @@ function readCache(path: string) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @private
 | 
					 | 
				
			||||||
 * Save the current platform variables to disk.
 | 
					 * Save the current platform variables to disk.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function saveCache(path: string): void {
 | 
					function saveCache(path: string): void {
 | 
				
			||||||
| 
						 | 
					@ -110,7 +113,6 @@ 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.
 | 
					 * parse it and return the result.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -118,7 +120,7 @@ function parseLatestPlatformHTML(html: string): ILatestResource {
 | 
				
			||||||
  const $ = cheerio.load(html);
 | 
					  const $ = cheerio.load(html);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Clean the JSON string
 | 
					  // Clean the JSON string
 | 
				
			||||||
  const unparsedText = $(f95selector.LU_TAGS_SCRIPT).html().trim();
 | 
					  const unparsedText = $(GENERIC.LATEST_UPDATES_TAGS_SCRIPT).html().trim();
 | 
				
			||||||
  const startIndex = unparsedText.indexOf("{");
 | 
					  const startIndex = unparsedText.indexOf("{");
 | 
				
			||||||
  const endIndex = unparsedText.lastIndexOf("}");
 | 
					  const endIndex = unparsedText.lastIndexOf("}");
 | 
				
			||||||
  const parsedText = unparsedText.substring(startIndex, endIndex + 1);
 | 
					  const parsedText = unparsedText.substring(startIndex, endIndex + 1);
 | 
				
			||||||
| 
						 | 
					@ -126,7 +128,6 @@ function parseLatestPlatformHTML(html: string): ILatestResource {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @private
 | 
					 | 
				
			||||||
 * Assign to the local variables the values from the F95Zone.
 | 
					 * Assign to the local variables the values from the F95Zone.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function assignLatestPlatformData(data: ILatestResource): void {
 | 
					function assignLatestPlatformData(data: ILatestResource): void {
 | 
				
			||||||
| 
						 | 
					@ -154,4 +155,5 @@ function assignLatestPlatformData(data: ILatestResource): void {
 | 
				
			||||||
  shared.setPrefixPair("others", Object.assign({}, scrapedData["Other"]));
 | 
					  shared.setPrefixPair("others", Object.assign({}, scrapedData["Other"]));
 | 
				
			||||||
  shared.setPrefixPair("tags", data.tags);
 | 
					  shared.setPrefixPair("tags", data.tags);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//#endregion
 | 
					//#endregion
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,7 @@ import cheerio from "cheerio";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Modules from file
 | 
					// Modules from file
 | 
				
			||||||
import shared from "../shared.js";
 | 
					import shared from "../shared.js";
 | 
				
			||||||
import { selectors as f95Selector } from "../constants/css-selector.js";
 | 
					import { THREAD_SEARCH } from "../constants/css-selector.js";
 | 
				
			||||||
import { urls as f95urls } from "../constants/url.js";
 | 
					import { urls as f95urls } from "../constants/url.js";
 | 
				
			||||||
import ThreadSearchQuery from "../classes/query/thread-search-query.js";
 | 
					import ThreadSearchQuery from "../classes/query/thread-search-query.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,7 +28,7 @@ import ThreadSearchQuery from "../classes/query/thread-search-query.js";
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export default async function fetchThreadHandiworkURLs(
 | 
					export default async function fetchThreadHandiworkURLs(
 | 
				
			||||||
  query: ThreadSearchQuery,
 | 
					  query: ThreadSearchQuery,
 | 
				
			||||||
  limit = 30
 | 
					  limit: number = 30
 | 
				
			||||||
): Promise<string[]> {
 | 
					): Promise<string[]> {
 | 
				
			||||||
  // Execute the query
 | 
					  // Execute the query
 | 
				
			||||||
  const response = await query.execute();
 | 
					  const response = await query.execute();
 | 
				
			||||||
| 
						 | 
					@ -47,12 +47,12 @@ export default async function fetchThreadHandiworkURLs(
 | 
				
			||||||
 * @param {number} limit
 | 
					 * @param {number} limit
 | 
				
			||||||
 * Maximum number of items to get. Default: 30
 | 
					 * Maximum number of items to get. Default: 30
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
async function fetchResultURLs(html: string, limit = 30): Promise<string[]> {
 | 
					async function fetchResultURLs(html: string, limit: number = 30): Promise<string[]> {
 | 
				
			||||||
  // Prepare cheerio
 | 
					  // Prepare cheerio
 | 
				
			||||||
  const $ = cheerio.load(html);
 | 
					  const $ = cheerio.load(html);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // 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(THREAD_SEARCH.BODY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Than we extract the URLs
 | 
					  // Than we extract the URLs
 | 
				
			||||||
  const urls = results
 | 
					  const urls = results
 | 
				
			||||||
| 
						 | 
					@ -74,10 +74,7 @@ async function fetchResultURLs(html: string, limit = 30): Promise<string[]> {
 | 
				
			||||||
function extractLinkFromResult(selector: cheerio.Cheerio): string {
 | 
					function extractLinkFromResult(selector: cheerio.Cheerio): string {
 | 
				
			||||||
  shared.logger.trace("Extracting thread link from result...");
 | 
					  shared.logger.trace("Extracting thread link from result...");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const partialLink = selector
 | 
					  const partialLink = selector.find(THREAD_SEARCH.THREAD_TITLE).attr("href").trim();
 | 
				
			||||||
    .find(f95Selector.GS_RESULT_THREAD_TITLE)
 | 
					 | 
				
			||||||
    .attr("href")
 | 
					 | 
				
			||||||
    .trim();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Compose and return the URL
 | 
					  // Compose and return the URL
 | 
				
			||||||
  return new URL(partialLink, f95urls.F95_BASE_URL).toString();
 | 
					  return new URL(partialLink, f95urls.F95_BASE_URL).toString();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,7 +13,7 @@ import axiosCookieJarSupport from "axios-cookiejar-support";
 | 
				
			||||||
// Modules from file
 | 
					// Modules from file
 | 
				
			||||||
import shared from "./shared.js";
 | 
					import shared from "./shared.js";
 | 
				
			||||||
import { urls } from "./constants/url.js";
 | 
					import { urls } from "./constants/url.js";
 | 
				
			||||||
import { selectors as f95selector } from "./constants/css-selector.js";
 | 
					import { GENERIC } from "./constants/css-selector.js";
 | 
				
			||||||
import LoginResult from "./classes/login-result.js";
 | 
					import LoginResult from "./classes/login-result.js";
 | 
				
			||||||
import { failure, Result, success } from "./classes/result.js";
 | 
					import { failure, Result, success } from "./classes/result.js";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
| 
						 | 
					@ -187,7 +187,7 @@ export async function getF95Token(): Promise<string> {
 | 
				
			||||||
  if (response.isSuccess()) {
 | 
					  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.value.data as string);
 | 
					    const $ = cheerio.load(response.value.data as string);
 | 
				
			||||||
    return $("body").find(f95selector.GET_REQUEST_TOKEN).attr("value");
 | 
					    return $("body").find(GENERIC.GET_REQUEST_TOKEN).attr("value");
 | 
				
			||||||
  } else throw response.value;
 | 
					  } else throw response.value;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -368,7 +368,7 @@ function manageLoginPOSTResponse(response: AxiosResponse<any>) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Get the error message (if any) and remove the new line chars
 | 
					  // Get the error message (if any) and remove the new line chars
 | 
				
			||||||
  const errorMessage = $("body")
 | 
					  const errorMessage = $("body")
 | 
				
			||||||
    .find(f95selector.LOGIN_MESSAGE_ERROR)
 | 
					    .find(GENERIC.LOGIN_MESSAGE_ERROR)
 | 
				
			||||||
    .text()
 | 
					    .text()
 | 
				
			||||||
    .replace(/\n/g, "");
 | 
					    .replace(/\n/g, "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue