-
-
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?