Skip to content

Commit

Permalink
feat(routes/landiannews): use wp-api, add category and tag routes (DI…
Browse files Browse the repository at this point in the history
…Ygod#18292)

* feat(routes/landiannews): use wp-api, add category and tag routes

* fix(routes/landiannews): use '_embed' search param instead

* feat(routes/landiannews/tag|category): use slug instead of id

* fix(routes/landiannews): cameCase

Co-authored-by: Tony <[email protected]>

* fix(routes/landiannews): apply review suggestion

* fix(routes/landiannews): fix example
  • Loading branch information
cscnk52 authored Feb 10, 2025
1 parent cafc7fa commit 50e9444
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 136 deletions.
48 changes: 48 additions & 0 deletions lib/routes/landiannews/category.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Data, DataItem, Route, ViewType } from '@/types';
import { fetchNewsItems, fetchCategory } from './utils';

export const handler = async (ctx): Promise<Data> => {
const slug = ctx.req.param('slug');

const { id, name } = await fetchCategory(slug);

const rootUrl = 'https://www.landiannews.com/';
const postApiUrl = `${rootUrl}wp-json/wp/v2/posts?_embed&categories=${id}`;

const items: DataItem[] = await fetchNewsItems(postApiUrl);

return {
title: `${name} - 蓝点网`,
description: '给你感兴趣的内容!',
link: `${rootUrl}${slug}`,
item: items,
};
};

export const route: Route = {
path: '/category/:slug',
name: '分类',
url: 'www.landiannews.com',
maintainers: ['cscnk52'],
handler,
example: '/landiannews/category/sells',
parameters: { slug: '分类名称' },
description: undefined,
categories: ['new-media'],
features: {
requireConfig: false,
requirePuppeteer: false,
antiCrawler: false,
supportRadar: true,
supportBT: false,
supportPodcast: false,
supportScihub: false,
},
radar: [
{
source: ['www.landiannews.com/:slug'],
target: '/category/:slug',
},
],
view: ViewType.Articles,
};
140 changes: 11 additions & 129 deletions lib/routes/landiannews/index.ts
Original file line number Diff line number Diff line change
@@ -1,143 +1,25 @@
import { type Data, type DataItem, type Route, ViewType } from '@/types';
import { Data, DataItem, Route, ViewType } from '@/types';
import { fetchNewsItems } from './utils';

import { art } from '@/utils/render';
import cache from '@/utils/cache';
import { getCurrentPath } from '@/utils/helpers';
import ofetch from '@/utils/ofetch';
import { parseDate } from '@/utils/parse-date';
import timezone from '@/utils/timezone';
export const handler = async (): Promise<Data> => {
const rootUrl = 'https://www.landiannews.com/';
const postApiUrl = `${rootUrl}wp-json/wp/v2/posts?_embed`;

import { type CheerioAPI, type Cheerio, type Element, load } from 'cheerio';
import { type Context } from 'hono';
import path from 'node:path';

const __dirname = getCurrentPath(import.meta.url);

export const handler = async (ctx: Context): Promise<Data> => {
const limit: number = Number.parseInt(ctx.req.query('limit') ?? '30', 10);

const baseUrl: string = 'https://www.landiannews.com';
const targetUrl: string = baseUrl;

const response = await ofetch(targetUrl);
const $: CheerioAPI = load(response);
const language = $('html').attr('lang') ?? 'zh-CN';

let items: DataItem[] = [];

items = $('section.article-list a.title')
.slice(0, limit)
.toArray()
.map((el): Element => {
const $el: Cheerio<Element> = $(el);

const processedItem: DataItem = {
title: $el.attr('title') ?? $el.text(),
link: $el.attr('href'),
language,
};

return processedItem;
});

items = (
await Promise.all(
items.map((item) => {
if (!item.link) {
return item;
}

return cache.tryGet(item.link, async (): Promise<DataItem> => {
const detailResponse = await ofetch(item.link);
const $$: CheerioAPI = load(detailResponse);

const title: string = $$('header.post-header h1').text();
const intro: string = $$('div.excerpt').text();

$$('div.excerpt').remove();

const description: string = art(path.join(__dirname, 'templates/description.art'), {
intro,
description: $$('div.content-post').html(),
});
const pubDateStr: string | undefined = $$('span.date').text();
const categoryEls: Element[] = $$('span.category a, div.article-tags a').toArray();
const categories: string[] = [...new Set(categoryEls.map((el) => $$(el).attr('title') ?? $$(el).text()).filter(Boolean))];
const authorEls: Element[] = $$('span.author a[title]').toArray();
const authors: DataItem['author'] = authorEls.map((authorEl) => {
const $$authorEl: Cheerio<Element> = $$(authorEl);

return {
name: $$authorEl.attr('title') ?? '',
url: $$authorEl.attr('href') ?? '',
avatar: $$authorEl.find('img.avatar').attr('src'),
};
});
const upDatedStr: string | undefined = pubDateStr;

let processedItem: DataItem = {
title,
description,
pubDate: pubDateStr ? timezone(parseDate(pubDateStr, 'YYYY年M月D日 HH:mm'), +8) : item.pubDate,
category: categories,
author: authors,
content: {
html: description,
text: description,
},
updated: upDatedStr ? timezone(parseDate(upDatedStr, 'YYYY年M月D日 HH:mm'), +8) : item.updated,
language,
};

const extraLinkEls: Element[] = $$('section.article-list a[title]').toArray();
const extraLinks = extraLinkEls
.map((extraLinkEl) => {
const $$extraLinkEl: Cheerio<Element> = $$(extraLinkEl);

return {
url: $$extraLinkEl.attr('href'),
type: 'related',
content_html: $$extraLinkEl.text(),
};
})
.filter((_): _ is { url: string; type: string; content_html: string } => true);

if (extraLinks) {
processedItem = {
...processedItem,
_extra: {
links: extraLinks,
},
};
}

return {
...item,
...processedItem,
};
});
})
)
).filter((_): _ is DataItem => true);
const items: DataItem[] = await fetchNewsItems(postApiUrl);

return {
title: $('title').text(),
description: $('meta[property="og:description"]').attr('content'),
link: targetUrl,
title: '蓝点网',
description: '给你感兴趣的内容!',
link: rootUrl,
item: items,
allowEmpty: true,
image: $('img.logo').attr('src'),
author: $('meta[property="og:site_name"]').attr('content'),
language,
id: $('meta[property="og:url"]').attr('content'),
};
};

export const route: Route = {
path: '/',
name: '资讯',
name: '首页',
url: 'www.landiannews.com',
maintainers: ['nczitzk'],
maintainers: ['nczitzk', 'cscnk52'],
handler,
example: '/landiannews',
parameters: undefined,
Expand Down
48 changes: 48 additions & 0 deletions lib/routes/landiannews/tag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Data, DataItem, Route, ViewType } from '@/types';
import { fetchNewsItems, fetchTag } from './utils';

export const handler = async (ctx): Promise<Data> => {
const slug = ctx.req.param('slug');

const { id, name } = await fetchTag(slug);

const rootUrl = 'https://www.landiannews.com/';
const postApiUrl = `${rootUrl}wp-json/wp/v2/posts?_embed&tags=${id}`;

const items: DataItem[] = await fetchNewsItems(postApiUrl);

return {
title: `${name} - 蓝点网`,
description: '给你感兴趣的内容!',
link: `${rootUrl}archives/tag/${slug}`,
item: items,
};
};

export const route: Route = {
path: '/tag/:slug',
name: '标签',
url: 'www.landiannews.com',
maintainers: ['cscnk52'],
handler,
example: '/landiannews/tag/linux-kernel',
parameters: { slug: '标签名称' },
description: undefined,
categories: ['new-media'],
features: {
requireConfig: false,
requirePuppeteer: false,
antiCrawler: false,
supportRadar: true,
supportBT: false,
supportPodcast: false,
supportScihub: false,
},
radar: [
{
source: ['www.landiannews.com/archives/tag/:slug'],
target: '/tag/:slug',
},
],
view: ViewType.Articles,
};
7 changes: 0 additions & 7 deletions lib/routes/landiannews/templates/description.art

This file was deleted.

34 changes: 34 additions & 0 deletions lib/routes/landiannews/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import ofetch from '@/utils/ofetch';
import cache from '@/utils/cache';

const rootUrl = 'https://www.landiannews.com/';

const fetchTaxonomy = async (slug: string, type: 'categories' | 'tags') => {
const taxonomyUrl = `${rootUrl}wp-json/wp/v2/${type}?slug=${slug}`;
const cachedTaxonomy = await cache.tryGet(taxonomyUrl, async () => {
const taxonomyData = await ofetch(taxonomyUrl);
if (!taxonomyData[0] || !taxonomyData[0].id || !taxonomyData[0].name) {
throw new Error(`${type} ${slug} not found`);
}
return { id: taxonomyData[0].id, name: taxonomyData[0].name };
});
return cachedTaxonomy;
};

const fetchCategory = async (categorySlug: string) => await fetchTaxonomy(categorySlug, 'categories');
const fetchTag = async (tagSlug: string) => await fetchTaxonomy(tagSlug, 'tags');

async function fetchNewsItems(apiUrl: string) {
const data = await ofetch(apiUrl);

return data.map((item) => ({
title: item.title.rendered,
description: item.content.rendered,
link: item.link,
pubDate: new Date(item.date).toUTCString(),
author: item._embedded.author[0].name,
category: item._embedded['wp:term'].flat().map((term) => term.name),
}));
}

export { fetchCategory, fetchTag, fetchNewsItems };

0 comments on commit 50e9444

Please sign in to comment.