Framework moderno y elegante para crear bots de Telegram con Node.js.
- 🎯 API Simple: Sintaxis clara y expresiva
- 📦 Modular: Arquitectura bien organizada
- ⚡ Descargas Avanzadas: Con progreso, lotes y cancelación
- 🎨 Markdown Personalizado: Soporte para formateo rico
- 🎬 FFmpeg Integrado: Generación de thumbnails y análisis de videos
- 🔄 Middleware: Sistema de middlewares tipo Express
- 💾 Sesiones: Persistencia automática
- 🛡️ Robusto: Manejo de errores y reintentos automáticos
npm install telegram debugCopia la carpeta zerogram/ a tu proyecto.
const Zerogram = require('./zerogram');
const bot = new Zerogram(
12345678, // API ID
'your_api_hash', // API Hash
'bot:token', // Bot Token
{
debug: true,
sessionsDir: './sessions'
}
);
// Inicializar
await bot.init();
// Comando simple
bot.command('start', async (ctx) => {
await ctx.reply('¡Hola! Soy tu bot 🤖');
});
// Comando con argumentos
bot.command('echo', async (ctx, args) => {
await ctx.reply(args.join(' ') || 'Envía algo para hacer echo');
});new Zerogram(apiId, apiHash, botToken, options)Parámetros:
apiId(number): Tu API ID de TelegramapiHash(string): Tu API HashbotToken(string): Token del bot de @BotFatheroptions(object):debug(boolean): Activar logs de debugsessionsDir(string): Directorio para sesionesmaxRetries(number): Reintentos de conexión (default: 3)retryDelay(number): Delay entre reintentos en ms (default: 2000)
Inicializa la conexión con Telegram.
await bot.init();Registra un comando.
bot.command('help', async (ctx, args) => {
await ctx.reply('**Comandos disponibles:**\n/start\n/help');
});Registra un callback para botones inline.
bot.onCallback('like', async (ctx) => {
await ctx.client.sendMessage(ctx.userId, {
message: '¡Te gustó! ❤️'
});
});Registra un middleware.
bot.use(async (ctx, next) => {
console.log('Nueva actualización:', ctx.update);
await next();
});Detiene el bot de forma segura.
await bot.stop();Cada handler recibe un objeto ctx enriquecido:
ctx.bot: Instancia del botctx.client: Cliente de Telegramctx.update: Actualización raw de Telegramctx.message: Objeto del mensaje
Responde al mensaje actual.
await ctx.reply('**Negrita**, __cursiva__, `código`');Envía un mensaje al chat actual.
await ctx.send('Hola mundo', { parseMode: 'html' });Envía un archivo.
await ctx.sendFile('./photo.jpg', {
caption: 'Mira esta foto'
});Obtiene el mensaje al que se está respondiendo.
const replyMsg = await ctx.getReplyMessage();
if (replyMsg) {
console.log('Respondiendo a:', replyMsg.text);
}Descarga medios con progreso.
const buffer = await ctx.downloadMedia(message, {
filePath: './downloads/video.mp4',
onProgress: (progress) => {
console.log(`${progress.percent.toFixed(1)}% - ${progress.speed} bytes/s`);
}
});Descarga múltiples archivos.
const results = await ctx.downloadMediaBatch(messages, {
dir: './downloads',
onProgress: (p) => {
console.log(`Archivo ${p.index}/${p.total}: ${p.percent.toFixed(1)}%`);
}
});Genera un thumbnail de un video.
const thumbnail = await ctx.thumbFromVideo(videoBuffer, {
seek: 1.5, // Segundo 1.5
width: 320
});Zerogram soporta markdown personalizado:
await ctx.reply('**Negrita**');
await ctx.reply('__Cursiva__');
await ctx.reply('`Código`');
await ctx.reply('[Link](https://example.com)');const Zerogram = require('./zerogram');
// Crear botones
const buttons = [
[
Zerogram.createButton('👍 Like', 'like:123'),
Zerogram.createButton('👎 Dislike', 'dislike:123')
],
[
Zerogram.urlButton('🌐 Website', 'https://example.com')
]
];
await ctx.reply('¿Te gusta?', { buttons });
// Manejar callback
bot.onCallback('like', async (ctx) => {
await ctx.client.answerCallbackQuery(ctx.queryId, {
message: '¡Gracias!',
alert: false
});
});Los middlewares se ejecutan antes de los handlers:
// Logger
bot.use(async (ctx, next) => {
console.log(`[${new Date().toISOString()}] Update received`);
await next();
});
// Auth
bot.use(async (ctx, next) => {
const userId = ctx.message?.peerId?.userId;
if (!isAllowed(userId)) {
await ctx.reply('No autorizado');
return; // No llamar a next()
}
await next();
});
// Error handler
bot.use(async (ctx, next) => {
try {
await next();
} catch (error) {
console.error('Error:', error);
await ctx.reply('❌ Ocurrió un error');
}
});const controller = new AbortController();
// Guardar en map global
ctx.downloadControllers.set(userId, controller);
try {
const buffer = await ctx.downloadMedia(message, {
controller,
onProgress: (p) => {
statusMsg.safeEdit(`Descargando: ${p.percent.toFixed(1)}%`);
}
});
} catch (error) {
if (error.message === 'DOWNLOAD_CANCELLED') {
await ctx.reply('⚠️ Descarga cancelada');
}
}
// Para cancelar:
const controller = ctx.downloadControllers.get(userId);
if (controller) {
controller.abort();
}const messages = await ctx.client.getMessages(chatId, { limit: 10 });
const results = await ctx.downloadMediaBatch(messages, {
dir: './downloads',
onProgress: (p) => {
statusMsg.safeEdit(
`📥 Descargando archivo ${p.index}/${p.total}\n` +
`Progreso: ${p.overallPercent.toFixed(1)}%\n` +
`Velocidad: ${formatSpeed(p.speed)}`
);
}
});
console.log('Descargados:', results.map(r => r.filePath));Zerogram incluye utilidades para trabajar con videos:
// Generar thumbnail
const thumbnail = await ctx.thumbFromVideo(videoBuffer, {
seek: 2.5, // Capturar en el segundo 2.5
width: 320, // Ancho del thumbnail
timeout: 10000 // Timeout en ms
});
await ctx.sendFile(thumbnail, {
caption: 'Thumbnail del video'
});
// Obtener duración
const duration = await ctx.bot.ffutil.duration(videoBuffer);
console.log(`Duración: ${duration}s`);my-bot/
├── commands/
│ ├── start.js
│ ├── help.js
│ └── download.js
├── callbacks/
│ └── actions.js
└── index.js
module.exports = async (ctx) => {
await ctx.reply('¡Bienvenido! 👋');
};module.exports = {
like: async (ctx) => {
await ctx.reply('¡Te gustó! ❤️');
},
dislike: async (ctx) => {
await ctx.reply('No te gustó 💔');
}
};const Zerogram = require('./zerogram');
const path = require('path');
const bot = new Zerogram(apiId, apiHash, botToken);
await bot.init();
// Cargar comandos
await Zerogram.loadModules(
path.join(__dirname, 'commands'),
'command',
(name, handler) => bot.command(name, handler)
);
// Cargar callbacks
await Zerogram.loadModules(
path.join(__dirname, 'callbacks'),
'callback',
(name, handler) => bot.onCallback(name, handler)
);Zerogram maneja automáticamente los errores de FloodWait:
// Se reintentará automáticamente después del tiempo requerido
await bot.init();bot.on('ready', () => {
console.log('✅ Bot iniciado');
});
bot.on('error', (error) => {
console.error('❌ Error:', error);
});
bot.on('unhandled', (ctx) => {
console.log('⚠️ Update no manejado:', ctx.update);
});
bot.on('stopped', () => {
console.log('🛑 Bot detenido');
});const Zerogram = require('./zerogram');
const path = require('path');
const bot = new Zerogram(apiId, apiHash, botToken);
await bot.init();
bot.command('download', async (ctx) => {
const replyMsg = await ctx.getReplyMessage();
if (!replyMsg?.media) {
return ctx.reply('❌ Responde a un archivo para descargarlo');
}
const statusMsg = await ctx.reply('📥 Descargando...');
const userId = ctx.message.peerId.userId.toString();
const controller = new AbortController();
ctx.downloadControllers.set(userId, controller);
try {
await ctx.downloadMedia(replyMsg, {
filePath: path.join('./downloads', `file_${Date.now()}`),
controller,
onProgress: (p) => {
statusMsg.safeEdit(
`📥 Descargando: ${p.percent.toFixed(1)}%\n` +
`Velocidad: ${(p.speed / 1024 / 1024).toFixed(2)} MB/s`
);
}
});
await statusMsg.safeEdit('✅ Descarga completada');
} catch (error) {
if (error.message === 'DOWNLOAD_CANCELLED') {
await statusMsg.safeEdit('⚠️ Descarga cancelada');
} else {
await statusMsg.safeEdit('❌ Error en la descarga');
}
} finally {
ctx.downloadControllers.delete(userId);
}
});
bot.command('cancel', async (ctx) => {
const userId = ctx.message.peerId.userId.toString();
const controller = ctx.downloadControllers.get(userId);
if (controller) {
controller.abort();
await ctx.reply('🛑 Cancelando descarga...');
} else {
await ctx.reply('⚠️ No hay descargas en curso');
}
});# FFmpeg paths (opcional)
export FFMPEG_PATH=/usr/bin/ffmpeg
export FFPROBE_PATH=/usr/bin/ffprobe
# Debug
export DEBUG=zerogram*const bot = new Zerogram(apiId, apiHash, botToken, {
debug: true,
sessionsDir: './sessions',
maxRetries: 5,
retryDelay: 3000,
connectionRetries: 3,
useWSS: true,
maxConcurrentDownloads: 2
});MIT
¡Las contribuciones son bienvenidas! Por favor:
- Fork el proyecto
- Crea una rama para tu feature
- Commit tus cambios
- Push a la rama
- Abre un Pull Request
- Usa
safeEditpara editar mensajes sin errores si el mensaje ya fue eliminado - Cancela descargas guardando el
AbortControlleren un Map global - Middlewares son perfectos para logging, auth y error handling
- Carga automática mantiene tu código organizado en archivos separados
- FFmpeg requiere tener instalado ffmpeg y ffprobe en tu sistema
- Issues: [GitHub Issues]
- Telegram: [https://t.me/Bots0075]
- Docs: [https://github.com/UserZero075/ZerogramJS/blob/main/README.md]
Made with ❤️ for the Telegram Bot community
