-
-
Save trevormcclellan/59b78544f416edf65f2c to your computer and use it in GitHub Desktop.
// ==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(); | |
} | |
thanks so much, for some strange reason - having a problem getting the text with boarding pass to my cricket iphone. Works fine sending to my Verizon work iphone - but can't get cricket to work - tried 2 different crickets #s. any ideas?
Looks like Southwest recently updated their check-in page and this is no longer working. :(
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.
I also tried installing and got the below error: :(
Error detail 1: GW7LGIbcSjyV-jyIvhECrA : e1310f27-f938-44ac-872e-36ed1f41e42e : 404611301
I use Greasemonkey in Firefox to run this. A few months ago, it started to be that nothing happened when I click the "Set Start Time" button (it used to open a dialog where I would enter the time I wanted it to submit the information.) Did something change on the website that prevents that dialog from opening?