mirror of
https://github.com/DIYgod/RSSHub.git
synced 2026-09-21 12:49:53 +08:00
feat(route): add Guandong Museum Exhibitions and news route (#22729)
* feat:add Guandong Museum Exhibitions and news * fix: update selector
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
import { load } from 'cheerio';
|
||||
import dayjs from 'dayjs';
|
||||
import type { Context } from 'hono';
|
||||
import { renderToString } from 'hono/jsx/dom/server';
|
||||
|
||||
import type { DataItem, Route } from '@/types';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
|
||||
import { namespace } from './namespace';
|
||||
|
||||
// convert exhibition date string to YYYY-MM-DD format, e.g. "2023年5月1日" or "2023/5/1" => "2023-05-01"
|
||||
const formatExhibitionDate = (d?: string) => {
|
||||
if (!d) {
|
||||
return;
|
||||
}
|
||||
return dayjs(d.replaceAll(/[年月/.]/g, '-').replaceAll('日', '')).format('YYYY-MM-DD');
|
||||
};
|
||||
|
||||
const parseExhibitionDuration = (duration?: string) => {
|
||||
const allDates = duration?.match(/\d{4}[./年-]\d{1,2}[./月-]\d{1,2}日?/g) || [];
|
||||
return {
|
||||
startDate: formatExhibitionDate(allDates[0]),
|
||||
endDate: formatExhibitionDate(allDates[1]),
|
||||
};
|
||||
};
|
||||
|
||||
export const route: Route = {
|
||||
path: '/exhibition/:type?',
|
||||
categories: ['travel'],
|
||||
example: '/gdmuseum/exhibition/temp',
|
||||
parameters: {
|
||||
type: 'Exhibition type, supported values: temp(临时展览), default: All exhibitions.',
|
||||
},
|
||||
name: 'Current Exhibitions',
|
||||
maintainers: ['magazian'],
|
||||
radar: [
|
||||
{
|
||||
source: ['www.gdmuseum.org.cn/col9/list'],
|
||||
target: '/exhibition',
|
||||
},
|
||||
],
|
||||
handler: async (ctx: Context) => {
|
||||
const typeParam = ctx.req.param('type') || 'all';
|
||||
|
||||
const museumName = namespace.zh?.name || namespace.name;
|
||||
const baseUrl = 'https://www.gdmuseum.org.cn';
|
||||
const url = `${baseUrl}/col9/list`;
|
||||
|
||||
const response = await got(url);
|
||||
const $ = load(response.data);
|
||||
|
||||
const list = $('.ULLIST li a[href^="/cn/col"]')
|
||||
.toArray()
|
||||
.map((el) => {
|
||||
const $item = $(el);
|
||||
const title = $item.find('.divtt.qui-dot').text();
|
||||
|
||||
if (typeParam === 'temp') {
|
||||
if (title.includes('常设展览')) {
|
||||
return null;
|
||||
}
|
||||
} else if (typeParam !== 'all') {
|
||||
return null;
|
||||
}
|
||||
|
||||
const rawLink = $item.attr('href');
|
||||
const itemLink = rawLink ? new URL(rawLink, baseUrl).href : '';
|
||||
|
||||
const rawSrc = $item.find('img').attr('src');
|
||||
const imgUrl = rawSrc ? new URL(rawSrc, baseUrl).href : undefined;
|
||||
|
||||
const textDurationAndLocation = $item.find('.quitxt.qui-dot').text().trim();
|
||||
const [fullDuration = '', location = ''] = textDurationAndLocation.split('|').map((p) => p.trim());
|
||||
|
||||
const { startDate, endDate } = parseExhibitionDuration(fullDuration);
|
||||
const pubDate = startDate ? parseDate(startDate) : undefined;
|
||||
|
||||
const description = renderToString(
|
||||
<div>
|
||||
{imgUrl && <img src={imgUrl} />}
|
||||
<br />
|
||||
<p>
|
||||
<b>地点:</b>
|
||||
{location || '参考详情'}
|
||||
</p>
|
||||
<p>
|
||||
<b>开展:</b>
|
||||
{startDate || '未定/常设'}
|
||||
</p>
|
||||
<p>
|
||||
<b>闭展:</b>
|
||||
{endDate || '未定/常设'}
|
||||
</p>
|
||||
{fullDuration && (
|
||||
<p>
|
||||
<small>原始展期:{fullDuration}</small>
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
return {
|
||||
title,
|
||||
link: itemLink,
|
||||
pubDate,
|
||||
description,
|
||||
// For further .ics file processing
|
||||
_extra: {
|
||||
museumName,
|
||||
location,
|
||||
startDate,
|
||||
endDate,
|
||||
},
|
||||
} as DataItem;
|
||||
})
|
||||
.filter((i): i is DataItem => i !== null);
|
||||
|
||||
return {
|
||||
title: `${museumName} - 正在热展${typeParam === 'temp' ? ' - 临时展览' : ''}`,
|
||||
link: url,
|
||||
language: 'zh-CN',
|
||||
item: list,
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
import type { Namespace } from '@/types';
|
||||
|
||||
export const namespace: Namespace = {
|
||||
name: 'Guangdong Museum',
|
||||
url: 'gdmuseum.org.cn',
|
||||
|
||||
zh: {
|
||||
name: '广东省博物馆',
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,58 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { DataItem, Route } from '@/types';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import timezone from '@/utils/timezone';
|
||||
|
||||
import { namespace } from './namespace';
|
||||
|
||||
export const route: Route = {
|
||||
path: '/information',
|
||||
categories: ['travel'],
|
||||
example: '/gdmuseum/information',
|
||||
name: 'Information',
|
||||
maintainers: ['magazian'],
|
||||
radar: [
|
||||
{
|
||||
source: ['www.gdmuseum.org.cn/cn/col51/list'],
|
||||
target: '/information',
|
||||
},
|
||||
],
|
||||
handler: async () => {
|
||||
const baseUrl = 'https://www.gdmuseum.org.cn';
|
||||
const apiUrl = `${baseUrl}/cn/col51/list`;
|
||||
const museumName = namespace.zh?.name || namespace.name;
|
||||
|
||||
const response = await got(apiUrl);
|
||||
const $ = load(response.data);
|
||||
|
||||
const list = $('.ULLIST li a[href^="/cn/col"]')
|
||||
.toArray()
|
||||
.map((el) => {
|
||||
const $item = $(el);
|
||||
|
||||
const rawLink = $item.attr('href') || '';
|
||||
const itemLink = new URL(rawLink, baseUrl).href;
|
||||
|
||||
const title = $item.find('h3.h3.qui-dot').text();
|
||||
const day = $item.find('time b').text().trim();
|
||||
const yearMonth = $item.find('time i').text().trim();
|
||||
|
||||
const pubDate = timezone(parseDate(`${yearMonth}-${day}`), 8);
|
||||
|
||||
return {
|
||||
title,
|
||||
link: itemLink,
|
||||
pubDate,
|
||||
} as DataItem;
|
||||
});
|
||||
|
||||
return {
|
||||
title: `${museumName} - 公告`,
|
||||
link: apiUrl,
|
||||
language: 'zh-CN',
|
||||
item: list,
|
||||
};
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user