Mejoras en el envío de plantillas con imágenes
- Agregar detección de URLs de Discord gifts para evitar botones de traducción - Enviar imágenes en orden correcto (texto-imagen-texto-imagen) en Discord y Telegram - Usar APP_URL del .env para las URLs de imágenes - Agregar funciones sendContentWithOrderedImagesAndButtons en ambos bots
This commit is contained in:
@@ -95,34 +95,29 @@ class DiscordSender
|
|||||||
$result = null;
|
$result = null;
|
||||||
|
|
||||||
if (!empty($images)) {
|
if (!empty($images)) {
|
||||||
// Verificar si las imágenes son locales o URLs
|
|
||||||
$localImages = [];
|
|
||||||
$remoteImages = [];
|
$remoteImages = [];
|
||||||
|
|
||||||
|
$appUrl = $_ENV['APP_URL'] ?? getenv('APP_URL') ?? '';
|
||||||
|
$baseUrl = rtrim($appUrl, '/');
|
||||||
|
|
||||||
foreach ($images as $imageUrl) {
|
foreach ($images as $imageUrl) {
|
||||||
if (strpos($imageUrl, 'http') === 0) {
|
if (strpos($imageUrl, 'http') === 0) {
|
||||||
// Es una URL remota
|
|
||||||
$remoteImages[] = $imageUrl;
|
$remoteImages[] = $imageUrl;
|
||||||
} elseif (file_exists($imageUrl)) {
|
|
||||||
// Es un archivo local
|
|
||||||
$localImages[] = $imageUrl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enviar imágenes locales como adjuntos
|
|
||||||
if (!empty($localImages)) {
|
|
||||||
$result = $this->sendMessageWithAttachments($channelId, $content, $localImages);
|
|
||||||
} else {
|
} else {
|
||||||
$result = $this->sendMessage($channelId, $content, null, $buttons);
|
// Convertir a URL usando APP_URL
|
||||||
|
$remoteImages[] = $baseUrl . '/' . ltrim($imageUrl, '/');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enviar imágenes remotas como embeds
|
// Enviar todas las imágenes como embeds
|
||||||
|
$result = $this->sendMessage($channelId, $content, null, $buttons);
|
||||||
|
|
||||||
foreach ($remoteImages as $imageUrl) {
|
foreach ($remoteImages as $imageUrl) {
|
||||||
$embed = [
|
$embed = [
|
||||||
'image' => ['url' => $imageUrl]
|
'image' => ['url' => $imageUrl]
|
||||||
];
|
];
|
||||||
$result = $this->sendMessage($channelId, '', $embed, $buttons);
|
$result = $this->sendMessage($channelId, '', $embed);
|
||||||
$buttons = null; // Solo enviar botones en el primer mensaje
|
$buttons = null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$result = $this->sendMessage($channelId, $content, null, $buttons);
|
$result = $this->sendMessage($channelId, $content, null, $buttons);
|
||||||
@@ -136,26 +131,48 @@ class DiscordSender
|
|||||||
* Divide el contenido en segmentos y los envía manteniendo el orden
|
* Divide el contenido en segmentos y los envía manteniendo el orden
|
||||||
*/
|
*/
|
||||||
public function sendContentWithOrderedImages(string $channelId, array $segments): void
|
public function sendContentWithOrderedImages(string $channelId, array $segments): void
|
||||||
|
{
|
||||||
|
$this->sendContentWithOrderedImagesAndButtons($channelId, $segments, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sendContentWithOrderedImagesAndButtons(string $channelId, array $segments, ?array $buttons = null): void
|
||||||
{
|
{
|
||||||
$channelId = $this->resolveUserToDmChannel($channelId);
|
$channelId = $this->resolveUserToDmChannel($channelId);
|
||||||
|
|
||||||
|
$appUrl = $_ENV['APP_URL'] ?? getenv('APP_URL') ?? '';
|
||||||
|
$baseUrl = rtrim($appUrl, '/');
|
||||||
|
|
||||||
|
$totalSegments = count($segments);
|
||||||
|
$currentSegment = 0;
|
||||||
|
|
||||||
foreach ($segments as $segment) {
|
foreach ($segments as $segment) {
|
||||||
|
$currentSegment++;
|
||||||
|
$isLastSegment = ($currentSegment === $totalSegments);
|
||||||
|
|
||||||
if ($segment['type'] === 'text') {
|
if ($segment['type'] === 'text') {
|
||||||
// Enviar texto
|
|
||||||
if (!empty(trim($segment['content']))) {
|
if (!empty(trim($segment['content']))) {
|
||||||
|
// Solo enviar botones en el último segmento de texto
|
||||||
|
if ($isLastSegment && $buttons) {
|
||||||
|
$this->sendMessage($channelId, $segment['content'], null, $buttons);
|
||||||
|
} else {
|
||||||
$this->sendMessage($channelId, $segment['content']);
|
$this->sendMessage($channelId, $segment['content']);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} elseif ($segment['type'] === 'image') {
|
} elseif ($segment['type'] === 'image') {
|
||||||
// Enviar imagen
|
|
||||||
$imagePath = $segment['src'];
|
$imagePath = $segment['src'];
|
||||||
|
|
||||||
if (strpos($imagePath, 'http') === 0) {
|
if (strpos($imagePath, 'http') === 0) {
|
||||||
// URL remota - enviar como embed
|
|
||||||
$embed = ['image' => ['url' => $imagePath]];
|
$embed = ['image' => ['url' => $imagePath]];
|
||||||
|
} else {
|
||||||
|
$imageUrl = $baseUrl . '/' . ltrim($imagePath, '/');
|
||||||
|
$embed = ['image' => ['url' => $imageUrl]];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Solo enviar botones en el último segmento
|
||||||
|
if ($isLastSegment && $buttons) {
|
||||||
|
$this->sendMessage($channelId, '', $embed, $buttons);
|
||||||
|
} else {
|
||||||
$this->sendMessage($channelId, '', $embed);
|
$this->sendMessage($channelId, '', $embed);
|
||||||
} elseif (file_exists($imagePath)) {
|
|
||||||
// Archivo local - enviar como adjunto
|
|
||||||
$this->sendMessageWithAttachments($channelId, '', [$imagePath]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,21 +113,15 @@ function handleTemplateCommand(PDO $pdo, Message $message, string $command): voi
|
|||||||
$template = $stmt->fetch();
|
$template = $stmt->fetch();
|
||||||
|
|
||||||
if ($template) {
|
if ($template) {
|
||||||
require_once __DIR__ . '/discord/converters/HtmlToDiscordMarkdownConverter.php';
|
|
||||||
require_once __DIR__ . '/discord/DiscordSender.php';
|
require_once __DIR__ . '/discord/DiscordSender.php';
|
||||||
require_once __DIR__ . '/src/Translate.php';
|
|
||||||
|
|
||||||
$converter = new \Discord\Converters\HtmlToDiscordMarkdownConverter();
|
|
||||||
|
|
||||||
$images = $converter->extractImages($template['message_content']);
|
|
||||||
$contentWithoutImages = $converter->removeImages($template['message_content']);
|
|
||||||
$content = $converter->convert($contentWithoutImages);
|
|
||||||
|
|
||||||
require_once __DIR__ . '/discord/DiscordSender.php';
|
|
||||||
require_once __DIR__ . '/src/Translate.php';
|
|
||||||
|
|
||||||
$sender = new \Discord\DiscordSender();
|
$sender = new \Discord\DiscordSender();
|
||||||
|
|
||||||
|
// Parsear el contenido manteniendo el orden texto-imagen
|
||||||
|
$segments = $sender->parseContent($template['message_content']);
|
||||||
|
|
||||||
|
if (!empty($segments)) {
|
||||||
|
// Obtener texto completo para botones de traducción
|
||||||
$plainText = $template['message_content'];
|
$plainText = $template['message_content'];
|
||||||
$plainText = preg_replace('/<br\s*\/?>/i', "\n", $plainText);
|
$plainText = preg_replace('/<br\s*\/?>/i', "\n", $plainText);
|
||||||
$plainText = preg_replace('/<\/p>/i', "\n", $plainText);
|
$plainText = preg_replace('/<\/p>/i', "\n", $plainText);
|
||||||
@@ -138,12 +132,9 @@ function handleTemplateCommand(PDO $pdo, Message $message, string $command): voi
|
|||||||
|
|
||||||
$translationButtons = getDiscordTranslationButtons($pdo, $plainText);
|
$translationButtons = getDiscordTranslationButtons($pdo, $plainText);
|
||||||
|
|
||||||
if (!empty($images)) {
|
// Enviar contenido ordenado con botones
|
||||||
$sender->sendMessageWithImages((string)$message->channel_id, $content, $images, $translationButtons);
|
$sender->sendContentWithOrderedImagesAndButtons((string)$message->channel_id, $segments, $translationButtons);
|
||||||
} else {
|
|
||||||
$sender->sendMessage((string)$message->channel_id, $content, null, $translationButtons);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$message->channel->sendMessage("❌ Plantilla no encontrada: #{$command}");
|
$message->channel->sendMessage("❌ Plantilla no encontrada: #{$command}");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifica si un texto contiene contenido real (no solo emojis, espacios, etc)
|
* Verifica si un texto contiene contenido real (no solo emojis, URLs de GIFs, espacios, etc)
|
||||||
* Los emojis se preservan en el texto, solo verificamos que hay más que eso
|
* Los emojis se preservan en el texto, solo verificamos que hay más que eso
|
||||||
*/
|
*/
|
||||||
function hasRealContent(string $text): bool
|
function hasRealContent(string $text): bool
|
||||||
@@ -10,23 +10,34 @@ function hasRealContent(string $text): bool
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hacer una copia para procesarla sin alterar el original
|
|
||||||
$clean = trim($text);
|
$clean = trim($text);
|
||||||
|
|
||||||
if (empty($clean)) {
|
if (empty($clean)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remover emojis y caracteres especiales, preservar solo letras, números y puntuación básica
|
// Remover URLs de GIFs y medias (tenor, giphy, media.tenor, cdn.discordapp, etc)
|
||||||
// Esta expresión regular mantiene letras, números y puntuación, elimina emojis
|
$clean = preg_replace('/https?:\/\/(www\.)?(tenor\.com|giphy\.com|media\.tenor\.com|cdn\.discordapp\.com|media\.discord|gifcdn|gfycat\.com|reddit\.com\/r\/[^\/]+\/comments\/)[^\s]*/i', '', $clean);
|
||||||
// Emojis Unicode: rangos múltiples de caracteres
|
|
||||||
$clean = preg_replace('/[\x{1F300}-\x{1F9FF}]/u', '', $clean); // Emojis de rango alto (0x1F300-0x1F9FF)
|
// Remover URLs de Discord gifts
|
||||||
$clean = preg_replace('/[\x{2600}-\x{26FF}]/u', '', $clean); // Símbolos de ajedrez, dados, etc
|
$clean = preg_replace('/https?:\/\/(www\.)?(discord\.gift|discord\.com\/gifts)[^\s]*/i', '', $clean);
|
||||||
$clean = preg_replace('/[\x{2B50}]/u', '', $clean); // Estrella
|
|
||||||
$clean = preg_replace('/[\x{00A0}\s]+/u', '', $clean); // Espacios en blanco (incluyendo no-breaking space)
|
// Remover otros URLs comunes (http://..., https://...)
|
||||||
$clean = preg_replace('/[\p{P}]/u', '', $clean); // Puntuación Unicode (incluyendo 👍)
|
$clean = preg_replace('/https?:\/\/[^\s]+/i', '', $clean);
|
||||||
|
|
||||||
|
$clean = trim($clean);
|
||||||
|
|
||||||
|
if (empty($clean)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remover emojis y caracteres especiales
|
||||||
|
$clean = preg_replace('/[\x{1F300}-\x{1F9FF}]/u', '', $clean);
|
||||||
|
$clean = preg_replace('/[\x{2600}-\x{26FF}]/u', '', $clean);
|
||||||
|
$clean = preg_replace('/[\x{2B50}]/u', '', $clean);
|
||||||
|
$clean = preg_replace('/[\x{00A0}\s]+/u', '', $clean);
|
||||||
|
$clean = preg_replace('/[\p{P}]/u', '', $clean);
|
||||||
|
|
||||||
// Si después de remover emojis y espacios no queda nada, es solo emojis
|
|
||||||
return !empty(trim($clean));
|
return !empty(trim($clean));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -247,20 +247,43 @@ class TelegramSender
|
|||||||
*/
|
*/
|
||||||
public function sendContentWithOrderedImages(int $chatId, array $segments): void
|
public function sendContentWithOrderedImages(int $chatId, array $segments): void
|
||||||
{
|
{
|
||||||
|
$this->sendContentWithOrderedImagesAndButtons($chatId, $segments, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enviar contenido con texto e imágenes en el orden correcto con botones
|
||||||
|
*/
|
||||||
|
public function sendContentWithOrderedImagesAndButtons(int $chatId, array $segments, ?array $buttons = null): void
|
||||||
|
{
|
||||||
|
$appUrl = $_ENV['APP_URL'] ?? getenv('APP_URL') ?? '';
|
||||||
|
$baseUrl = rtrim($appUrl, '/');
|
||||||
|
|
||||||
|
$totalSegments = count($segments);
|
||||||
|
$currentSegment = 0;
|
||||||
|
|
||||||
foreach ($segments as $segment) {
|
foreach ($segments as $segment) {
|
||||||
|
$currentSegment++;
|
||||||
|
$isLastSegment = ($currentSegment === $totalSegments);
|
||||||
|
|
||||||
if ($segment['type'] === 'text') {
|
if ($segment['type'] === 'text') {
|
||||||
// Enviar texto
|
|
||||||
if (!empty(trim($segment['content']))) {
|
if (!empty(trim($segment['content']))) {
|
||||||
|
if ($isLastSegment && $buttons) {
|
||||||
|
$this->sendMessage($chatId, $segment['content'], $buttons);
|
||||||
|
} else {
|
||||||
$this->sendMessage($chatId, $segment['content']);
|
$this->sendMessage($chatId, $segment['content']);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} elseif ($segment['type'] === 'image') {
|
} elseif ($segment['type'] === 'image') {
|
||||||
$imagePath = $segment['src'];
|
$imagePath = $segment['src'];
|
||||||
|
|
||||||
if (file_exists($imagePath)) {
|
// Convertir ruta local a URL usando APP_URL
|
||||||
// Es un archivo local
|
if (strpos($imagePath, 'http') !== 0) {
|
||||||
$this->sendPhoto($chatId, $imagePath);
|
$imagePath = $baseUrl . '/' . ltrim($imagePath, '/');
|
||||||
} elseif (strpos($imagePath, 'http') === 0) {
|
}
|
||||||
// Es una URL remota
|
|
||||||
|
if ($isLastSegment && $buttons) {
|
||||||
|
$this->sendPhoto($chatId, $imagePath, null, $buttons);
|
||||||
|
} else {
|
||||||
$this->sendPhoto($chatId, $imagePath);
|
$this->sendPhoto($chatId, $imagePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -335,26 +335,25 @@ function sendTemplateByCommand(PDO $pdo, Telegram\TelegramSender $sender, int $c
|
|||||||
$template = $stmt->fetch();
|
$template = $stmt->fetch();
|
||||||
|
|
||||||
if ($template) {
|
if ($template) {
|
||||||
$converter = new Telegram\Converters\HtmlToTelegramHtmlConverter();
|
// Parsear el contenido manteniendo el orden texto-imagen
|
||||||
$content = $converter->convert($template['message_content']);
|
$segments = $sender->parseContent($template['message_content']);
|
||||||
|
|
||||||
|
if (!empty($segments)) {
|
||||||
|
// Obtener texto completo para botones de traducción
|
||||||
$plainText = $template['message_content'];
|
$plainText = $template['message_content'];
|
||||||
$plainText = preg_replace('/<br\s*\/?>/i', "\n", $plainText);
|
$plainText = preg_replace('/<br\s*\/?>/i', "\n", $plainText);
|
||||||
$plainText = preg_replace('/<\/p>/i', "\n", $plainText);
|
$plainText = preg_replace('/<\/p>/i', "\n", $plainText);
|
||||||
$plainText = preg_replace('/<p[^>]*>/i', '', $plainText);
|
$plainText = preg_replace('/<p[^>]*>/i', '', $plainText);
|
||||||
$plainText = strip_tags($plainText);
|
$plainText = strip_tags($plainText);
|
||||||
$plainText = html_entity_decode($plainText, ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
$plainText = html_entity_decode($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('/[ \t]+/', ' ', $plainText);
|
||||||
$plainText = preg_replace('/\n\s*\n/', "\n", $plainText);
|
$plainText = preg_replace('/\n\s*\n/', "\n", $plainText);
|
||||||
$plainText = trim($plainText);
|
$plainText = trim($plainText);
|
||||||
|
|
||||||
$translationButtons = getTelegramTranslationButtons($pdo, $plainText);
|
$translationButtons = getTelegramTranslationButtons($pdo, $plainText);
|
||||||
|
|
||||||
if ($translationButtons) {
|
// Enviar contenido ordenado con botones
|
||||||
$sender->sendMessage($chatId, $content, $translationButtons);
|
$sender->sendContentWithOrderedImagesAndButtons($chatId, $segments, $translationButtons);
|
||||||
} else {
|
|
||||||
$sender->sendMessage($chatId, $content);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$sender->sendMessage($chatId, "❌ Plantilla no encontrada: #{$command}");
|
$sender->sendMessage($chatId, "❌ Plantilla no encontrada: #{$command}");
|
||||||
|
|||||||
Reference in New Issue
Block a user