From e12fe38168e74b8509adfb0a8ade39592ce4a9ff Mon Sep 17 00:00:00 2001 From: stupidcomputer Date: Thu, 11 Jul 2024 00:45:24 -0500 Subject: [PATCH] add a simple message fetching functionality --- .gitignore | 2 + groupme_sync/__init__.py | 0 groupme_sync/__main__.py | 14 +++++ groupme_sync/groupme.py | 131 +++++++++++++++++++++++++++++++++++++++ shell.nix | 13 ++++ 5 files changed, 160 insertions(+) create mode 100644 .gitignore create mode 100644 groupme_sync/__init__.py create mode 100644 groupme_sync/__main__.py create mode 100644 groupme_sync/groupme.py create mode 100644 shell.nix diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0fcc40a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +__pycache__/ +token \ No newline at end of file diff --git a/groupme_sync/__init__.py b/groupme_sync/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/groupme_sync/__main__.py b/groupme_sync/__main__.py new file mode 100644 index 0000000..e8b3fcd --- /dev/null +++ b/groupme_sync/__main__.py @@ -0,0 +1,14 @@ +from sys import argv + +from .groupme import GroupMe + +def main() -> None: + filename = argv[1] + with open(filename, "r") as file: + token = file.readlines()[0].rstrip() + + chats = GroupMe(token) + for message in chats: + print(message) + +main() \ No newline at end of file diff --git a/groupme_sync/groupme.py b/groupme_sync/groupme.py new file mode 100644 index 0000000..038f7cd --- /dev/null +++ b/groupme_sync/groupme.py @@ -0,0 +1,131 @@ +from dataclasses import dataclass +from typing import ClassVar, Any +from urllib.parse import urlencode +from time import sleep + +from requests import get + +@dataclass +class GroupMe: + """ + The class implementing a GroupMe api client. + + A very thin wrapper at best + """ + + http_api_url: ClassVar[str] = "https://api.groupme.com/v3" + api_token: str + latest_message_ids = {} + iteration_to_return = [] + + def _get(self, url: str, params: dict[str, str] = {}): + token_qs = {"token": self.api_token} + params = {**token_qs, **params} # combine the dicts + + url = "{}{}?{}".format(self.http_api_url, url, urlencode(params)) + + print(url) + + return get(url) + + def _update_latest(self, group_id: str, request: list) -> None: + """ + Update the latest messages dictionary with a list of JSON-encoded + message objects. It's the stuff you get from the /groups/{}/messages + endpoint. + """ + + try: + messages = request["messages"] + except KeyError: + return + + latest_message = 0 + latest_message_id = None + for message in messages: + created_at = int(message["created_at"]) + + if created_at > latest_message: + latest_message = created_at + latest_message_id = message["id"] + + if latest_message_id: + self.latest_message_ids[group_id] = latest_message_id + + @property + def groups(self): + r = self._get("/groups") + return r.json()["response"] + + @property + def chats(self): + r = self._get("/chats") + return r.json()["response"] + + @property + def grouplikes(self): + return self.groups + self.chats + + def get_messages_from_group(self, group_id: str): + r = self._get("/groups/{}/messages".format(group_id)) + r = r.json()["response"] + + self._update_latest(group_id, r) + return r + + def get_messages_from_group_after_message_id(self, group_id: str, message_id: str): + if not message_id: + return self.get_messages_from_group(group_id) + + r = self._get("/groups/{}/messages".format(group_id), {"since_id": message_id}) + if r.status_code == 304: # none updated yet + return { + "messages": [] + } + r = r.json()["response"] + + self._update_latest(group_id, r) + return r + + def get_new_messages_from_group(self, group_id: str): + return self.get_messages_from_group_after_message_id( + group_id, + self.latest_message_ids[group_id] + ) + + def get_all_new_messages(self): + messages = [] + for i in self.groups: + try: + last_message_id = self.latest_message_ids[i["id"]] + except KeyError: + last_message_id = None + + messages_to_append = self.get_messages_from_group_after_message_id(i["id"], last_message_id)["messages"] + for index, message in enumerate(messages_to_append): + messages_to_append[index]["group_name"] = i["name"] + + messages += messages_to_append + + return messages + + def __iter__(self): # iterate to get new messages + for group in self.groups: + # we don't want to return past messages + self.get_messages_from_group(group["id"]) + + return self + + def __next__(self): + # check if there's any messages on the stack + if self.iteration_to_return: + return self.iteration_to_return.pop() + + # else scan for new messages + new = [] + while not new: + sleep(10) + new = self.get_all_new_messages() + + self.iteration_to_return = new + return self.iteration_to_return.pop() \ No newline at end of file diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..f1a788f --- /dev/null +++ b/shell.nix @@ -0,0 +1,13 @@ +{ pkgs ? import {} }: + +let + my-python-packages = ps: with ps; [ + requests + websockets + ]; +in + pkgs.mkShell { + packages = [ + (pkgs.python3.withPackages my-python-packages) + ]; + } \ No newline at end of file