feat(route): add 12306火车票消息 and refactor to V2 (#9031)

* feat(route): add 12306火车票消息 and refactor to V2

* fix(route): change guid

* fix(route): change to use RSSHub's default UA

* fix(route): add handle exception
This commit is contained in:
Fatpandac
2022-02-09 21:00:18 +08:00
committed by GitHub
parent 1b4b3c5c28
commit 8ea8033e9b
8 changed files with 179 additions and 3 deletions

View File

@@ -10,6 +10,10 @@ pageClass: routes
<Route author="LogicJake" example="/12306/zxdt" path="/12306/zxdt/:id?" :paramsDesc="['铁路局id可在 URL 中找到,不填默认显示所有铁路局动态']"/>
### 售票信息
<Route author="Fatpandac" example="/12306/2022-02-19/重庆/永川东" path="/12306/:date/:from/:to/:type?" :paramsDesc="['时间', '始发站', '终点站', '售票类型,成人和学生可选,默认为成人']"/>
## All the Flight Deals
### 特价机票

View File

@@ -1422,9 +1422,6 @@ router.get('/ui-cn/user/:id', lazyloadRouteHandler('./routes/ui-cn/user'));
// Dcard
router.get('/dcard/:section/:type?', lazyloadRouteHandler('./routes/dcard/section'));
// 12306
router.get('/12306/zxdt/:id?', lazyloadRouteHandler('./routes/12306/zxdt'));
// 北京天文馆每日一图
router.get('/bjp/apod', lazyloadRouteHandler('./routes/bjp/apod'));

108
lib/v2/12306/index.js Normal file
View File

@@ -0,0 +1,108 @@
const got = require('@/utils/got');
const { art } = require('@/utils/render');
const path = require('path');
const config = require('@/config').value;
const rootUrl = 'https://kyfw.12306.cn';
async function getJSESSIONID(linkUrl) {
const res = await got({
method: 'get',
url: linkUrl,
headers: {
UserAgent: config.ua,
Referer: 'https://www.12306.cn/index/index.html',
},
});
return res.headers['set-cookie'].join().match(/JSESSIONID=([^;]+);/)[0];
}
function getStationInfo(stationName, ctx) {
return ctx.cache.tryGet(stationName, async () => {
const res = await got({
method: 'get',
url: `${rootUrl}/otn/resources/js/framework/station_name.js`,
headers: {
UserAgent: config.ua,
Referer: 'https://kyfw.12306.cn/otn/leftTicket/init',
},
});
return res.data
.split('@')
.map((item) => {
const itemData = item.split('|');
return itemData.indexOf(stationName) !== -1
? {
code: itemData[2],
name: itemData[1],
}
: null;
})
.filter((item) => item)[0];
});
}
module.exports = async (ctx) => {
const date = ctx.params.date;
const fromStationInfo = await getStationInfo(ctx.params.from, ctx);
const toStationInfo = await getStationInfo(ctx.params.to, ctx);
const type = ctx.params.type ?? 'ADULT';
const apiUrl = `${rootUrl}/otn/leftTicket/queryA?leftTicketDTO.train_date=${date}&leftTicketDTO.from_station=${fromStationInfo.code}&leftTicketDTO.to_station=${toStationInfo.code}&purpose_codes=${type}`;
const linkUrl = `${rootUrl}/otn/leftTicket/init?linktypeid=dc&fs=${fromStationInfo.code}&ts=${toStationInfo.code}&date=${date}&flag=N,N,Y`;
const response = await got.get(apiUrl, {
headers: {
UserAgent: config.ua,
Referer: 'https://kyfw.12306.cn/otn/leftTicket/init',
Cookie: await getJSESSIONID(linkUrl),
},
});
const data = response.data.data.result;
const map = response.data.data.map;
if (data.length === 0) {
throw '没有找到相关车次,请检查参数是否正确';
}
const items = data.map((item) => {
const itemData = item.split('|');
const trainInfo = {
trainNo: itemData[3],
fromStation: map[itemData[6]],
toStation: map[itemData[7]],
startTime: itemData[8],
arriveTime: itemData[9],
duration: itemData[10],
today: itemData[11],
A9: itemData[32],
M: itemData[31],
O: itemData[30],
A6: itemData[29],
A4: itemData[28],
F: itemData[27],
A3: itemData[26],
A2: itemData[25],
A1: itemData[24],
WZ: itemData[23],
QT: itemData[22],
};
return {
title: `${trainInfo.fromStation}${trainInfo.toStation} ${trainInfo.startTime} ${trainInfo.arriveTime}`,
description: art(path.join(__dirname, 'templates/train.art'), {
trainInfo,
}),
link: linkUrl,
guid: item,
};
});
ctx.state.data = {
title: `${fromStationInfo.name}${toStationInfo.name} ${date}`,
link: linkUrl,
item: items,
};
};

View File

@@ -0,0 +1,4 @@
module.exports = {
'/:date/:from/:to/:type?': ['Fatpandac'],
'/zxdt/:id?': ['LogicJake'],
};

28
lib/v2/12306/radar.js Normal file
View File

@@ -0,0 +1,28 @@
module.exports = {
'12306.cn': {
_name: '12306',
kyfw: [
{
title: '售票信息',
docs: 'https://docs.rsshub.app/travel.html#_12306-shou-shu-piao-piao-xin-shen-xi',
source: ['/', '/otn/leftTicket/init'],
target: (params, url) => {
const searchParams = new URL(url).searchParams;
const from = searchParams.get('fs').split(',')[0];
const to = searchParams.get('ts').split(',')[0];
const date = searchParams.get('date');
return `/12306/${date}/${from}/${to}`;
},
},
],
www: [
{
title: '最新动态',
docs: 'https://docs.rsshub.app/travel.html#_12306-zui-cuo-xin-dong-tai',
source: ['/', '/mormhweb/1/:id/index_fl.html'],
target: '/12306/zxdt/:id',
},
],
},
};

4
lib/v2/12306/router.js Normal file
View File

@@ -0,0 +1,4 @@
module.exports = function (router) {
router.get('/:date/:from/:to/:type?', require('./index'));
router.get('/zxdt/:id?', require('./zxdt'));
};

View File

@@ -0,0 +1,31 @@
<text>车次:{{ trainInfo.trainNo}}</text>
<br>
<text>始发站:{{ trainInfo.fromStation}} → {{ trainInfo.toStation}}</text>
<br>
<text>出发时间:{{ trainInfo.startTime}}</text>
<br>
<text>到达时间:{{ trainInfo.arriveTime}}</text>
<br>
<text>历时:{{ trainInfo.duration}} {{ trainInfo.today === 'N' ? '次日达' : '' }}</text>
<br>
<text>商务座/特等座:{{ trainInfo.A9 ? trainInfo.A9 : '无' }}</text>
<br>
<text>一等座:{{ trainInfo.M ? trainInfo.M : '无' }}</text>
<br>
<text>二等座/二等包座:{{ trainInfo.O ? trainInfo.O : '无' }}</text>
<br>
<text>高级软卧:{{ trainInfo.A6 ? trainInfo.A6 : '无' }}</text>
<br>
<text>软卧/一等卧:{{ trainInfo.A4 ? trainInfo.A4 : '无' }}</text>
<br>
<text>动卧:{{ trainInfo.F ? trainInfo.F : '无' }}</text>
<br>
<text>硬卧/二等卧:{{ trainInfo.A3 ? trainInfo.A3 : '无' }}</text>
<br>
<text>软座: {{ trainInfo.A2 ? trainInfo.A2 : '无' }}</text>
<br>
<text>硬座: {{ trainInfo.A1 ? trainInfo.A1 : '无' }}</text>
<br>
<text>无座: {{ trainInfo.WZ ? trainInfo.WZ : '无' }}</text>
<br>
<text>其他: {{ trainInfo.QT ? trainInfo.QT : '无' }}</text>