Skip to content

Instantly share code, notes, and snippets.

@jricardo27
Last active March 28, 2022 13:15
Show Gist options
  • Save jricardo27/f215c111ec7bbf18f60830cb9dd3d5f2 to your computer and use it in GitHub Desktop.
Save jricardo27/f215c111ec7bbf18f60830cb9dd3d5f2 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name Flight Centre Extra Filter
// @author Ricardo Perez
// @namespace jricardo27/FlightCentreExtraFilter
// @version 0.1
// @description Hide unwanted flights from search
// @include *://*.flightcentre.com.au/*
// @require https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js
// @grant none
// ==/UserScript==
(function() {
'use strict';
const FILTER_BY_MAXIMUM_STOPS = "FILTER_BY_MAXIMUM_STOPS";
const FILTER_BY_MAXIMUM_TIME = "FILTER_BY_MAXIMUM_TIME";
/* ------------------------------------------------------- */
/* Values to configure */
const MAXIMUM_STOPS = 2;
const MAXIMUM_HOURS_GO = 50; // hours, leave blank if not want to filter
const MAXIMUM_HOURS_BACK = 60; // hours, leave blank if not want to filter
// List of airport abbreviatures to include, leave blank if not want to filter.
const OUTBOUND_AIRPORTS = ["MEL", "BOG", "AKL", "SCL"];
const INBOUND_AIRPORTS = ["MEL", "BOG", "LAX"]; // "JFK", "EWR", "SFO"
const FILTER_BY = [];
/* ------------------------------------------------------- */
function customObserver(target, callback, config) {
this.target = target || document;
this.config = config || {childList: true, characterData: true, attributes: true, subtree: true};
const that = this;
this.ob = new MutationObserver(function (mut, obsSelf) {
callback(that, mut, obsSelf);
});
}
customObserver.prototype = {
connect: function () {
this.ob.observe(this.target, this.config);
},
disconnect: function () {
this.ob.disconnect();
}
};
/* ------------------------------------------------------- */
const FLIGHT_RESULTS = "#flightResults"
const FLIGHT_BOX = ".test-combinedTrip";
const OUTBOUND_BOX = ".test-outboundJourney";
const INBOUND_BOX = ".test-inboundJourney";
const STOPS_BOX = ".jss414";
const DURATION_BOX = ".test-duration";
const AIRPORT_BOX = ".test-journeyStopAirport"
const applyFilter = () => {
let messageShown = false;
let outboundExcludedAiports = new Set();
let inboundExcludedAiports = new Set();
let aiportAbbrv = null;
$(FLIGHT_BOX).each((index, rawElem) => {
const boxElem = $(rawElem);
const outboundBox = $(boxElem.find(OUTBOUND_BOX)[0]);
const inboundBox = $(boxElem.find(INBOUND_BOX)[0]);
if (FILTER_BY.includes(FILTER_BY_MAXIMUM_STOPS)) {
if (!messageShown) {
console.log(`Filtering by number of stops. Hiding any over ${MAXIMUM_STOPS} stops.`);
messageShown = true
}
hideFlightsOverMaximumStops(boxElem);
}
if(FILTER_BY.includes(FILTER_BY_MAXIMUM_TIME)) {
if (!messageShown) {
console.log(`Filtering by duration. Hiding any over ${MAXIMUM_HOURS_GO}h going and ${MAXIMUM_HOURS_BACK}h back.`);
messageShown = true
}
hideFlightsOverMaximumTime(boxElem);
}
aiportAbbrv = hideExcludedAiports(boxElem, outboundBox, OUTBOUND_AIRPORTS);
if (aiportAbbrv) {
outboundExcludedAiports.add(aiportAbbrv);
}
aiportAbbrv = hideExcludedAiports(boxElem, inboundBox, INBOUND_AIRPORTS);
if (aiportAbbrv) {
inboundExcludedAiports.add(aiportAbbrv);
}
});
if (outboundExcludedAiports.size > 0) {
console.log(`Hiding flights stoping in outbound aiports: ${Array.from(outboundExcludedAiports)}`);
}
if (inboundExcludedAiports.size > 0) {
console.log(`Hiding flights stoping in inbound aiports: ${Array.from(inboundExcludedAiports)}`);
}
};
const hideBox = (boxElem) => {
// boxElem.hide();
boxElem.css("background-color", "crimson");
}
const hideFlightsOverMaximumStops = (boxElem) => {
boxElem.find(STOPS_BOX).each(function () {
const stopElem = $(this);
const stops = parseInt(stopElem.text());
if (stops > MAXIMUM_STOPS) {
hideBox(boxElem);
}
});
};
const getHours = (elem) => {
return parseInt(elem.text().split("h")[0]);
};
const hideFlightsOverMaximumTime = (boxElem) => {
const durationElems = boxElem.find(DURATION_BOX);
const hours1 = getHours($(durationElems[0]));
const hours2 = getHours($(durationElems[1]));
if (MAXIMUM_HOURS_GO && hours1 > MAXIMUM_HOURS_GO) {
hideBox(boxElem);
}
if (MAXIMUM_HOURS_BACK && hours2 > MAXIMUM_HOURS_BACK) {
hideBox(boxElem);
}
};
const hideExcludedAiports = (boxElem, flightBox, includedAirports) => {
let airportAbbrv = null;
if(includedAirports.length > 0) {
flightBox.find(AIRPORT_BOX).each(function () {
const airportElem = $(this);
airportAbbrv = airportElem.text();
if (!includedAirports.includes(airportAbbrv)) {
hideBox(boxElem);
return false; // Break loop.
}
airportAbbrv = null;
});
}
return airportAbbrv;
}
/**
Userscript will run from here.
**/
document.onreadystatechange = () => {
// Wait until fligths are loaded.
const observer = new customObserver($(FLIGHT_RESULTS)[0], (obs, mutations) => {
console.log("Flights loaded");
if ($(".test-combinedResultsScreen")) {
console.log("Executing extra filter");
applyFilter();
}
}, {childList: true, subtree: true});
observer.connect();
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment