From 4e635b0042ff116e3ee4dc6b43c3b53fde93e376 Mon Sep 17 00:00:00 2001 From: Hash Borgir Date: Mon, 12 Feb 2024 06:20:31 -0700 Subject: [PATCH] First commit --- bot.py | 59 ++++ hcbot.py | 326 +++++++++++++++++++ plugins/__pycache__/commands.cpython-310.pyc | Bin 0 -> 1519 bytes plugins/__pycache__/date.cpython-310.pyc | Bin 0 -> 1132 bytes plugins/__pycache__/fortune.cpython-310.pyc | Bin 0 -> 976 bytes plugins/__pycache__/isup.cpython-310.pyc | Bin 0 -> 1319 bytes plugins/__pycache__/karma.cpython-310.pyc | Bin 0 -> 2365 bytes plugins/__pycache__/proxy.cpython-310.pyc | Bin 0 -> 4854 bytes plugins/__pycache__/youtube.cpython-310.pyc | Bin 0 -> 1624 bytes plugins/commands.py | 45 +++ plugins/date.py | 28 ++ plugins/fortune.py | 23 ++ plugins/isup.py | 37 +++ plugins/karma.py | 85 +++++ plugins/proxy.py | 103 ++++++ plugins/youtube.py | 39 +++ requirements.txt | 3 + 17 files changed, 748 insertions(+) create mode 100755 bot.py create mode 100755 hcbot.py create mode 100644 plugins/__pycache__/commands.cpython-310.pyc create mode 100644 plugins/__pycache__/date.cpython-310.pyc create mode 100644 plugins/__pycache__/fortune.cpython-310.pyc create mode 100644 plugins/__pycache__/isup.cpython-310.pyc create mode 100644 plugins/__pycache__/karma.cpython-310.pyc create mode 100644 plugins/__pycache__/proxy.cpython-310.pyc create mode 100644 plugins/__pycache__/youtube.cpython-310.pyc create mode 100644 plugins/commands.py create mode 100644 plugins/date.py create mode 100644 plugins/fortune.py create mode 100644 plugins/isup.py create mode 100644 plugins/karma.py create mode 100644 plugins/proxy.py create mode 100644 plugins/youtube.py create mode 100644 requirements.txt diff --git a/bot.py b/bot.py new file mode 100755 index 0000000..75fd9f7 --- /dev/null +++ b/bot.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python + +import os +import logging +from dotenv import load_dotenv +import simplematrixbotlib as botlib + +# Load environment variables from .env file +load_dotenv() + +# Bot configuration settings +MATRIX_URL = os.getenv("MATRIX_URL") +MATRIX_USER = os.getenv("MATRIX_USER") +MATRIX_PASS = os.getenv("MATRIX_PASS") + +ADMIN_USER = "@hashborgir:mozilla.org" + +PREFIX = '!' + +creds = botlib.Creds(MATRIX_URL, MATRIX_USER, MATRIX_PASS) +bot = botlib.Bot(creds) + +# Setup logging +logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s', level=logging.INFO) + +# Load plugins +PLUGINS_DIR = "plugins" + +def load_plugins(): + plugins = [] + for plugin_file in os.listdir(PLUGINS_DIR): + if plugin_file.endswith(".py"): + plugin_name = os.path.splitext(plugin_file)[0] + try: + plugin_module = __import__(f"{PLUGINS_DIR}.{plugin_name}", fromlist=[""]) + plugins.append(plugin_module) + logging.info(f"Loaded plugin: {plugin_name}") + except Exception as e: + logging.error(f"Error loading plugin {plugin_name}: {e}") + return plugins + +plugins = load_plugins() + +@bot.listener.on_message_event +async def handle_commands(room, message): + """ + Function to handle incoming command messages. + + Args: + room (Room): The Matrix room where the command was invoked. + message (RoomMessage): The message object containing the command. + + Returns: + None + """ + for plugin in plugins: + await plugin.handle_command(room, message, bot, PREFIX) + +bot.run() diff --git a/hcbot.py b/hcbot.py new file mode 100755 index 0000000..5d259df --- /dev/null +++ b/hcbot.py @@ -0,0 +1,326 @@ +#!/usr/bin/env python + +import subprocess +import sqlite3 +import time +import os +import random +import socket +from urllib.parse import urlparse +import datetime +import simplematrixbotlib as botlib +import requests +from pytube import YouTube +import logging +import inspect + + +MATRIX_URL = "https://matrix.org" +MATRIX_USER = "@hcbot:matrix.org" +MATRIX_PASS = "W4iy$nt^qp~&$K~$w@@jEhnT" + +creds = botlib.Creds(MATRIX_URL, MATRIX_USER, MATRIX_PASS) +bot = botlib.Bot(creds) + +PREFIX = '!' + +# Setup logging +logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s', level=logging.INFO) + +# Database setup +conn = sqlite3.connect('karma.db') +c = conn.cursor() +c.execute('''CREATE TABLE IF NOT EXISTS karma + (username TEXT PRIMARY KEY, points INTEGER)''') +conn.commit() +conn.close() + +async def ping_proxy(proxy): + """ + Ping a proxy server to check its availability. + + Args: + proxy (str): The proxy server address in the format 'ip:port'. + + Returns: + float or str: The ping time in milliseconds if the proxy is up, or 'N/A' if it's down. + """ + ip, port = proxy.split(':') + start_time = time.time() + try: + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.settimeout(5) + result = sock.connect_ex((ip, int(port))) + if result == 0: + return round((time.time() - start_time) * 1000, 2) + except Exception as e: + logging.error(f"Error pinging proxy {proxy}: {e}") + return "N/A" + +@bot.listener.on_message_event +async def commands(room, message): + """ + Command to display the list of available commands and their descriptions. + + Args: + room (Room): The Matrix room where the command was invoked. + message (RoomMessage): The message object containing the command. + + Returns: + None + """ + match = botlib.MessageMatch(room, message, bot, PREFIX) + if match.is_not_from_this_bot() and match.prefix() and match.command("commands"): + logging.info("Fetching commands documentation") + commands_message = """ + **Available Commands:** + + **!fortune** + Returns a random fortune message. + + **!date** + Displays the current date and time. + + **!proxy** + Retrieves and tests random SOCKS5 and HTTP proxies. + + **!isup ** + Checks if the specified domain or IP address is reachable. + + **!karma ** + Retrieves the karma points for the specified user. + + **!karma up** + Increases the karma points for the specified user by 1. + + **!karma down** + Decreases the karma points for the specified user by 1. + """ + await bot.api.send_markdown_message(room.room_id, commands_message) + logging.info("Sent commands documentation to the room") + + +@bot.listener.on_message_event +async def fortune(room, message): + """ + Command to get a random fortune. + + Args: + room (Room): The Matrix room where the command was invoked. + message (RoomMessage): The message object containing the command. + + Returns: + None + """ + match = botlib.MessageMatch(room, message, bot, PREFIX) + if match.is_not_from_this_bot() and match.prefix() and match.command("fortune"): + logging.info("Received !fortune command") + fortune_output = subprocess.run(['/usr/games/fortune'], capture_output=True).stdout.decode('UTF-8') + await bot.api.send_text_message(room.room_id, fortune_output) + logging.info("Sent fortune to the room") + +@bot.listener.on_message_event +async def date(room, message): + """ + Command to get the current date and time. + + Args: + room (Room): The Matrix room where the command was invoked. + message (RoomMessage): The message object containing the command. + + Returns: + None + """ + match = botlib.MessageMatch(room, message, bot, PREFIX) + if match.is_not_from_this_bot() and match.prefix() and match.command("date"): + logging.info("Fetching current date and time") + current_datetime = datetime.datetime.now() + day_of_week = current_datetime.strftime("%A") + month = current_datetime.strftime("%B") + year = current_datetime.strftime("%Y") + time = current_datetime.strftime("%I:%M:%S %p") + date_message = f"Today is **{day_of_week}** of **{month}** in **{year}**. The time is **{time}**" + await bot.api.send_markdown_message(room.room_id, date_message) + logging.info("Sent current date and time to the room") + +@bot.listener.on_message_event +async def proxy(room, message): + """ + Command to get random SOCKS5 and HTTP proxies. + + Args: + room (Room): The Matrix room where the command was invoked. + message (RoomMessage): The message object containing the command. + + Returns: + None + """ + match = botlib.MessageMatch(room, message, bot, PREFIX) + if match.is_not_from_this_bot() and match.prefix() and match.command("proxy"): + logging.info("Received !proxy command") + socks5_proxies = requests.get('https://raw.githubusercontent.com/TheSpeedX/SOCKS-List/master/socks5.txt').text.splitlines() + http_proxies = requests.get('https://raw.githubusercontent.com/TheSpeedX/SOCKS-List/master/http.txt').text.splitlines() + + random_socks5_proxy = random.choice(socks5_proxies) + random_http_proxy = random.choice(http_proxies) + + socks5_ping = await ping_proxy(random_socks5_proxy) + http_ping = await ping_proxy(random_http_proxy) + + await bot.api.send_text_message(room.room_id, f"Random SOCKS5 Proxy: {random_socks5_proxy} - Ping time: {socks5_ping} ms") + await bot.api.send_text_message(room.room_id, f"Random HTTP Proxy: {random_http_proxy} - Ping time: {http_ping} ms") + logging.info("Sent proxies to the room") + +@bot.listener.on_message_event +async def isup(room, message): + """ + Command to check if a website or server is up. + + Args: + room (Room): The Matrix room where the command was invoked. + message (RoomMessage): The message object containing the command. + + Returns: + None + """ + match = botlib.MessageMatch(room, message, bot, PREFIX) + if match.is_not_from_this_bot() and match.prefix() and match.command("isup"): + logging.info("Received !isup command") + args = match.args() + if len(args) != 1: + await bot.api.send_text_message(room.room_id, "Usage: !isup ") + logging.info("Sent usage message to the room") + return + + target = args[0] + try: + response = os.system(f"ping -c 1 {target}") + if response == 0: + await bot.api.send_text_message(room.room_id, f"{target} is up") + else: + await bot.api.send_text_message(room.room_id, f"{target} is down") + logging.info(f"Sent status of {target} to the room") + except Exception as e: + await bot.api.send_text_message(room.room_id, f"Error: {e}") + logging.error(f"Error occurred while checking {target}: {e}") + +@bot.listener.on_message_event +async def karma(room, message): + """ + Command to manage karma points for users. + + Args: + room (Room): The Matrix room where the command was invoked. + message (RoomMessage): The message object containing the command. + + Returns: + None + """ + match = botlib.MessageMatch(room, message, bot, PREFIX) + if match.is_not_from_this_bot() and match.prefix() and match.command("karma"): + logging.info("Received !karma command") + args = match.args() + sender = str(message.sender) + + if len(args) == 0: + # Query sender's own karma + conn = sqlite3.connect('karma.db') + c = conn.cursor() + c.execute('''CREATE TABLE IF NOT EXISTS karma + (username TEXT PRIMARY KEY, points INTEGER)''') + c.execute('''INSERT OR IGNORE INTO karma (username, points) VALUES (?, ?)''', (sender, 0)) + c.execute('''SELECT points FROM karma WHERE username = ?''', (sender,)) + points = c.fetchone()[0] + conn.close() + await bot.api.send_text_message(room.room_id, f"{sender}'s karma points: {points}") + logging.info(f"Sent {sender}'s karma points ({points}) to the room") + elif len(args) == 1: + username = args[0] + + if username == sender: + await bot.api.send_text_message(room.room_id, "You cannot modify your own karma.") + logging.info("Sent self-modification warning message to the room") + return + + conn = sqlite3.connect('karma.db') + c = conn.cursor() + c.execute('''CREATE TABLE IF NOT EXISTS karma + (username TEXT PRIMARY KEY, points INTEGER)''') + c.execute('''INSERT OR IGNORE INTO karma (username, points) VALUES (?, ?)''', (username, 0)) + c.execute('''SELECT points FROM karma WHERE username = ?''', (username,)) + points = c.fetchone()[0] + conn.close() + await bot.api.send_text_message(room.room_id, f"{username}'s karma points: {points}") + logging.info(f"Sent {username}'s karma points ({points}) to the room") + elif len(args) == 2: + username, action = args + if action not in ['up', 'down']: + await bot.api.send_text_message(room.room_id, "Invalid action. Use 'up' or 'down'.") + logging.info("Sent invalid action message to the room") + return + + if username == sender: + await bot.api.send_text_message(room.room_id, "You cannot modify your own karma.") + logging.info("Sent self-modification warning message to the room") + return + + conn = sqlite3.connect('karma.db') + c = conn.cursor() + c.execute('''CREATE TABLE IF NOT EXISTS karma + (username TEXT PRIMARY KEY, points INTEGER)''') + + if action == 'up': + c.execute('''UPDATE karma SET points = points + 1 WHERE username = ?''', (username,)) + else: + c.execute('''UPDATE karma SET points = points - 1 WHERE username = ?''', (username,)) + + conn.commit() + c.execute('''SELECT points FROM karma WHERE username = ?''', (username,)) + points = c.fetchone()[0] + conn.close() + + await bot.api.send_text_message(room.room_id, f"{username}'s karma points: {points}") + logging.info(f"Sent {username}'s karma points ({points}) to the room") + else: + await bot.api.send_text_message(room.room_id, "Usage: !karma [username] [up/down]") + logging.info("Sent usage message to the room") + + +import re + +@bot.listener.on_message_event +async def youtube(room, message): + """ + Command to fetch YouTube video information from links. + + Args: + room (Room): The Matrix room where the command was invoked. + message (RoomMessage): The message object containing the command. + + Returns: + None + """ + match = botlib.MessageMatch(room, message, bot) + if match.is_not_from_this_bot() and re.search(r'youtube\.com/watch\?v=', message.body): + logging.info("YouTube link detected") + video_id_match = re.search(r'youtube\.com/watch\?v=([^\s]+)', message.body) + if video_id_match: + video_id = video_id_match.group(1) + youtube_url = f"https://www.youtube.com/watch?v={video_id}" + logging.info(f"Fetching information for YouTube video: {youtube_url}") + try: + video = YouTube(youtube_url) + title = video.title + description = video.description + length = video.length + views = video.views + author = video.author + info_message = f"""Title: {title} | Length: {length} seconds | Views: {views} | Description: {description}""" + await bot.api.send_markdown_message(room.room_id, info_message) + logging.info("Sent YouTube video information to the room") + except Exception as e: + logging.error(f"Error fetching YouTube video information: {str(e)}") + await bot.api.send_text_message(room.room_id, "Error fetching YouTube video information.") + + +bot.run() diff --git a/plugins/__pycache__/commands.cpython-310.pyc b/plugins/__pycache__/commands.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..23a484e02bf38843a212fad40d05afcb1acf2048 GIT binary patch literal 1519 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 literal 0 HcmV?d00001 diff --git a/plugins/__pycache__/proxy.cpython-310.pyc b/plugins/__pycache__/proxy.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7aa98e11400261914df0c6313958b36fe764cf4c GIT binary patch literal 4854 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 F_y-B9Cv literal 0 HcmV?d00001 diff --git a/plugins/commands.py b/plugins/commands.py new file mode 100644 index 0000000..44239fc --- /dev/null +++ b/plugins/commands.py @@ -0,0 +1,45 @@ +# plugins/commands.py + +import logging +import simplematrixbotlib as botlib + +async def handle_command(room, message, bot, PREFIX): + """ + Function to handle the !commands command. + + Args: + room (Room): The Matrix room where the command was invoked. + message (RoomMessage): The message object containing the command. + + Returns: + None + """ + match = botlib.MessageMatch(room, message, bot, PREFIX) + if match.is_not_from_this_bot() and match.prefix() and match.command("commands"): + logging.info("Fetching commands documentation") + commands_message = """ + **Available Commands:** + + **!fortune** + Returns a random fortune message. + + **!date** + Displays the current date and time. + + **!proxy** + Retrieves and tests random SOCKS5 and HTTP proxies. + + **!isup ** + Checks if the specified domain or IP address is reachable. + + **!karma ** + Retrieves the karma points for the specified user. + + **!karma up** + Increases the karma points for the specified user by 1. + + **!karma down** + Decreases the karma points for the specified user by 1. + """ + await bot.api.send_markdown_message(room.room_id, commands_message) + logging.info("Sent commands documentation to the room") diff --git a/plugins/date.py b/plugins/date.py new file mode 100644 index 0000000..ea582c0 --- /dev/null +++ b/plugins/date.py @@ -0,0 +1,28 @@ +# plugins/date.py + +import datetime +import logging +import simplematrixbotlib as botlib + +async def handle_command(room, message, bot, PREFIX): + """ + Function to handle the !date command. + + Args: + room (Room): The Matrix room where the command was invoked. + message (RoomMessage): The message object containing the command. + + Returns: + None + """ + match = botlib.MessageMatch(room, message, bot, PREFIX) + if match.is_not_from_this_bot() and match.prefix() and match.command("date"): + logging.info("Fetching current date and time") + current_datetime = datetime.datetime.now() + day_of_week = current_datetime.strftime("%A") + month = current_datetime.strftime("%B") + year = current_datetime.strftime("%Y") + time = current_datetime.strftime("%I:%M:%S %p") + date_message = f"Today is **{day_of_week}** of **{month}** in **{year}**. The time is **{time}**" + await bot.api.send_markdown_message(room.room_id, date_message) + logging.info("Sent current date and time to the room") diff --git a/plugins/fortune.py b/plugins/fortune.py new file mode 100644 index 0000000..0a1de27 --- /dev/null +++ b/plugins/fortune.py @@ -0,0 +1,23 @@ +# plugins/fortune.py + +import subprocess +import logging +import simplematrixbotlib as botlib + +async def handle_command(room, message, bot, PREFIX): + """ + Function to handle the !fortune command. + + Args: + room (Room): The Matrix room where the command was invoked. + message (RoomMessage): The message object containing the command. + + Returns: + None + """ + match = botlib.MessageMatch(room, message, bot, PREFIX) + if match.is_not_from_this_bot() and match.prefix() and match.command("fortune"): + logging.info("Received !fortune command") + fortune_output = subprocess.run(['/usr/games/fortune'], capture_output=True).stdout.decode('UTF-8') + await bot.api.send_text_message(room.room_id, fortune_output) + logging.info("Sent fortune to the room") diff --git a/plugins/isup.py b/plugins/isup.py new file mode 100644 index 0000000..f12f7cc --- /dev/null +++ b/plugins/isup.py @@ -0,0 +1,37 @@ +# plugins/isup.py + +import os +import logging +import simplematrixbotlib as botlib + +async def handle_command(room, message, bot, PREFIX): + """ + Function to handle the !isup command. + + Args: + room (Room): The Matrix room where the command was invoked. + message (RoomMessage): The message object containing the command. + + Returns: + None + """ + match = botlib.MessageMatch(room, message, bot, PREFIX) + if match.is_not_from_this_bot() and match.prefix() and match.command("isup"): + logging.info("Received !isup command") + args = match.args() + if len(args) != 1: + await bot.api.send_text_message(room.room_id, "Usage: !isup ") + logging.info("Sent usage message to the room") + return + + target = args[0] + try: + response = os.system(f"ping -c 1 {target}") + if response == 0: + await bot.api.send_text_message(room.room_id, f"{target} is up") + else: + await bot.api.send_text_message(room.room_id, f"{target} is down") + logging.info(f"Sent status of {target} to the room") + except Exception as e: + await bot.api.send_text_message(room.room_id, f"Error: {e}") + logging.error(f"Error occurred while checking {target}: {e}") diff --git a/plugins/karma.py b/plugins/karma.py new file mode 100644 index 0000000..38b0853 --- /dev/null +++ b/plugins/karma.py @@ -0,0 +1,85 @@ +# plugins/karma.py + +import sqlite3 +import logging +import simplematrixbotlib as botlib + +async def handle_command(room, message, bot, PREFIX): + """ + Function to handle the !karma command. + + Args: + room (Room): The Matrix room where the command was invoked. + message (RoomMessage): The message object containing the command. + + Returns: + None + """ + match = botlib.MessageMatch(room, message, bot, PREFIX) + if match.is_not_from_this_bot() and match.prefix() and match.command("karma"): + logging.info("Received !karma command") + args = match.args() + sender = str(message.sender) + + if len(args) == 0: + # Query sender's own karma + conn = sqlite3.connect('karma.db') + c = conn.cursor() + c.execute('''CREATE TABLE IF NOT EXISTS karma + (username TEXT PRIMARY KEY, points INTEGER)''') + c.execute('''INSERT OR IGNORE INTO karma (username, points) VALUES (?, ?)''', (sender, 0)) + c.execute('''SELECT points FROM karma WHERE username = ?''', (sender,)) + points = c.fetchone()[0] + conn.close() + await bot.api.send_text_message(room.room_id, f"{sender}'s karma points: {points}") + logging.info(f"Sent {sender}'s karma points ({points}) to the room") + elif len(args) == 1: + username = args[0] + + if username == sender: + await bot.api.send_text_message(room.room_id, "You cannot modify your own karma.") + logging.info("Sent self-modification warning message to the room") + return + + conn = sqlite3.connect('karma.db') + c = conn.cursor() + c.execute('''CREATE TABLE IF NOT EXISTS karma + (username TEXT PRIMARY KEY, points INTEGER)''') + c.execute('''INSERT OR IGNORE INTO karma (username, points) VALUES (?, ?)''', (username, 0)) + c.execute('''SELECT points FROM karma WHERE username = ?''', (username,)) + points = c.fetchone()[0] + conn.close() + await bot.api.send_text_message(room.room_id, f"{username}'s karma points: {points}") + logging.info(f"Sent {username}'s karma points ({points}) to the room") + elif len(args) == 2: + username, action = args + if action not in ['up', 'down']: + await bot.api.send_text_message(room.room_id, "Invalid action. Use 'up' or 'down'.") + logging.info("Sent invalid action message to the room") + return + + if username == sender: + await bot.api.send_text_message(room.room_id, "You cannot modify your own karma.") + logging.info("Sent self-modification warning message to the room") + return + + conn = sqlite3.connect('karma.db') + c = conn.cursor() + c.execute('''CREATE TABLE IF NOT EXISTS karma + (username TEXT PRIMARY KEY, points INTEGER)''') + + if action == 'up': + c.execute('''UPDATE karma SET points = points + 1 WHERE username = ?''', (username,)) + else: + c.execute('''UPDATE karma SET points = points - 1 WHERE username = ?''', (username,)) + + conn.commit() + c.execute('''SELECT points FROM karma WHERE username = ?''', (username,)) + points = c.fetchone()[0] + conn.close() + + await bot.api.send_text_message(room.room_id, f"{username}'s karma points: {points}") + logging.info(f"Sent {username}'s karma points ({points}) to the room") + else: + await bot.api.send_text_message(room.room_id, "Usage: !karma [username] [up/down]") + logging.info("Sent usage message to the room") diff --git a/plugins/proxy.py b/plugins/proxy.py new file mode 100644 index 0000000..3a65547 --- /dev/null +++ b/plugins/proxy.py @@ -0,0 +1,103 @@ +# plugins/proxy.py + +import os +import logging +import random +import requests +import socket +import asyncio +import time +import simplematrixbotlib as botlib + +# Function to test SOCKS4 proxies +async def test_socks4_proxy(proxy): + try: + start_time = time.time() + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.settimeout(5) + s.connect((proxy.split(':')[0], int(proxy.split(':')[1]))) + latency = round((time.time() - start_time) * 1000, 2) + logging.info(f"Tested SOCKS4 proxy {proxy}. Latency: {latency} ms") + return True, latency + except Exception as e: + logging.error(f"Error testing SOCKS4 proxy {proxy}: {e}") + return False, None + +# Function to test SOCKS5 proxies +async def test_socks5_proxy(proxy): + try: + start_time = time.time() + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.settimeout(5) + s.connect((proxy.split(':')[0], int(proxy.split(':')[1]))) + latency = round((time.time() - start_time) * 1000, 2) + logging.info(f"Tested SOCKS5 proxy {proxy}. Latency: {latency} ms") + return True, latency + except Exception as e: + logging.error(f"Error testing SOCKS5 proxy {proxy}: {e}") + return False, None + +# Function to test HTTP proxies +async def test_http_proxy(proxy): + local_ip = requests.get("https://api.ipify.org").text + try: + response = requests.get("https://api.ipify.org", proxies={"http": proxy}, timeout=5).text + if response.strip() != local_ip.strip(): + logging.info(f"Tested anonymous HTTP proxy {proxy}") + return True + else: + logging.info(f"HTTP proxy {proxy} is not anonymous") + return False + except Exception as e: + logging.error(f"Error testing HTTP proxy {proxy}: {e}") + return False + +async def handle_command(room, message, bot, PREFIX): + """ + Function to handle the !proxy command. + + Args: + room (Room): The Matrix room where the command was invoked. + message (RoomMessage): The message object containing the command. + + Returns: + None + """ + match = botlib.MessageMatch(room, message, bot, PREFIX) + if match.is_not_from_this_bot() and match.prefix() and match.command("proxy"): + logging.info("Received !proxy command") + try: + # Fetch SOCKS4 proxy + socks4_proxies = requests.get('https://raw.githubusercontent.com/TheSpeedX/SOCKS-List/master/socks4.txt', timeout=5).text.splitlines() + random.shuffle(socks4_proxies) + for proxy in socks4_proxies: + is_working, latency = await test_socks4_proxy(proxy) + if is_working: + await bot.api.send_text_message(room.room_id, f"SOCKS4 Proxy: {proxy} - Latency: {latency} ms") + break + + # Fetch SOCKS5 proxy + socks5_proxies = requests.get('https://raw.githubusercontent.com/TheSpeedX/SOCKS-List/master/socks5.txt', timeout=5).text.splitlines() + random.shuffle(socks5_proxies) + for proxy in socks5_proxies: + is_working, latency = await test_socks5_proxy(proxy) + if is_working: + await bot.api.send_text_message(room.room_id, f"SOCKS5 Proxy: {proxy} - Latency: {latency} ms") + break + + # Fetch HTTP proxy + http_proxies = requests.get('https://raw.githubusercontent.com/TheSpeedX/SOCKS-List/master/http.txt', timeout=5).text.splitlines() + random.shuffle(http_proxies) + for proxy in http_proxies: + is_working = await test_http_proxy(proxy) + if is_working: + await bot.api.send_text_message(room.room_id, f"HTTP Proxy: {proxy}") + break + + logging.info("Sent proxies to the room") + except asyncio.TimeoutError: + await bot.api.send_text_message(room.room_id, "Failed to fetch or test proxies. The operation timed out.") + logging.error("Proxy fetch and test operation timed out") + except Exception as e: + await bot.api.send_text_message(room.room_id, f"An error occurred: {e}") + logging.error(f"Error fetching or testing proxies: {e}") diff --git a/plugins/youtube.py b/plugins/youtube.py new file mode 100644 index 0000000..4260b08 --- /dev/null +++ b/plugins/youtube.py @@ -0,0 +1,39 @@ +# plugins/youtube.py + +import re +import logging +from pytube import YouTube +import simplematrixbotlib as botlib + +async def handle_command(room, message, bot, PREFIX): + """ + Function to handle YouTube video information from links. + + Args: + room (Room): The Matrix room where the command was invoked. + message (RoomMessage): The message object containing the command. + + Returns: + None + """ + match = botlib.MessageMatch(room, message, bot) + if match.is_not_from_this_bot() and re.search(r'youtube\.com/watch\?v=', message.body): + logging.info("YouTube link detected") + video_id_match = re.search(r'youtube\.com/watch\?v=([^\s]+)', message.body) + if video_id_match: + video_id = video_id_match.group(1) + youtube_url = f"https://www.youtube.com/watch?v={video_id}" + logging.info(f"Fetching information for YouTube video: {youtube_url}") + try: + video = YouTube(youtube_url) + title = video.title + description = video.description + length = video.length + views = video.views + author = video.author + info_message = f"""Title: {title} | Length: {length} seconds | Views: {views} | Description: {description}""" + await bot.api.send_markdown_message(room.room_id, info_message) + logging.info("Sent YouTube video information to the room") + except Exception as e: + logging.error(f"Error fetching YouTube video information: {str(e)}") + await bot.api.send_text_message(room.room_id, "Error fetching YouTube video information.") diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..b3c5408 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +simplematrixbotlib +python-dotenv +pathlib