From 5240b434a3f71490641086f467c0bf5dcc9ffe70 Mon Sep 17 00:00:00 2001 From: Carlos Sanchez Date: Mon, 1 May 2023 11:21:45 -0400 Subject: [PATCH] Searching complete? --- contentapi.py | 3 ++- main.py | 48 ++++++++++++++++++++++++++++++++++++---------- setup.bat | 2 +- test_contentapi.py | 24 +++++++++++++++++++++-- 4 files changed, 63 insertions(+), 14 deletions(-) diff --git a/contentapi.py b/contentapi.py index d0f7855..30d3a2a 100644 --- a/contentapi.py +++ b/contentapi.py @@ -104,10 +104,11 @@ class ApiContext: def api_status(self): return self.get("status") + # Access the raw search endpoint of the API (you must construct the special contentapi request yourself!) def search(self, requests): return self.post("request", requests) - # A very basic search for outputting to the console. Many assumptions are made! + # A very basic search for outputting to the console. Constructs the contentapi search request for you: many assumptions are made! def basic_search(self, searchterm, limit = 0): return self.search({ "values": { diff --git a/main.py b/main.py index bd58cc9..b95b562 100644 --- a/main.py +++ b/main.py @@ -9,6 +9,7 @@ import re import toml import readchar import websocket +import win_unicode_console from collections import OrderedDict from colorama import Fore, Back, Style, init as colorama_init @@ -17,6 +18,7 @@ import contentapi import myutils CONFIGFILE="config.toml" +MAXTITLE=25 # The entire config object with all defaults config = { @@ -42,6 +44,7 @@ commands = OrderedDict([ def main(): print("Program start") + win_unicode_console.enable() colorama_init() # colorama init load_or_create_global_config() @@ -66,12 +69,22 @@ def main(): ws = websocket.WebSocketApp(context.websocket_endpoint()) # Might as well reuse the websocket object for my websocket context data (oops, is that bad?) + ws.context = context ws.user_info = context.user_me() - ws.current_room = config["default_room"] - ws.current_room_data = False ws.pause_output = False # Whether all output from the websocket should be paused (including status updates) ws.output_buffer = [] # Individual print statements buffered from output. ws.main_config = config + ws.current_room = 0 + ws.current_room_data = False + + # Go out and get the default room if one was provided. + if config["default_room"]: + try: + ws.current_room_data = context.get_by_id("content", config["default_room"]) + ws.current_room = config["default_room"] + printr(Fore.GREEN + "Found default room %s" % ws.current_room_data["name"]) + except Exception as ex: + printr(Fore.YELLOW + "Error searching for default room %d: %s" % (config["default_room"], ex)) # set the callback functions ws.on_open = ws_onopen @@ -93,11 +106,10 @@ def ws_onopen(ws): def main_loop(): printstatus = True - print(Fore.GREEN + Style.BRIGHT + "\n-- Connected to live updates! --" + Style.RESET_ALL) + printr(Fore.GREEN + Style.BRIGHT + "\n-- Connected to live updates! --") - # TODO: check to see if the id is a valid room if not ws.current_room: - print(Fore.YELLOW + "* You are not connected to any room! Press 'S' to search for a room! *" + Style.RESET_ALL) + printr(Fore.YELLOW + "* You are not connected to any room! Press 'S' to search for a room! *") # The infinite input loop! Or something! while True: @@ -176,10 +188,22 @@ def search(ws): return match = re.match(r'#(\d+)', searchterm) if match: - digits = int(match.group(1)) - - num = int(digits) - print(num) + roomid = int(match.group(1)) + try: + ws.current_room_data = ws.context.get_by_id("content", roomid) + ws.current_room = roomid + print(Fore.GREEN + "Set room to %s" % ws.current_room_data["name"] + Style.RESET_ALL) + return + except Exception as ex: + print(Fore.RED + "Couldn't find room with id %d" % roomid + Style.RESET_ALL) + elif searchterm: + # Go search for rooms and display them + result = ws.context.basic_search(searchterm)["objects"]["content"] + if len(result): + for content in result: + printr(Style.BRIGHT + "%7s" % ("#%d" % content["id"]) + Style.RESET_ALL + " - %s" % content["name"]) + else: + printr(Style.DIM + " -- No results -- ") # Either pull the token from a file, or get the login from the command # line if that doesn't work. WILL test your token against the real API @@ -218,11 +242,15 @@ def print_statusline(ws): # if ws_context.connected: bg = Back.GREEN else: bg = Back.RED if ws.current_room: name = ws.current_room_data["name"] - room = "'" + (name[:12] + '...' if len(name) > 15 else name) + "'" + room = "'" + (name[:(MAXTITLE - 3)] + '...' if len(name) > MAXTITLE else name) + "'" else: room = Fore.RED + Style.DIM + "NONE" + Style.NORMAL + Fore.BLACK print(Back.GREEN + Fore.BLACK + "\n " + ws.user_info["username"] + " - " + room + " CTRL: h s g u i q " + Style.RESET_ALL) +# Print and then reset the style +def printr(msg): + print(msg + Style.RESET_ALL) + # Because python reasons if __name__ == "__main__": main() \ No newline at end of file diff --git a/setup.bat b/setup.bat index 1c1d0b5..890f8b0 100644 --- a/setup.bat +++ b/setup.bat @@ -4,7 +4,7 @@ REM Change python whatever set pyexe=python34\python.exe REM The list of packages this thing requires (maybe?) -set packages=requests colorama==0.4.1 websocket-client toml readchar +set packages=requests colorama==0.4.1 websocket-client toml readchar win-unicode-console REM Actually install the packages... maybe? %pyexe% -m pip install %packages% \ No newline at end of file diff --git a/test_contentapi.py b/test_contentapi.py index 556ec03..4be1451 100644 --- a/test_contentapi.py +++ b/test_contentapi.py @@ -6,12 +6,14 @@ import logging class TestContentapi(unittest.TestCase): def setUp(self) -> None: - # MAYBE change this some time? + # MAYBE change all these some time? Should connect to a local instance!! self.api = contentapi.ApiContext("https://oboy.smilebasicsource.com/api", logging) + self.known_content_id = 384 + self.known_name = "Megathread" def test_apistatus(self): result = self.api.api_status() - self.assertTrue("version" in result) + self.assertIn("version", result) def test_is_token_valid_none(self): self.assertFalse(self.api.is_token_valid()) @@ -19,7 +21,25 @@ class TestContentapi(unittest.TestCase): def test_is_token_valid_garbage(self): self.api.token = "literalgarbage" self.assertFalse(self.api.is_token_valid()) + + def test_get_by_id_notfound(self): + try: + self.api.get_by_id("content", 0) + except contentapi.NotFoundError: + return + self.assertFalse(True, "Didn't throw expected exception!") + + def test_get_by_id_known(self): + result = self.api.get_by_id("content", self.known_content_id) + self.assertIn("id", result) + self.assertEqual(result["id"], self.known_content_id) + + def test_basic_search(self): + result = self.api.basic_search(self.known_name) + self.assertIn("content", result["objects"]) + self.assertTrue(len(result["objects"]["content"]) >= 1) + self.assertTrue(any(self.known_name in item["name"] for item in result["objects"]["content"])) if __name__ == '__main__': unittest.main() \ No newline at end of file