UNPKG

rsshub

Version:
84 lines (83 loc) 2.93 kB
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 };