def process_alert(config, plane): pf.log(f"Building Discord alert for {plane['icao']}") dbinfo = pf.get_plane_info(plane['icao']) fa_link = pf.flightaware_link(plane['icao'], plane['tail_num']) title = f"Plane Alert - {plane['plane_desc']}" color = 0xf2e718 squawk = plane.get('squawk', "") if pf.is_emergency(squawk): title = f"Air Emergency! {plane['tail_num']} squawked {squawk}" color = 0xff0000 description = f"" if plane.get('owner', "") != "": description = f"Operated by **{plane.get('owner')}**" location = get_readable_location(plane) if location == "": # No location info, just embed ADSBX link description += f"\nTrack on [ADSB Exchange]({plane['adsbx_url']})" else: description += f"\nSeen near [**{location}**]({plane['adsbx_url']})" webhook, embed = pf.discord.build(config["DISCORD_FEEDER_NAME"], config["PA_DISCORD_WEBHOOKS"], title, description, color=color) pf.attach_media(config, "PA", dbinfo, webhook, embed) # Attach data fields pf.discord.field(embed, "ICAO", plane['icao']) pf.discord.field(embed, "Tail Number", f"[{plane['tail_num']}]({fa_link})") if plane.get('callsign', "") != "": pf.discord.field(embed, "Callsign", plane['callsign']) if plane.get('time', "") != "": pf.discord.field(embed, "First Seen", f"{plane['time']} {pf.get_timezone_str()}") if dbinfo.get('category', "") != "": pf.discord.field(embed, "Category", dbinfo['category']) if dbinfo.get('tag1', "") != "": pf.discord.field(embed, "Tag", dbinfo['tag1']) if dbinfo.get('tag2', "") != "": pf.discord.field(embed, "Tag", dbinfo['tag2']) if dbinfo.get('tag3', "") != "": pf.discord.field(embed, "Tag", dbinfo['tag3']) if dbinfo.get('link', "") != "": pf.discord.field(embed, "Link", f"[Learn More]({dbinfo['link']})") # Send the message pf.send(webhook, config)
def get_readable_location(plane): loc = geolocator.reverse("{}, {}".format(plane['lat'], plane['long']), exactly_one=True, language='en') if loc is None: pf.log("[error] No geolocation information return for '{}, {}'".format( plane['lat'], plane['long'])) return "" adr = loc.raw.get('address', {}) print("Location data:") print(adr) village = adr.get('village', "") municipality = adr.get('municipality', "") city = adr.get('city', "") town = adr.get('town', "") country = adr.get('country', "") country_code = adr.get('country_code', "").upper() place = city or town or village or municipality if country_code == "US": state = pf.get_us_state_abbrev(adr.get('state', "")) return f"{place}, {state}, {country_code}" else: return f"{place}, {country}"
def main(): pf.init_log("plane-alert/send-discord-alert") # Load configuration config = pf.load_config() if len(sys.argv) != 2: print( "No input record passed\n\tUsage: ./send-discord-alert.py <csvline>" ) sys.exit(1) # CSV format is: # ICAO,TailNr,Owner,PlaneDescription,date,time,lat,lon,callsign,adsbx_url,squawk row = sys.argv[1].split(',') alert = { "icao": row[0].strip(), "tail_num": row[1].strip(), "owner": row[2].strip(), "plane_desc": row[3], "date": row[4], "time": row[5], "lat": row[6], "long": row[7], "callsign": row[8].strip(), "adsbx_url": row[9], "squawk": row[10] if len(row) > 10 else "", } # Process file and send alerts process_alert(config, alert) pf.log(f"Done sending Discord alert for {alert['icao']}")
def main(): pf.init_log("planefence/send-discord-alert") # Load configuration config = pf.load_config() if len(sys.argv) < 2: print("No input file passed\n\tUsage: ./send-discord-alert.py <csvline> <airline?>") sys.exit(1) record = sys.argv[1].split(',') alert = { "icao": record[0], "tail_num": record[1].lstrip("@"), "first_seen": record[2], "last_seen": record[3], "alt": int(record[4]) if record[4].isdigit() else 0, "min_dist": record[5], "adsbx_url": record[6], "airline": sys.argv[2] if len(sys.argv) == 3 else "" } process_alert(config, alert) pf.log(f"Done sending alerts to Discord")
def process_alert(config, plane): pf.log(f"Building discord message for {plane['icao']}") # Gather up some info for the message name = plane['tail_num'] if plane["airline"] != "": name = plane['airline'] fa_link = pf.flightaware_link(plane['icao'], plane['tail_num']) webhook, embed = pf.discord.build( config["DISCORD_FEEDER_NAME"], config["PF_DISCORD_WEBHOOKS"], f"{name} is overhead at {pf.altitude_str(config, plane['alt'])}", f"[Track on ADS-B Exchange]({plane['adsbx_url']})") pf.attach_media(config, "PF", plane, webhook, embed) # Attach data fields pf.discord.field(embed, "ICAO", plane['icao']) pf.discord.field(embed, "Tail Number", f"[{plane['tail_num']}]({fa_link})") pf.discord.field(embed, "Distance", f"{plane['min_dist']}{pf.distance_unit(config)}") time_seen = plane['first_seen'].split(" ")[1] pf.discord.field(embed, "First Seen", f"{time_seen} {pf.get_timezone_str()}") # Send the message pf.send(webhook, config)
def load_alerts(alerts_file): alerts = [] with open(alerts_file) as csvfile: reader = csv.reader(csvfile) for row in reader: # Format: # ICAO,Registration,FirstSeen,LastSeen,Alt,MinDist,adsbx_url,,,,,,tweet_url # Fields after adsbx_url are optional # If FlightNum has an @ prefixing the tail number it was tweeted alert = { "icao": row[0].strip(), "tail_num": row[1].strip(), "first_seen": row[2], "last_seen": row[3], "alt": row[4], "min_dist": row[5], "adsbx_url": row[6], } alerts.append(alert) pf.log(f"Loaded {len(alerts)} Planefence alerts") return alerts