Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save trevormcclellan/59b78544f416edf65f2c to your computer and use it in GitHub Desktop.
Save trevormcclellan/59b78544f416edf65f2c to your computer and use it in GitHub Desktop.
Auto Check-In to Southwest Flights.user.js
// ==UserScript==
// @name Auto Check-In to Southwest Flights
// @namespace http://www.ryanizzo.com/southwest-auto-check-in/
// @version 1.5.1
// @author Nicholas Buroojy (http://userscripts.org/users/83813)
// @contributor Ryan Izzo (http://www.ryanizzo.com)
// @contributor JR Hehnly (http://www.okstorms.com @stormchasing)
// @description Automatically check in to Southwest Airline flights at the appropriate time.
// @include https://southwest.com/flight/retrieveCheckinDoc.html*
// @include https://southwest.com/flight/selectPrintDocument*
// @include https://www.southwest.com/flight/retrieveCheckinDoc.html*
// @include https://www.southwest.com/flight/selectCheckinDocDelivery.html*
// @include https://www.southwest.com/flight/selectPrintDocument*
// @grant GM_getValue
// @grant GM_setValue
// @copyright 2009+, Nicholas Buroojy (http://userscripts.org/users/83813)
// @license GPL version 3 or any later version; http://www.gnu.org/copyleft/gpl.html
// ==/UserScript==
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// History
//
// 10/2012 v1.2 Ryan Izzo (ryanizzo.com)
// Updated to use new Southwest Check In page, added validation
//
// 7/2014 v1.3 Ryan Izzo (ryanizzo.com)
// Moved script to GitHub since UserScripts appears dead
//
// 10/2014 v1.4 JR Hehnly (okstorms.com)
// Added phone number entry to auto-text boarding pass docs to mobile device
//
//3/28/2016 v1.5.1 Trevor McClellan (github.com/trevormcclellan)
// Fixed phone number entry system
//
// TODO: Use Southwest's server's time instead of the client's clock.
// TODO: Test select passenger page.
///////////// CHECK IN PAGE ////////////////
var globalSubmitDate;
/**
* @brief Submit the check in form on the Southwest Check In Online page.
*/
function submitNow()
{
try{
//alert(msRemaining + " " + globalSubmitDate);
var form = document.getElementById("itineraryLookup");
form.submit();
}
catch(e){
alert('An error has occurred: '+e.message);
}
}
/**
* @brief Display the countdown.
*
* TODO: Some formatting is wrong eg ("1:0:12" means 1 hour and 12 seconds remain). Make sure everything is represented with 2 digits.
*/
function displayCountdown()
{
try{
var area = document.getElementById("countdown");
var timeRemain = globalSubmitDate - new Date();
var days = Math.floor(timeRemain / (1000 * 60 * 60 * 24));
var hours = Math.floor(timeRemain / (1000 * 60 * 60)) % 24;
var minutes = Math.floor(timeRemain / (1000 * 60)) % 60;
//round to the nearest second
var seconds = Math.round(timeRemain / 1000) % 60;
//Don't print negative time.
if (hours < 0 || minutes < 0 || seconds < 0)
{
area.innerHTML = "Checking In...";
return;
}
area.innerHTML = "Time Remaining: <strong>";
//If 0 days remain, omit them.
if (days != 0)
area.innerHTML += days + "d ";
//If 0 hours remain, omit them.
if (hours != 0)
area.innerHTML += hours + "h ";
//Add padding to minute
if (minutes !=0 )
//area.innerHTML += "0";
area.innerHTML += minutes + "m ";
//Add padding to second
//if (seconds < 10)
//area.innerHTML += "0";
area.innerHTML += seconds;
area.innerHTML += "s</strong>";
}
catch(e){
alert('An error has occurred: '+e.message);
}
}
/**
* @brief Updates the countdown every second.
*/
function displayCountdownWrapper()
{
try{
window.setInterval(displayCountdown, 1000);
}
catch(e){
alert('An error has occurred: '+e.message);
}
}
/**
* @brief Begins the delay at the next even second.
*/
function beginDelay()
{
try{
var confNumber = document.getElementById("confirmationNumber").value;
var firstName = document.getElementById("firstName").value;
var lastName = document.getElementById("lastName").value;
var month = document.getElementById("month-input").value;
var day = document.getElementById("day-input").value;
var year = document.getElementById("year-input").value;
var hour = document.getElementById("hour-input").value;
var minute = document.getElementById("minute-input").value;
var second = document.getElementById("second-input").value;
var phoneArea = document.getElementById("phoneArea").value;
var phonePrefix = document.getElementById("phonePrefix").value;
var phoneNumber = document.getElementById("phoneNumber").value;
if(confNumber == "" || firstName == "" || lastName == "" ){
alert("Must fill out Confirmation Number and Name.");
}
else if(month == "" || month == "mm" || day == "" || day == "dd" || year == "" || year == "yyyy"
|| hour == "" || hour == "hh" || minute == "" || minute == "mm" || second == "" ){
alert("Must fill out Date and Time.");
}
else if(year.length < 4 ){
alert("Year must be 4 characters.");
}
else if (phoneArea.search(/\d\d\d/g) == -1 || phonePrefix.search(/\d\d\d/g) == -1 || phoneNumber.search(/\d\d\d\d/g) == -1) {
alert("Invalid phone number provided.");
}
else{
//save the text number for later
GM_setValue("phoneArea", phoneArea);
GM_setValue("phonePrefix", phonePrefix);
GM_setValue("phoneNumber", phoneNumber);
//Build a date
var submitDate = new Date();
//submitDate.setMonth(month - 1);
//submitDate.setDate(day);
submitDate.setFullYear(year, month - 1, day);
submitDate.setHours(hour);
submitDate.setMinutes(minute);
submitDate.setSeconds(second);
submitDate.setMilliseconds(0);
var now = new Date();
var msRemaining = submitDate - now;
//alert(submitDate + " - " + now + " = " + msRemaining);
var maxDays = 14;
if(msRemaining < 0)
alert("Date/Time must be in the future.");
else if(msRemaining > maxDays * 1000 * 60 * 60 * 24)
alert("Date/Time cannot be more than " + maxDays + " days in the future." + msRemaining);
else{
//Install the timeout to submit the form.
window.setTimeout(submitNow, msRemaining);
globalSubmitDate = submitDate;
//Install a short term timeout to call the countdown wrapper at the beginning of the next second.
window.setTimeout(displayCountdownWrapper, msRemaining % 1000);
}
}
}
catch(e){
alert('An error has occurred: '+e.message);
}
}
/**
* @brief Edits the check in page; Adds Date, time, and Auto Check In button
*
* TODO Error handling. (Auto notify the developer when southwest page changes)
*/
function checkInPageFormEdit()
{
try{
var leftPanel = document.getElementsByClassName("checkIn_form_leftPanel")[0];
//All of our stuff will go in this div.
var delayDiv = document.createElement("div");
delayDiv.setAttribute('id','checkInDelay');
var dateSelect = document.createElement("span");
dateSelect.setAttribute('id','date-select');
//The big label at the top of the menu
var mainLabel = document.createElement("h4");
mainLabel.setAttribute('class','swa_feature_checkInOnline_form_header');
mainLabel.innerHTML = "Set Check In Date and Time";
dateSelect.innerHTML += "<br/>";
dateSelect.appendChild(mainLabel);
//The date portion.
var today = new Date();
var dateLabel = document.createElement("label");
dateLabel.innerHTML = "<span class=\"required\">*</span> Date:";
var monthInput = document.createElement("input");
monthInput.setAttribute('id','month-input');
monthInput.setAttribute('type','text');
monthInput.setAttribute('maxlength','2');
monthInput.setAttribute('size','2');
monthInput.setAttribute('value',today.getMonth()+1);
monthInput.setAttribute('onfocus','if(this.value==\'mm\') this.value=\'\';');
monthInput.setAttribute('style','margin-left:7em');
monthInput.setAttribute('tabindex','5');
var dayInput = document.createElement("input");
dayInput.setAttribute('id','day-input');
dayInput.setAttribute('type','text');
dayInput.setAttribute('maxlength','2');
dayInput.setAttribute('size','2');
dayInput.setAttribute('value',today.getDate());
dayInput.setAttribute('onfocus','if(this.value==\'dd\') this.value=\'\';');
dayInput.setAttribute('tabindex','6');
var yearInput = document.createElement("input");
yearInput.setAttribute('id','year-input');
yearInput.setAttribute('type','text');
yearInput.setAttribute('maxlength','4');
yearInput.setAttribute('size','4');
yearInput.setAttribute('value',today.getFullYear());
yearInput.setAttribute('onfocus','if(this.value==\'yyyy\') this.value=\'\';');
yearInput.setAttribute('tabindex','7');
dateSelect.appendChild(dateLabel);
dateSelect.appendChild(monthInput);
dateSelect.innerHTML += "/";
dateSelect.appendChild(dayInput);
dateSelect.innerHTML += "/";
dateSelect.appendChild(yearInput);
// The time portion.
var timeLabel = document.createElement("label");
timeLabel.innerHTML = "<span class=\"required\">*</span> Time: (24-hour format) ";
var hourInput = document.createElement("input");
hourInput.setAttribute('id','hour-input');
hourInput.setAttribute('type','text');
hourInput.setAttribute('maxlength','2');
//hourInput.setAttribute('style','margin-left:10px');
hourInput.setAttribute('size','2');
hourInput.setAttribute('value',today.getHours());
hourInput.setAttribute('onfocus','if(this.value==\'hh\') this.value=\'\';');
hourInput.setAttribute('tabindex','8');
var minuteInput = document.createElement("input");
minuteInput.setAttribute('id','minute-input');
minuteInput.setAttribute('type','text');
minuteInput.setAttribute('maxlength','2');
minuteInput.setAttribute('size','2');
minuteInput.setAttribute('value',today.getMinutes());
minuteInput.setAttribute('onfocus','if(this.value==\'mm\') this.value=\'\';');
minuteInput.setAttribute('tabindex','9');
var secondInput = document.createElement("input");
secondInput.setAttribute('id','second-input');
secondInput.setAttribute('type','text');
secondInput.setAttribute('maxlength','2');
secondInput.setAttribute('size','2');
secondInput.setAttribute('value','02');
secondInput.setAttribute('tabindex','10');
dateSelect.innerHTML += "<br/><br/>";
dateSelect.appendChild(timeLabel);
dateSelect.appendChild(hourInput);
dateSelect.innerHTML += ":";
dateSelect.appendChild(minuteInput);
dateSelect.innerHTML += ":";
dateSelect.appendChild(secondInput);
delayDiv.appendChild(dateSelect);
//auto-text boarding pass section
var autoTextArea = document.createElement("div");
var textLabel = document.createElement("label");
textLabel.innerHTML = "<span class=\"required\">*</span> Boarding pass text number: ";
var phoneArea = document.createElement("input");
phoneArea.setAttribute('id','phoneArea');
phoneArea.setAttribute('type','text');
phoneArea.setAttribute('maxlength','3');
phoneArea.setAttribute('size','3');
phoneArea.setAttribute('value', GM_getValue("phoneArea") != undefined ? GM_getValue("phoneArea") : '');
phoneArea.setAttribute('tabindex','12');
var phonePrefix = document.createElement("input");
phonePrefix.setAttribute('id','phonePrefix');
phonePrefix.setAttribute('type','text');
phonePrefix.setAttribute('maxlength','3');
phonePrefix.setAttribute('size','3');
phonePrefix.setAttribute('value', GM_getValue("phonePrefix") != undefined ? GM_getValue("phonePrefix") : '');
phonePrefix.setAttribute('tabindex','13');
var phoneNumber = document.createElement("input");
phoneNumber.setAttribute('id','phoneNumber');
phoneNumber.setAttribute('type','text');
phoneNumber.setAttribute('maxlength','4');
phoneNumber.setAttribute('size','4');
phoneNumber.setAttribute('value', GM_getValue("phoneNumber") != undefined ? GM_getValue("phoneNumber") : '');
phoneNumber.setAttribute('tabindex','14');
autoTextArea.innerHTML += "<br/>";
autoTextArea.appendChild(textLabel);
autoTextArea.innerHTML += "(";
autoTextArea.appendChild(phoneArea);
autoTextArea.innerHTML += ")";
autoTextArea.appendChild(phonePrefix);
autoTextArea.innerHTML += "-";
autoTextArea.appendChild(phoneNumber);
delayDiv.appendChild(autoTextArea);
delayDiv.innerHTML += "<br/><br />";
// The area that displays how much time remains before the form is submitted.
var countdownArea = document.createElement("div");
countdownArea.setAttribute('id','countdown');
countdownArea.innerHTML = "Click to start countdown";
delayDiv.appendChild(countdownArea);
// Auto Check In button
var delayButton = document.createElement("input");
delayButton.setAttribute('id','delay-button');
delayButton.setAttribute('type','button');
delayButton.setAttribute('style','float: right; background-color: #FF3300; color: white');
delayButton.setAttribute('value','Auto Check In');
delayButton.addEventListener("click", beginDelay, true);
delayButton.setAttribute('tabindex','11');
delayDiv.appendChild(delayButton);
leftPanel.appendChild(delayDiv);
}
catch(e){
alert('An error has occurred: '+e.message);
}
}
///////////// SELECT PASSENGER PAGE ////////////////
//automatically select all passengers and submit the form
function autoPassengerPage()
{
try{
//find error notification
if(document.title == "Error")
return;
// Check all the check boxes.
var node_list = document.getElementsByTagName('input');
for (var i = 0; i < node_list.length; i++) {
var node = node_list[i];
if (node.getAttribute('type') == 'checkbox') {
node.checked = true;
}
}
//Click the print button
var button = document.getElementById("printDocumentsButton");
button.click();
}
catch(e){
alert('An error has occurred: '+e.message);
}
}
///////////// BOARDING DOC DELIVERY PAGE ////////////////
function autoTextBoardingDocs()
{
try{
//find error notification
if (document.title == "Error")
return;
//check the Text checkbox if it's there
var textCheckbox = document.getElementById("optionText");
if (textCheckbox == null || !GM_getValue("phoneArea") || !GM_getValue("phonePrefix") || !GM_getValue("phoneNumber"))
return;
textCheckbox.checked = "checked";
//fill the mobile number
var phoneArea = document.getElementById("phoneArea").value = GM_getValue( "phoneArea");
var phonePrefix = document.getElementById("phonePrefix").value = GM_getValue("phonePrefix");
var phoneNumber = document.getElementById("phoneNumber").value = GM_getValue("phoneNumber");
//Click the continue button
var button = document.getElementById("checkin_button");
button.click();
}
catch(e){
alert('An error has occurred: '+e.message);
}
}
//case of the select boarding pass page (regex match the url)
if(/selectPrintDocument/.test(document.location.href))
{
autoPassengerPage();
}
//case of the check in page
else if(/retrieveCheckinDoc/.test(document.location.href))
{
checkInPageFormEdit();
}
else if(/selectCheckinDocDelivery/.test(document.location.href))
{
autoTextBoardingDocs();
}
@csultan
Copy link

csultan commented Sep 24, 2017

Thanks for putting this together. I tried installing but get an error:
Error detail 1: lm7jMeg1QLS2NhST9FlX0Q : 79a5fa9c-941e-4085-a6c9-7bf7ebc92169 : 40461130109/23/2017 - 21:00:08
Seems like this would be really slick, so if you get a chance to let me knwo what I'm doing wrong, I'd really appreciate it. If not, no worries. Still looks like this was cool while it lasted.

@sheaway10
Copy link

I also tried installing and got the below error: :(
Error detail 1: GW7LGIbcSjyV-jyIvhECrA : e1310f27-f938-44ac-872e-36ed1f41e42e : 404611301

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment