query("SELECT language_code, flag_emoji FROM supported_languages WHERE is_active = 1"); $languages = $stmt->fetchAll(); if (count($languages) <= 1) { return []; } return [ 'telegram' => buildTelegramTranslationButtons($pdo, $languages, $text), 'discord' => buildDiscordTranslationButtons($languages, $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']; // Convertir saltos de párrafo a saltos de línea $plainText = preg_replace('/<\/p>/i', "\n", $plainText); $plainText = preg_replace('/
]*>/i', '', $plainText);
$plainText = preg_replace('/
/i', "\n", $plainText);
// Eliminar HTML
$plainText = html_entity_decode(strip_tags($plainText), ENT_QUOTES | ENT_HTML5, 'UTF-8');
// Limpiar espacios múltiples pero preservar saltos de línea
$plainText = preg_replace('/[ \t]+/', ' ', $plainText);
$plainText = preg_replace('/\n\s*\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;
// Enviar cada segmento en el orden correcto
foreach ($segments as $segment) {
if ($segment['type'] === 'text') {
// Convertir el texto al formato de la plataforma
$textContent = ConverterFactory::convert($schedule['platform'], $segment['content']);
if (!empty(trim($textContent))) {
// Agregar botones de traducción al último segmento de texto
$buttons = null;
if ($segment === end($segments)) {
$buttons = $schedule['platform'] === 'telegram'
? $translationButtons['telegram']
: $translationButtons['discord'];
}
if ($schedule['platform'] === 'telegram') {
$sender->sendMessage($schedule['platform_id'], $textContent, $buttons);
} else {
$sender->sendMessage($schedule['platform_id'], $textContent, null, $buttons);
}
$messageCount++;
}
} elseif ($segment['type'] === 'image') {
$imagePath = $segment['src'];
// Quitar parámetros de URL si los hay
$imgPath = parse_url($imagePath, PHP_URL_PATH) ?: $imagePath;
if (file_exists($imgPath)) {
// Es un archivo local
$sender->sendMessageWithAttachments($schedule['platform_id'], '', [$imgPath]);
$messageCount++;
} elseif (strpos($imagePath, 'http') === 0) {
// Es una URL remota
$embed = ['image' => ['url' => $imagePath]];
$sender->sendMessage($schedule['platform_id'], '', $embed);
$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";
}