mirror of
https://github.com/DIYgod/RSSHub.git
synced 2025-12-16 02:42:57 +08:00
Add option to output the cheapest flight only by Hopper (#484)
This commit is contained in:
@@ -172,7 +172,7 @@ id, App Store app id,必选,如 QQ 的链接为 https://itunes.apple.com/cn/
|
||||
|
||||
### App Store/Mac App Store 价格更新(限免) <Author uid="HenryQW"/>
|
||||
|
||||
举例: [https://rsshub.app/appstore/price/cn/mac/id115244347](https://rsshub.app/appstore/price/cn/mac/id115244347)
|
||||
举例: [https://rsshub.app/appstore/price/cn/mac/id1152443474](https://rsshub.app/appstore/price/cn/mac/id1152443474)
|
||||
|
||||
路由: `/appstore/price/:country/:type/:id`
|
||||
|
||||
@@ -1890,12 +1890,16 @@ type,可选,不填则默认为 `all`
|
||||
|
||||
### Hopper 特价机票 <Author uid="HenryQW"/>
|
||||
|
||||
举例: 伦敦希思罗 ✈ 北京首都国际 [https://rsshub.app/hopper/LHR/PEK](https://rsshub.app/hopper/LHR/PEK)
|
||||
本路由返回由 Hopper 算法给出的现在可购入最便宜的折扣机票,通常包含 6 个结果。出行日期将由 Hopper 算法定义,可能是明天也可能是 10 个月后。
|
||||
|
||||
路由: `/hopper/:from/:to?`
|
||||
举例: 伦敦希思罗 ✈ 北京首都国际 [https://rsshub.app/hopper/1/LHR/PEK](https://rsshub.app/hopper/1/LHR/PEK)
|
||||
|
||||
路由: `/hopper/:lowestOnly/:from/:to?`
|
||||
|
||||
参数:
|
||||
|
||||
lowestOnly: 是否只返回最低价机票,`1`:是,其他任意值:否
|
||||
|
||||
from: 始发地,IATA 国际航空运输协会机场代码
|
||||
|
||||
to: 目的地,IATA 国际航空运输协会机场代码,可选,缺省则目的地为`任意城市`
|
||||
|
||||
@@ -150,7 +150,7 @@ id, App Store app id, obtain from the app URL `https://itunes.apple.com/us/app/r
|
||||
|
||||
### App Store/Mac App Store Price Drop Alert <Author uid="HenryQW"/>
|
||||
|
||||
eg: [https://rsshub.app/appstore/price/cn/mac/id115244347](https://rsshub.app/appstore/price/cn/mac/id115244347)
|
||||
eg: [https://rsshub.app/appstore/price/us/mac/id1152443474](https://rsshub.app/appstore/price/cn/mac/id1152443474)
|
||||
|
||||
Route: `/appstore/price/:country/:type/:id`
|
||||
|
||||
@@ -455,12 +455,16 @@ Parameters:
|
||||
|
||||
### Hopper Flight Deals <Author uid="HenryQW"/>
|
||||
|
||||
Eg: London Heathrow Airport ✈ Beijing Capital International Airport [https://rsshub.app/hopper/LHR/PEK](https://rsshub.app/hopper/LHR/PEK)
|
||||
This route returns a list of flight deals (in most cases, 6 flight deals) for a period defined by Hopper's algorithm, which means the travel date will be totally random (could be tomorrow or 10 months from now).
|
||||
|
||||
Route: `/hopper/:from/:to?`
|
||||
Eg: London Heathrow Airport ✈ Beijing Capital International Airport [https://rsshub.app/hopper/1/LHR/PEK](https://rsshub.app/hopper/1/LHR/PEK)
|
||||
|
||||
Route: `/hopper/:lowestOnly/:from/:to?`
|
||||
|
||||
Parameters:
|
||||
|
||||
- lowestOnly, set to `1` will return the cheapest deal only, instead of all deals, so you don't get spammed
|
||||
|
||||
- from, origin airport IATA code
|
||||
|
||||
- to, destination airport IATA code, optional, if unset the destination will be set to `anywhere`
|
||||
|
||||
@@ -422,6 +422,6 @@ router.get('/appstore/update/:country/:id', require('./routes/appstore/update'))
|
||||
router.get('/appstore/price/:country/:type/:id', require('./routes/appstore/price'));
|
||||
|
||||
// Hopper
|
||||
router.get('/hopper/:from/:to?', require('./routes/hopper/index'));
|
||||
router.get('/hopper/:lowestOnly/:from/:to?', require('./routes/hopper/index'));
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@@ -3,8 +3,10 @@ const config = require('../../config');
|
||||
const cheerio = require('cheerio');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const from = ctx.params.from;
|
||||
const to = ctx.params.to || 'Anywhere';
|
||||
const from = ctx.params.from.toUpperCase();
|
||||
const to = ctx.params.to !== undefined ? ctx.params.to.toUpperCase() : 'Anywhere';
|
||||
|
||||
const type = ctx.params.lowestOnly;
|
||||
|
||||
const url = `https://www.hopper.com/deals/best/from/${from}/to/${to}`;
|
||||
const title = `Hopper - Flights From ${from} to ${to}`;
|
||||
@@ -23,39 +25,38 @@ module.exports = async (ctx) => {
|
||||
|
||||
const $ = cheerio.load(response.data);
|
||||
const list = $('div.prices li a');
|
||||
const items = [];
|
||||
|
||||
if (type === '1') {
|
||||
let lowest = 99999;
|
||||
let lowIndex = 0;
|
||||
|
||||
list.map((i, e) => {
|
||||
const current = parseInt(
|
||||
$(e)
|
||||
.find('.price')
|
||||
.text()
|
||||
.replace(/\D/g, '')
|
||||
);
|
||||
|
||||
if (current < lowest) {
|
||||
lowest = current;
|
||||
lowIndex = i;
|
||||
}
|
||||
});
|
||||
|
||||
items.push(formatDesc($(list[lowIndex])));
|
||||
} else {
|
||||
list.map((i, e) => {
|
||||
items.push(formatDesc($(e)));
|
||||
});
|
||||
}
|
||||
|
||||
ctx.state.data = {
|
||||
title,
|
||||
link: url,
|
||||
description: title,
|
||||
item: list
|
||||
.map((i, e) => {
|
||||
const item = $(e).attr('href');
|
||||
let reg = new RegExp('destination=(.*?)&', 'g');
|
||||
const destination = reg.exec(item)[1];
|
||||
reg = new RegExp('origin=(.*?)&', 'g');
|
||||
const origin = reg.exec(item)[1];
|
||||
reg = new RegExp('departureDate=(.*?)&', 'g');
|
||||
const departureDate = reg.exec(item)[1];
|
||||
reg = new RegExp('returnDate=(.*?)&', 'g');
|
||||
const returnDate = reg.exec(item)[1];
|
||||
|
||||
const price = $(list[i])
|
||||
.find('.price')
|
||||
.text();
|
||||
|
||||
const title = `${origin} ✈ ${destination} ${getMonthYear(departureDate)} for ${price}`;
|
||||
|
||||
const description = `<table><tbody><tr><th align="left" style="border: 1px solid black;">From</th><th align="left" style="border: 1px solid black;">To</th><th align="left" style="border: 1px solid black;">Price</th></tr><tr><td style="border: 1px solid black;">
|
||||
${origin}</td><td style="border: 1px solid black;">${destination}</td><td style="border: 1px solid black;">${price}</td></tr></tbody></table>${formatDate(departureDate)} ✈ ${formatDate(returnDate)}`;
|
||||
return {
|
||||
title,
|
||||
description,
|
||||
guid: item,
|
||||
link: item,
|
||||
};
|
||||
})
|
||||
.get(),
|
||||
item: items,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -75,3 +76,28 @@ function getMonthYear(v) {
|
||||
year: 'numeric',
|
||||
});
|
||||
}
|
||||
|
||||
function formatDesc(e) {
|
||||
const item = e.attr('href');
|
||||
let reg = new RegExp('destination=(.*?)&', 'g');
|
||||
const destination = reg.exec(item)[1];
|
||||
reg = new RegExp('origin=(.*?)&', 'g');
|
||||
const origin = reg.exec(item)[1];
|
||||
reg = new RegExp('departureDate=(.*?)&', 'g');
|
||||
const departureDate = reg.exec(item)[1];
|
||||
reg = new RegExp('returnDate=(.*?)&', 'g');
|
||||
const returnDate = reg.exec(item)[1];
|
||||
|
||||
const price = e.find('.price').text();
|
||||
|
||||
const title = `${origin} ✈ ${destination} ${getMonthYear(departureDate)} for ${price}`;
|
||||
|
||||
const description = `<table><tbody><tr><th align="left" style="border: 1px solid black;">From</th><th align="left" style="border: 1px solid black;">To</th><th align="left" style="border: 1px solid black;">Price</th></tr><tr><td style="border: 1px solid black;">
|
||||
${origin}</td><td style="border: 1px solid black;">${destination}</td><td style="border: 1px solid black;">${price}</td></tr></tbody></table>${formatDate(departureDate)} ✈ ${formatDate(returnDate)}`;
|
||||
return {
|
||||
title,
|
||||
description,
|
||||
guid: item,
|
||||
link: item,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user