1
0
mirror of https://github.com/pyro2927/SouthwestCheckin.git synced 2025-12-06 01:13:19 +00:00
Files
SouthwestCheckin/checkin.py
2017-12-28 18:37:57 -08:00

125 lines
4.8 KiB
Python
Executable File

#!/usr/bin/env python
"""Southwest Checkin.
Usage:
checkin.py CONFIRMATION_NUMBER FIRST_NAME LAST_NAME [-v | --verbose]
checkin.py (-h | --help)
checkin.py --version
Options:
-h --help Show this screen.
-v --verbose Show debugging information.
--version Show version.
"""
from datetime import datetime
from datetime import timedelta
from dateutil.parser import parse
from docopt import docopt
from geopy import geocoders
from math import trunc
from tzlocal import get_localzone
import pytz
import requests
import sys
import time
API_KEY = 'l7xxb3dcccc4a5674bada48fc6fcf0946bc8'
USER_EXPERIENCE_KEY = 'AAAA3198-4545-46F4-9A05-BB3E868BEFF5'
BASE_URL = 'https://mobile.southwest.com/api/'
CHECKIN_EARLY_SECONDS = 5
CHECKIN_INTERVAL_SECONDS = 0.25
MAX_ATTEMPTS = 40
# Pulled from proxying the Southwest iOS App
headers = {'Host': 'mobile.southwest.com', 'Content-Type': 'application/json', 'X-API-Key': API_KEY, 'X-User-Experience-Id': USER_EXPERIENCE_KEY, 'Accept': '*/*'}
# You might ask yourself, "Why the hell does this exist?"
# Basically, there sometimes appears a "hiccup" in Southwest where things
# aren't exactly available 24-hours before, so we try a few times
def safe_request(url, body=None):
attempts = 0
while True:
if body is not None:
r = requests.post(url, headers=headers, json=body)
else:
r = requests.get(url, headers=headers)
data = r.json()
if 'httpStatusCode' in data and data['httpStatusCode'] in ['NOT_FOUND', 'BAD_REQUEST', 'FORBIDDEN']:
attempts += 1
print(data['message'])
if attempts > MAX_ATTEMPTS:
sys.exit("Unable to get data, killing self")
time.sleep(CHECKIN_INTERVAL_SECONDS)
continue
return data
def lookup_existing_reservation(number, first, last):
# Find our existing record
url = "{}mobile-misc/v1/mobile-misc/page/view-reservation/{}?first-name={}&last-name={}".format(BASE_URL, number, first, last)
data = safe_request(url)
return data['viewReservationViewPage']
def get_checkin_data(number, first, last):
url = "{}mobile-air-operations/v1/mobile-air-operations/page/check-in/{}?first-name={}&last-name={}".format(BASE_URL, number, first, last)
data = safe_request(url)
return data['checkInViewReservationPage']
def checkin(number, first, last):
data = get_checkin_data(number, first, last)
info_needed = data['_links']['checkIn']
url = "{}mobile-air-operations{}".format(BASE_URL, info_needed['href'])
print("Attempting check-in...")
return safe_request(url, info_needed['body'])['checkInConfirmationPage']
def schedule_checkin(flight_time, number, first, last):
checkin_time = flight_time - timedelta(days=1)
current_time = datetime.now(pytz.utc).astimezone(get_localzone())
# check to see if we need to sleep until 24 hours before flight
if checkin_time > current_time:
# calculate duration to sleep
delta = (checkin_time - current_time).total_seconds() - CHECKIN_EARLY_SECONDS
# pretty print our wait time
m, s = divmod(delta, 60)
h, m = divmod(m, 60)
print("Too early to check in. Waiting {} hours, {} minutes, {} seconds".format(trunc(h), trunc(m), s))
time.sleep(delta)
data = checkin(number, first, last)
for flight in data['flights']:
for doc in flight['passengers']:
print("{} got {}{}!".format(doc['name'], doc['boardingGroup'], doc['boardingPosition']))
def auto_checkin(reservation_number, first_name, last_name):
body = lookup_existing_reservation(reservation_number, first_name, last_name)
# setup a geocoder
# needed since Southwest no longer includes TZ information in reservations
g = geocoders.GoogleV3()
# Get our local current time
now = datetime.now(pytz.utc).astimezone(get_localzone())
tomorrow = now + timedelta(days=1)
# find all eligible legs for checkin
for leg in body['bounds']:
# calculate departure for this leg
airport = "{}, {}".format(leg['departureAirport']['name'], leg['departureAirport']['state'])
takeoff = "{} {}".format(leg['departureDate'], leg['departureTime'])
point = g.geocode(airport).point
airport_tz = g.timezone(point)
date = airport_tz.localize(datetime.strptime(takeoff, '%Y-%m-%d %H:%M'))
if date > now:
# found a flight for checkin!
print("Flight information found, departing {} at {}".format(airport, date.strftime('%b %d %I:%M%p')))
schedule_checkin(date, reservation_number, first_name, last_name)
if __name__ == '__main__':
arguments = docopt(__doc__, version='Southwest Checkin 0.2')
# work work
reservation_number = arguments['CONFIRMATION_NUMBER']
first_name = arguments['FIRST_NAME']
last_name = arguments['LAST_NAME']
auto_checkin(reservation_number, first_name, last_name)