Change createURL to execute
parent
839016daa3
commit
1d7e06da4c
|
@ -1,10 +1,13 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
import { AxiosResponse } from 'axios';
|
||||||
// Public modules from npm
|
// Public modules from npm
|
||||||
import validator from 'class-validator';
|
import validator from 'class-validator';
|
||||||
|
|
||||||
// Module from files
|
// Module from files
|
||||||
import { IQuery, TCategory, TQueryInterface } from "../../interfaces.js";
|
import { IQuery, TCategory, TQueryInterface } from "../../interfaces.js";
|
||||||
|
import { GenericAxiosError, UnexpectedResponseContentType } from '../errors.js';
|
||||||
|
import { Result } from '../result.js';
|
||||||
import LatestSearchQuery, { TLatestOrder } from './latest-search-query.js';
|
import LatestSearchQuery, { TLatestOrder } from './latest-search-query.js';
|
||||||
import ThreadSearchQuery, { TThreadOrder } from './thread-search-query.js';
|
import ThreadSearchQuery, { TThreadOrder } from './thread-search-query.js';
|
||||||
|
|
||||||
|
@ -28,6 +31,8 @@ import ThreadSearchQuery, { TThreadOrder } from './thread-search-query.js';
|
||||||
* `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";
|
||||||
|
type TLatestResult = Result<GenericAxiosError | UnexpectedResponseContentType, string>;
|
||||||
|
type TThreadResult = Result<GenericAxiosError, AxiosResponse<any>>;
|
||||||
|
|
||||||
export default class HandiworkSearchQuery implements IQuery {
|
export default class HandiworkSearchQuery implements IQuery {
|
||||||
|
|
||||||
|
@ -38,6 +43,7 @@ export default class HandiworkSearchQuery implements IQuery {
|
||||||
//#endregion Private fields
|
//#endregion Private fields
|
||||||
|
|
||||||
//#region Properties
|
//#region Properties
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keywords to use in the search.
|
* Keywords to use in the search.
|
||||||
*/
|
*/
|
||||||
|
@ -69,9 +75,11 @@ export default class HandiworkSearchQuery implements IQuery {
|
||||||
})
|
})
|
||||||
public page: number = 1;
|
public page: number = 1;
|
||||||
itype: TQueryInterface = "HandiworkSearchQuery";
|
itype: TQueryInterface = "HandiworkSearchQuery";
|
||||||
|
|
||||||
//#endregion Properties
|
//#endregion Properties
|
||||||
|
|
||||||
//#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
|
||||||
|
@ -90,13 +98,11 @@ export default class HandiworkSearchQuery implements IQuery {
|
||||||
return DEFAULT_SEARCH_TYPE;
|
return DEFAULT_SEARCH_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public validate(): boolean {
|
public validate(): boolean { return validator.validateSync(this).length === 0; }
|
||||||
return validator.validateSync(this).length === 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public createURL(): URL {
|
public async execute(): Promise<TLatestResult | TThreadResult> {
|
||||||
// Local variables
|
// Local variables
|
||||||
let url = null;
|
let response: TLatestResult | TThreadResult = null;
|
||||||
|
|
||||||
// Check if the query is valid
|
// Check if the query is valid
|
||||||
if (!this.validate()) {
|
if (!this.validate()) {
|
||||||
|
@ -104,10 +110,10 @@ export default class HandiworkSearchQuery implements IQuery {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert the query
|
// Convert the query
|
||||||
if (this.selectSearchType() === "latest") url = this.cast<LatestSearchQuery>("LatestSearchQuery").createURL();
|
if (this.selectSearchType() === "latest") response = await this.cast<LatestSearchQuery>("LatestSearchQuery").execute();
|
||||||
else url = this.cast<ThreadSearchQuery>("ThreadSearchQuery").createURL();
|
else response = await this.cast<ThreadSearchQuery>("ThreadSearchQuery").execute();
|
||||||
|
|
||||||
return url;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public cast<T extends IQuery>(type: TQueryInterface): T {
|
public cast<T extends IQuery>(type: TQueryInterface): T {
|
||||||
|
@ -122,9 +128,11 @@ export default class HandiworkSearchQuery implements IQuery {
|
||||||
// Cast the result to T
|
// Cast the result to T
|
||||||
return returnValue as T;
|
return returnValue as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion Public methods
|
//#endregion Public methods
|
||||||
|
|
||||||
//#region Private methods
|
//#region Private methods
|
||||||
|
|
||||||
private castToLatest(): LatestSearchQuery {
|
private castToLatest(): LatestSearchQuery {
|
||||||
// Cast the basic query object and copy common values
|
// Cast the basic query object and copy common values
|
||||||
const query: LatestSearchQuery = new LatestSearchQuery;
|
const query: LatestSearchQuery = new LatestSearchQuery;
|
||||||
|
@ -165,5 +173,6 @@ export default class HandiworkSearchQuery implements IQuery {
|
||||||
|
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
}
|
}
|
|
@ -7,6 +7,7 @@ import validator from 'class-validator';
|
||||||
import { urls } from "../../constants/url.js";
|
import { urls } from "../../constants/url.js";
|
||||||
import PrefixParser from '../prefix-parser.js';
|
import PrefixParser from '../prefix-parser.js';
|
||||||
import { IQuery, TCategory, TQueryInterface } from "../../interfaces.js";
|
import { IQuery, TCategory, TQueryInterface } from "../../interfaces.js";
|
||||||
|
import { fetchHTML } from '../../network-helper.js';
|
||||||
|
|
||||||
// Type definitions
|
// Type definitions
|
||||||
export type TLatestOrder = "date" | "likes" | "views" | "title" | "rating";
|
export type TLatestOrder = "date" | "likes" | "views" | "title" | "rating";
|
||||||
|
@ -18,11 +19,14 @@ type TDate = 365 | 180 | 90 | 30 | 14 | 7 | 3 | 1;
|
||||||
export default class LatestSearchQuery implements IQuery {
|
export default class LatestSearchQuery implements IQuery {
|
||||||
|
|
||||||
//#region Private fields
|
//#region Private fields
|
||||||
|
|
||||||
private static MAX_TAGS = 5;
|
private static MAX_TAGS = 5;
|
||||||
private static MIN_PAGE = 1;
|
private static MIN_PAGE = 1;
|
||||||
|
|
||||||
//#endregion Private fields
|
//#endregion Private fields
|
||||||
|
|
||||||
//#region Properties
|
//#region Properties
|
||||||
|
|
||||||
public category: TCategory = 'games';
|
public category: TCategory = 'games';
|
||||||
/**
|
/**
|
||||||
* Ordering type.
|
* Ordering type.
|
||||||
|
@ -52,20 +56,47 @@ export default class LatestSearchQuery implements IQuery {
|
||||||
})
|
})
|
||||||
public page = LatestSearchQuery.MIN_PAGE;
|
public page = LatestSearchQuery.MIN_PAGE;
|
||||||
itype: TQueryInterface = "LatestSearchQuery";
|
itype: TQueryInterface = "LatestSearchQuery";
|
||||||
|
|
||||||
//#endregion Properties
|
//#endregion Properties
|
||||||
|
|
||||||
//#region Public methods
|
//#region Public methods
|
||||||
|
|
||||||
public validate(): boolean {
|
public validate(): boolean { return validator.validateSync(this).length === 0; }
|
||||||
return validator.validateSync(this).length === 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public createURL(): URL {
|
public async execute() {
|
||||||
// Check if the query is valid
|
// Check if the query is valid
|
||||||
if (!this.validate()) {
|
if (!this.validate()) {
|
||||||
throw new Error(`Invalid query: ${validator.validateSync(this).join("\n")}`);
|
throw new Error(`Invalid query: ${validator.validateSync(this).join("\n")}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prepare the URL
|
||||||
|
const url = this.prepareGETurl();
|
||||||
|
const decoded = decodeURIComponent(url.toString());
|
||||||
|
|
||||||
|
// Fetch the result
|
||||||
|
return await fetchHTML(decoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
public findNearestDate(d: Date): TDate {
|
||||||
|
// Find the difference between today and the passed date
|
||||||
|
const diff = this.dateDiffInDays(new Date(), d);
|
||||||
|
|
||||||
|
// Find the closest valid value in the array
|
||||||
|
const closest = [365, 180, 90, 30, 14, 7, 3, 1].reduce(function (prev, curr) {
|
||||||
|
return (Math.abs(curr - diff) < Math.abs(prev - diff) ? curr : prev);
|
||||||
|
});
|
||||||
|
|
||||||
|
return closest as TDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion Public methods
|
||||||
|
|
||||||
|
//#region Private methods
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare the URL by filling out the GET parameters with the data in the query.
|
||||||
|
*/
|
||||||
|
private prepareGETurl(): URL {
|
||||||
// Create the URL
|
// Create the URL
|
||||||
const url = new URL(urls.F95_LATEST_PHP);
|
const url = new URL(urls.F95_LATEST_PHP);
|
||||||
url.searchParams.set("cmd", "list");
|
url.searchParams.set("cmd", "list");
|
||||||
|
@ -92,20 +123,6 @@ export default class LatestSearchQuery implements IQuery {
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
public findNearestDate(d: Date): TDate {
|
|
||||||
// Find the difference between today and the passed date
|
|
||||||
const diff = this.dateDiffInDays(new Date(), d);
|
|
||||||
|
|
||||||
// Find the closest valid value in the array
|
|
||||||
const closest = [365, 180, 90, 30, 14, 7, 3, 1].reduce(function (prev, curr) {
|
|
||||||
return (Math.abs(curr - diff) < Math.abs(prev - diff) ? curr : prev);
|
|
||||||
});
|
|
||||||
|
|
||||||
return closest as TDate;
|
|
||||||
}
|
|
||||||
//#endregion Public methods
|
|
||||||
|
|
||||||
//#region Private methods
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -118,5 +135,7 @@ export default class LatestSearchQuery implements IQuery {
|
||||||
|
|
||||||
return Math.floor((utc2 - utc1) / MS_PER_DAY);
|
return Math.floor((utc2 - utc1) / MS_PER_DAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion Private methodss
|
//#endregion Private methodss
|
||||||
|
|
||||||
}
|
}
|
|
@ -7,6 +7,11 @@ import validator from 'class-validator';
|
||||||
import { IQuery, TCategory, TQueryInterface } from "../../interfaces.js";
|
import { IQuery, TCategory, TQueryInterface } from "../../interfaces.js";
|
||||||
import { urls } from "../../constants/url.js";
|
import { urls } from "../../constants/url.js";
|
||||||
import PrefixParser from "./../prefix-parser.js";
|
import PrefixParser from "./../prefix-parser.js";
|
||||||
|
import { fetchPOSTResponse } from '../../network-helper.js';
|
||||||
|
import { AxiosResponse } from 'axios';
|
||||||
|
import { GenericAxiosError } from '../errors.js';
|
||||||
|
import { Result } from '../result.js';
|
||||||
|
import Shared from '../../shared.js';
|
||||||
|
|
||||||
// Type definitions
|
// Type definitions
|
||||||
export type TThreadOrder = "relevance" | "date" | "last_update" | "replies";
|
export type TThreadOrder = "relevance" | "date" | "last_update" | "replies";
|
||||||
|
@ -14,10 +19,13 @@ export type TThreadOrder = "relevance" | "date" | "last_update" | "replies";
|
||||||
export default class ThreadSearchQuery implements IQuery {
|
export default class ThreadSearchQuery implements IQuery {
|
||||||
|
|
||||||
//#region Private fields
|
//#region Private fields
|
||||||
|
|
||||||
static MIN_PAGE = 1;
|
static MIN_PAGE = 1;
|
||||||
|
|
||||||
//#endregion Private fields
|
//#endregion Private fields
|
||||||
|
|
||||||
//#region Properties
|
//#region Properties
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keywords to use in the search.
|
* Keywords to use in the search.
|
||||||
*/
|
*/
|
||||||
|
@ -57,78 +65,89 @@ export default class ThreadSearchQuery implements IQuery {
|
||||||
})
|
})
|
||||||
public page: number = 1;
|
public page: number = 1;
|
||||||
itype: TQueryInterface = "ThreadSearchQuery";
|
itype: TQueryInterface = "ThreadSearchQuery";
|
||||||
|
|
||||||
//#endregion Properties
|
//#endregion Properties
|
||||||
|
|
||||||
//#region Public methods
|
//#region Public methods
|
||||||
|
|
||||||
public validate(): boolean {
|
public validate(): boolean { return validator.validateSync(this).length === 0; }
|
||||||
return validator.validateSync(this).length === 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public createURL(): URL {
|
public async execute(): Promise<Result<GenericAxiosError, AxiosResponse<any>>> {
|
||||||
// Check if the query is valid
|
// Check if the query is valid
|
||||||
if (!this.validate()) {
|
if (!this.validate()) {
|
||||||
throw new Error(`Invalid query: ${validator.validateSync(this).join("\n")}`);
|
throw new Error(`Invalid query: ${validator.validateSync(this).join("\n")}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the URL
|
|
||||||
const url = new URL(urls.F95_SEARCH_URL);
|
|
||||||
|
|
||||||
// Specifiy if only the title should be searched
|
// Define the POST parameters
|
||||||
if (this.onlyTitles) url.searchParams.set("c[title_only]", "1");
|
const params = this.preparePOSTParameters();
|
||||||
|
|
||||||
|
// Return the POST response
|
||||||
|
return await fetchPOSTResponse(urls.F95_SEARCH_URL, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion Public methods
|
||||||
|
|
||||||
|
//#region Private methods
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare the parameters for post request with the data in the query.
|
||||||
|
*/
|
||||||
|
private preparePOSTParameters(): { [s: string]: string } {
|
||||||
|
// Local variables
|
||||||
|
const params = {};
|
||||||
|
|
||||||
|
// Ad the session token
|
||||||
|
params["_xfToken"] = Shared.session.token;
|
||||||
|
|
||||||
|
// Specify if only the title should be searched
|
||||||
|
if (this.onlyTitles) params["c[title_only]"] = "1";
|
||||||
|
|
||||||
// Add keywords
|
// Add keywords
|
||||||
const encodedKeywords = this.keywords ?? "*";
|
params["keywords"] = this.keywords ?? "*";
|
||||||
url.searchParams.set("q", encodedKeywords);
|
|
||||||
|
|
||||||
// Specify the scope of the search (only "threads/post")
|
// Specify the scope of the search (only "threads/post")
|
||||||
url.searchParams.set("t", "post");
|
params["search_type"] = "post";
|
||||||
|
|
||||||
// Set the dates
|
// Set the dates
|
||||||
if (this.newerThan) {
|
if (this.newerThan) {
|
||||||
const date = this.convertShortDate(this.newerThan);
|
const date = this.convertShortDate(this.newerThan);
|
||||||
url.searchParams.set("c[newer_than]", date);
|
params["c[newer_than]"] = date;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.olderThan) {
|
if (this.olderThan) {
|
||||||
const date = this.convertShortDate(this.olderThan);
|
const date = this.convertShortDate(this.olderThan);
|
||||||
url.searchParams.set("c[older_than]", date);
|
params["c[older_than]"] = date;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set included and excluded tags
|
// Set included and excluded tags (joined with a comma)
|
||||||
// The tags are first joined with a comma, then encoded to URI
|
if (this.includedTags) params["c[tags]"] = this.includedTags.join(",");
|
||||||
const includedTags = encodeURIComponent(this.includedTags.join(","));
|
if (this.excludedTags) params["c[excludeTags]"] = this.excludedTags.join(",");
|
||||||
const excludedTags = encodeURIComponent(this.excludedTags.join(","));
|
|
||||||
if (includedTags) url.searchParams.set("c[tags]", includedTags);
|
|
||||||
if (excludedTags) url.searchParams.set("c[excludeTags]", excludedTags);
|
|
||||||
|
|
||||||
// Set minimum reply number
|
// Set minimum reply number
|
||||||
if (this.minimumReplies > 0) url.searchParams.set("c[min_reply_count]", this.minimumReplies.toString());
|
if (this.minimumReplies > 0) params["c[min_reply_count]"] = this.minimumReplies.toString();
|
||||||
|
|
||||||
// Add prefixes
|
// Add prefixes
|
||||||
const parser = new PrefixParser();
|
const parser = new PrefixParser();
|
||||||
const ids = parser.prefixesToIDs(this.includedPrefixes);
|
const ids = parser.prefixesToIDs(this.includedPrefixes);
|
||||||
for (let i = 0; i < ids.length; i++) {
|
for (let i = 0; i < ids.length; i++) {
|
||||||
const name = `c[prefixes][${i}]`;
|
const name = `c[prefixes][${i}]`;
|
||||||
url.searchParams.set(name, ids[i].toString());
|
params[name] = ids[i].toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the category
|
// Set the category
|
||||||
url.searchParams.set("c[child_nodes]", "1"); // Always set
|
params["c[child_nodes]"] = "1"; // Always set
|
||||||
if (this.category) {
|
if (this.category) {
|
||||||
const catID = this.categoryToID(this.category).toString();
|
const catID = this.categoryToID(this.category).toString();
|
||||||
url.searchParams.set("c[nodes][0]", catID);
|
params["c[nodes][0]"] = catID;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the other values
|
// Set the other values
|
||||||
url.searchParams.set("o", this.order.toString());
|
params["o"] = this.order.toString();
|
||||||
url.searchParams.set("page", this.page.toString());
|
params["page"] = this.page.toString();
|
||||||
|
|
||||||
return url;
|
return params;
|
||||||
}
|
}
|
||||||
//#endregion Public methods
|
|
||||||
|
|
||||||
//#region Private methods
|
|
||||||
/**
|
/**
|
||||||
* Convert a date in the YYYY-MM-DD format taking into account the time zone.
|
* Convert a date in the YYYY-MM-DD format taking into account the time zone.
|
||||||
*/
|
*/
|
||||||
|
@ -152,6 +171,7 @@ export default class ThreadSearchQuery implements IQuery {
|
||||||
|
|
||||||
return catMap[category as string];
|
return catMap[category as string];
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion Private methods
|
//#endregion Private methods
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
export const urls = {
|
export const urls = {
|
||||||
F95_BASE_URL: "https://f95zone.to",
|
F95_BASE_URL: "https://f95zone.to",
|
||||||
F95_SEARCH_URL: "https://f95zone.to/search/105286576/",
|
F95_SEARCH_URL: "https://f95zone.to/search/search/",
|
||||||
F95_LATEST_UPDATES: "https://f95zone.to/latest",
|
F95_LATEST_UPDATES: "https://f95zone.to/latest",
|
||||||
F95_THREADS: "https://f95zone.to/threads/",
|
F95_THREADS: "https://f95zone.to/threads/",
|
||||||
F95_LOGIN_URL: "https://f95zone.to/login/login",
|
F95_LOGIN_URL: "https://f95zone.to/login/login",
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// Modules from file
|
// Modules from file
|
||||||
import { fetchGETResponse } from "../network-helper.js";
|
|
||||||
import LatestSearchQuery from "../classes/query/latest-search-query.js";
|
import LatestSearchQuery from "../classes/query/latest-search-query.js";
|
||||||
import { urls as f95url } from "../constants/url.js";
|
import { urls as f95url } from "../constants/url.js";
|
||||||
|
|
||||||
|
@ -23,11 +22,8 @@ export default async function fetchLatestHandiworkURLs(query: LatestSearchQuery,
|
||||||
let noMorePages = false;
|
let noMorePages = false;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
// Prepare the URL
|
|
||||||
const url = query.createURL().toString();
|
|
||||||
|
|
||||||
// Fetch the response (application/json)
|
// Fetch the response (application/json)
|
||||||
const response = await fetchGETResponse(url);
|
const response = await query.execute();
|
||||||
|
|
||||||
// Save the URLs
|
// Save the URLs
|
||||||
if (response.isSuccess()) {
|
if (response.isSuccess()) {
|
||||||
|
|
|
@ -4,13 +4,13 @@
|
||||||
import cheerio from "cheerio";
|
import cheerio from "cheerio";
|
||||||
|
|
||||||
// Modules from file
|
// Modules from file
|
||||||
import { fetchHTML } from "../network-helper.js";
|
|
||||||
import shared from "../shared.js";
|
import shared from "../shared.js";
|
||||||
import { selectors as f95Selector } from "../constants/css-selector.js";
|
import { selectors as f95Selector } 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";
|
||||||
|
|
||||||
//#region Public methods
|
//#region Public methods
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the URLs of the handiwork' threads that match the passed parameters.
|
* Gets the URLs of the handiwork' threads that match the passed parameters.
|
||||||
* You *must* be logged.
|
* You *must* be logged.
|
||||||
|
@ -21,42 +21,37 @@ import ThreadSearchQuery from "../classes/query/thread-search-query.js";
|
||||||
* @returns {Promise<String[]>} URLs of the handiworks
|
* @returns {Promise<String[]>} URLs of the handiworks
|
||||||
*/
|
*/
|
||||||
export default async function fetchThreadHandiworkURLs(query: ThreadSearchQuery, limit: number = 30): Promise<string[]> {
|
export default async function fetchThreadHandiworkURLs(query: ThreadSearchQuery, limit: number = 30): Promise<string[]> {
|
||||||
// Get the query
|
// Execute the query
|
||||||
const url = decodeURI(query.createURL().href);
|
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
|
||||||
return await fetchResultURLs(url, limit);
|
if (response.isSuccess()) return await fetchResultURLs(response.value.data as string, limit);
|
||||||
|
else throw response.value
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion Public methods
|
//#endregion Public methods
|
||||||
|
|
||||||
//#region Private methods
|
//#region Private methods
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the URLs of the threads resulting from the F95Zone search.
|
* Gets the URLs of the threads resulting from the F95Zone search.
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* Maximum number of items to get. Default: 30
|
* Maximum number of items to get. Default: 30
|
||||||
* @return {Promise<String[]>} List of URLs
|
|
||||||
*/
|
*/
|
||||||
async function fetchResultURLs(url: string, limit: number = 30): Promise<string[]> {
|
async function fetchResultURLs(html: string, limit: number = 30): Promise<string[]> {
|
||||||
shared.logger.trace(`Fetching ${url}...`);
|
// Prepare cheerio
|
||||||
|
const $ = cheerio.load(html);
|
||||||
|
|
||||||
// Fetch HTML and prepare Cheerio
|
// Here we get all the DIV that are the body of the various query results
|
||||||
const html = await fetchHTML(url);
|
const results = $("body").find(f95Selector.GS_RESULT_BODY);
|
||||||
|
|
||||||
if (html.isSuccess()) {
|
// Than we extract the URLs
|
||||||
const $ = cheerio.load(html.value);
|
const urls = results.slice(0, limit).map((idx, el) => {
|
||||||
|
const elementSelector = $(el);
|
||||||
|
return extractLinkFromResult(elementSelector);
|
||||||
|
}).get();
|
||||||
|
|
||||||
// Here we get all the DIV that are the body of the various query results
|
return urls;
|
||||||
const results = $("body").find(f95Selector.GS_RESULT_BODY);
|
|
||||||
|
|
||||||
// Than we extract the URLs
|
|
||||||
const urls = results.slice(0, limit).map((idx, el) => {
|
|
||||||
const elementSelector = $(el);
|
|
||||||
return extractLinkFromResult(elementSelector);
|
|
||||||
}).get();
|
|
||||||
|
|
||||||
return urls;
|
|
||||||
} else throw html.value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -75,4 +70,5 @@ function extractLinkFromResult(selector: cheerio.Cheerio): string {
|
||||||
// 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion Private methods
|
//#endregion Private methods
|
|
@ -288,8 +288,9 @@ export interface IQuery {
|
||||||
*/
|
*/
|
||||||
validate(): boolean,
|
validate(): boolean,
|
||||||
/**
|
/**
|
||||||
* From the query values it generates the corresponding URL for the platform.
|
* Search with the data in the query and returns the result.
|
||||||
|
*
|
||||||
* If the query is invalid it throws an exception.
|
* If the query is invalid it throws an exception.
|
||||||
*/
|
*/
|
||||||
createURL(): URL,
|
execute(): any,
|
||||||
}
|
}
|
Loading…
Reference in New Issue