feat(route/gmu): Add GMU routes (#19182)

* Add GMU routes

* fix rules

* fix

* fix some logic errors and redundancies

* update pnpm-lock.yaml to sync with package.json

* fix package.json

* update

* GitButler Workspace Commit

This is placeholder commit and will be replaced by a merge of yourvirtual branches.

Due to GitButler managing multiple virtual branches, you cannot switch back and
forth between git branches and virtual branches easily. 

If you switch to another branch, GitButler will need to be reinitialized.
If you commit on this branch, GitButler will throw it away.

For more information about what we're doing here, check out our docs:
https://docs.gitbutler.com/features/virtual-branches/integration-branch

* add parameters

* fix namespace

* fix type?

* Revert "fix type?"

This reverts commit 9bf7b1f949947214d41b77d636b2aeacc2fb07e5.

* fix type?

* fix: add newline at end of package.json

---------

Co-authored-by: GitButler <gitbutler@gitbutler.com>
This commit is contained in:
FrankFahey 2025-06-08 21:48:35 +08:00 committed by GitHub
parent 9b15262fc9
commit e29b4d5696
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 316 additions and 0 deletions

View File

@ -0,0 +1,7 @@
import type { Namespace } from '@/types';
export const namespace: Namespace = {
name: '赣南医科大学',
url: 'gmu.cn',
lang: 'zh-CN',
};

136
lib/routes/gmu/news.ts Normal file
View File

@ -0,0 +1,136 @@
import got from '@/utils/got';
import { load } from 'cheerio';
import { parseDate } from '@/utils/parse-date';
import type { Context } from 'hono';
import type { Route } from '@/types';
import cache from '@/utils/cache';
export const route: Route = {
path: '/news/:type?',
categories: ['university'],
example: '/gmu/news/gyyw',
parameters: {
type: {
description: '新闻类型,见下表,默认为 gyyw',
options: [
{ value: 'gyyw', label: '赣医要闻' },
{ value: 'ybdt', label: '院部动态' },
{ value: 'mtgy', label: '媒体赣医' },
{ value: 'xsjz', label: '学术讲座' },
],
default: 'gyyw',
},
},
features: {
requireConfig: false,
requirePuppeteer: false,
antiCrawler: false,
supportBT: false,
supportPodcast: false,
supportScihub: false,
},
radar: [
{
source: ['gmu.cn/xwzx/gyyw.htm', 'gmu.cn/'],
target: '/news/gyyw',
},
{
source: ['gmu.cn/xwzx/ybdt.htm'],
target: '/news/ybdt',
},
{
source: ['gmu.cn/xwzx/mtgy.htm'],
target: '/news/mtgy',
},
{
source: ['gmu.cn/xwzx/xsjz.htm'],
target: '/news/xsjz',
},
],
name: '新闻中心',
maintainers: ['FrankFahey'],
url: 'gmu.cn/xwzx/gyyw.htm',
handler,
};
export async function handler(ctx: Context) {
const type = (ctx.req.param?.('type') as string) || 'gyyw';
const newsType = {
gyyw: { title: '赣医要闻', url: '/xwzx/gyyw.htm' },
ybdt: { title: '院部动态', url: '/xwzx/ybdt.htm' },
mtgy: { title: '媒体赣医', url: '/xwzx/mtgy.htm' },
xsjz: { title: '学术讲座', url: '/xwzx/xsjz.htm' },
}[type] || { title: '赣医要闻', url: '/xwzx/gyyw.htm' };
const baseUrl = 'https://gmu.cn';
const link = `${baseUrl}${newsType.url}`;
const response = await got(link, {
https: {
rejectUnauthorized: false,
},
});
const $ = load(response.data);
const list = $('.list ul li');
const items = await Promise.all(
list.toArray().map(async (item) => {
const element = $(item);
const a = element.find('a');
const dateText = element.find('i').text();
const href = a.attr('href');
const title = a.text().trim();
if (!href || !title) {
return null;
}
const pubDate = parseDate(dateText);
if (!pubDate) {
return null;
}
const fullLink = new URL(href, link).href;
// Use cache.tryGet to cache the article content
return await cache.tryGet(`gmu:news:${fullLink}`, async () => {
try {
const contentResponse = await got(fullLink, {
https: {
rejectUnauthorized: false,
},
});
const content = load(contentResponse.data);
// 获取新闻内容
const articleContent = content('.v_news_content').html() || '暂无详细内容';
return {
title,
link: fullLink,
pubDate,
description: articleContent,
};
} catch {
// 如果获取文章内容失败,返回基本信息
return {
title,
link: fullLink,
pubDate,
description: '暂无详细内容',
};
}
});
})
);
const result = items.filter((item): item is { title: string; link: string; pubDate: Date; description: string } => item !== null);
return {
title: `赣南医科大学 - ${newsType.title}`,
link,
description: `赣南医科大学${newsType.title}`,
item: result,
};
}

173
lib/routes/gmu/yjs.ts Normal file
View File

@ -0,0 +1,173 @@
import got from '@/utils/got';
import { load } from 'cheerio';
import { parseDate } from '@/utils/parse-date';
import type { Route } from '@/types';
import type { Context } from 'hono';
import cache from '@/utils/cache';
const sections = {
zsgz: {
tzgg: { title: '招生工作 - 通知公告', path: '/zsgz/tzgg.htm' },
xwsd: { title: '招生工作 - 新闻速递', path: '/zsgz/xwsd.htm' },
},
pygz: {
tzgg: { title: '培养工作 - 通知公告', path: '/pygz/tzgg.htm' },
gzzd: { title: '培养工作 - 规章制度', path: '/pygz/gzzd.htm' },
},
xwgz: {
tzgg: { title: '学位工作 - 通知公告', path: '/xwgz/tzgg.htm' },
dsgl: { title: '学位工作 - 导师管理', path: '/xwgz/dsgl.htm' },
xwgl: { title: '学位工作 - 学位管理', path: '/xwgz/xwgl.htm' },
pggz: { title: '学位工作 - 评估工作', path: '/xwgz/pggz.htm' },
},
xsgz: {
tzgg: { title: '学生工作 - 通知公告', path: '/xsgz/tzgg.htm' },
xwsd: { title: '学生工作 - 新闻速递', path: '/xsgz/xwsd.htm' },
xshd: { title: '学生工作 - 学生活动', path: '/xsgz/xshd.htm' },
jzgz: { title: '学生工作 - 奖助工作', path: '/xsgz/jzgz.htm' },
},
xzzx: {
zsxz: { title: '下载中心 - 招生下载', path: '/xzzx/zsxz.htm' },
pyxz: { title: '下载中心 - 培养下载', path: '/xzzx/pyxz.htm' },
// xsxz: { title: '下载中心 - 学生下载', path: '/xzzx/xsxz.htm' },
xwxz: { title: '下载中心 - 学位下载', path: '/xzzx/xwxz.htm' },
},
};
export const route: Route = {
path: '/yjs/:type/:subtype',
categories: ['university'],
example: '/gmu/yjs/zsgz/tzgg',
parameters: {
type: {
description: '分类,见下表',
options: [
{ value: 'zsgz', label: '招生工作' },
{ value: 'pygz', label: '培养工作' },
{ value: 'xwgz', label: '学位工作' },
{ value: 'xsgz', label: '学生工作' },
{ value: 'xzzx', label: '下载中心' },
],
},
subtype: {
description: '子分类,见下表',
options: [
{ value: 'tzgg', label: '通知公告' },
{ value: 'xwsd', label: '新闻速递' },
{ value: 'gzzd', label: '规章制度' },
{ value: 'dsgl', label: '导师管理' },
{ value: 'xwgl', label: '学位管理' },
{ value: 'pggz', label: '评估工作' },
{ value: 'xshd', label: '学生活动' },
{ value: 'jzgz', label: '奖助工作' },
{ value: 'zsxz', label: '招生下载' },
{ value: 'pyxz', label: '培养下载' },
{ value: 'xwxz', label: '学位下载' },
],
},
},
features: {
requireConfig: false,
requirePuppeteer: false,
antiCrawler: false,
supportBT: false,
supportPodcast: false,
supportScihub: false,
},
name: '研究生院',
maintainers: ['FrankFahey'],
radar: [
{
source: ['yjs.gmu.cn/:type/:subtype.htm', 'yjs.gmu.cn/'],
target: '/yjs/:type/:subtype',
},
],
handler,
};
export async function handler(ctx: Context) {
const { type, subtype } = ctx.req.param();
if (!sections[type] || !sections[type][subtype]) {
throw new Error('Invalid type or subtype');
}
const { title, path } = sections[type][subtype];
const baseUrl = 'https://yjs.gmu.cn';
const link = baseUrl + path;
const response = await got(link, {
https: {
rejectUnauthorized: false,
},
});
const $ = load(response.data);
// 更新选择器以匹配研究生院网站的实际结构
const list = $('.n_listxx1 li');
if (list.length === 0) {
throw new Error('No content found. The page structure might have changed.');
}
const items = await Promise.all(
list.toArray().map(async (item) => {
const element = $(item);
const a = element.find('a');
const dateText = element.find('span').text();
const href = a.attr('href');
const itemTitle = a.text().trim();
if (!href || !itemTitle) {
return null;
}
const pubDate = parseDate(dateText);
if (!pubDate) {
return null;
}
const fullLink = new URL(href, link).href;
// Use cache.tryGet to cache the article content
return await cache.tryGet(`gmu:yjs:${fullLink}`, async () => {
try {
const contentResponse = await got(fullLink, {
https: {
rejectUnauthorized: false,
},
});
const content = load(contentResponse.data);
// 获取新闻内容
const articleContent = content('.v_news_content').html() || '暂无详细内容';
return {
title: itemTitle,
link: fullLink,
pubDate,
description: articleContent,
};
} catch {
// 如果获取文章内容失败,返回基本信息
return {
title: itemTitle,
link: fullLink,
pubDate,
description: '暂无详细内容',
};
}
});
})
);
const result = items.filter((item): item is { title: string; link: string; pubDate: Date; description: string } => item !== null);
return {
title,
link,
description: `广州医科大学研究生院 - ${title}`,
item: result,
};
}