From bf1083de75568bca266f453d2cafb30406ffb7b6 Mon Sep 17 00:00:00 2001 From: Tony Date: Thu, 31 Oct 2024 18:37:33 -0700 Subject: [PATCH] refactor: use bbob instead of bbcodejs (1point3acres) (#17396) * refactor: use bbob instead of bbcodejs (1point3acres) * refactor: use bbob instead of bbcodejs (counter-strike) * fix: minor fixes * fix(route/counter-strike/news): handle optional attributes in customPreset --- lib/routes/1point3acres/thread.ts | 4 +- lib/routes/1point3acres/utils.ts | 94 ++++++++++++++++++++++++++----- lib/routes/counter-strike/news.ts | 54 ++++++++++++++++-- package.json | 4 +- pnpm-lock.yaml | 72 ++++++++++++++++++++--- 5 files changed, 198 insertions(+), 30 deletions(-) diff --git a/lib/routes/1point3acres/thread.ts b/lib/routes/1point3acres/thread.ts index 6940d7536daa2b..48987e0373d119 100644 --- a/lib/routes/1point3acres/thread.ts +++ b/lib/routes/1point3acres/thread.ts @@ -3,7 +3,9 @@ import cache from '@/utils/cache'; import { rootUrl, apiRootUrl, types, ProcessThreads } from './utils'; export const route: Route = { - path: ['/post/:type?/:order?', '/thread/:type?/:order?'], + path: '/thread/:type?/:order?', + example: '/1point3acres/thread/hot', + parameters: { type: '帖子分类, 见下表,默认为 hot,即热门帖子', order: '排序方式,见下表,默认为空,即最新回复' }, name: '帖子', categories: ['bbs'], maintainers: ['EthanWng97', 'DIYgod', 'nczitzk'], diff --git a/lib/routes/1point3acres/utils.ts b/lib/routes/1point3acres/utils.ts index 01ecb09b045569..c90830d36644cc 100644 --- a/lib/routes/1point3acres/utils.ts +++ b/lib/routes/1point3acres/utils.ts @@ -5,7 +5,9 @@ import got from '@/utils/got'; import { parseDate } from '@/utils/parse-date'; import { art } from '@/utils/render'; import path from 'node:path'; -import bbcode from 'bbcodejs'; +import type { BBobCoreTagNodeTree } from '@bbob/types'; +import bbobHTML from '@bbob/html'; +import presetHTML5 from '@bbob/preset-html5'; const rootUrl = 'https://instant.1point3acres.com'; const apiRootUrl = 'https://api.1point3acres.com'; @@ -15,6 +17,17 @@ const types = { hot: '热门帖子', }; +const swapLinebreak = (tree: BBobCoreTagNodeTree) => + tree.walk((node) => { + if (typeof node === 'string' && node === '\n') { + return { + tag: 'br', + content: null, + }; + } + return node; + }); + const ProcessThreads = async (tryGet, apiUrl, order) => { const response = await got({ method: 'get', @@ -24,8 +37,6 @@ const ProcessThreads = async (tryGet, apiUrl, order) => { }, }); - const bbcodeParser = new bbcode.Parser(); - const items = await Promise.all( response.data.threads.map((item) => { const result = { @@ -48,20 +59,73 @@ const ProcessThreads = async (tryGet, apiUrl, order) => { }, }); - const data = detailResponse.data; + const thread = detailResponse.data.thread; + + const customPreset = presetHTML5.extend((tags) => ({ + ...tags, + attach: (node, { render }) => { + const id = render(node.content); + const attachment = thread.attachment_list.find((a) => a.aid === Number.parseInt(id)); + + if (attachment.isimage) { + return { + tag: 'img', + attrs: { + src: attachment.url, + }, + }; + } + + return { + tag: 'a', + attrs: { + href: `https://www.1point3acres.com/bbs/plugin.php?id=attachcenter:page&aid=${id}`, + rel: 'noopener', + target: '_blank', + }, + content: `https://www.1point3acres.com/bbs/plugin.php?id=attachcenter:page&aid=${id}`, + }; + }, + url: (node) => { + const link = Object.keys(node.attrs as Record)[0]; + if (link.startsWith('https://link.1p3a.com/?url=')) { + const url = decodeURIComponent(link.replace('https://link.1p3a.com/?url=', '')); + return { + tag: 'a', + attrs: { + href: url, + rel: 'noopener', + target: '_blank', + }, + content: node.content, + }; + } + + return { + tag: 'a', + attrs: { + href: link, + rel: 'noopener', + target: '_blank', + }, + content: node.content, + }; + }, + })); - result.description = bbcodeParser.toHTML(data.thread.message_bbcode); + result.description = bbobHTML(thread.message_bbcode, [customPreset(), swapLinebreak]); - for (const a of data.thread.attachment_list) { - if (a.isimage === 1) { - result.description = result.description.replaceAll( - new RegExp(`\\[attach\\]${a.aid}\\[\\/attach\\]`, 'g'), - art(path.join(__dirname, 'templates/image.art'), { - url: a.url, - height: a.height, - width: a.width, - }) - ); + if (!thread.message_bbcode.includes('[attach]') && thread.attachment_list.length > 0) { + for (const a of thread.attachment_list) { + result.description += + a.isimage === 1 + ? '
' + + art(path.join(__dirname, 'templates/image.art'), { + url: a.url, + height: a.height, + width: a.width, + }) + : ''; } } } catch { diff --git a/lib/routes/counter-strike/news.ts b/lib/routes/counter-strike/news.ts index d7d5abc5c07895..7e4c2c6a1c74a5 100644 --- a/lib/routes/counter-strike/news.ts +++ b/lib/routes/counter-strike/news.ts @@ -1,10 +1,56 @@ import { Route } from '@/types'; +import type { BBobCoreTagNodeTree, PresetFactory } from '@bbob/types'; import got from '@/utils/got'; import { load } from 'cheerio'; -import bbcode from 'bbcodejs'; +import bbobHTML from '@bbob/html'; +import presetHTML5 from '@bbob/preset-html5'; import { parseDate } from '@/utils/parse-date'; +const swapLinebreak = (tree: BBobCoreTagNodeTree) => + tree.walk((node) => { + if (typeof node === 'string' && node === '\n') { + return { + tag: 'br', + content: null, + }; + } + return node; + }); + +const customPreset: PresetFactory = presetHTML5.extend((tags) => ({ + ...tags, + url: (node) => ({ + tag: 'a', + attrs: { + href: Object.keys(node.attrs as Record)[0], + rel: 'noopener', + target: '_blank', + }, + content: node.content, + }), + video: (node, { render }) => ({ + tag: 'video', + attrs: { + controls: '', + preload: 'metadata', + poster: node.attrs?.poster, + }, + content: render( + Object.entries({ + webm: 'video/webm', + mp4: 'video/mp4', + }).map(([key, type]) => ({ + tag: 'source', + attrs: { + src: node.attrs?.[key], + type, + }, + })) + ), + }), +})); + export const handler = async (ctx) => { const { category = 'all', language = 'english' } = ctx.req.param(); const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 100; @@ -25,14 +71,12 @@ export const handler = async (ctx) => { }, }); - const bbcodeParser = new bbcode.Parser(); - const items = response.events - .filter((item) => (category === 'updates' ? item.event_type === 12 : item.event_type !== 12)) + .filter((item) => (category === 'updates' ? item.event_type === 12 : item.event_type)) .slice(0, limit) .map((item) => { const title = item.event_name; - const description = bbcodeParser.toHTML(item.announcement_body.body); + const description = bbobHTML(item.announcement_body.body, [customPreset(), swapLinebreak]); const guid = `counter-strike-news-${item.gid}`; return { diff --git a/package.json b/package.json index 352dd106f12ea1..35a35b388df03c 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,8 @@ "*.yml": "eslint --cache --fix" }, "dependencies": { + "@bbob/html": "4.1.1", + "@bbob/preset-html5": "4.1.1", "@hono/node-server": "1.13.3", "@hono/zod-openapi": "0.16.4", "@notionhq/client": "2.2.15", @@ -67,7 +69,6 @@ "@tonyrl/rand-user-agent": "2.0.81", "aes-js": "3.1.2", "art-template": "4.13.2", - "bbcodejs": "0.0.4", "cheerio": "1.0.0", "chrono-node": "2.7.7", "city-timezones": "1.3.0", @@ -137,6 +138,7 @@ "devDependencies": { "@babel/preset-env": "7.26.0", "@babel/preset-typescript": "7.26.0", + "@bbob/types": "4.1.1", "@eslint/eslintrc": "3.1.0", "@eslint/js": "9.13.0", "@microsoft/eslint-formatter-sarif": "3.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cbdaf292e59f20..99fd097c303a07 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,12 @@ importers: .: dependencies: + '@bbob/html': + specifier: 4.1.1 + version: 4.1.1 + '@bbob/preset-html5': + specifier: 4.1.1 + version: 4.1.1 '@hono/node-server': specifier: 1.13.3 version: 1.13.3(hono@4.6.8) @@ -59,9 +65,6 @@ importers: art-template: specifier: 4.13.2 version: 4.13.2 - bbcodejs: - specifier: 0.0.4 - version: 0.0.4 cheerio: specifier: 1.0.0 version: 1.0.0 @@ -264,6 +267,9 @@ importers: '@babel/preset-typescript': specifier: 7.26.0 version: 7.26.0(@babel/core@7.26.0) + '@bbob/types': + specifier: 4.1.1 + version: 4.1.1 '@eslint/eslintrc': specifier: 3.1.0 version: 3.1.0 @@ -966,6 +972,27 @@ packages: resolution: {integrity: sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==} engines: {node: '>=6.9.0'} + '@bbob/core@4.1.1': + resolution: {integrity: sha512-cH2Fi+K1R0lKlEcUk+vQbOWP3Lny+A/jyYvrN1pRL71TEdamvbvlb5vTT8dwtOs5hWKFxMsDOcIVchjVaZmiFg==} + + '@bbob/html@4.1.1': + resolution: {integrity: sha512-u1PsKlsM9os+TI9zqB2jh3CdGuZrNcGCAII/ZocgoW/asu49OXWQrcGHheJqBbeZLRagXMHYTWJ+W/DvDEgZ3g==} + + '@bbob/parser@4.1.1': + resolution: {integrity: sha512-pNSx4WWp9qBpUf8pgfINEAxtN0E829IPNdDioP8JNf2N3enFFrDWdkVq3TnEy2QWyTBhEA+n5ARMM+lSId1w5A==} + + '@bbob/plugin-helper@4.1.1': + resolution: {integrity: sha512-Ew7V2Yym+Os6wtiR4Se1irudFY5wLSTZGRNy8CSPq3QqBMk1LDi7phQvj8SFfqFCElG/UDciQb07lE7KQpiqbA==} + + '@bbob/preset-html5@4.1.1': + resolution: {integrity: sha512-9dgO0Jui2qYshObGezso9AU30dtFYGg0AfvxDONATkL+1lBpIvwUrL3Xj+gDUotAdRw6QHCaU0x+rplxa0CLnA==} + + '@bbob/preset@4.1.1': + resolution: {integrity: sha512-Qas/hd1jOoZiux9LyPDStxxbSM/qVyts3ZJmFFHa3uzT0d7mKrnHjnI7qahHdo7Ry8CyrvGDDD8qL2A4bIfMqA==} + + '@bbob/types@4.1.1': + resolution: {integrity: sha512-QnA0S8YpnEUFBV8KbU5DnqydDJaIFyxp656sWGLtvHqkxNGOOSRWc1m1YqFqfrHM7tmphr4AQybFeHqE1a2/2w==} + '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} @@ -2212,9 +2239,6 @@ packages: resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==} engines: {node: '>=10.0.0'} - bbcodejs@0.0.4: - resolution: {integrity: sha512-y7dPUdqXMMUeR0bBv/9hcLTMwkBRuVCK+9aJgYGYvdkIdXBfrEiEiVw5Cg8iluRCG7YzLFWoX6VEmNe1HeP0wA==} - bcrypt-pbkdf@1.0.2: resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} @@ -6525,6 +6549,40 @@ snapshots: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 + '@bbob/core@4.1.1': + dependencies: + '@bbob/parser': 4.1.1 + '@bbob/plugin-helper': 4.1.1 + '@bbob/types': 4.1.1 + + '@bbob/html@4.1.1': + dependencies: + '@bbob/core': 4.1.1 + '@bbob/plugin-helper': 4.1.1 + '@bbob/types': 4.1.1 + + '@bbob/parser@4.1.1': + dependencies: + '@bbob/plugin-helper': 4.1.1 + '@bbob/types': 4.1.1 + + '@bbob/plugin-helper@4.1.1': + dependencies: + '@bbob/types': 4.1.1 + + '@bbob/preset-html5@4.1.1': + dependencies: + '@bbob/plugin-helper': 4.1.1 + '@bbob/preset': 4.1.1 + '@bbob/types': 4.1.1 + + '@bbob/preset@4.1.1': + dependencies: + '@bbob/plugin-helper': 4.1.1 + '@bbob/types': 4.1.1 + + '@bbob/types@4.1.1': {} + '@bcoe/v8-coverage@0.2.3': {} '@bundled-es-modules/cookie@2.0.0': @@ -7743,8 +7801,6 @@ snapshots: basic-ftp@5.0.5: {} - bbcodejs@0.0.4: {} - bcrypt-pbkdf@1.0.2: dependencies: tweetnacl: 0.14.5