Hace algún tiempo te enseñé a tomar fotos con cualquier cámara y en cualquier dispositivo usando JavaScript. Hoy te voy a enseñar cómo tomar una foto de la cámara y enviarla a Telegram desde cualquier dispositivo, sea móvil o de escritorio.
![Foto con cámara usando JavaScript y Telegram](https://parzibyte.me/blog/wp-content/uploads/2024/05/Foto-con-camara-usando-JavaScript-y-Telegram.png)
Vas a aprender a tener un tipo de cámara de vigilancia fácil, configurable y ejecutable en cualquier teléfono o computadora, todo gracias al poder de JavaScript en el navegador web y la API de Bot de Telegram.
Por mencionar algunas ventajas: las fotos tomadas serán almacenadas en la nube de manera segura, puedes tenerlas en privado o compartirlas con un grupo o canal, no hay límite de almacenamiento en la nube y puedes usar cualquier dispositivo con cámara sin instalar nada.
Cámara de seguridad con Telegram
Con el código que te expondré hoy vas a ser capaz de convertir cualquier dispositivo en una cámara que envía fotos periódicas e instantáneamente en nombre de un Bot de Telegram. No vas a necesitar instalar nada, porque la app se va a ejecutar en el navegador web.
La webapp es totalmente configurable y puedes indicar el id de chat así como el token del bot directamente en la URL, por lo que no necesitas contar con un servidor propio; puedes hacer todo desde el lado del cliente.
Vas a ser capaz de elegir cualquier webcam USB o una cámara de tu teléfono ya sea la trasera o frontal; cualquier cámara conectada al dispositivo funcionará y te permitirá enviar fotos ilimitadas a un chat individual, grupo o canal.
Obtener acceso a la cámara
Se puede acceder a cualquier cámara desde JavaScript, obviamente con el debido permiso. También podemos enumerar los dispositivos disponibles y mostrar el stream en un elemento de tipo video así:
const mostrarStream = idDeDispositivo => {
_getUserMedia({
video: {
// Justo aquí indicamos cuál dispositivo usar
deviceId: idDeDispositivo,
}
},
async (streamObtenido) => {
// Aquí ya tenemos permisos, ahora sí llenamos el select,
// pues si no, no nos daría el nombre de los dispositivos
if ($listaDeDispositivos.length <= 0) {
llenarSelectConDispositivosDisponibles();
}
// Escuchar cuando seleccionen otra opción y entonces llamar a esta función
$listaDeDispositivos.onchange = () => {
// Detener el stream
if (stream) {
stream.getTracks().forEach(function (track) {
track.stop();
});
}
// Mostrar el nuevo stream con el dispositivo seleccionado
mostrarStream($listaDeDispositivos.value);
}
// Simple asignación
stream = streamObtenido;
// Mandamos el stream de la cámara al elemento de vídeo
$video.srcObject = stream;
// Refrescar el canvas
await $video.play();
canvasFueraDePantalla = new OffscreenCanvas($video.videoWidth, $video.videoHeight);
contextoCanvas = canvasFueraDePantalla.getContext("2d");
// Prevenir enviar dos fotos cuando se cambia el dispositivo
if (!yaEstaEnviandoFotos) {
tomarFotoPeriodicamente();
yaEstaEnviandoFotos = true;
}
}, (error) => {
console.log("Permiso denegado o error: ", error);
$estado.innerHTML = "No se puede acceder a la cámara, o no diste permiso.";
});
}
La parte importante es que, cuando obtenemos el stream, comenzamos a tomar fotos periódicamente usando el dispositivo seleccionado por el usuario:
if (!yaEstaEnviandoFotos) {
tomarFotoPeriodicamente();
yaEstaEnviandoFotos = true;
}
Tomando foto del stream con JavaScript
Con el código de arriba vamos a estar viendo el vídeo en tiempo real. Para tomar una foto debemos pausar el vídeo, dibujarlo en un canvas y convertir ese canvas a BLOB. Sí, es un proceso que suena largo pero que se lleva tan solo unos milisegundos.
Recientemente aprendí a usar el OffscreenCanvas y lo he utilizado aquí para tomar una foto y convertirla a archivo listo para ser enviado como foto a Telegram en nombre de un Bot:
const tomarFoto = async () => {
//Pausar reproducción
$video.pause();
canvasFueraDePantalla.width = $video.videoWidth;
canvasFueraDePantalla.height = $video.videoHeight;
//Obtener contexto del canvas y dibujar sobre él
contextoCanvas.drawImage($video, 0, 0, canvasFueraDePantalla.width, canvasFueraDePantalla.height);
//Reanudar reproducción
await $video.play();
let foto = await canvasFueraDePantalla.convertToBlob(); //Esta es la foto, en base 64
await enviarImagen(ID_CHAT, TOKEN, foto);
}
El proceso es básicamente pausar el video, dibujarlo en el canvas
con drawImage
, volver a reproducir el vídeo y después convertir el canvas a BLOB con convertToBlob
para obtener la foto tomada como un montón de bytes, es decir, como un archivo.
Esa foto es la que vamos a enviar a la API de Telegram.
Enviando la foto a Telegram
La función enviarImagen queda como se ve a continuación. La he sacado del post donde te explico cómo enviar una foto seleccionada por el usuario a Telegram desde JavaScript, mismo que te recomiendo leer para que entiendas el funcionamiento:
const enviarImagen = async (idChat, token, imagen) => {
const url = `https://api.telegram.org/bot${token}/sendPhoto`;
const fd = new FormData();
fd.append("chat_id", idChat)
const caption = `${$listaDeDispositivos.options[$listaDeDispositivos.selectedIndex].text} ${formateador.format(new Date())}`;
fd.append("caption", caption);
fd.append("photo", imagen);
const respuestaHttp = await fetch(url, {
method: 'POST',
body: fd,
});
return {
respuesta: await respuestaHttp.json(),
codigo: respuestaHttp.status,
};
}
Por cierto, la descripción de la foto contendrá el nombre del dispositivo usado para tomarla y también la fecha y hora del momento en el que fue enviada a Telegram.
Foto periódicamente con Telegram
Ya vimos cómo tomar la foto con la cámara usando JavaScript y cómo enviarla a Telegram. Ahora veamos la función que usa a esos dos métodos y las toma periódicamente haciendo la función de fotos periódicas:
const tomarFotoPeriodicamente = async () => {
while (true) {
await tomarFoto();
await sleep(TIEMPO_ESPERA_ENTRE_FOTOS_EN_MILISEGUNDOS);
}
}
Como puedes ver, toma y envía la foto pero después espera algunos segundos antes de tomar la siguiente foto. Este tiempo de espera lo he colocado yo y, al momento de escribir este post, es de 2 segundos. Tú puedes quitarlo o modificarlo si quieres más frames por segundo.
Poniendo todo junto
Te dejo el código completo en GitHub. La verdad me sorprende lo mucho que se puede lograr al usar las APIs correctas; hace varios años esto no habría sido posible.
![Foto enviada con Bot de Telegram usando JS para acceder a la cámara](https://parzibyte.me/blog/wp-content/uploads/2024/05/Foto-enviada-con-Bot-de-Telegram-usando-JS-para-acceder-a-la-camara.jpg)
Con lo que te enseñé aquí puedes convertir, de manera instantánea, cualquier dispositivo en una cámara de vigilancia. Ah, y también puedes usar varios dispositivos al mismo tiempo para tener más ángulos.
Token e id
En este post asumo que ya tienes tu token del Bot, mismo que el BotFather te debió brindar. Si no, solo habla con él en https://t.me/botfather y crea un nuevo Bot para obtener tu token.
También estoy suponiendo que ya conoces el id de chat, grupo o canal. Si no lo tienes puedes obtener el id de usuario reenviando un mensaje al Bot https://t.me/get_id_bot o https://t.me/JsonDumpBot (no estoy afiliado ni tengo relación con ellos) y estoy seguro de que debe haber distintas maneras de obtenerlo
Demostración y modo de uso
Puedes probar la demostración en el siguiente enlace: https://parzibyte.github.io/ejemplos-javascript/foto-camara-telegram/?token=TU_TOKEN_VA_EN_ESTE_LUGAR&idChat=AQUI_VA_EL_ID_DE_CHAT
Solo que debes indicar tu token y el id de chat al que quieres enviar las fotos en la misma URL antes de acceder.
Obviamente también puedes modificar el código para que el token e id de chat no se lean de la URL y mejor estén definidos en el mismo código.
Yo lo he hecho así por la facilidad de configuración, ya que con el mismo enlace puedes enviar la foto a distintos chats desde varios dispositivos sin estar modificando el código por cada uno.