from datetime import datetime, timedelta import pytz from bs4 import BeautifulSoup from alertproviders.http_alert_provider import HTTPAlertProvider from data.alert import Alert from data.sig_ref import SIGRef class BOTA(HTTPAlertProvider): """Alert provider for Beaches on the Air""" POLL_INTERVAL_SEC = 1800 ALERTS_URL = "https://www.beachesontheair.com/" def __init__(self, provider_config): super().__init__(provider_config, self.ALERTS_URL, self.POLL_INTERVAL_SEC) def _http_response_to_alerts(self, http_response): new_alerts = [] # Find the table of upcoming alerts bs = BeautifulSoup(http_response.content.decode(), features="lxml") if not bs.body: return new_alerts div = bs.body.find('div', attrs={'class': 'view-activations-public'}) if div: table = div.find('table', attrs={'class': 'views-table'}) if table: tbody = table.find('tbody') if not tbody: return new_alerts for row in tbody.find_all('tr'): cells = row.find_all('td') first_cell_anchor = cells[0].find('a') if len(cells) > 0 else None second_cell_anchor = cells[1].find('a') if len(cells) > 1 else None if not first_cell_anchor or not second_cell_anchor: continue first_cell_text = first_cell_anchor.get_text().strip() ref_name = first_cell_text.split(" by ")[0] dx_call = second_cell_anchor.get_text().strip().upper() # Get the date, dealing with the fact we get no year so have to figure out if it's last year or next year date_span = cells[2].find('span') if len(cells) > 2 else None if not date_span: continue date_text = date_span.get_text().strip() date_time = datetime.strptime(date_text, "%d %b - %H:%M UTC").replace(tzinfo=pytz.UTC) date_time = date_time.replace(year=datetime.now(pytz.UTC).year) # If this was more than a day ago, activation is actually next year if date_time < datetime.now(pytz.UTC) - timedelta(days=1): date_time = date_time.replace(year=datetime.now(pytz.UTC).year + 1) # Convert to our alert format alert = Alert(source=self.name, dx_calls=[dx_call], sig_refs=[SIGRef(id=ref_name, sig="BOTA")], start_time=date_time.timestamp(), is_dxpedition=False) new_alerts.append(alert) return new_alerts