rsshub
Version:
Make RSS Great Again!
143 lines (141 loc) • 5.34 kB
JavaScript
import { n as init_esm_shims, t as __dirname } from "./esm-shims-CzJ_djXG.mjs";
import "./config-C37vj7VH.mjs";
import { t as ViewType } from "./types-D84BRIt4.mjs";
import "./dist-BInvbO1W.mjs";
import "./logger-Czu8UMNd.mjs";
import { t as ofetch_default } from "./ofetch-BIyrKU3Y.mjs";
import { t as parseDate } from "./parse-date-BrP7mxXf.mjs";
import { t as art } from "./render-BQo6B4tL.mjs";
import path from "node:path";
import { load } from "cheerio";
//#region lib/routes/scoop/apps.ts
init_esm_shims();
const orderbys = (desc) => {
const base = {
0: "search.score() desc, Metadata/OfficialRepositoryNumber desc, NameSortable asc",
1: "NameSortable asc, Metadata/OfficialRepositoryNumber desc, Metadata/RepositoryStars desc, Metadata/Committed desc",
2: "Metadata/Committed desc, Metadata/OfficialRepositoryNumber desc, Metadata/RepositoryStars desc"
};
if (desc === "1") return base;
const inverted = {};
for (const key in base) inverted[key] = base[key].replaceAll(/\b(desc|asc)\b/gi, (match) => match.toLowerCase() === "desc" ? "asc" : "desc");
return inverted;
};
const filters = {
o: "Metadata/OfficialRepositoryNumber eq 1",
dm: "Metadata/DuplicateOf eq null"
};
const handler = async (ctx) => {
const { query = "s=2&d=1&n=true&dm=true&o=true" } = ctx.req.param();
const limit = Number.parseInt(ctx.req.query("limit") ?? "50", 10);
const baseUrl = "https://scoop.sh";
const apiBaseUrl = "https://scoopsearch.search.windows.net";
const targetUrl = new URL(`/#/apps?${query}`, baseUrl).href;
const apiUrl = new URL("indexes/apps/docs/search", apiBaseUrl).href;
const targetResponse = await ofetch_default(targetUrl);
const language = load(targetResponse)("html").attr("lang") ?? "en";
const scriptRegExp = /<script type="module" crossorigin src="(.*?)"><\/script>/;
const scriptUrl = scriptRegExp.test(targetResponse) ? new URL(targetResponse.match(scriptRegExp)?.[1], baseUrl).href : "";
if (!scriptUrl) throw new Error("JavaScript file not found.");
const key = (await ofetch_default(scriptUrl, { parseResponse: (txt) => txt })).match(/VITE_APP_AZURESEARCH_KEY:"(.*?)"/)?.[1];
if (!key) throw new Error("Key not found.");
const isOffcial = !query.includes("o=false");
const isDistinct = !query.includes("dm=false");
const sort = query.match(/s=(\d+)/)?.[1] ?? "2";
const desc = query.match(/d=(\d+)/)?.[1] ?? "1";
const response = await ofetch_default(apiUrl, {
method: "post",
query: { "api-version": "2020-06-30" },
headers: {
"api-key": key,
origin: baseUrl,
referer: baseUrl
},
body: {
count: true,
search: "",
searchMode: "all",
filter: [isOffcial ? filters.o : void 0, isDistinct ? filters.dm : void 0].filter(Boolean).join(" and "),
orderby: orderbys(desc)[sort],
skip: 0,
top: limit,
select: "Id,Name,NamePartial,NameSuffix,Description,Notes,Homepage,License,Version,Metadata/Repository,Metadata/FilePath,Metadata/OfficialRepository,Metadata/RepositoryStars,Metadata/Committed,Metadata/Sha",
highlight: "Name,NamePartial,NameSuffix,Description,Version,License,Metadata/Repository",
highlightPreTag: "<mark>",
highlightPostTag: "</mark>"
}
});
let items = [];
items = response.value.slice(0, limit).map((item) => {
const repositoryName = item.Metadata.Repository.split(/\//).slice(-2).join("/");
const title = `${item.Name} ${item.Version} in ${repositoryName}`;
const description = art(path.join(__dirname, "templates/description-fe4e5583.art"), { item });
const pubDate = item.Metadata.Committed;
const linkUrl = item.Homepage;
const authors = [{
name: repositoryName,
url: item.Metadata.Repository,
avatar: void 0
}];
const guid = `scoop-${item.Name}-${item.Version}-${item.Metadata.Sha}`;
const updated = pubDate;
return {
title,
description,
pubDate: pubDate ? parseDate(pubDate) : void 0,
link: linkUrl,
author: authors,
guid,
id: guid,
content: {
html: description,
text: description
},
updated: updated ? parseDate(updated) : void 0,
language
};
});
const author = "Scoop";
return {
title: `${author} - Apps`,
description: void 0,
link: targetUrl,
item: items,
allowEmpty: true,
author,
language,
id: targetUrl
};
};
const route = {
path: "/apps/:query?",
name: "Apps",
url: "scoop.sh",
maintainers: ["nczitzk"],
handler,
example: "/scoop/apps",
parameters: { query: { description: "Query, `s=2&d=1&n=true&dm=true&o=true` by default" } },
description: `::: tip
To subscribe to [Apps](https://scoop.sh/#/apps?s=2&d=1&n=true&dm=true&o=true), where the source URL is \`https://scoop.sh/#/apps?s=2&d=1&n=true&dm=true&o=true\`, extract the certain parts from this URL to be used as parameters, resulting in the route as [\`/scoop/apps/s=2&d=1&n=true&dm=true&o=true\`](https://rsshub.app/scoop/apps/s=2&d=1&n=true&dm=true&o=true).
:::`,
categories: ["program-update"],
features: {
requireConfig: false,
requirePuppeteer: false,
antiCrawler: false,
supportRadar: true,
supportBT: false,
supportPodcast: false,
supportScihub: false
},
radar: [{
source: ["scoop.sh/#/apps", "scoop.sh"],
target: (_, url) => {
const query = new URL(url).searchParams.toString() ?? void 0;
return `/scoop/apps${query ? `/${query}` : ""}`;
}
}],
view: ViewType.Notifications
};
//#endregion
export { handler, route };