added matrix version of the bot
This commit is contained in:
6
matrix/.env
Normal file
6
matrix/.env
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
API_BASE_URL=<your directus API url>
|
||||||
|
BEARER_TOKEN=<your bearer token>
|
||||||
|
MATRIX_HOMESERVER=https://matrix.example.com
|
||||||
|
MATRIX_USER=@marketplacebaybot:matrix.example.com
|
||||||
|
MATRIX_PASSWORD=MyBotPassowrd
|
||||||
|
ALLOWED_ROOMS=#marketplacebay:matrix.example.com,#anotherroom:matrix.example.com,!sjahdfg2343646511:matrix.example.com # room IDs starting with ! are the internal IDs of the room
|
||||||
174
matrix/MTbot.py
Normal file
174
matrix/MTbot.py
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
import os
|
||||||
|
import requests
|
||||||
|
import base64
|
||||||
|
import re
|
||||||
|
import json
|
||||||
|
import asyncio
|
||||||
|
from datetime import datetime
|
||||||
|
from nio import AsyncClient, MatrixRoom, RoomMessageText, RoomMessageFormatted
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
# MATRIX DIRECTUS BOT
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
API_BASE_URL = os.getenv("API_BASE_URL") # Configure in .env
|
||||||
|
BEARER_TOKEN = os.getenv("BEARER_TOKEN") # Configure in .env
|
||||||
|
MATRIX_HOMESERVER = os.getenv("MATRIX_HOMESERVER") # Configure in .env
|
||||||
|
MATRIX_USER = os.getenv("MATRIX_USER") # Configure in .env
|
||||||
|
MATRIX_PASSWORD = os.getenv("MATRIX_PASSWORD") # Configure in .env
|
||||||
|
BOT_USER_ID = os.getenv("MATRIX_USER") # Use the bot's Matrix ID to ignore its own messages
|
||||||
|
ALLOWED_ROOMS = os.getenv("ALLOWED_ROOMS", "").split(",") # Comma-separated list of allowed room IDs
|
||||||
|
|
||||||
|
# UUID validation pattern
|
||||||
|
UUID_PATTERN = re.compile(r'^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$')
|
||||||
|
|
||||||
|
# In-memory search tracking
|
||||||
|
active_searches = {}
|
||||||
|
|
||||||
|
# Track bot startup time
|
||||||
|
BOT_START_TIME = datetime.now()
|
||||||
|
|
||||||
|
async def log_activity(message: str) -> None:
|
||||||
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
print(f"[{timestamp}] {message}")
|
||||||
|
|
||||||
|
async def send_response(client: AsyncClient, room_id: str, message: str) -> None:
|
||||||
|
await client.room_send(
|
||||||
|
room_id=room_id,
|
||||||
|
message_type="m.room.message",
|
||||||
|
content={
|
||||||
|
"msgtype": "m.text",
|
||||||
|
"body": message
|
||||||
|
}
|
||||||
|
)
|
||||||
|
await log_activity(f"Sent response: '{message}'")
|
||||||
|
|
||||||
|
async def process_message(client: AsyncClient, room: MatrixRoom, event: RoomMessageText) -> None:
|
||||||
|
# Ignore messages from the bot itself
|
||||||
|
if event.sender == BOT_USER_ID:
|
||||||
|
return
|
||||||
|
|
||||||
|
room_id = room.room_id
|
||||||
|
# Check if the room is allowed
|
||||||
|
if room_id not in ALLOWED_ROOMS:
|
||||||
|
await log_activity(f"Ignored message from unauthorized room: {room_id}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Ignore messages sent before the bot started
|
||||||
|
if event.server_timestamp / 1000 < BOT_START_TIME.timestamp():
|
||||||
|
await log_activity(f"Ignored old message from {room_id}")
|
||||||
|
return
|
||||||
|
|
||||||
|
user_message = event.body.strip().lower()
|
||||||
|
sender = event.sender
|
||||||
|
await log_activity(f"Received message from {sender} in {room_id}: '{user_message}'")
|
||||||
|
|
||||||
|
# Handle cancellation
|
||||||
|
if user_message in ['cancel', 'abort']:
|
||||||
|
active_searches.pop(room_id, None)
|
||||||
|
await send_response(client, room_id, "❌ Operation cancelled. You can start a new search.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check if room has an active search
|
||||||
|
if room_id in active_searches:
|
||||||
|
try:
|
||||||
|
index = int(user_message) - 1
|
||||||
|
search_results = active_searches[room_id]
|
||||||
|
if 0 <= index < len(search_results):
|
||||||
|
selected_uuid = search_results[index]['uuid']
|
||||||
|
del active_searches[room_id] # Clear active search after selection
|
||||||
|
await process_uuid(client, room_id, selected_uuid)
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
await send_response(client, room_id, "❌ Invalid index. Please enter a valid number or type 'cancel' to abort.")
|
||||||
|
return
|
||||||
|
except ValueError:
|
||||||
|
await send_response(client, room_id, "❌ Please enter a valid number or type 'cancel' to abort.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check if input is UUID
|
||||||
|
if UUID_PATTERN.match(user_message):
|
||||||
|
await process_uuid(client, room_id, user_message)
|
||||||
|
else:
|
||||||
|
await perform_search(client, room_id, user_message)
|
||||||
|
|
||||||
|
async def perform_search(client: AsyncClient, room_id: str, query: str) -> None:
|
||||||
|
try:
|
||||||
|
headers = {"Authorization": f"Bearer {BEARER_TOKEN}"}
|
||||||
|
search_params = {
|
||||||
|
"filter": json.dumps({
|
||||||
|
"_or": [
|
||||||
|
{"name": {"_icontains": query}},
|
||||||
|
{"creator": {"_icontains": query}}
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
"fields": "uuid,name,creator,version,download_hash",
|
||||||
|
"limit": "10"
|
||||||
|
}
|
||||||
|
|
||||||
|
response = requests.get(url=f"{API_BASE_URL}", headers=headers, params=search_params)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
data = response.json().get('data', [])
|
||||||
|
if not data:
|
||||||
|
await send_response(client, room_id, "🔍 No results found for your query.")
|
||||||
|
return
|
||||||
|
|
||||||
|
active_searches[room_id] = data # Track active search for the room
|
||||||
|
results_list = [f"{idx + 1}. {item.get('name', 'N/A')} by {item.get('creator', 'N/A')}" for idx, item in enumerate(data)]
|
||||||
|
response_message = "🔍 Search Results:\n" + "\n".join(results_list) + "\n\nReply with the number to view details, or type 'cancel' to abort."
|
||||||
|
await send_response(client, room_id, response_message)
|
||||||
|
except Exception as e:
|
||||||
|
await log_activity(f"Search error: {str(e)}")
|
||||||
|
await send_response(client, room_id, "⚠️ Error processing search")
|
||||||
|
|
||||||
|
async def process_uuid(client: AsyncClient, room_id: str, uuid: str) -> None:
|
||||||
|
try:
|
||||||
|
headers = {"Authorization": f"Bearer {BEARER_TOKEN}"}
|
||||||
|
response = requests.get(f"{API_BASE_URL}{uuid}", headers=headers)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
data = response.json().get('data', {})
|
||||||
|
if not data:
|
||||||
|
await send_response(client, room_id, "❌ No information found for this UUID.")
|
||||||
|
return
|
||||||
|
|
||||||
|
download_hashes = data.get('download_hash', '')
|
||||||
|
decoded_urls = []
|
||||||
|
|
||||||
|
if download_hashes:
|
||||||
|
for i, hash_part in enumerate(download_hashes.split(','), 1):
|
||||||
|
try:
|
||||||
|
decoded = base64.b64decode(hash_part.strip()).decode('utf-8')
|
||||||
|
decoded_urls.append(f"{i}. {decoded}")
|
||||||
|
except:
|
||||||
|
decoded_urls.append(f"{i}. Invalid hash")
|
||||||
|
|
||||||
|
formatted_message = (
|
||||||
|
f"UUID: {data.get('uuid', 'N/A')}\n"
|
||||||
|
f"Name: {data.get('name', 'N/A')}\n"
|
||||||
|
f"Creator: {data.get('creator', 'N/A')}\n"
|
||||||
|
f"Version: {data.get('version', 'N/A')}\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
if decoded_urls:
|
||||||
|
formatted_message += "Download URLs:\n" + "\n".join(decoded_urls)
|
||||||
|
else:
|
||||||
|
formatted_message += "No download URLs found"
|
||||||
|
|
||||||
|
await send_response(client, room_id, f"📦 Addon Information:\n{formatted_message}")
|
||||||
|
except Exception as e:
|
||||||
|
await log_activity(f"UUID processing error: {str(e)}")
|
||||||
|
await send_response(client, room_id, "⚠️ Error fetching UUID details")
|
||||||
|
|
||||||
|
async def main() -> None:
|
||||||
|
client = AsyncClient(MATRIX_HOMESERVER, MATRIX_USER)
|
||||||
|
await client.login(MATRIX_PASSWORD)
|
||||||
|
await log_activity(f"Logged in as {MATRIX_USER}")
|
||||||
|
client.add_event_callback(lambda room, event: process_message(client, room, event), RoomMessageText)
|
||||||
|
await client.sync_forever(timeout=30000)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
asyncio.run(main())
|
||||||
3
matrix/requirements.txt
Normal file
3
matrix/requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
matrix-nio
|
||||||
|
python-dotenv
|
||||||
|
requests
|
||||||
Reference in New Issue
Block a user