From a270bc3296ebb30088766b42e676191eae6bf0dc Mon Sep 17 00:00:00 2001 From: MrRaph_ Date: Tue, 3 Dec 2024 11:44:43 +0100 Subject: [PATCH] v0.1.0 --- base-config.yaml | 1 + hoarder.py | 210 ++++++++++++++++++++++++++++++++++++++++------- maubot.yaml | 2 +- 3 files changed, 182 insertions(+), 31 deletions(-) diff --git a/base-config.yaml b/base-config.yaml index 64c2165..3408a8b 100644 --- a/base-config.yaml +++ b/base-config.yaml @@ -1,3 +1,4 @@ hoarder_url: "http://hoarder.local" hoarder_api_key: "votre_cle_api" +hoarder_list_name: "list_name" command_prefix: hoarder \ No newline at end of file diff --git a/hoarder.py b/hoarder.py index f9571e1..26b76e2 100644 --- a/hoarder.py +++ b/hoarder.py @@ -4,13 +4,13 @@ from typing import Type from mautrix.util.config import BaseProxyConfig, ConfigUpdateHelper from maubot import Plugin, MessageEvent from maubot.handlers import event, command -from datetime import datetime # Setup config file class Config(BaseProxyConfig): def do_update(self, helper: ConfigUpdateHelper) -> None: helper.copy("hoarder_url") helper.copy("hoarder_api_key") + helper.copy("hoarder_list_name") helper.copy("command_prefix") class HoarderForwarder(Plugin): @@ -22,35 +22,54 @@ class HoarderForwarder(Plugin): def get_config_class(cls) -> Type[BaseProxyConfig]: return Config - async def get_page_title(self, url: str) -> str: - """Récupère le titre de la page web à partir de l'URL sans utiliser BeautifulSoup.""" - try: - async with aiohttp.ClientSession() as session: - async with session.get(url) as response: - if response.status == 200: - html = await response.text() - # Rechercher la balise - match = re.search(r"<title>(.*?)", html, re.IGNORECASE | re.DOTALL) - if match: - return match.group(1).strip() - else: - return "Sans titre" - else: - return "Titre introuvable" - except Exception as e: - print(f"Erreur lors de la récupération du titre: {e}") - return "Erreur" - - @command.new( - "hoarder", - ) + async def send_message(evt: MessageEvent, message: str, formatted: bool = False, in_thread: bool = False): + """ + Envoie un message en réponse à un événement Matrix, avec support des threads. + + Args: + evt (MessageEvent): L'événement de type message auquel répondre. + message (str): Le texte du message à envoyer. + formatted (bool): Si True, le message sera envoyé en tant que texte formaté (HTML). + in_thread (bool): Si True, le message sera envoyé en tant que réponse dans un thread. + """ + content = { + "body": message, + "msgtype": "m.text" if not formatted else "m.notice", + } + + if formatted: + content["formatted_body"] = message + content["format"] = "org.matrix.custom.html" + + if in_thread: + # Ajouter des métadonnées pour créer un thread + content["m.relates_to"] = { + "rel_type": "m.thread", + "event_id": evt.event_id # ID de l'événement original pour le thread + } + + # Envoyer le message + await evt.client.send_message( + room_id=evt.room_id, # Envoyer dans la même salle + content=content + ) + + @command.new("hoarder", require_subcommand=True, help="Commandes pour gérer Hoarder.") + async def base_command(self, evt: MessageEvent): + """Commande principale pour Hoarder (placeholder).""" + #await evt.reply("Utilisez `!hoarder help` pour voir les commandes disponibles.") + pass + @base_command.subcommand("bookmark", help="Ajoute un bookmark à Hoarder.") @command.argument("url", pass_raw=True, required=True) - async def send_to_hoarder(self, evt: MessageEvent, url: str) -> None: + async def bookmark(self, evt: MessageEvent, url: str) -> None: await evt.mark_read() - hoarder_url = self.config["hoarder_url"] + '/api/trpc/bookmarks.createBookmark' + hoarder_list = await self.ensure_list_exists(evt, self.config["hoarder_list_name"]) + + hoarder_url = self.config["hoarder_url"] api_key = self.config["hoarder_api_key"] + create_endpoint = f"{hoarder_url}/api/trpc/bookmarks.createBookmark" self.log.info(hoarder_url) #title = await self.get_page_title(url) # Récupère le titre de la page @@ -73,10 +92,141 @@ class HoarderForwarder(Plugin): try: async with aiohttp.ClientSession() as session: - async with session.post(hoarder_url, json=payload, headers=headers) as response: - if response.status == 201: - self.log.info(f"URL envoyée avec succès à Hoarder : {url}") + async with session.post(create_endpoint, json=payload, headers=headers) as response: + if response.status == 200 or response.status == 201 or response.status == 204: + data = await response.json() + bookmark_id = data[0]["result"]["data"]["json"]["id"] + await self.send_message(evt, f"Bookmark créé avec succès : {bookmark_id}", in_thread=True) + self.add_bookmark_to_list(bookmark_id, hoarder_list) + return bookmark_id else: - self.log.error(f"Échec de l'envoi de l'URL à Hoarder : {response.status}") + await self.send_message(evt, f"Erreur lors de la création du bookmark : {response.status}", in_thread=True) + print(await response.text()) except Exception as e: - self.log.exception(f"Erreur lors de l'envoi de l'URL à Hoarder : {e}") + await self.send_message(evt, f"Erreur lors de la création du bookmark : {e}", in_thread=True) + return None + + async def get_all_lists(self, evt: MessageEvent): + """Récupère la liste des listes sur Hoarder.""" + hoarder_url = self.config["hoarder_url"] + api_key = self.config["hoarder_api_key"] + list_endpoint = f"{hoarder_url}/api/v1/lists" + + headers = { + "Authorization": f"Bearer {api_key}", + "Content-Type": "application/json", + "Accept": "application/json", + } + + try: + async with aiohttp.ClientSession() as session: + async with session.get(list_endpoint, headers=headers) as response: + if response.status == 200: + data = await response.json() + return data.get("lists", []) + else: + await self.send_message(evt, f"Erreur lors de la récupération des listes : {response.status}", in_thread=True) + return [] + except Exception as e: + await self.send_message(evt, f"Erreur lors de la récupération des listes : {e}", in_thread=True) + return [] + + async def find_list_by_name(self, evt: MessageEvent, name: str) -> str: + """Vérifie si une liste existe et retourne son ID si elle est trouvée.""" + lists = await self.get_all_lists(evt) + for lst in lists: + if lst["name"] == name: + await self.send_message(evt, f"Liste trouvée : {name} (ID : {lst['id']})", in_thread=True) + return lst["id"] + await self.send_message(evt, f"Aucune liste trouvée avec le nom : {name}", in_thread=True) + return None + + async def create_list(self, evt: MessageEvent, name: str) -> str: + """Crée une nouvelle liste avec le nom donné et retourne son ID.""" + hoarder_url = self.config["hoarder_url"] + api_key = self.config["hoarder_api_key"] + create_endpoint = f"{hoarder_url}/api/trpc/lists.createList" + + headers = { + "Authorization": f"Bearer {api_key}", + "Content-Type": "application/json", + "Accept": "application/json", + } + + payload = { + "json": { + "icon": "💬", # Icône par défaut + "name": name + } + } + + try: + async with aiohttp.ClientSession() as session: + async with session.post(create_endpoint, json=payload, headers=headers) as response: + if response.status == 200 or response.status == 201 or response.status == 204: + data = await response.json() + list_id = data["result"]["data"]["json"]["id"] + await self.send_message(evt, f"Liste créée avec succès : {name} (ID : {list_id})", in_thread=True) + return list_id + else: + await self.send_message(evt, f"Erreur lors de la création de la liste : {response.status}", in_thread=True) + return None + except Exception as e: + await self.send_message(evt, f"Erreur lors de la création de la liste : {e}", in_thread=True) + return None + + async def ensure_list_exists(self, evt: MessageEvent, name: str) -> str: + """Vérifie si une liste existe, sinon la crée.""" + list_id = await self.find_list_by_name(evt, name) + if list_id is None: + await self.send_message(evt, f"La liste '{name}' n\'existe pas, création en cours...", in_thread=True) + list_id = await self.create_list(evt, name) + return list_id + + async def add_bookmark_to_list(self, evt: MessageEvent, bookmark_id: str): + """Ajoute un bookmark à une liste donnée.""" + hoarder_url = self.config["hoarder_url"] + api_key = self.config["hoarder_api_key"] + + list_id = await self.ensure_list_exists(evt, self.config["hoarder_list_name"]) + add_to_list_endpoint = f"{hoarder_url}/api/v1/lists/{list_id}/bookmarks" + + headers = { + "Authorization": f"Bearer {api_key}", + "Content-Type": "application/json", + "Accept": "application/json", + } + + payload = { + "bookmarkId": bookmark_id + } + + try: + async with aiohttp.ClientSession() as session: + async with session.put(add_to_list_endpoint, headers=headers) as response: + if response.status == 200 or response.status == 201 or response.status == 204: + await self.send_message(evt, f"Bookmark {bookmark_id} ajouté à la liste {list_id} avec succès.", in_thread=True) + return True + else: + await self.send_message(evt, f"Erreur lors de l'ajout à la liste : {response.status}", in_thread=True) + await self.send_message(evt, await response.text(), in_thread=True) + return False + except Exception as e: + await self.send_message(evt, f"Erreur lors de l'ajout du bookmark à la liste : {e}", in_thread=True) + return False + + @base_command.subcommand("help", help="Affiche l'aide pour les commandes Hoarder.") + async def hoarder_help(self, evt: MessageEvent): + """Affiche un message d'aide pour les commandes Hoarder.""" + help_message = ( + "💬 **Commandes disponibles pour Hoarder Bot** 💬\n" + "- `!hoarder bookmark ` : Ajoute le lien spécifié à votre liste Hoarder.\n" + "- `!hoarder help` : Affiche ce message d'aide.\n\n" + "⚙️ **Configuration** :\n" + "Assurez-vous que l'URL de base de votre installation d'Hoarder est définie dans la configuration sous `hoarder_url`.\n\n" + "Assurez-vous que la clef API d'Hoarder est définie dans la configuration sous `hoarder_api_key`.\n\n" + "Assurez-vous que la liste cible est définie dans la configuration sous `hoarder_list_name`.\n\n" + "📘 **Documentation supplémentaire** :\n" + "Consultez les guides sur [Hoarder](https://docs.hoarder.app)." + ) + await evt.reply(help_message) \ No newline at end of file diff --git a/maubot.yaml b/maubot.yaml index a4f8e09..10be18e 100644 --- a/maubot.yaml +++ b/maubot.yaml @@ -8,7 +8,7 @@ maubot: 0.1.0 id: fr.mrraph.hoarder-bot # A PEP 440 compliant version string. -version: 0.0.2 +version: 0.1.0 # The SPDX license identifier for the plugin. https://spdx.org/licenses/ # Optional, assumes all rights reserved if omitted.