#!/usr/bin/env python3 # Copyright (C) 2019 James E. Blair # # This file is part of Email-assistant. # # Email-assistant is free software: you can redistribute it and/or # modify it under the terms of the GNU Affero General Public License # as published by the Free Software Foundation, either version 3 of # the License, or (at your option) any later version. # # Email-assistant 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 Email-assistant. If not, see # . import re import logging import hashlib from bs4 import BeautifulSoup import dateutil.parser import dateutil.tz import inscriptis import vobject from email_assistant import iata from email_assistant import plugin def parse_dep_arr(dep_date, flight_date, flight_time, code): flight_year = dep_date.year tz = iata.tzmap[code] flight_time = dateutil.parser.parse(flight_date + ' ' + flight_time) if flight_time.year < flight_year: flight_time.replace(year=flight_year) flight_time = flight_time.replace(tzinfo=dateutil.tz.gettz(tz)) return flight_time class Plugin(plugin.Plugin): name = 'delta' def match(self, msg): if ('DeltaAirLines@e.delta.com' in msg['From'] and 'Your Flight Receipt' in msg['Subject']): return True def get_events(self, msg): events = [] for part in msg.walk(): if part.get_content_type() == 'text/html': soup = BeautifulSoup(part.get_payload(decode=True), 'html.parser') flights = [] flight = None dep_date = None start = soup.find(string=re.compile('FLIGHT INFO STARTS')) for row in start.parent.find_all('tr', recursive=False): row = [x.strip() for x in row.strings if x.strip()] if len(row) == 3 and row[1:] == ['DEPART', 'ARRIVE']: dep_date = row[0] continue if dep_date is None: continue f = { 'dep_date': dep_date, #'num': row[0], #'cabin': row[1], 'dep_city': row[2], 'dep_time': row[3], 'arr_city': row[4], 'arr_time': row[5]} if len(row) > 6: f['arr_date'] = row[6].replace('*', '').strip() else: f['arr_date'] = dep_date flights.append(f) start = soup.find(string=re.compile('Checked Bag Allowance')) while start.name != 'table': start = start.parent start = start.parent while start.name != 'table': start = start.parent index = 0 for row in start.find_all('tr', recursive=False): row = [x.strip() for x in row.strings if x.strip()] if len(row) != 3: continue try: dep_date = dateutil.parser.parse(row[0]) except Exception: continue f = flights[index] f['dep_code'] = row[1].split()[-1].strip() f['arr_code'] = row[2].split()[-1].strip() f['dep_dt'] = parse_dep_arr( dep_date, f['dep_date'], f['dep_time'], f['dep_code']) f['arr_dt'] = parse_dep_arr( dep_date, f['arr_date'], f['arr_time'], f['arr_code']) index += 1 for f in flights: self.log.debug('%s %s %s %s', f['dep_dt'], f['arr_dt'], f['dep_code'], f['arr_code']) cal = vobject.iCalendar() event = cal.add('vevent') event.add('dtstart').value = f['dep_dt'] event.add('dtend').value = f['arr_dt'] summary = "Flight from %s to %s" % (f['dep_code'], f['arr_code']) event.add('summary').value = summary text = inscriptis.get_text(str(soup)) text = re.sub(r'([^ ]+)\s*\n', '\\1\n', text) event.add('description').value = text event.add('location').value = "%s airport" % (f['dep_code'],) uid = hashlib.sha1((str(f['dep_time']) + summary).encode('utf8')).hexdigest() event.add('uid').value = uid events.append(cal) return events