Foto con cámara usando JavaScript y Telegram

Monitorear cámara web con Telegram y JavaScript

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
Foto con cámara usando JavaScript y Telegram

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
Foto enviada con Bot de Telegram usando JS para acceder a la cámara

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.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *