fix(modb): cache article bodies with bounded detail requests

This commit is contained in:
DIYgod
2026-10-15 13:29:56 +08:00
parent bc585bf6e5
commit e949bce5de
+33 -12
View File
@@ -1,5 +1,6 @@
import { load } from 'cheerio';
import { escapeUTF8 } from 'entities/escape';
import pMap from 'p-map';
import type { DataItem, Route } from '@/types';
import cache from '@/utils/cache';
@@ -34,6 +35,20 @@ interface TopicDoc {
tags?: string[];
}
class ArticleBodyUnavailableError extends Error {}
const getArticleDescription = (link: string) =>
cache.tryGet(`modb:topic:article-body:v1:${link}`, async () => {
const response = await ofetch(link);
const $ = load(response);
const article = $('div.editor-content-styl.article-style').first();
article.find('script, style').remove();
if (!article.text().trim() && !article.find('img, video, audio, iframe, table').length) {
throw new ArticleBodyUnavailableError(`The MODB article does not expose a public body: ${link}`);
}
return { description: article.html()! };
});
async function handler(ctx) {
const baseUrl = 'https://www.modb.pro';
const topicId = ctx.req.param('id');
@@ -44,7 +59,7 @@ async function handler(ctx) {
columnId: topicId,
},
});
const list = response.list.flatMap((item): Array<DataItem & { link: string }> => {
const list: Array<DataItem & { link: string }> = response.list.flatMap((item): Array<DataItem & { link: string }> => {
const doc: TopicDoc | undefined = item.type === 0 ? item.knowledge : item.type === 1 ? item.dbDoc : undefined;
if (!doc?.title || item.rid === undefined || item.rid === null) {
logger.error(`Unsupported or incomplete topic entry of type ${item.type}`);
@@ -64,17 +79,23 @@ async function handler(ctx) {
];
});
const items = await Promise.all(
list.map((item) =>
item.description === undefined
? cache.tryGet(item.link, async () => {
const response = await ofetch(item.link);
const $ = load(response);
item.description = $('div.editor-content-styl.article-style').first().html();
return item;
})
: item
)
const items = await pMap(
list,
async (item) => {
if (item.description !== undefined) {
return item;
}
try {
const details = await getArticleDescription(item.link);
return { ...item, ...details };
} catch (error) {
if (error instanceof ArticleBodyUnavailableError) {
return item;
}
throw error;
}
},
{ concurrency: 3 }
);
return {