rsshub
Version:
Make RSS Great Again!
131 lines (116 loc) • 4.34 kB
text/typescript
import { Route } from '@/types';
import cache from '@/utils/cache';
import got from '@/utils/got';
import { art } from '@/utils/render';
import path from 'node:path';
import { config } from '@/config';
import InvalidParameterError from '@/errors/types/invalid-parameter';
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) {
return 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.includes(stationName)
? {
code: itemData[2],
name: itemData[1],
}
: null;
})
.find(Boolean);
});
}
export const route: Route = {
path: '/:date/:from/:to/:type?',
categories: ['travel'],
example: '/12306/2022-02-19/重庆/永川东',
parameters: { date: '时间,格式为(YYYY-MM-DD)', from: '始发站', to: '终点站', type: '售票类型,成人和学生可选,默认为成人' },
features: {
requireConfig: false,
requirePuppeteer: false,
antiCrawler: false,
supportBT: false,
supportPodcast: false,
supportScihub: false,
},
name: '售票信息',
maintainers: ['Fatpandac'],
handler,
};
async function handler(ctx) {
const date = ctx.req.param('date');
const fromStationInfo = await getStationInfo(ctx.req.param('from'));
const toStationInfo = await getStationInfo(ctx.req.param('to'));
const type = ctx.req.param('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),
},
});
if (response.data.data === undefined || response.data.data.length === 0) {
throw new InvalidParameterError('没有找到相关车次,请检查参数是否正确');
}
const data = response.data.data.result;
const map = response.data.data.map;
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: Object.values(trainInfo).join('|'),
};
});
return {
title: `${fromStationInfo.name} → ${toStationInfo.name} ${date}`,
link: linkUrl,
item: items,
};
}