From 034e923bb7a68885facc1eb1e57388bdf6fc12e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rnar=20Kaarevik?= Date: Thu, 12 Dec 2024 23:07:32 +0100 Subject: [PATCH 1/3] extracted atb api query to function --- crystal_orb.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/crystal_orb.py b/crystal_orb.py index b4325e2..a26c32d 100644 --- a/crystal_orb.py +++ b/crystal_orb.py @@ -13,6 +13,9 @@ STOP_PLACES = { "hesthagen": "41620" } +def get_departures(stop_place: str, atb_api_url: str = ATB_API_URL): + return requests.get(atb_api_url + stop_place).json()["departures"] + def format_departure(departure_dict: dict) -> str: """Formats the json supplied by mpolden's atb api to a single line of text quickly summarizing the scheduled bus. @@ -39,14 +42,17 @@ def write_to_socket(s: str, mpv_socket) -> None: if __name__ == "__main__": - input_stop_place = sys.argv[1] + try: + input_stop_place = sys.argv[1] + except: + input_stop_place = "no input was given" + if input_stop_place in STOP_PLACES.keys(): active_stop_place = STOP_PLACES[input_stop_place] else: active_stop_place = STOP_PLACES["gløshaugen"] - r = requests.get(ATB_API_URL + active_stop_place) - departures = r.json()["departures"] + departures = get_departures(active_stop_place) sorted_departures = sorted(departures, key = lambda d: d["scheduledDepartureTime"]) # ensure mpv is running with the ipc-server socket set in MPV_SOCKET From 331d3bb608ebd6302a2feeafc40f45d72891bb6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rnar=20Kaarevik?= Date: Thu, 12 Dec 2024 23:11:20 +0100 Subject: [PATCH 2/3] cli for the crystal orb atb bus querier --- crystal_orb_cli.py | 158 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 crystal_orb_cli.py diff --git a/crystal_orb_cli.py b/crystal_orb_cli.py new file mode 100644 index 0000000..2b944e6 --- /dev/null +++ b/crystal_orb_cli.py @@ -0,0 +1,158 @@ +#!/usr/bin/python3 +import dataclasses +import sys +from datetime import datetime + +from crystal_orb import get_departures +from crystal_orb import STOP_PLACES + +""" +Ideas: +- If time is less than 15 min from now, time text turns red? + - Maybe far-away departures are faint? +- If realtime, then color green +- Different + +""" + +def pad(s, total_length, justification="l"): + if len(s) >= total_length: + return s[0:total_length] + else: + surplus = total_length - len(s) + out_str = " " * total_length + if justification == "l": + return s + " "*surplus + elif justification == "m": + return " "*(surplus//2) + s + " "*(surplus - surplus//2) + elif justification == "r": + return " "*surplus + s + else: + raise ValueError(f"Justification was {justification}, which is not l, m or r.") + +@dataclasses.dataclass +class Departure: + line: int + departure_time: datetime + destination: str + is_realtime: bool + towards_midtbyen: bool + + def __post_init__(self): + self.departure_time = datetime.fromisoformat(self.departure_time) + + def colorize(self): + out_str = "" + out_str += "\033[2;20;35m" + str(self.departure_time.time()) + "\033[0m" + out_str += ": " + out_str += pad(str(self.line), 4, justification="r") + out_str += " " + out_str += "\033[3;37m" + pad(self.destination, 35+19) + "\033[0m" + out_str += " (" + if self.is_realtime: out_str += "\033[0;32mR\033[0m" + else: out_str += " " + + out_str += ", " + if self.towards_midtbyen: out_str += "\033[0;32mTo \033[0m" + else: out_str += "\033[0;31mFrom\033[0m" + + out_str += ")" + return out_str + + +def get_departure_as_classes(stop_place: str): + departures = get_departures(STOP_PLACES[stop_place]) + departures = [ + Departure( + d["line"], + d["scheduledDepartureTime"], + d["destination"], + d["isRealtimeData"], + d["isGoingTowardsCentrum"]) + for d in departures + ] + return sorted(departures, key = lambda d: d.departure_time) + +def print_colorized_departures(stop_place: str): + departures = get_departure_as_classes(stop_place) + for dep in departures: + print(dep.colorize()) + +def print_help_info(): + print( +"""Help info for the crystal orb cli. +Possible commands: + : query the api for all busses from the given stop place +-h or --help : Show this screen +--list-stop-places : List the admissible stop places, + This is configured in the STOP_PLACES dict in crystal_orb.py""") + +if __name__ == "__main__": + args = sys.argv + # If no arguments are passed, we just print the default stop + if len(args) < 2: + print_colorized_departures("gløshaugen") + sys.exit(0) + + if "-h" in args or "--help" in args: + print_help_info() + sys.exit(0) + + # Values for control flow and processing on the available departures + stop_place = "gløshaugen" + bus_line = None + towards_city_center = None + take_one = False + + # Parse input arguments to the program + for i, arg in enumerate(args): + if i == 1 and arg[0] != "-": # First argument is taken as the stop place + stop_place = arg.lower() + elif arg == "--next": # Limits to only giving "the next bus" matching the query + take_one = True + elif arg == "-b" or arg == "--bus": # Limit to specific bus line + try: + bus_line = args[i+1] + except: + print("Bus line not supplied to -b or --bus.") + elif arg == "--list-stop-places" or arg == "-l": # Just print stop places + print("Admissible stop places:") + for place in STOP_PLACES.keys(): + print(f"\t{place}") + sys.exit() + elif arg == "-t" or arg == "--to": # Limit to buses going to town + towards_city_center = True + elif arg == "-f" or arg == "--from": # Limit to buses leaving town + towards_city_center = False + elif arg == "-s" or arg == "--stop": # Change stop + try: + stop_place = args[i+1].lower() + except: + print("Stop place not supplied to -s or --stop") + else: + pass + + # Arguments are parsed, we can execute the query + try: + deps = get_departure_as_classes(stop_place) + except: + print(f"Stop {stop_place} not admissible. Run --list-stop-places for help.") + sys.exit(0) + + if bus_line is not None: + deps = list(filter(lambda d: str(d.line) == bus_line, deps)) + if towards_city_center is not None: + if towards_city_center: + deps = list(filter(lambda d: d.towards_midtbyen, deps)) + else: + deps = list(filter(lambda d: not d.towards_midtbyen, deps)) + + if take_one: + print(deps[0].colorize()) + else: + for dep in deps: + print(dep.colorize()) + + sys.exit(0) + + From a07f58551d6130d1e2769f347527f6663fe21e48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rnar=20Kaarevik?= Date: Thu, 12 Dec 2024 23:16:43 +0100 Subject: [PATCH 3/3] updated short version of --next and fixed the help message --- crystal_orb_cli.py | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/crystal_orb_cli.py b/crystal_orb_cli.py index 2b944e6..2278f68 100644 --- a/crystal_orb_cli.py +++ b/crystal_orb_cli.py @@ -6,15 +6,6 @@ from datetime import datetime from crystal_orb import get_departures from crystal_orb import STOP_PLACES -""" -Ideas: -- If time is less than 15 min from now, time text turns red? - - Maybe far-away departures are faint? -- If realtime, then color green -- Different - -""" - def pad(s, total_length, justification="l"): if len(s) >= total_length: return s[0:total_length] @@ -82,10 +73,23 @@ def print_help_info(): print( """Help info for the crystal orb cli. Possible commands: - : query the api for all busses from the given stop place --h or --help : Show this screen ---list-stop-places : List the admissible stop places, - This is configured in the STOP_PLACES dict in crystal_orb.py""") + + query the api for all busses from the given stop place +-h or --help + Show this screen +-l or --list-stop-places + List the admissible stop places. + This is configured in the STOP_PLACES dict in crystal_orb.py +-n or --next + Limit the response to only the next bus matching the query +-b or --bus + Limit the response to only the supplied bus line +-s or --stop + Change the stop place to the supplied place +-t or --to + Limit the response to buses going into town +-f or --from + Limit the response to buses going away from town""") if __name__ == "__main__": args = sys.argv @@ -108,7 +112,7 @@ if __name__ == "__main__": for i, arg in enumerate(args): if i == 1 and arg[0] != "-": # First argument is taken as the stop place stop_place = arg.lower() - elif arg == "--next": # Limits to only giving "the next bus" matching the query + elif arg == "-n" or arg == "--next": # Limits to only giving "the next bus" matching the query take_one = True elif arg == "-b" or arg == "--bus": # Limit to specific bus line try: