diff --git a/docs/travel.md b/docs/travel.md index d49fb611c9..47ae09ac61 100644 --- a/docs/travel.md +++ b/docs/travel.md @@ -10,6 +10,10 @@ pageClass: routes +### 售票信息 + + + ## All the Flight Deals ### 特价机票 diff --git a/lib/router.js b/lib/router.js index 7060899bcd..c6068343e4 100644 --- a/lib/router.js +++ b/lib/router.js @@ -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')); diff --git a/lib/v2/12306/index.js b/lib/v2/12306/index.js new file mode 100644 index 0000000000..84e0f53b34 --- /dev/null +++ b/lib/v2/12306/index.js @@ -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, + }; +}; diff --git a/lib/v2/12306/maintainer.js b/lib/v2/12306/maintainer.js new file mode 100644 index 0000000000..bca746f4fd --- /dev/null +++ b/lib/v2/12306/maintainer.js @@ -0,0 +1,4 @@ +module.exports = { + '/:date/:from/:to/:type?': ['Fatpandac'], + '/zxdt/:id?': ['LogicJake'], +}; diff --git a/lib/v2/12306/radar.js b/lib/v2/12306/radar.js new file mode 100644 index 0000000000..3675c84d61 --- /dev/null +++ b/lib/v2/12306/radar.js @@ -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', + }, + ], + }, +}; diff --git a/lib/v2/12306/router.js b/lib/v2/12306/router.js new file mode 100644 index 0000000000..f454271a94 --- /dev/null +++ b/lib/v2/12306/router.js @@ -0,0 +1,4 @@ +module.exports = function (router) { + router.get('/:date/:from/:to/:type?', require('./index')); + router.get('/zxdt/:id?', require('./zxdt')); +}; diff --git a/lib/v2/12306/templates/train.art b/lib/v2/12306/templates/train.art new file mode 100644 index 0000000000..ea1522ff96 --- /dev/null +++ b/lib/v2/12306/templates/train.art @@ -0,0 +1,31 @@ +车次:{{ trainInfo.trainNo}} +
+始发站:{{ trainInfo.fromStation}} → {{ trainInfo.toStation}} +
+出发时间:{{ trainInfo.startTime}} +
+到达时间:{{ trainInfo.arriveTime}} +
+历时:{{ trainInfo.duration}} {{ trainInfo.today === 'N' ? '次日达' : '' }} +
+商务座/特等座:{{ trainInfo.A9 ? trainInfo.A9 : '无' }} +
+一等座:{{ trainInfo.M ? trainInfo.M : '无' }} +
+二等座/二等包座:{{ trainInfo.O ? trainInfo.O : '无' }} +
+高级软卧:{{ trainInfo.A6 ? trainInfo.A6 : '无' }} +
+软卧/一等卧:{{ trainInfo.A4 ? trainInfo.A4 : '无' }} +
+动卧:{{ trainInfo.F ? trainInfo.F : '无' }} +
+硬卧/二等卧:{{ trainInfo.A3 ? trainInfo.A3 : '无' }} +
+软座: {{ trainInfo.A2 ? trainInfo.A2 : '无' }} +
+硬座: {{ trainInfo.A1 ? trainInfo.A1 : '无' }} +
+无座: {{ trainInfo.WZ ? trainInfo.WZ : '无' }} +
+其他: {{ trainInfo.QT ? trainInfo.QT : '无' }} diff --git a/lib/routes/12306/zxdt.js b/lib/v2/12306/zxdt.js similarity index 100% rename from lib/routes/12306/zxdt.js rename to lib/v2/12306/zxdt.js