rsshub
Version:
Make RSS Great Again!
150 lines (147 loc) • 6.11 kB
JavaScript
import { t as parseDate } from "./parse-date-Cr0wQjV_.mjs";
import { r as getSubPath } from "./common-utils-DtQojudb.mjs";
import { t as got_default } from "./got-BTowW50G.mjs";
import { Fragment, jsx, jsxs } from "hono/jsx/jsx-runtime";
import { load } from "cheerio";
import { renderToString } from "hono/jsx/dom/server";
//#region lib/routes/metacritic/util.ts
const sorts = {
metascore: {
id: "metaScore",
name: "Metascore"
},
userscore: {
id: "userScore",
name: "User Score"
},
popular: {
id: "popularityCount",
name: "Most Popular"
},
new: {
id: "releaseDate",
name: "Releases"
}
};
const types = {
game: {
id: "games",
name: "Games"
},
movie: {
id: "movies",
name: "Movies"
},
tv: {
id: "tv",
name: "TV Shows"
},
albums: {
id: "albums",
name: "Music"
}
};
//#endregion
//#region lib/routes/metacritic/index.tsx
const renderDescription = (image, description, score) => renderToString(/* @__PURE__ */ jsxs(Fragment, { children: [
image ? /* @__PURE__ */ jsx("figure", { children: /* @__PURE__ */ jsx("img", {
src: image.src,
alt: image.alt
}) }) : null,
description ? /* @__PURE__ */ jsx("p", { children: description }) : null,
score ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", { children: "Metascore:" }), score] }) : null
] }));
const route = {
path: "/game/:sort?/:filter?",
categories: ["new-media"],
example: "/metacritic/game",
parameters: {
sort: "Sort, see below, `new` for Newest Releases by default",
filter: "Filter"
},
description: `| Metascore | User Score | Most Popular | Newest Releases |
| --------- | ---------- | ------------ | --------------- |
| metascore | userscore | popular | new |
::: tip
The Filter parameter comes from the corresponding page URL. The following is an example:
The URL of [Action Games to Play on PS5](https://www.metacritic.com/browse/game/all/all/all-time/new/?platform=ps5\\&genre=action) is \`https://www.metacritic.com/browse/game/all/all/all-time/new/?platform=ps5&genre=action\`. The Filter parameter is \`platform=ps5&genre=action\` and the route is [\`/metacritic/game/new/platform=ps5&genre=action\`](https://rsshub.app/metacritic/game/new/platform=ps5\\&genre=action)
:::`,
radar: [{
source: ["metacritic.com/browse/game/*"],
target: "/game"
}],
name: "Games",
maintainers: ["HenryQW", "nczitzk"],
handler
};
async function handler(ctx) {
const type = getSubPath(ctx).split("/", 2)[1];
const { sort = "new", filter } = ctx.req.param();
const limit = ctx.req.query("limit") ? Number(ctx.req.query("limit")) : 50;
const rootUrl = "https://www.metacritic.com";
const apiUrl = new URL("finder/metacritic/web", "https://backend.metacritic.com").href;
const currentUrlObject = new URL(`/browse/${type}/all/all/all-time/${sort}/${filter ? `?${filter}` : ""}`, rootUrl);
const currentUrlParams = currentUrlObject.searchParams;
const currentUrl = currentUrlObject.href;
const { data: currentResponse } = await got_default(currentUrl);
const apiKey = currentResponse.match(/apiKey=(.*?)&/)[1];
const searchParams = {
sortBy: `-${sorts[sort].id}`,
productType: types[type].id,
limit,
apiKey
};
const genres = currentUrlParams.getAll("genre").join(",").toLowerCase();
const releaseTypes = currentUrlParams.getAll("releaseType").join(",");
const releaseYearMin = currentUrlParams.get("releaseYearMin");
const releaseYearMax = currentUrlParams.get("releaseYearMax");
if (genres) searchParams.genres = genres;
if (releaseTypes) searchParams.releaseType = releaseTypes;
if (releaseYearMin) searchParams.releaseYearMin = releaseYearMin;
if (releaseYearMax) searchParams.releaseYearMax = releaseYearMax;
const platforms = currentUrlParams.getAll("platform");
const networks = currentUrlParams.getAll("network");
if (platforms.length || networks.length) {
const labels = {};
const labelPattern = String.raw`\{label:"([^"]+)",value:(\d+),href:a,meta:\{mcDisplayWeight`;
const matches = currentResponse.match(new RegExp(labelPattern, "g"));
for (const m of matches) {
const matches = m.match(new RegExp(labelPattern));
labels[matches[1].toLowerCase().split(/(\s\(|\\u002f(?!\s))/, 1)[0].replaceAll("-", "---").replaceAll(/\s\/\s/g, "-or-").replaceAll("+", "-plus").replaceAll(/\s/g, "-")] = matches[2];
}
if (platforms.length) searchParams.gamePlatformIds = platforms.map((p) => Object.hasOwn(labels, p) ? labels[p] : void 0).filter(Boolean).join(",");
if (networks.length) searchParams.streamingNetworkIds = networks.map((p) => Object.hasOwn(labels, p) ? labels[p] : void 0).filter(Boolean).join(",");
}
const { data: response } = await got_default(apiUrl, { searchParams });
const items = response.data.items.slice(0, limit).map((item) => ({
title: item.title,
link: new URL(`${type}/${item.slug}`, rootUrl).href,
description: renderDescription(item.image ? {
src: new URL(`a/img/catalog${item.image.bucketPath}`, rootUrl).href,
alt: item.image.alt
} : void 0, item.description, item.criticScoreSummary?.score ?? void 0),
category: item.genres?.map((c) => c.name),
guid: `metacritic-${item.id}`,
pubDate: parseDate(item.releaseDate),
upvotes: item.criticScoreSummary?.positiveCount ? Number(item.criticScoreSummary?.positiveCount) : 0,
downvotes: item.criticScoreSummary?.negativeCount ? Number(item.criticScoreSummary?.negativeCount) : 0,
comments: item.criticScoreSummary?.reviewCount ? Number(item.criticScoreSummary?.reviewCount) : 0
}));
const $ = load(currentResponse);
const icon = new URL($("meta[data-hid=\"msapplication-task-metacritic\"]").prop("content").split("icon-uri=").pop(), rootUrl).href;
return {
item: items,
title: $("title").text(),
link: currentUrl,
description: $("meta[name=\"description\"]").prop("content"),
language: $("html").prop("lang"),
image: $("link[rel=\"icon\"]").prop("content"),
icon,
logo: icon,
subtitle: $("meta[name=\"msapplication-tooltip\"]").prop("content"),
author: $("meta[name=\"twitter:site\"]").prop("content"),
allowEmpty: true
};
}
//#endregion
export { route as n, handler as t };