UNPKG

rsshub

Version:
133 lines (131 loc) 4.64 kB
import { n as init_esm_shims, t as __dirname } from "./esm-shims-CzJ_djXG.mjs"; import { t as ofetch_default } from "./ofetch-BIyrKU3Y.mjs"; import { t as art } from "./render-BQo6B4tL.mjs"; import path from "node:path"; import { load } from "cheerio"; //#region lib/routes/app-sales/util.ts init_esm_shims(); const baseUrl = "https://www.app-sales.net"; /** * Formats price change information into a standardized tag * @param priceOld - Old price * @param priceNew - New price * @param priceDisco - Discount * @returns Formatted price change tag string. Returns empty string when no new price exists. */ const formatPriceChangeTag = (priceOld, priceNew, priceDisco) => priceNew?.trim() ? `[${[ priceOld && `${priceOld}→`, priceNew, priceDisco && ` ${priceDisco}` ].filter(Boolean).join("")}]` : ""; /** * Processes DOM elements into structured data items * @param $ - CheerioAPI instance * @param selector - CSS selector for target elements * @returns Parsed data items array. */ const processItems = ($, selector) => $(selector).toArray().map((el) => { const $el = $(el); const appName = $el.find("p.app-name").text()?.trim(); const appDev = $el.find("p.app-dev").text()?.trim(); const appNote = $el.find("p.app-dev").next("p")?.text()?.trim() ?? ""; const rating = $el.find("p.rating").contents().last().text()?.trim(); const downloads = $el.find("p.downloads").contents().last().text()?.trim(); const bookmarks = $el.find("p.bookmarks").contents().last().text()?.trim(); const priceNew = $el.find("div.price-new").text()?.trim(); const priceOld = $el.find("div.price-old").text()?.trim(); const priceDisco = $el.find("div.price-disco").text()?.trim(); const isHot = $el.hasClass("sale-hot"); const isFree = priceNew?.toLocaleUpperCase() === "FREE"; const title = `${appName} ${formatPriceChangeTag(priceOld, priceNew, priceDisco)}`; const image = $el.find("div.app-icon img").attr("src"); const linkUrl = $el.find("div.sale-list-action a").attr("href"); const description = art(path.join(__dirname, "templates/description-4540098f.art"), { images: image ? [{ alt: `${appName}-${appDev}`, src: image }] : void 0, appName, appDev, appNote, rating, downloads, bookmarks, priceNew, priceOld, priceDisco, linkUrl }); const categories = [isHot ? "Hot" : void 0, isFree ? "Free" : void 0].filter(Boolean); const authors = appDev; const guid = [ appName, appDev, rating, downloads, bookmarks, priceNew ].filter(Boolean).join("-"); return { title: title.trim(), description, link: linkUrl, category: categories, author: authors, guid, id: guid, content: { html: description, text: description }, image, banner: image }; }); /** * Retrieves pagination URLs from page navigation * @param $ - CheerioAPI instance * @param targetUrl - Base URL for relative path resolution * @returns Array of absolute pagination URLs. */ const getAvailablePageUrls = ($, targetUrl) => $("ul.pagination li.waves-effect a").slice(0, -1).toArray().filter((el) => { return $(el).attr("href"); }).map((el) => { const $el = $(el); return new URL($el.attr("href"), targetUrl).href; }); /** * Aggregates items across paginated pages * @param $ - Initial page CheerioAPI instance * @param selector - Target element CSS selector * @param targetUrl - Base URL for pagination requests * @param country - Country ID for request headers * @param limit - Maximum number of items to return * @returns Aggregated items array within specified limit. */ const fetchItems = async ($, selector, targetUrl, country, limit) => { const initialItems = processItems($, selector); if (initialItems.length >= limit) return initialItems.slice(0, limit); /** * Recursive helper function to process paginated URLs * * @param remainingUrls - Array of URLs yet to be processed * @param aggregated - Accumulator for collected items * * @returns Promise resolving to aggregated items */ const processPage = async (remainingUrls, aggregated) => { if (aggregated.length >= limit || remainingUrls.length === 0) return aggregated.slice(0, limit); const [currentUrl, ...restUrls] = remainingUrls; try { const pageItems = processItems(load(await ofetch_default(currentUrl, { headers: { Cookie: `countryId=${country};` } })), selector); const newItems = [...aggregated, ...pageItems]; return newItems.length >= limit ? newItems.slice(0, limit) : processPage(restUrls, newItems); } catch { return processPage(restUrls, aggregated); } }; return await processPage(getAvailablePageUrls($, targetUrl), initialItems); }; //#endregion export { fetchItems as n, baseUrl as t };