import sqlite3 import mysql.connector import json from mysql.connector import Error as MySQLError from botdiscord.config import get_db_config, get_db_type _connection = None def get_connection(): global _connection db_type = get_db_type() if db_type == "mysql": if _connection is None or not _connection.is_connected(): db_config = get_db_config() try: _connection = mysql.connector.connect( host=db_config.get("host", "localhost"), port=db_config.get("port", 3306), user=db_config.get("user", "root"), password=db_config.get("password", ""), database=db_config.get("name", "mi_red") ) except MySQLError as e: print(f"Error connecting to MySQL: {e}") raise return _connection else: import os from botdiscord.config import get_db_path db_path = get_db_path() db_dir = os.path.dirname(db_path) if db_dir and not os.path.exists(db_dir): os.makedirs(db_dir, exist_ok=True) return sqlite3.connect(db_path) def close_connection(): global _connection if _connection and _connection.is_connected(): _connection.close() _connection = None def _execute_query(query, params=None, fetch=False): db_type = get_db_type() if db_type == "mysql": conn = get_connection() cursor = conn.cursor() try: cursor.execute(query, params or ()) if fetch: result = cursor.fetchall() else: conn.commit() result = cursor.lastrowid return result finally: cursor.close() else: conn = get_connection() cursor = conn.cursor() try: cursor.execute(query, params or ()) if fetch: result = cursor.fetchall() else: conn.commit() result = cursor.lastrowid return result finally: cursor.close() def init_db(): db_type = get_db_type() if db_type == "mysql": conn = get_connection() cursor = conn.cursor() cursor.execute('''CREATE TABLE IF NOT EXISTS guild_languages (guild_id BIGINT NOT NULL, lang_code VARCHAR(10) NOT NULL, PRIMARY KEY (guild_id, lang_code)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4''') cursor.execute('''CREATE TABLE IF NOT EXISTS bot_config (`key` VARCHAR(255) NOT NULL, value TEXT, PRIMARY KEY (`key`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4''') cursor.execute('''CREATE TABLE IF NOT EXISTS available_languages (code VARCHAR(10) NOT NULL, name VARCHAR(100) NOT NULL, flag VARCHAR(20), PRIMARY KEY (code)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4''') cursor.execute('''CREATE TABLE IF NOT EXISTS bot_languages (bot_type VARCHAR(50) NOT NULL, lang_code VARCHAR(10) NOT NULL, PRIMARY KEY (bot_type, lang_code)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4''') # Nuevas tablas para caché y persistencia cursor.execute('''CREATE TABLE IF NOT EXISTS messages (message_id BIGINT PRIMARY KEY, guild_id BIGINT, author_id BIGINT, content TEXT NOT NULL, mentions_map JSON, bot_type ENUM('discord', 'telegram') NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4''') cursor.execute('''CREATE TABLE IF NOT EXISTS translations (id INT AUTO_INCREMENT PRIMARY KEY, message_id BIGINT NOT NULL, target_lang VARCHAR(10) NOT NULL, translated_text TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (message_id) REFERENCES messages(message_id) ON DELETE CASCADE, UNIQUE KEY idx_msg_lang (message_id, target_lang)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4''') # Tabla para traducciones de la interfaz web cursor.execute('''CREATE TABLE IF NOT EXISTS ui_translations (id INT AUTO_INCREMENT PRIMARY KEY, original_text TEXT NOT NULL, target_lang VARCHAR(10) NOT NULL, translated_text TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY idx_ui_lang (original_text(255), target_lang)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4''') conn.commit() cursor.close() else: conn = get_connection() c = conn.cursor() c.execute('''CREATE TABLE IF NOT EXISTS guild_languages (guild_id INTEGER, lang_code TEXT, PRIMARY KEY (guild_id, lang_code))''') c.execute('''CREATE TABLE IF NOT EXISTS bot_config (key TEXT PRIMARY KEY, value TEXT)''') c.execute('''CREATE TABLE IF NOT EXISTS available_languages (code TEXT PRIMARY KEY, name TEXT, flag TEXT)''') c.execute('''CREATE TABLE IF NOT EXISTS bot_languages (bot_type TEXT, lang_code TEXT, PRIMARY KEY (bot_type, lang_code))''') # SQLite equivalents c.execute('''CREATE TABLE IF NOT EXISTS messages (message_id INTEGER PRIMARY KEY, guild_id INTEGER, author_id INTEGER, content TEXT NOT NULL, mentions_map TEXT, bot_type TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)''') c.execute('''CREATE TABLE IF NOT EXISTS translations (id INTEGER PRIMARY KEY AUTOINCREMENT, message_id INTEGER NOT NULL, target_lang TEXT NOT NULL, translated_text TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE(message_id, target_lang))''') conn.commit() conn.close() def set_available_languages(languages: list): db_type = get_db_type() if db_type == "mysql": conn = get_connection() cursor = conn.cursor() cursor.execute("DELETE FROM available_languages") for lang in languages: cursor.execute("INSERT INTO available_languages (code, name, flag) VALUES (%s, %s, %s)", (lang.get("code"), lang.get("name"), lang.get("flag", ""))) conn.commit() cursor.close() else: conn = get_connection() c = conn.cursor() c.execute("DELETE FROM available_languages") for lang in languages: c.execute("INSERT OR REPLACE INTO available_languages (code, name, flag) VALUES (?, ?, ?)", (lang.get("code"), lang.get("name"), lang.get("flag", ""))) conn.commit() conn.close() def get_available_languages() -> list: db_type = get_db_type() if db_type == "mysql": conn = get_connection() cursor = conn.cursor() cursor.execute("SELECT code, name, flag FROM available_languages ORDER BY name") rows = cursor.fetchall() cursor.close() return [{"code": row[0], "name": row[1], "flag": row[2] or ""} for row in rows] else: conn = get_connection() c = conn.cursor() c.execute("SELECT code, name, flag FROM available_languages ORDER BY name") langs = [{"code": row[0], "name": row[1], "flag": row[2] or ""} for row in c.fetchall()] conn.close() return langs def set_bot_languages(bot_type: str, lang_codes: list): db_type = get_db_type() if db_type == "mysql": conn = get_connection() cursor = conn.cursor() cursor.execute("DELETE FROM bot_languages WHERE bot_type = %s", (bot_type,)) for code in lang_codes: cursor.execute("INSERT INTO bot_languages (bot_type, lang_code) VALUES (%s, %s)", (bot_type, code)) conn.commit() cursor.close() else: conn = get_connection() c = conn.cursor() c.execute("DELETE FROM bot_languages WHERE bot_type = ?", (bot_type,)) for code in lang_codes: c.execute("INSERT INTO bot_languages (bot_type, lang_code) VALUES (?, ?)", (bot_type, code)) conn.commit() conn.close() def get_bot_languages(bot_type: str) -> list: db_type = get_db_type() if db_type == "mysql": conn = get_connection() cursor = conn.cursor() cursor.execute("SELECT lang_code FROM bot_languages WHERE bot_type = %s", (bot_type,)) rows = cursor.fetchall() cursor.close() return [row[0] for row in rows] else: conn = get_connection() c = conn.cursor() c.execute("SELECT lang_code FROM bot_languages WHERE bot_type = ?", (bot_type,)) langs = [row[0] for row in c.fetchall()] conn.close() return langs def get_active_languages(guild_id: int) -> list: db_type = get_db_type() if db_type == "mysql": conn = get_connection() cursor = conn.cursor() cursor.execute("SELECT lang_code FROM guild_languages WHERE guild_id = %s", (guild_id,)) rows = cursor.fetchall() cursor.close() return [row[0] for row in rows] else: conn = get_connection() c = conn.cursor() c.execute("SELECT lang_code FROM guild_languages WHERE guild_id = ?", (guild_id,)) langs = [row[0] for row in c.fetchall()] conn.close() return langs def set_active_languages(guild_id: int, lang_codes: list): db_type = get_db_type() if db_type == "mysql": conn = get_connection() cursor = conn.cursor() cursor.execute("DELETE FROM guild_languages WHERE guild_id = %s", (guild_id,)) for code in lang_codes: cursor.execute("INSERT INTO guild_languages (guild_id, lang_code) VALUES (%s, %s)", (guild_id, code)) conn.commit() cursor.close() else: conn = get_connection() c = conn.cursor() c.execute("DELETE FROM guild_languages WHERE guild_id = ?", (guild_id,)) for code in lang_codes: c.execute("INSERT INTO guild_languages (guild_id, lang_code) VALUES (?, ?)", (guild_id, code)) conn.commit() conn.close() def get_config_value(key: str) -> str: db_type = get_db_type() if db_type == "mysql": conn = get_connection() cursor = conn.cursor() cursor.execute("SELECT value FROM bot_config WHERE `key` = %s", (key,)) row = cursor.fetchone() cursor.close() return row[0] if row else None else: conn = get_connection() c = conn.cursor() c.execute("SELECT value FROM bot_config WHERE key = ?", (key,)) row = c.fetchone() conn.close() return row[0] if row else None def set_config_value(key: str, value: str): db_type = get_db_type() if db_type == "mysql": conn = get_connection() cursor = conn.cursor() cursor.execute("INSERT INTO bot_config (`key`, value) VALUES (%s, %s) ON DUPLICATE KEY UPDATE value = %s", (key, value, value)) conn.commit() cursor.close() else: conn = get_connection() c = conn.cursor() c.execute("INSERT OR REPLACE INTO bot_config (key, value) VALUES (?, ?)", (key, value)) conn.commit() conn.close() def save_message(message_id: int, guild_id: int, author_id: int, content: str, mentions_map: dict, bot_type: str): db_type = get_db_type() mentions_json = json.dumps(mentions_map) if db_type == "mysql": conn = get_connection() cursor = conn.cursor() query = """INSERT INTO messages (message_id, guild_id, author_id, content, mentions_map, bot_type) VALUES (%s, %s, %s, %s, %s, %s) ON DUPLICATE KEY UPDATE content = %s, mentions_map = %s""" cursor.execute(query, (message_id, guild_id, author_id, content, mentions_json, bot_type, content, mentions_json)) conn.commit() cursor.close() else: conn = get_connection() c = conn.cursor() c.execute("INSERT OR REPLACE INTO messages (message_id, guild_id, author_id, content, mentions_map, bot_type) VALUES (?, ?, ?, ?, ?, ?)", (message_id, guild_id, author_id, content, mentions_json, bot_type)) conn.commit() conn.close() def get_message(message_id: int): db_type = get_db_type() if db_type == "mysql": conn = get_connection() cursor = conn.cursor(dictionary=True) cursor.execute("SELECT content, mentions_map, bot_type FROM messages WHERE message_id = %s", (message_id,)) row = cursor.fetchone() cursor.close() if row: if row['mentions_map']: row['mentions_map'] = json.loads(row['mentions_map']) return row else: conn = get_connection() c = conn.cursor() c.execute("SELECT content, mentions_map, bot_type FROM messages WHERE message_id = ?", (message_id,)) row = c.fetchone() conn.close() if row: return { 'content': row[0], 'mentions_map': json.loads(row[1]) if row[1] else {}, 'bot_type': row[2] } return None def save_translation(message_id: int, target_lang: str, translated_text: str): db_type = get_db_type() if db_type == "mysql": conn = get_connection() cursor = conn.cursor() query = "INSERT INTO translations (message_id, target_lang, translated_text) VALUES (%s, %s, %s) ON DUPLICATE KEY UPDATE translated_text = %s" cursor.execute(query, (message_id, target_lang, translated_text, translated_text)) conn.commit() cursor.close() else: conn = get_connection() c = conn.cursor() c.execute("INSERT OR REPLACE INTO translations (message_id, target_lang, translated_text) VALUES (?, ?, ?)", (message_id, target_lang, translated_text)) conn.commit() conn.close() def get_cached_translation(message_id: int, target_lang: str) -> str: db_type = get_db_type() if db_type == "mysql": conn = get_connection() cursor = conn.cursor() cursor.execute("SELECT translated_text FROM translations WHERE message_id = %s AND target_lang = %s", (message_id, target_lang)) row = cursor.fetchone() cursor.close() return row[0] if row else None else: conn = get_connection() c = conn.cursor() c.execute("SELECT translated_text FROM translations WHERE message_id = ? AND target_lang = ?", (message_id, target_lang)) row = c.fetchone() conn.close() return row[0] if row else None def get_ui_translation(text: str, target_lang: str) -> str: db_type = get_db_type() if db_type == "mysql": conn = get_connection() cursor = conn.cursor() cursor.execute("SELECT translated_text FROM ui_translations WHERE original_text = %s AND target_lang = %s", (text, target_lang)) row = cursor.fetchone() cursor.close() return row[0] if row else None else: conn = get_connection() c = conn.cursor() c.execute("SELECT translated_text FROM ui_translations WHERE original_text = ? AND target_lang = ?", (text, target_lang)) row = c.fetchone() conn.close() return row[0] if row else None def save_ui_translation(text: str, target_lang: str, translated_text: str): db_type = get_db_type() if db_type == "mysql": conn = get_connection() cursor = conn.cursor() cursor.execute("INSERT INTO ui_translations (original_text, target_lang, translated_text) VALUES (%s, %s, %s) ON DUPLICATE KEY UPDATE translated_text = %s", (text, target_lang, translated_text, translated_text)) conn.commit() cursor.close() else: conn = get_connection() c = conn.cursor() c.execute("INSERT OR REPLACE INTO ui_translations (original_text, target_lang, translated_text) VALUES (?, ?, ?)", (text, target_lang, translated_text)) conn.commit() conn.close()