rsshub
Version:
Make RSS Great Again!
205 lines (202 loc) • 6.21 kB
JavaScript
import { n as init_esm_shims, t as __dirname } from "./esm-shims-CzJ_djXG.mjs";
import { t as config } from "./config-C37vj7VH.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 cache_default } from "./cache-Bo__VnGm.mjs";
import { t as art } from "./render-BQo6B4tL.mjs";
import { t as invalid_parameter_default } from "./invalid-parameter-rr4AgGpp.mjs";
import { t as isValidHost } from "./valid-host-C-u5eW3j.mjs";
import path from "node:path";
//#region lib/routes/fanbox/utils.ts
init_esm_shims();
function getHeaders() {
const sessionid = config.fanbox.session;
return {
origin: "https://fanbox.cc",
cookie: sessionid ? `FANBOXSESSID=${sessionid}` : ""
};
}
function embedUrlMap(urlEmbed) {
switch (urlEmbed.type) {
case "html": return urlEmbed.html;
case "fanbox.post": return art(path.join(__dirname, "templates/fanbox-post-12425d7b.art"), {
postUrl: `https://${urlEmbed.postInfo.creatorId}.fanbox.cc/posts/${urlEmbed.postInfo.id}`,
title: urlEmbed.postInfo.title,
user: urlEmbed.postInfo.user,
excerpt: urlEmbed.postInfo.excerpt
});
default: return "";
}
}
function passageConv(p) {
const seg = [...p.text];
if (p.styles) p.styles.map((s) => {
switch (s.type) {
case "bold":
seg[s.offset] = `<b>` + seg[s.offset];
seg[s.offset + s.length - 1] += `</b>`;
break;
default:
}
return s;
});
if (p.links) p.links.map((l) => {
seg[l.offset] = `<a href="${l.url}">` + seg[l.offset];
seg[l.offset + l.length - 1] += `</a>`;
return l;
});
return seg.join("");
}
function parseText(body) {
return body.text || "";
}
function parseImage(body) {
let ret = body.text || "";
for (const i of body.images) ret += `<hr><img src="${i.originalUrl}">`;
return ret;
}
function parseFile(body) {
let ret = body.text || "";
for (const f of body.files) ret += `<br><a href="${f.url}" download="${f.name}.${f.extension}">${f.name}.${f.extension}</a>`;
return ret;
}
async function parseVideo(body) {
let ret = "";
switch (body.video.serviceProvider) {
case "soundcloud":
ret += await getSoundCloudEmbedUrl(body.video.videoId);
break;
case "youtube":
ret += `<iframe src="https://www.youtube-nocookie.com/embed/${body.video.videoId}" frameborder="0" referrerpolicy="strict-origin-when-cross-origin"></iframe>`;
break;
case "vimeo":
ret += `<iframe src="https://player.vimeo.com/video/${body.video.videoId}" frameborder="0"></iframe>`;
break;
default:
}
ret += `<br>${body.text}`;
return ret;
}
async function parseArtile(body) {
let ret = [];
for (let x = 0; x < body.blocks.length; ++x) {
const b = body.blocks[x];
ret.push("<p>");
switch (b.type) {
case "p":
ret.push(passageConv(b));
break;
case "header":
ret.push(`<h2>${b.text}</h2>`);
break;
case "image": {
const i = body.imageMap[b.imageId];
ret.push(`<img src="${i.originalUrl}">`);
break;
}
case "file": {
const file = body.fileMap[b.fileId];
ret.push(`<a href="${file.url}" download="${file.name}.${file.extension}">${file.name}.${file.extension}</a>`);
break;
}
case "url_embed":
ret.push(embedUrlMap(body.urlEmbedMap[b.urlEmbedId]));
break;
default:
}
}
ret = await Promise.all(ret);
return ret.join("");
}
async function parseDetail(i) {
let ret = "";
if (i.feeRequired !== 0) ret += `Fee Required: <b>${i.feeRequired} JPY/month</b><hr>`;
if (i.coverImageUrl) ret += `<img src="${i.coverImageUrl}"><hr>`;
if (!i.body) {
ret += i.excerpt;
return ret;
}
switch (i.type) {
case "text":
ret += parseText(i.body);
break;
case "file":
ret += parseFile(i.body);
break;
case "image":
ret += parseImage(i.body);
break;
case "video":
ret += await parseVideo(i.body);
break;
case "article":
ret += await parseArtile(i.body);
break;
default: ret += "<b>Unsupported content (RSSHub)</b>";
}
return ret;
}
function parseItem(item) {
return cache_default.tryGet(`fanbox-${item.id}-${item.updatedDatetime}`, async () => {
const postDetail = await ofetch_default(`https://api.fanbox.cc/post.info?postId=${item.id}`, { headers: {
...getHeaders(),
"User-Agent": config.trueUA
} });
return {
title: item.title || `No title`,
description: await parseDetail(postDetail.body),
pubDate: parseDate(item.updatedDatetime),
link: `https://${item.creatorId}.fanbox.cc/posts/${item.id}`,
category: item.tags
};
});
}
async function getSoundCloudEmbedUrl(videoId) {
const videoUrl = `https://soundcloud.com/${videoId}`;
return (await ofetch_default(`https://soundcloud.com/oembed?url=${encodeURIComponent(videoUrl)}&format=json&maxheight=400&format=json`)).html;
}
//#endregion
//#region lib/routes/fanbox/index.ts
const route = {
path: "/:creator",
categories: ["social-media"],
example: "/fanbox/official",
parameters: { creator: "fanbox user name" },
maintainers: ["KarasuShin"],
name: "Creator",
handler,
features: {
requireConfig: [{
name: "FANBOX_SESSION_ID",
description: "Required for private posts. Can be found in browser DevTools -> Application -> Cookies -> https://www.fanbox.cc -> FANBOXSESSID",
optional: true
}],
nsfw: true
}
};
async function handler(ctx) {
const creator = ctx.req.param("creator");
if (!isValidHost(creator)) throw new invalid_parameter_default("Invalid user name");
let title = `Fanbox - ${creator}`;
let description;
let image;
try {
const userInfoResponse = await ofetch_default(`https://api.fanbox.cc/creator.get?creatorId=${creator}`, { headers: getHeaders() });
title = `Fanbox - ${userInfoResponse.body.user.name}`;
description = userInfoResponse.body.description;
image = userInfoResponse.body.user.iconUrl;
} catch {}
const postListResponse = await ofetch_default(`https://api.fanbox.cc/post.listCreator?creatorId=${creator}&limit=20`, { headers: getHeaders() });
const items = await Promise.all(postListResponse.body.map((i) => parseItem(i)));
return {
title,
link: `https://${creator}.fanbox.cc`,
description,
image,
item: items
};
}
//#endregion
export { route };