Compilar wkhtmltopdf para debian bookworm

wkhtmltopdf de momento es la única forma que tengo para generar PDF en python, tras un upgrade de sistema operativo en un servidor tengo la necesidad de actualizar también a la última versión wkhtmltopdf pero al ser un proyecto tan viejo, no han preparado paquetes deb con el qt activado en su repositorio (recuerdo que la versión que viene en los repositorios de debian, no trae qt activado).

No queda otra que compilar los sources y al hacerlo me he encontrado con una gran aventura mañanera (documentación que brilla por su ausencia), así que aquí dejo la solución:

# cd ~
# git clone https://github.com/wkhtmltopdf/wkhtmltopdf.git
# cd wkhtmltopdf
# mkdir build
# cd build

Ahora necesitamos instalar las dependencias necesarias para poder compilar wkhtmltopdf

# apt -y install build-essential xorg libxrender1 libxext6 libfontconfig1 libssl-dev git qtbase5-dev qt5-qmake libqt5webkit5-dev g++ cmake bison flex gperf ruby python3 pkg-config libglu1-mesa-dev libqt5xmlpatterns5-dev libqt5svg5-dev

Y lo compilamos

# qmake ../wkhtmltopdf.pro
# make
# make install

Ahora creo los enlaces simbólicos necesarios para que mi aplicación de django que tiene configurada una ruta específica de donde se encuentran los binarios, los encuentre

# cd /usr/local/bin
# ln -s /usr/bin/wkhtmltopdf .
# ln -s /usr/bin/wkhtmltoimage .

Y listos.

La recomendación del desarrollador es que nos migremos a puppeteer. …

Montar RAID de un NAS con Linux

Hace un par de semanas que estoy trabajando en un caso que tengo varios discos duros y unidades de memoria cifradas con LUKS2 y no es posible conocer la contraseña. Quien la puso no está y el trabajo consiste en tratar de recuperar todos los datos posibles.

Dentro de los dispositivos a localizar datos se encuentra un NAS “NETGEAR ReadyNAS” con 4 discos de 4Tb y del cuál no dispongo del alimentador y el que tengo no funciona. El otro día analicé los discos de forma individual pero evidentemente estaban en RAID y precisaba de una máquina que me permitiese conectar como mínimo 6 discos.

Hoy he puesto los 4 discos en el servidor, con el hd del sistema y otro para almacenar los datos (por esto 6 discos) y he montado el raid usando mdadm, basándome en qué el NAS como es común suelen usar Linux.

Lo primero será ver si ha detectado los discos

root@IAIA-Capa8:~# lsblk
NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
sda      8:0    0 476.9G  0 disk 
├─sda1   8:1    0   512M  0 part /boot/efi
├─sda2   8:2    0 475.5G  0 part /
└─sda3   8:3    0   976M  0 part [SWAP]
sdb      8:16   0 476.9G  0 disk 
└─sdb1   8:17   0 476.9G  0 part /mnt/hd1
sdc      8:32   0   2.7T  0 disk 
├─sdc1   8:33   0     4G  0 part 
├─sdc2   8:34   0   512M  0 part 
└─sdc3   8:35   0   2.7T  0 part 
sdd      8:48   0   3.6T  0 disk 
└─sdd1   8:49   0   3.6T  0 part /mnt/hd2
sde      8:64   0   2.7T  0 disk 
├─sde1   8:65   

Eliminar el fondo de un vídeo

Hoy me ha llegado otro reto que he terminado resolviendo con IA :)

Se trata de un vídeo en el que aparece una persona y detrás una fea y arrugada sábana blanca que en el vídeo se ve amarillenta. El pedido ha sido eliminar el fondo.

Las opciones iniciales eran hacerlo con kdenlive o con blender y muchas horas de marcar puntitos para cada uno de los frames. El vídeo en cuestión tiene un total de 7933 frames y como que no…

He empezado a buscar opciones y he encontrado clipdrop (cerrado aunque tiene opción de API) y he decidido seguir buscando. En la búsqueda he encontrado backgroundremover interesante pero con resultados deplorables y finalmente rembg (con mejores resultados pero enfocado a imágenes).

Así que de nuevo la solución ha sido crear un script. Esta vez me he decantado por bash.

#!/bin/bash

# Fix video's FPS
echo "Converting video to 30 FPS..."
ffmpeg -i video.mp4 -r 30 -c:v libx264 -crf 18 -preset fast -c:a copy video_30.mp4

# Crea temp directories
#mkdir -p original_images
#mkdir -p processed_images

# Generate one image for each frame and save to original_images directory
echo "Extracting frames as images..."
ffmpeg -i video_30.mp4 -vf "fps=30" original_images/frame_%04d.png

# Delete the background of each image of original_images to processed_images
echo "Removing backgrounds from images..."
for img in original_images/frame_*.png; do
    output_name="processed_images/$(basename "$img")"
    rembg i "$img" "$output_name"
done

# Join all the images from processed_images to a video and use audio from video_30.mp4
echo "Combining processed images into a video with 

Django: peticiones wsgi y asgi simultaneas (htmx y websockets)

Muy feliz de finalmente tenerlo funcionando! no sé si es la mejor forma, pero la cuestión es que funciona :D

Estos días me estoy peleando en hacer funcionar un chatbot con stream de openai sobre django. Me ha llevado un par de días de hacerlo funcionar pero aquí lo tenemos :D

Básicamente después de perderme entre decenas de páginas de documentación y abrir y cerrar otras decenas más de pestañas del navegador, lo que terminé haciendo fue localizar una aplicación que sí hacía lo que yo quería y luego la he implementado a mi aplicación. La aplicación que funcionaba like a charm en local es Django OpenAI-Powered Chatbot with HTMX Streaming. También recomiendo esta otra documentación (Learn to use Websockets with Django by building your own ChatGPT) que si eres relativamente nuevo con esto de htmx y websockets te va a aclarar mucho el tema :)

Inicié implementando el manual de saaspegasus pero no funcionaba. Así que he decidido directamente integrar el código de django_chatbot a mi aplicación y tampoco funcionaba… hasta que he visto lo de daphne! El python manage.py runserver de toda la vida no es síncrono pero daphne si, y lo que permite es activar las conexiones asíncronas. Al aplicar esto, todo ha empezado a funcionar :D

Después ha venido la parte de ponerlo en producción que de nuevo me he perdido entre múltiples páginas pero finalmente lo que sacado y aquí lo dejo para saber como implementarlo la próxima vez y también para otro …

Instalar dudle con debian 12

Por fin otra tarea menos! Esta ya daba vergüenzilla y todo al tener la instalación anterior de dudle aún con Debian 6!!! Así que directamente lo que he planteado es hacer una instalación limpia y los datos que puedan estar ahí, que pasen a mejor vida! Aunque creo que los datos aún serían compatibles, parece que tienen el mismo formato.

Vamos a ver como se hace ahora la instalación. Para ello he seguido el repositorio de github del proyecto que omite la información de la instalación y configuración de apache.

Primero vamos a instalar las dependencias:

# apt -y install apache2 git ruby-dev libxml2-dev zlib1g-dev
# gem install ratom

A continuación clonamos el repositorio en algún sitio del servidor, en mi caso lo he dejado en /var/www/dudle

# cd /var/www
# git clone https://github.com/kellerben/dudle.git

Ahora vamos a descargar los ficheros .mo correspondientes a los ficheros de idioma compilados. Vamos a crear un script, le damos permisos de ejecución, lo ejecutamos y finalmente borramos el fichero.

# cd dudle/locale

# vi download_mo.sh
for i in ??; do
	wget -O $i/dudle.mo https://dudle.inf.tu-dresden.de/locale/`basename $i`/dudle.mo
done

# chmod +x download_mo.sh

# ./download_mo.sh

# rm download_mo.sh

Ahora configuramos apache:

# cd /etc/apache2/sites-available

# vi dudle.conf
<VirtualHost *:80>
        ServerName      dudle.marsupi.org
        ServerAlias     *.dudle.marsupi.org dudle.lamardebits.org *.dudle.lamardebits.org dudle.lamardebits.cat *.dudle.lamardebits.cat
        ServerAdmin     xxx@lamardebits.org
        DocumentRoot    /var/www/dudle/

        ErrorLog        /var/log/apache2/dudle.error.log
        CustomLog       /var/log/apache2/dudle.access.log combined

	<Directory "/var/www/dudle">
		AllowOverride All

    		SetEnv RUBYLIB /var/www/dudle/
    		SetEnv RUBYOPT "-E UTF-8:UTF-8"
    		SetEnv GIT_AUTHOR_NAME="Blackhold"
    		SetEnv GIT_AUTHOR_EMAIL=xxx@domain.com
    		SetEnv GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"
    		SetEnv GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"

		Order allow,deny
		Allow from all
	</Directory>
</VirtualHost>

# cd /etc/apache2/sites-enabled/; rm 

Django runserver sobre https

Estos dos últimos meses he estado trabajando con una tienda virtual desarrollada con django llamada django oscar. Muy interesante el juguete, tunearla ha habido momentos de todo, en algunos momentos era una delicia por la documentación que tienen y por otros iba más perdida que un pingüino en el desierto y los atascos eran monumentales además de la presión del cliente que tenía que tener el proyecto en funcionamiento un mes y pico antes de que se me diese acceso al código para poder arreglar y aplicar las funcionalidades extra que se requerían. El proyecto era uno que había dejado a medias otro desarrollador y tuve que rehacer todo el código porqué tal como se me entregó la aplicación había cosas básicas de funcionamiento rotas, además de variables en inglés, en castellano y catalán (no es el primer proyecto que me encuentro así).

Django oscar se usa como aplicación de Backend y de frontend hay desplegado un NextJS que tras dar alguna que otra vuelta he terminado modificando alguna cosa.

En entorno local de desarrollo todo funcionaba correctamente, pero al ponerlo en producción la cosa se ha puesto divertida y ha requerido investigar varias cosas que voy a exponer en este post en modo de notas.

La aplicación de frontend se conecta con django oscar por API y hasta que no añadí la opción CSRF_TRUSTED_ORIGINS la comunicación era infructuosa.

# vi settings.py
# this allows nextjs to connect to django without using csrf_token
CSRF_TRUSTED_ORIGINS = 'http://127.0.0.1'
CSRF_COOKIE_SAMESITE = "None"

Conectar moodle y wordpress

Hay algunas tareas de estas que se convierten en titánicas y no sabes muy bien el porqué y esta lo ha sido. Así que traigo este post para que otra persona que quiera montar este sistema no tenga que dar tantas vueltas y poder hacerlo a la primera :)

Hace unos meses que estamos preparando cursos bajo la marca escueladeeuropa. Los cursos la idea es montarlos en el LMS Moodle (learning management system), pero luego quedaba la cosa como los vendíamos… nos dijimos, sería chulo que los cursos se vendiesen solos a través de la página web hecha con wordpress… y ahí empezó la carrera.

Conectar wordpress y moodle es posible gracias a dos plugins, el primero edwiser y el segundo lmsace. El primero es mucho más intuitivo pero a la que quieres empezar a conectarlo con woocommerce, paga. El segundo… ¡ay el segundo! ¡vamos a verlo!

Concepto
La idea es que en tu moodle tienes unos cursos y en tu wordpress el woocommerce. Para conectar moodle y wordpress es necesario primero de todo crear los usuarios en wordpress que luego se crearán automáticamente en moodle. Esto se llama “user enrolment”.

Para conectar ambos programas será necesario instalar 1 plugin en wordpress y (atención) 2 en moodle! todo lo que necesitas saber lo encontrarás en la wiki de lmsace.

Moodle

Empezamos con moodle, será necesario instalar los dos plugins, lmsace-connect-moodle y lmsace-connect-moodleauth. El segundo aunque en la wiki pone que es opcional, hasta que no lo he …

script para identificar registros duplicados en sqlite3

En uno de mis proyectos estamos ya en la recta final a punto de poner en producción el nuevo programa. A último momento siempre te encuentras con aquellas puñetitas que hacen que la migración no salga como es lo esperado, es por esto que es muy importante practicar la migración al igual que si de una audición se tratase.

La puñetita con la que me he encontrado trata precisamente de la importación de datos mas grande, la de una tabla de 4Gb de datos, que contiene las lecturas de unos sensores, he decidido separarlas en alrededor de 4.000 ficheros de base de datos sqlite3, uno para cada uno de los sensores. Al realizar la importación de cada uno de los sensores de forma individual, de maravilla, pero a la que se hace el proceso de migración de todos los sensores, algunas de las lecturas se duplican y no he conseguido hallar el porqué ocurre.

Ya hace unos días puse un par de controles que si el fichero ya existía o la base de datos estaba siendo usada, pasase al siguiente sensor, aún así seguían duplicandose los datos. La solución era añadir un tercer control que comprobase que el registro ya estaba guardado, pero que ralentizaría la migración de los datos de forma significativa y la primera migración el interés es que sea lo más ágil posible. Así que dándole un par de vueltas y muy importante, tras más de 24h de no tocar el código (se llama descansar), he encontrado …

Gitlab: configurar el envío de correos electrónicos

Gilab es un software para gestionar repositorios de software. Existe github y gitlab tiene también su repositorio público. Gitlab permite la instalación del software en tu propia infraestructura.

En éste otro post explicaba como instalarlo y actualizarlo con sus repositorios. Hoy veremos como configurar gitlab para que mande correos electrónicos.

Lo primero que tendremos que hacer es modificar el fichero de configuración que se encuentra en /etc/gitlab/gitlab.rb, buscar las siguientes líneas, descomentarlas y configurarlas de la siguiente forma (para que funcione con la configuración del servidor de correo electrónico instalado con modoboa)

# vi /etc/gitlab/gitlab.rb
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "mail.capa8.net"
gitlab_rails['smtp_port'] = 587
gitlab_rails['smtp_user_name'] = "noreply@capa8.net"
gitlab_rails['smtp_password'] = "xxxxxxxxxxx"
gitlab_rails['smtp_domain'] = "capa8.net"
gitlab_rails['smtp_authentication'] = "login"
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['smtp_tls'] = false
gitlab_rails['smtp_pool'] = true

gitlab_rails['gitlab_email_enabled'] = true

gitlab_rails['gitlab_email_from'] = 'noreply@capa8.net'
gitlab_rails['gitlab_email_display_name'] = 'GitLab Capa8'
gitlab_rails['gitlab_email_reply_to'] = 'noreply@capa8.net'

A continuación ejecutamos lo siguiente para aplicar la nueva configuración

# gitlab-ctl reconfigure

Una vez realizado el reconfigure, entramos en la consola de gitlab y comprobamos que la configuración se haya aplicado y mandamos un correo electrónico de prueba

# gitlab-rails console -e production
--------------------------------------------------------------------------------
 Ruby:         ruby 3.0.6p216 (2023-03-30 revision 23a532679b) [x86_64-linux]
 GitLab:       15.11.0 (96ee37680b6) FOSS
 GitLab Shell: 14.18.0
 PostgreSQL:   13.8
------------------------------------------------------------[ booted in 32.38s ]
Loading production environment (Rails 6.1.7.2)

irb(main):001:Notify.test_email('info@capa8.net', 'Hello World', 'This is a test message').deliver_now

Y si todo es correcto, deberías recibir un correo electrónico de prueba.…

Instalar imapsync en debian 11

Seguimos con temas de correo. Una de las herramientas que uso para migrar buzones de un servidor a otro es imapsync. Vamos a verlo como lo instalamos.

He usado este manual de clouding.io. Al ejecutar el proceso he descubierto una cosa que me ha encantado! normalmente para concatenar comandos de terminal uso &&, he visto que también es posible usar ;!!! me ha gustado esta! :D

Vamos a ver como lo instalamos

Dependencias

root@imapsync:~# apt update && apt install -y libtest-simple-perl libtest-requires-perl libtest-mock-guard-perl libtest-fatal-perl libpar-packer-perl libnet-ssleay-perl libio-compress-perl libdigest-hmac-perl libcrypt-ssleay-perl libssl-dev libauthen-ntlm-perl libclass-load-perl libcgi-pm-perl libcrypt-openssl-rsa-perl libdata-uniqid-perl libencode-imaputf7-perl libfile-copy-recursive-perl libfile-tail-perl libio-socket-inet6-perl libio-socket-ssl-perl libio-tee-perl libhtml-parser-perl libjson-webtoken-perl libmail-imapclient-perl libparse-recdescent-perl libmodule-scandeps-perl libreadonly-perl libregexp-common-perl libsys-meminfo-perl libterm-readkey-perl libtest-mockobject-perl libtest-pod-perl libunicode-string-perl liburi-perl libwww-perl libtest-nowarnings-perl libtest-deep-perl libtest-warn-perl make cpanminus git rcs gcc libproc-processtable-perl

Otra dependencia que me he encontrado que ha pedido instalar (donde he descubierto lo del ;)

root@imapsync:~# apt-get install apt-file; apt-file update

Configurar módulos

Ahora vamos a configurar algunos módulos que serán necesarios para hacer funcionar imapsync

root@imapsync:~# cpanm Crypt::OpenSSL::RSA Crypt::OpenSSL::Random --force
root@imapsync:~# cpanm Mail::IMAPClient JSON::WebToken Test::MockObject Dist::CheckConflicts
root@imapsync:~# cpanm Unicode::String Data::Uniqid --force
root@imapsync:~# cpanm Mail::IMAPClient IO::Socket::SSL

Instalar imapsync

Ahora para instalarlo, vamos a clonar el repositorio e instalaremos el programa

root@imapsync:~# cd /opt && git clone https://github.com/imapsync/imapsync.git
root@imapsync:~# cd imapsync && make install

Si todo está correcto, copiamos el binario en el directorio de binarios

root@imapsync:~# cp imapsync /usr/bin/imapsync

Para comprobar que el programa se ha instalado correctamente usamos:

root@imapsync:~# imapsync --testslive

Usar imapsync

Cuando migramos un servidor de correo, tenemos el servidor antiguo …