Skip to content

Commit 7bbf971

Browse files
authored
feat(route): add dbaplus资讯 (#20134)
* feat(route): add dbaplus资讯 * fix typo
1 parent 51260eb commit 7bbf971

File tree

2 files changed

+414
-0
lines changed

2 files changed

+414
-0
lines changed

lib/routes/dbaplus/new.ts

Lines changed: 393 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,393 @@
1+
import { type Data, type DataItem, type Route, ViewType } from '@/types';
2+
3+
import { art } from '@/utils/render';
4+
import cache from '@/utils/cache';
5+
import ofetch from '@/utils/ofetch';
6+
import { parseDate } from '@/utils/parse-date';
7+
import timezone from '@/utils/timezone';
8+
9+
import { type CheerioAPI, type Cheerio, load } from 'cheerio';
10+
import type { Element } from 'domhandler';
11+
import { type Context } from 'hono';
12+
import path from 'node:path';
13+
14+
export const handler = async (ctx: Context): Promise<Data> => {
15+
const { id = '9' } = ctx.req.param();
16+
const limit: number = Number.parseInt(ctx.req.query('limit') ?? '30', 10);
17+
18+
const baseUrl: string = 'https://dbaplus.cn';
19+
const targetUrl: string = new URL(`news-${id}-1.html`, baseUrl).href;
20+
21+
const response = await ofetch(targetUrl);
22+
const $: CheerioAPI = load(response);
23+
const language = $('html').attr('lang') ?? 'zh';
24+
25+
let items: DataItem[] = [];
26+
27+
items = $('ul.media-list li.media')
28+
.slice(0, limit)
29+
.toArray()
30+
.map((el): Element => {
31+
const $el: Cheerio<Element> = $(el);
32+
const $aEl: Cheerio<Element> = $el.find('h3.media-heading a');
33+
34+
const title: string = $aEl.text();
35+
const image: string | undefined = $el.find('img.media-object').attr('src');
36+
const description: string | undefined = art(path.join(__dirname, 'templates/description.art'), {
37+
images: image
38+
? [
39+
{
40+
src: image,
41+
alt: title,
42+
},
43+
]
44+
: undefined,
45+
intro: $el.find('div.mt10').html(),
46+
});
47+
const pubDateStr: string | undefined = $el
48+
.find('span.time')
49+
.text()
50+
.replaceAll(/(|)/g, '-')
51+
.replace('日', '');
52+
const linkUrl: string | undefined = $aEl.attr('href');
53+
const authorEls: Element[] = $el.find('span.user').toArray();
54+
const authors: DataItem['author'] = authorEls.map((authorEl) => {
55+
const $authorEl: Cheerio<Element> = $(authorEl);
56+
57+
return {
58+
name: $authorEl.text(),
59+
url: undefined,
60+
avatar: undefined,
61+
};
62+
});
63+
const upDatedStr: string | undefined = pubDateStr;
64+
65+
const processedItem: DataItem = {
66+
title,
67+
description,
68+
pubDate: pubDateStr ? parseDate(pubDateStr) : undefined,
69+
link: linkUrl,
70+
author: authors,
71+
content: {
72+
html: description,
73+
text: description,
74+
},
75+
image,
76+
banner: image,
77+
updated: upDatedStr ? parseDate(upDatedStr) : undefined,
78+
language,
79+
};
80+
81+
return processedItem;
82+
});
83+
84+
items = await Promise.all(
85+
items.map((item) => {
86+
if (!item.link) {
87+
return item;
88+
}
89+
90+
return cache.tryGet(item.link, async (): Promise<DataItem> => {
91+
const detailResponse = await ofetch(item.link);
92+
const $$: CheerioAPI = load(detailResponse);
93+
94+
const title: string = $$('h2.title').text();
95+
const description: string | undefined =
96+
item.description +
97+
art(path.join(__dirname, 'templates/description.art'), {
98+
description: $$('div.new-detailed').html(),
99+
});
100+
const pubDateStr: string | undefined = $$('span.time').first().text();
101+
const categories: string[] = $$('meta[name="keywords"]').attr('content')?.split(',') ?? [];
102+
const authorEls: Element[] = $$('span.user').toArray();
103+
const authors: DataItem['author'] = authorEls.map((authorEl) => {
104+
const $$authorEl: Cheerio<Element> = $$(authorEl);
105+
106+
return {
107+
name: $$authorEl.text(),
108+
url: undefined,
109+
avatar: undefined,
110+
};
111+
});
112+
const upDatedStr: string | undefined = pubDateStr;
113+
114+
const processedItem: DataItem = {
115+
title,
116+
description,
117+
pubDate: pubDateStr ? timezone(parseDate(pubDateStr), +8) : item.pubDate,
118+
category: categories,
119+
author: authors,
120+
content: {
121+
html: description,
122+
text: description,
123+
},
124+
updated: upDatedStr ? timezone(parseDate(upDatedStr), +8) : item.updated,
125+
language,
126+
};
127+
128+
return {
129+
...item,
130+
...processedItem,
131+
};
132+
});
133+
})
134+
);
135+
136+
const description: string = $('meta[name="description"]').attr('content') ?? '';
137+
138+
return {
139+
title: $('title').text().split(//)[0],
140+
description,
141+
link: targetUrl,
142+
item: items,
143+
allowEmpty: true,
144+
image: $('div.navbar-header img').attr('src'),
145+
author: description.split(//)[0],
146+
language,
147+
id: targetUrl,
148+
};
149+
};
150+
151+
export const route: Route = {
152+
path: '/news/:id?',
153+
name: '资讯',
154+
url: 'dbaplus.cn',
155+
maintainers: ['nczitzk'],
156+
handler,
157+
example: '/dbaplus/news/9',
158+
parameters: {
159+
category: {
160+
description: '分类,默认为 `9`,即全部,可在对应分类页 URL 中找到',
161+
options: [
162+
{
163+
label: '全部',
164+
value: '9',
165+
},
166+
{
167+
label: '数据库',
168+
value: '153',
169+
},
170+
{
171+
label: '国产数据库',
172+
value: '217',
173+
},
174+
{
175+
label: 'ORACLE',
176+
value: '10',
177+
},
178+
{
179+
label: 'MySQL',
180+
value: '11',
181+
},
182+
{
183+
label: 'SQL优化',
184+
value: '155',
185+
},
186+
{
187+
label: 'Newsletter',
188+
value: '156',
189+
},
190+
{
191+
label: '其它',
192+
value: '154',
193+
},
194+
{
195+
label: '运维',
196+
value: '134',
197+
},
198+
{
199+
label: '大数据',
200+
value: '73',
201+
},
202+
{
203+
label: '架构',
204+
value: '141',
205+
},
206+
{
207+
label: 'PaaS云',
208+
value: '72',
209+
},
210+
{
211+
label: '职场生涯',
212+
value: '149',
213+
},
214+
{
215+
label: '标准评估',
216+
value: '248',
217+
},
218+
{
219+
label: '这里有毒',
220+
value: '21',
221+
},
222+
{
223+
label: '最新活动',
224+
value: '152',
225+
},
226+
{
227+
label: '往期干货',
228+
value: '148',
229+
},
230+
{
231+
label: '特别策划',
232+
value: '150',
233+
},
234+
{
235+
label: '荐书',
236+
value: '151',
237+
},
238+
],
239+
},
240+
},
241+
description: `:::tip
242+
订阅 [资讯](https://dbaplus.cn/news-9-1.html),其源网址为 \`https://dbaplus.cn/news-9-1.html\`,请参考该 URL 指定部分构成参数,此时路由为 [\`/dbaplus/news/9\`](https://rsshub.app/dbaplus/news/9)。
243+
244+
:::
245+
246+
<details>
247+
<summary>更多分类</summary>
248+
249+
| [全部](https://dbaplus.cn/news-9-1.html) | [数据库](https://dbaplus.cn/news-153-1.html) | [运维](https://dbaplus.cn/news-134-1.html) | [大数据](https://dbaplus.cn/news-73-1.html) | [架构](https://dbaplus.cn/news-141-1.html) |
250+
| ---------------------------------------- | -------------------------------------------- | ------------------------------------------ | ------------------------------------------- | ------------------------------------------ |
251+
| [9](https://rsshub.app/dbaplus/news/9) | [153](https://rsshub.app/dbaplus/news/153) | [134](https://rsshub.app/dbaplus/news/134) | [73](https://rsshub.app/dbaplus/news/73) | [141](https://rsshub.app/dbaplus/news/141) |
252+
253+
| [PaaS云](https://dbaplus.cn/news-72-1.html) | [职场生涯](https://dbaplus.cn/news-149-1.html) | [标准评估](https://dbaplus.cn/news-248-1.html) | [这里有毒](https://dbaplus.cn/news-21-1.html) |
254+
| ------------------------------------------- | ---------------------------------------------- | ---------------------------------------------- | --------------------------------------------- |
255+
| [72](https://rsshub.app/dbaplus/news/72) | [149](https://rsshub.app/dbaplus/news/149) | [248](https://rsshub.app/dbaplus/news/248) | [21](https://rsshub.app/dbaplus/news/21) |
256+
257+
#### [数据库](https://dbaplus.cn/news-153-1.html)
258+
259+
| [国产数据库](https://dbaplus.cn/news-217-1.html) | [ORACLE](https://dbaplus.cn/news-10-1.html) | [MySQL](https://dbaplus.cn/news-11-1.html) | [SQL优化](https://dbaplus.cn/news-155-1.html) | [Newsletter](https://dbaplus.cn/news-156-1.html) |
260+
| ------------------------------------------------ | ------------------------------------------- | ------------------------------------------ | --------------------------------------------- | ------------------------------------------------ |
261+
| [217](https://rsshub.app/dbaplus/news/217) | [10](https://rsshub.app/dbaplus/news/10) | [11](https://rsshub.app/dbaplus/news/11) | [155](https://rsshub.app/dbaplus/news/155) | [156](https://rsshub.app/dbaplus/news/156) |
262+
263+
| [其它](https://dbaplus.cn/news-154-1.html) |
264+
| ------------------------------------------ |
265+
| [154](https://rsshub.app/dbaplus/news/154) |
266+
267+
#### [这里有毒](https://dbaplus.cn/news-21-1.html)
268+
269+
| [最新活动](https://dbaplus.cn/news-152-1.html) | [往期干货](https://dbaplus.cn/news-148-1.html) | [特别策划](https://dbaplus.cn/news-150-1.html) | [荐书](https://dbaplus.cn/news-151-1.html) |
270+
| ---------------------------------------------- | ---------------------------------------------- | ---------------------------------------------- | ------------------------------------------ |
271+
| [152](https://rsshub.app/dbaplus/news/152) | [148](https://rsshub.app/dbaplus/news/148) | [150](https://rsshub.app/dbaplus/news/150) | [151](https://rsshub.app/dbaplus/news/151) |
272+
273+
</details>
274+
`,
275+
categories: ['programming'],
276+
features: {
277+
requireConfig: false,
278+
requirePuppeteer: false,
279+
antiCrawler: false,
280+
supportRadar: true,
281+
supportBT: false,
282+
supportPodcast: false,
283+
supportScihub: false,
284+
},
285+
radar: [
286+
{
287+
source: ['dbaplus.cn/news*'],
288+
target: (_, url) => {
289+
const urlObj: URL = new URL(url);
290+
const href: string = urlObj.href;
291+
const id: string | undefined = href.match(/-(\d+)-\.html/)?.[1];
292+
293+
return `/dbaplus/news${id ? `/${id}` : ''}`;
294+
},
295+
},
296+
{
297+
title: '全部',
298+
source: ['dbaplus.cn/news-9-1.html'],
299+
target: '/news/9',
300+
},
301+
{
302+
title: '数据库',
303+
source: ['dbaplus.cn/news-153-1.html'],
304+
target: '/news/153',
305+
},
306+
{
307+
title: '国产数据库',
308+
source: ['dbaplus.cn/news-217-1.html'],
309+
target: '/news/217',
310+
},
311+
{
312+
title: 'ORACLE',
313+
source: ['dbaplus.cn/news-10-1.html'],
314+
target: '/news/10',
315+
},
316+
{
317+
title: 'MySQL',
318+
source: ['dbaplus.cn/news-11-1.html'],
319+
target: '/news/11',
320+
},
321+
{
322+
title: 'SQL优化',
323+
source: ['dbaplus.cn/news-155-1.html'],
324+
target: '/news/155',
325+
},
326+
{
327+
title: 'Newsletter',
328+
source: ['dbaplus.cn/news-156-1.html'],
329+
target: '/news/156',
330+
},
331+
{
332+
title: '其它',
333+
source: ['dbaplus.cn/news-154-1.html'],
334+
target: '/news/154',
335+
},
336+
{
337+
title: '运维',
338+
source: ['dbaplus.cn/news-134-1.html'],
339+
target: '/news/134',
340+
},
341+
{
342+
title: '大数据',
343+
source: ['dbaplus.cn/news-73-1.html'],
344+
target: '/news/73',
345+
},
346+
{
347+
title: '架构',
348+
source: ['dbaplus.cn/news-141-1.html'],
349+
target: '/news/141',
350+
},
351+
{
352+
title: 'PaaS云',
353+
source: ['dbaplus.cn/news-72-1.html'],
354+
target: '/news/72',
355+
},
356+
{
357+
title: '职场生涯',
358+
source: ['dbaplus.cn/news-149-1.html'],
359+
target: '/news/149',
360+
},
361+
{
362+
title: '标准评估',
363+
source: ['dbaplus.cn/news-248-1.html'],
364+
target: '/news/248',
365+
},
366+
{
367+
title: '这里有毒',
368+
source: ['dbaplus.cn/news-21-1.html'],
369+
target: '/news/21',
370+
},
371+
{
372+
title: '最新活动',
373+
source: ['dbaplus.cn/news-152-1.html'],
374+
target: '/news/152',
375+
},
376+
{
377+
title: '往期干货',
378+
source: ['dbaplus.cn/news-148-1.html'],
379+
target: '/news/148',
380+
},
381+
{
382+
title: '特别策划',
383+
source: ['dbaplus.cn/news-150-1.html'],
384+
target: '/news/150',
385+
},
386+
{
387+
title: '荐书',
388+
source: ['dbaplus.cn/news-151-1.html'],
389+
target: '/news/151',
390+
},
391+
],
392+
view: ViewType.Articles,
393+
};

0 commit comments

Comments
 (0)