feat(route): web.dev (#14746)
* feat(route): web.dev * add parameter descriptions * Update lib/routes/web/articles.ts Co-authored-by: Tony <TonyRL@users.noreply.github.com> * Update lib/routes/web/articles.ts Co-authored-by: Tony <TonyRL@users.noreply.github.com> * Update lib/routes/web/blog.ts Co-authored-by: Tony <TonyRL@users.noreply.github.com> * Update lib/routes/web/series.ts Co-authored-by: Tony <TonyRL@users.noreply.github.com> ---------
This commit is contained in:
parent
cb1ac8e0b4
commit
85b46d7120
|
|
@ -0,0 +1,23 @@
|
|||
import type { Data, Route } from '@/types';
|
||||
import { fetchItems } from './utils';
|
||||
|
||||
export const route: Route = {
|
||||
path: '/articles',
|
||||
categories: ['programming'],
|
||||
example: '/web/articles',
|
||||
radar: [{
|
||||
source: ['web.dev/articles'],
|
||||
}],
|
||||
name: 'Articles',
|
||||
maintainers: ['KarasuShin'],
|
||||
handler,
|
||||
};
|
||||
|
||||
async function handler(): Promise<Data> {
|
||||
return {
|
||||
title: 'Articles',
|
||||
link: 'https://web.dev/articles',
|
||||
image: 'https://web.dev/_pwa/web/icons/icon-144x144.png',
|
||||
item: await fetchItems('family_url:/articles'),
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import type { Data, Route } from '@/types';
|
||||
import { fetchItems } from './utils';
|
||||
|
||||
export const route: Route = {
|
||||
path: '/blog',
|
||||
categories: ['programming'],
|
||||
example: '/web/blog',
|
||||
radar: [{
|
||||
source: ['web.dev/blog'],
|
||||
}],
|
||||
name: 'Blog',
|
||||
maintainers: ['KarasuShin'],
|
||||
handler,
|
||||
};
|
||||
|
||||
async function handler(): Promise<Data> {
|
||||
return {
|
||||
title: 'Blog',
|
||||
link: 'https://web.dev/blog',
|
||||
image: 'https://web.dev/_pwa/web/icons/icon-144x144.png',
|
||||
item: await fetchItems('type:blog'),
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
import type { Namespace } from '@/types';
|
||||
|
||||
export const namespace: Namespace = {
|
||||
name: 'web.dev',
|
||||
url: 'web.dev',
|
||||
};
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
import type { Data, Route } from '@/types';
|
||||
import { fetchItems, hyphen2Pascal } from './utils';
|
||||
|
||||
export const route: Route = {
|
||||
path: '/series/:seriesName',
|
||||
parameters: { seriesName: 'topic name in the series section' },
|
||||
categories: ['programming'],
|
||||
example: '/web/series/new-to-the-web',
|
||||
radar: [{
|
||||
source: ['web.dev/series/:seriesName'],
|
||||
target: '/series/:seriesName',
|
||||
}],
|
||||
name: 'Series',
|
||||
maintainers: ['KarasuShin'],
|
||||
handler,
|
||||
description: `:::tip
|
||||
The \`seriesName\` can be extracted from the Series page URL: \`https://web.dev/series/:seriesName\`
|
||||
:::`,
|
||||
};
|
||||
|
||||
async function handler(ctx): Promise<Data> {
|
||||
const seriesName = ctx.req.param('seriesName');
|
||||
|
||||
return {
|
||||
title: seriesName,
|
||||
link: `https://web.dev/series/${seriesName}`,
|
||||
image: 'https://web.dev/_pwa/web/icons/icon-144x144.png',
|
||||
item: await fetchItems(`category:${hyphen2Pascal(seriesName)}`),
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
import type { DataItem } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
|
||||
type ArticleData = [
|
||||
string,
|
||||
string,
|
||||
unknown,
|
||||
string,
|
||||
string,
|
||||
number[],
|
||||
string,
|
||||
string,
|
||||
unknown,
|
||||
unknown,
|
||||
string[],
|
||||
string,
|
||||
string[],
|
||||
string,
|
||||
string,
|
||||
unknown,
|
||||
string[],
|
||||
string,
|
||||
string,
|
||||
number,
|
||||
string[],
|
||||
unknown,
|
||||
number,
|
||||
string[],
|
||||
number,
|
||||
number,
|
||||
];
|
||||
|
||||
export async function fetchItems(queryParam: string): Promise<DataItem[]> {
|
||||
const res = await got<string>('https://web.dev/_d/dynamic_content', {
|
||||
body: `[null,null,null, "${queryParam}",null,null,null,null,31,null,null,null,2]`,
|
||||
method: 'post',
|
||||
});
|
||||
const data = JSON.parse(res.data.replace(/^[^[]*/, '')) as [ArticleData[], number];
|
||||
const items = await Promise.all(
|
||||
data[0].map((item) => {
|
||||
const link = item[6];
|
||||
return cache.tryGet(link, async () => {
|
||||
const { data: articleHtml } = await got.get<string>(link);
|
||||
const $ = load(articleHtml);
|
||||
const articleBody = $('.devsite-article-body');
|
||||
articleBody.find('.wd-authors').remove();
|
||||
|
||||
return {
|
||||
title: item[0],
|
||||
pubDate: new Date(item[5][0] * 1e3),
|
||||
description: articleBody.html(),
|
||||
link,
|
||||
};
|
||||
}) as unknown as DataItem;
|
||||
})
|
||||
);
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
export function hyphen2Pascal(value: string) {
|
||||
return value
|
||||
.split('-')
|
||||
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
||||
.join('');
|
||||
}
|
||||
Loading…
Reference in New Issue