rsshub
Version:
Make RSS Great Again!
84 lines (83 loc) • 2.93 kB
JavaScript
import { t as config } from "./config-CCmw1BNE.mjs";
import "./types-DNj6Etbg.mjs";
import { t as logger } from "./logger-BKy98Y8B.mjs";
import { t as parseDate } from "./parse-date-Cr0wQjV_.mjs";
import { t as cache_default } from "./cache-BkqOokyU.mjs";
import { n as outPlaywright } from "./playwright-o20DiLNh.mjs";
import sanitizeHtml from "sanitize-html";
//#region lib/routes/sotwe/user.ts
const route = {
path: "/user/:id",
categories: ["social-media"],
example: "/sotwe/user/_RSSHub",
parameters: { id: "Twitter username" },
features: {
requireConfig: false,
requirePuppeteer: true,
antiCrawler: true,
supportBT: false,
supportPodcast: false,
supportScihub: false
},
radar: [{
source: ["www.sotwe.com/:id"],
target: "/user/:id"
}],
name: "User timeline - Sotwe",
maintainers: ["TonyRL"],
handler,
view: 2
};
const renderMedia = (mediaEntities) => mediaEntities.map((e) => {
switch (e.type) {
case "photo": return `<img src="${e.mediaURL}">`;
case "video": {
const video = e.videoInfo.variants.filter((v) => v.type === "video/mp4").toSorted((a, b) => b.bitrate - a.bitrate)[0];
return `<video controls preload="metadata" poster="${e.mediaURL}"><source src="${video.url}" type="video/mp4"></video>`;
}
default: return "";
}
}).join("<br>");
const renderDescription = (item) => `${renderMedia(item.mediaEntities)}<br>${item.text.replaceAll("\n", "<br>")}${item.quotedStatus ? `<br>${renderDescription(item.quotedStatus)}` : ""}${item.retweetedStatus ? `<br>${renderDescription(item.retweetedStatus)}` : ""}`;
async function handler(ctx) {
const baseUrl = "https://www.sotwe.com";
const { id } = ctx.req.param();
const data = await cache_default.tryGet(`sotwe:user:${id}`, async () => {
const context = await outPlaywright();
const page = await context.newPage();
await page.route("**/*", (route) => {
const request = route.request();
[
"document",
"script",
"xhr",
"fetch"
].includes(request.resourceType()) ? route.continue() : route.abort();
});
const apiUrl = `${baseUrl}/api/v3/user/${id}/`;
logger.http(`Requesting ${apiUrl}`);
await page.goto(apiUrl, { waitUntil: "domcontentloaded" });
const response = await page.evaluate(() => document.documentElement.textContent);
await page.close();
await context.close();
return JSON.parse(response || "{}");
}, config.cache.routeExpire, false);
const items = data.data.map((item) => ({
title: sanitizeHtml(item.text.split("\n", 1)[0], {
allowedTags: [],
allowedAttributes: {}
}),
description: renderDescription(item),
link: `https://x.com/${id}/status/${item.id}`,
pubDate: parseDate(item.createdAt, "x")
}));
return {
title: `${data.info.name} @${data.info.screenName} - Twitter Profile | Sotwe`,
description: data.info.description,
link: `${baseUrl}/${id}`,
image: data.info.profileImageThumbnail,
item: items
};
}
//#endregion
export { route };