- Agregar columnas telegram_enabled y discord_enabled a supported_languages - Nueva interfaz en admin/languages.php con checkboxes para Telegram y Discord - Los bots ahora solo muestran botones de traducción para los idiomas seleccionados por plataforma
258 lines
10 KiB
PHP
Executable File
258 lines
10 KiB
PHP
Executable File
<?php
|
|
|
|
require_once __DIR__ . '/includes/db.php';
|
|
require_once __DIR__ . '/common/helpers/sender_factory.php';
|
|
require_once __DIR__ . '/common/helpers/converter_factory.php';
|
|
require_once __DIR__ . '/includes/schedule_helpers.php';
|
|
|
|
use Common\Helpers\SenderFactory;
|
|
use Common\Helpers\ConverterFactory;
|
|
|
|
define('DAEMON_MODE', php_sapi_name() === 'cli' && !isset($_GET['run']));
|
|
define('SLEEP_INTERVAL', 5);
|
|
|
|
function getTranslationButtons(PDO $pdo, string $text): array
|
|
{
|
|
$stmtTelegram = $pdo->query("SELECT language_code, flag_emoji FROM supported_languages WHERE is_active = 1 AND telegram_enabled = 1");
|
|
$telegramLanguages = $stmtTelegram->fetchAll();
|
|
|
|
$stmtDiscord = $pdo->query("SELECT language_code, flag_emoji FROM supported_languages WHERE is_active = 1 AND discord_enabled = 1");
|
|
$discordLanguages = $stmtDiscord->fetchAll();
|
|
|
|
if (count($telegramLanguages) <= 1 && count($discordLanguages) <= 1) {
|
|
return [];
|
|
}
|
|
|
|
return [
|
|
'telegram' => count($telegramLanguages) > 1 ? buildTelegramTranslationButtons($pdo, $telegramLanguages, $text) : [],
|
|
'discord' => count($discordLanguages) > 1 ? buildDiscordTranslationButtons($discordLanguages, $text) : []
|
|
];
|
|
}
|
|
|
|
function buildTelegramTranslationButtons(PDO $pdo, array $languages, string $text): array
|
|
{
|
|
if (count($languages) <= 1) {
|
|
return [];
|
|
}
|
|
|
|
// Guardar texto en la base de datos con hash consistente
|
|
$textHash = md5($text);
|
|
$stmt = $pdo->prepare("INSERT INTO translation_cache (text_hash, original_text) VALUES (?, ?) ON DUPLICATE KEY UPDATE original_text = VALUES(original_text)");
|
|
$stmt->execute([$textHash, $text]);
|
|
|
|
$buttons = [];
|
|
|
|
foreach ($languages as $lang) {
|
|
$buttons[] = [
|
|
'text' => $lang['flag_emoji'] . ' ' . strtoupper($lang['language_code']),
|
|
'callback_data' => 'translate:' . $lang['language_code'] . ':' . $textHash
|
|
];
|
|
}
|
|
|
|
return [
|
|
'inline_keyboard' => array_chunk($buttons, 3)
|
|
];
|
|
}
|
|
|
|
function buildDiscordTranslationButtons(array $languages, string $text): array
|
|
{
|
|
$buttons = [];
|
|
|
|
$textHash = md5($text);
|
|
|
|
foreach ($languages as $lang) {
|
|
$buttons[] = [
|
|
'label' => $lang['flag_emoji'] . ' ' . strtoupper($lang['language_code']),
|
|
'custom_id' => 'translate_' . $lang['language_code'] . ':' . $textHash,
|
|
'style' => 1
|
|
];
|
|
}
|
|
|
|
return [
|
|
[
|
|
'type' => 1,
|
|
'components' => array_slice($buttons, 0, 5)
|
|
]
|
|
];
|
|
}
|
|
|
|
function processScheduledMessages(): array
|
|
{
|
|
$pdo = getDbConnection();
|
|
|
|
$stmt = $pdo->query("SELECT NOW() as now");
|
|
$now = $stmt->fetch()['now'];
|
|
|
|
$stmt = $pdo->prepare("
|
|
SELECT s.*, m.content, r.platform_id, r.platform, r.name as recipient_name
|
|
FROM schedules s
|
|
JOIN messages m ON s.message_id = m.id
|
|
JOIN recipients r ON s.recipient_id = r.id
|
|
WHERE s.status = 'pending'
|
|
AND s.send_time <= ?
|
|
ORDER BY s.send_time ASC
|
|
LIMIT 50
|
|
");
|
|
$stmt->execute([$now]);
|
|
$schedules = $stmt->fetchAll();
|
|
|
|
$results = ['processed' => 0, 'sent' => 0, 'failed' => 0];
|
|
|
|
foreach ($schedules as $schedule) {
|
|
$stmt = $pdo->prepare("UPDATE schedules SET status = 'processing' WHERE id = ?");
|
|
$stmt->execute([$schedule['id']]);
|
|
|
|
try {
|
|
$sender = SenderFactory::create($schedule['platform']);
|
|
|
|
// Obtener botones de traducción (convertir HTML a texto plano)
|
|
$plainText = $schedule['content'];
|
|
// Marcar donde hay imágenes
|
|
$plainText = preg_replace('/<img[^>]+src=["\']([^"\']+)["\'][^>]*>/i', "\n[IMAGEN]\n", $plainText);
|
|
// Convertir saltos de párrafo y br a saltos de línea dobles
|
|
$plainText = preg_replace('/<\/p>/i', "\n\n", $plainText);
|
|
$plainText = preg_replace('/<p[^>]*>/i', '', $plainText);
|
|
$plainText = preg_replace('/<br\s*\/?>/i', "\n", $plainText);
|
|
// Eliminar HTML restante
|
|
$plainText = html_entity_decode(strip_tags($plainText), ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
|
// Limpiar espacios múltiples pero preservar saltos de línea (máximo 2)
|
|
$plainText = preg_replace('/[ \t]+/', ' ', $plainText);
|
|
$plainText = preg_replace('/\n{3,}/', "\n\n", $plainText);
|
|
$plainText = trim($plainText);
|
|
$translationButtons = getTranslationButtons($pdo, $plainText);
|
|
|
|
// Parsear el contenido HTML en segmentos manteniendo el orden
|
|
$segments = $sender->parseContent($schedule['content']);
|
|
|
|
$messageCount = 0;
|
|
$totalSegments = count($segments);
|
|
$currentSegment = 0;
|
|
|
|
// Enviar cada segmento en el orden correcto
|
|
foreach ($segments as $segment) {
|
|
$currentSegment++;
|
|
$isLastSegment = ($currentSegment === $totalSegments);
|
|
|
|
if ($segment['type'] === 'text') {
|
|
// Convertir el texto al formato de la plataforma
|
|
$textContent = ConverterFactory::convert($schedule['platform'], $segment['content']);
|
|
|
|
if (!empty(trim($textContent))) {
|
|
$buttons = null;
|
|
if ($isLastSegment && $schedule['platform'] !== 'telegram') {
|
|
$buttons = $translationButtons['discord'];
|
|
}
|
|
|
|
if ($schedule['platform'] === 'telegram') {
|
|
$sender->sendMessage($schedule['platform_id'], $textContent);
|
|
} else {
|
|
$sender->sendMessage($schedule['platform_id'], $textContent, null, $buttons);
|
|
}
|
|
$messageCount++;
|
|
}
|
|
} elseif ($segment['type'] === 'image') {
|
|
$imagePath = $segment['src'];
|
|
|
|
$appUrl = $_ENV['APP_URL'] ?? getenv('APP_URL') ?? '';
|
|
$baseUrl = rtrim($appUrl, '/');
|
|
|
|
$buttons = null;
|
|
if ($isLastSegment && $schedule['platform'] !== 'telegram') {
|
|
$buttons = $translationButtons['discord'];
|
|
}
|
|
|
|
if ($schedule['platform'] === 'telegram') {
|
|
if (strpos($imagePath, 'http') !== 0) {
|
|
$imageUrl = $baseUrl . '/' . ltrim($imagePath, '/');
|
|
} else {
|
|
$imageUrl = $imagePath;
|
|
}
|
|
$sender->sendPhoto($schedule['platform_id'], $imageUrl);
|
|
$messageCount++;
|
|
} else {
|
|
$imgPath = parse_url($imagePath, PHP_URL_PATH) ?: $imagePath;
|
|
if (file_exists($imgPath)) {
|
|
$sender->sendMessageWithImages($schedule['platform_id'], '', [$imgPath], $buttons);
|
|
$messageCount++;
|
|
} elseif (strpos($imagePath, 'http') === 0) {
|
|
$embed = ['image' => ['url' => $imagePath]];
|
|
$sender->sendMessage($schedule['platform_id'], '', $embed, $buttons);
|
|
$messageCount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Enviar botones de traducción en mensaje separado para Telegram
|
|
if ($schedule['platform'] === 'telegram' && !empty($translationButtons['telegram'])) {
|
|
$translationMessage = "🌐 <b>Traducciones disponibles:</b>\nHaz clic en una bandera para ver la traducción";
|
|
$sender->sendMessage($schedule['platform_id'], $translationMessage, $translationButtons['telegram']);
|
|
$messageCount++;
|
|
}
|
|
|
|
$stmt = $pdo->prepare("
|
|
INSERT INTO sent_messages (schedule_id, recipient_id, platform_message_id, message_count, sent_at)
|
|
VALUES (?, ?, ?, ?, NOW())
|
|
");
|
|
$stmt->execute([$schedule['id'], $schedule['recipient_id'], '', $messageCount]);
|
|
|
|
if ($schedule['is_recurring']) {
|
|
$nextTime = calculateNextSendTime($schedule['recurring_days'], $schedule['recurring_time']);
|
|
|
|
$stmt = $pdo->prepare("
|
|
INSERT INTO schedules (message_id, recipient_id, send_time, status, is_recurring, recurring_days, recurring_time, created_at)
|
|
VALUES (?, ?, ?, 'pending', 1, ?, ?, NOW())
|
|
");
|
|
$stmt->execute([
|
|
$schedule['message_id'],
|
|
$schedule['recipient_id'],
|
|
$nextTime,
|
|
$schedule['recurring_days'],
|
|
$schedule['recurring_time']
|
|
]);
|
|
}
|
|
|
|
$stmt = $pdo->prepare("UPDATE schedules SET status = 'sent', sent_at = NOW() WHERE id = ?");
|
|
$stmt->execute([$schedule['id']]);
|
|
|
|
$results['sent']++;
|
|
|
|
} catch (Exception $e) {
|
|
$stmt = $pdo->prepare("UPDATE schedules SET status = 'failed', error_message = ? WHERE id = ?");
|
|
$stmt->execute([$e->getMessage(), $schedule['id']]);
|
|
|
|
$results['failed'];
|
|
}
|
|
|
|
$results['processed']++;
|
|
}
|
|
|
|
return $results;
|
|
}
|
|
|
|
function logMessage(string $message): void
|
|
{
|
|
echo "[" . date('Y-m-d H:i:s') . "] " . $message . PHP_EOL;
|
|
}
|
|
|
|
if (DAEMON_MODE) {
|
|
logMessage("Process Queue Worker started");
|
|
|
|
while (true) {
|
|
try {
|
|
$results = processScheduledMessages();
|
|
|
|
if ($results['processed'] > 0) {
|
|
logMessage("Processed: {$results['processed']}, Sent: {$results['sent']}, Failed: {$results['failed']}");
|
|
}
|
|
} catch (Exception $e) {
|
|
logMessage("Error: " . $e->getMessage());
|
|
}
|
|
|
|
sleep(SLEEP_INTERVAL);
|
|
}
|
|
} else {
|
|
$results = processScheduledMessages();
|
|
echo "Processed: {$results['processed']}, Sent: {$results['sent']}, Failed: {$results['failed']}\n";
|
|
}
|