Crea en tu servidor web una RSS de tu canal Telegram para facilitar su uso en tus propias webs y el seguimiento por tus lectores más allá de Telegram.
Creamos una carpeta en un lugar accesible por URL, en nuestro ejemplo en la correspondiente a tudominio.com/feed
Iniciamos el proyecto:
npm init -y
Cargamos dependencias:
npm install node-telegram-bot-api rss
Creamos index.js
, el programa que va a crear rss.xml
en tudominio.com/feed/rss.xml
// index.js (Versión Mejorada)
// 1. Importamos las librerías necesarias
const TelegramBot = require('node-telegram-bot-api');
const RSS = require('rss');
const fs = require('fs');
const path = require('path');
// 2. Configuración del Bot y del Canal
const TOKEN = process.env.TELEGRAM_TOKEN || 'TOKEN DE TU ROBOT EN EL CANAL';
const CHANNEL_ID = process.env.TELEGRAM_CHANNEL_ID || '@TUCANAL';
// 3. Configuración del Feed RSS
const feed = new RSS({
title: 'Feed del canal xx en Telegram',
description: 'Últimas publicaciones del canal XX con enlaces.',
feed_url: 'http://TUDOMINIO.COM/feed/rss.xml',
site_url: 'http://TUDOMINIO.COM',
language: 'es',
pubDate: new Date(),
ttl: '60',
});
const feedPath = path.join(__dirname, 'rss.xml');
// --- FUNCIONES AUXILIARES ---
// Expresión regular para URLs (http/https)
const urlRegex = /(https?:\/\/[^\s]+)/g;
// Extrae el primer enlace encontrado en el texto
function findFirstUrl(text) {
if (!text) return null;
const matches = text.match(urlRegex);
return matches ? matches[0] : null;
}
// Extrae la primera frase completa (hasta el primer '.' o '?')
function getFirstSentence(text) {
if (!text) return 'Nuevo post';
// Buscar primeros índices de '.' y '?'
const dotIndex = text.indexOf('.');
const questionIndex = text.indexOf('?');
let endIndex = -1;
if (dotIndex !== -1 && questionIndex !== -1) {
endIndex = Math.min(dotIndex, questionIndex);
} else if (dotIndex !== -1) {
endIndex = dotIndex;
} else if (questionIndex !== -1) {
endIndex = questionIndex;
}
if (endIndex === -1) {
return text.substring(0, 150);
}
return text.substring(0, endIndex + 1);
}
// Elimina todas las URLs del texto
function removeUrls(text) {
if (!text) return '';
return text.replace(urlRegex, '').trim();
}
// Elimina el carácter '#' pero conserva la palabra
function removeHashtags(text) {
if (!text) return '';
return text.replace(/#(\w+)/g, '$1');
}
// Genera y guarda el feed RSS
function generateFeed(item) {
feed.item(item);
const xml = feed.xml({ indent: true });
try {
fs.writeFileSync(feedPath, xml);
console.log(`✅ Feed RSS actualizado: ${item.title}`);
} catch (err) {
console.error('❌ Error al escribir RSS:', err);
}
}
// Iniciar bot y escuchar el canal
console.log('🤖 Bot iniciado.');
const bot = new TelegramBot(TOKEN, { polling: true });
bot.on('channel_post', async (msg) => {
if (msg.chat.id.toString() !== CHANNEL_ID.toString() && `@${msg.chat.username}` !== CHANNEL_ID) {
return;
}
const raw = msg.text || msg.caption || '';
// Limpiar hashtags antes de procesar
const text = removeHashtags(raw);
const link = findFirstUrl(text);
if (!link) {
console.log('-> Ignorado (sin enlace)');
return;
}
// Obtener la primera frase como rawTitle
const rawTitle = getFirstSentence(text);
// Determinar título: quitar solo el punto final, no el '?' de preguntas
let title;
if (rawTitle.endsWith('.')) {
title = rawTitle.slice(0, -1);
} else {
title = rawTitle;
}
// Descripción: quitar la frase del rawTitle y URLs
let descText = text.replace(rawTitle, '').trim();
let descHtml = removeUrls(descText).replace(/\n/g, '<br>');
// Agregar soporte de imagen o vídeo
try {
if (msg.photo) {
const fileId = msg.photo[msg.photo.length - 1].file_id;
const linkPhoto = await bot.getFileLink(fileId);
descHtml += `<br><br><img src="${linkPhoto}" alt="Imagen" style="max-width:100%;">`;
} else if (msg.video) {
const fileId = msg.video.file_id;
const linkVideo = await bot.getFileLink(fileId);
descHtml += `<br><br><p><a href="${linkVideo}">🎬 Ver vídeo</a></p>`;
}
} catch (err) {
console.error('❌ Error fichero:', err.message);
}
// Crear item y actualizar RSS
const item = {
title,
description: descHtml,
url: link,
guid: msg.message_id,
date: new Date(msg.date * 1000),
custom_elements: [{ 'content:encoded': { _cdata: descHtml } }]
};
generateFeed(item);
});
bot.on('polling_error', (err) => {
console.error('❌ Polling error:', err.code, err.message);
});
Probamos que el programa funciona corriendo index.js
y subiendo una noticia al canal sin parar el programa
cd /var/www/html/maximalismo/centro/feed/
node index.js
Paramos el programa.
Instalamos pm2
para no usar cron
y desde la carpeta del proyecto lo ponemos en marcha
npm install pm2 -g
# Desde la carpeta del proyecto
pm2 start index.js --name "telegram-rss-bot"
Y ahora tendría que aparecer la RSS en: http://tudominio.com/feed/rss.xml
Si quisiera reiniciar pm2 porque modifico el código u otra cosa
pm2 restart telegram-rss-bot
