Herramientas Informaticas

Categoría: Uncategorized Página 1 de 14

Cómo Instalar y Configurar Plex Media Server en CachyOS: La Guía Definitiva 🎬🍿

Entrada fija

¿Tienes una biblioteca repleta de películas, series, documentales o música y quieres acceder a ella desde cualquier televisor, smartphone o consola de tu casa? Crear tu propio servidor multimedia personal es la mejor decisión que puedes tomar.

Cuando pensamos en servidores domésticos, solemos imaginar distribuciones tradicionales como Ubuntu Server o Debian. Sin embargo, CachyOS —la distribución ultrarrápida basada en Arch Linux y optimizada para procesadores modernos— es una opción formidable para este propósito. Gracias a sus optimizaciones de kernel y su gestión de rendimiento en tiempo real, tu servidor multimedia volará. ⚡

En esta guía práctica y directa al grano, aprenderás cómo instalar, configurar y sacarle el máximo provecho a Plex Media Server en CachyOS, paso a paso y sin complicaciones. ¡Manos a la obra! 🛠️

1. ¿Por qué elegir CachyOS para tu servidor Plex? 🏎️

Antes de entrar en comandos de terminal, vale la pena entender qué ventajas aporta CachyOS a un entorno multimedia:

  1. Rendimiento compilado para tu procesador: CachyOS aprovecha las instrucciones avanzadas (x86-64-v3 y v4), lo que reduce el uso innecesario de ciclos de CPU.
  2. Kernels optimizados (BORE / EEVDF): Gestionan de forma sobresaliente los procesos en segundo plano. Mientras Plex escanea metadatos o convierte un video, el resto del sistema no sufre tirones.
  3. Drivers gráficos al día: Al estar basada en Arch Linux con modelo rolling release, cuentas siempre con las versiones más recientes de Mesa, VA-API y controladores de video para transcodificación por hardware.

2. Requisitos previos y puesta a punto del sistema 💻

Para comenzar con buen pie, es importante que tu instalación de CachyOS esté completamente actualizada y cuente con las herramientas esenciales de desarrollo y compilación.

Abre tu emulador de terminal favorito y ejecuta:

Bash

# 1. Actualizar repositorios y paquetes del sistema
sudo pacman -Syu

# 2. Instalar herramientas de compilación básicas
sudo pacman -S --needed base-devel git

Verifica también que cuentas con un asistente para AUR (Arch User Repository) como paru o yay.

3. Método 1: Instalación Nativa vía AUR (Recomendado) 📦

La instalación nativa es la opción más directa y ligera, ya que integra Plex como un servicio nativo del sistema operativo gestionado por systemd.

Paso 1: Descargar e instalar el paquete

Ejecuta el siguiente comando con tu gestor AUR:

Bash

paru -S plex-media-server

(Si utilizas yay, simplemente sustituye paru por yay).

El asistente compilará e integrará los binarios oficiales de Plex en el sistema.

Paso 2: Habilitar e iniciar el servicio

Una vez terminada la instalación, debemos indicarle al sistema que arranque Plex inmediatamente y que lo inicie de forma automática cada vez que enciendas el equipo:

Bash

sudo systemctl enable --now plexmediaserver.service

Paso 3: Comprobar el estado

Para asegurarte de que el servicio está funcionando sin errores, ejecuta:

Bash

systemctl status plexmediaserver.service

Si todo ha ido bien, verás un punto verde indicando que el estado es active (running). ✅

4. Método 2: Despliegue mediante Docker y Docker Compose 🐳

Si prefieres aislar Plex del sistema base o planeas combinarlo con otras aplicaciones (como gestores de descargas o paneles de control), Docker es una alternativa modular y muy ordenada.

Paso 1: Instalar el motor Docker

Bash

sudo pacman -S docker docker-compose
sudo systemctl enable --now docker.service
sudo usermod -aG docker $USER

(Nota: Cierra y vuelve a abrir tu sesión de usuario para que el grupo Docker tome efecto).

Paso 2: Crear el archivo docker-compose.yml

Crea una carpeta para el proyecto y dentro genera el archivo de configuración:

Bash

mkdir -p ~/servidor-plex && cd ~/servidor-plex
nano docker-compose.yml

Pega la siguiente configuración (usando la imagen oficial de LinuxServer):

YAML

services:
  plex:
    image: lscr.io/linuxserver/plex:latest
    container_name: plex
    network_mode: host
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/Mazatlan
      - VERSION=docker
    volumes:
      - ./config:/config
      - /mnt/almacenamiento/series:/tv
      - /mnt/almacenamiento/peliculas:/movies
    restart: unless-stopped

Paso 3: Levantar el contenedor

Para ponerlo en marcha en segundo plano:

Bash

docker compose up -d

5. El Gran Dolor de Cabeza en Linux: Permisos y Discos Secundarios 🔑

El 90% de los problemas en Plex bajo Linux ocurren cuando el servidor no puede ver las películas que tienes guardadas en tus discos.

En la instalación nativa, el servidor se ejecuta bajo el usuario del sistema plex. Este usuario necesita permisos de lectura y ejecución en las carpetas donde guardas tu contenido.

Regla de oro: No guardes medios dentro de tu /home

Evita colocar tus carpetas de películas dentro de /home/tu_usuario/. En Arch Linux y CachyOS, los directorios personales tienen permisos estrictos (700 o 750) que bloquean el acceso a cualquier servicio externo.

👉 Lo ideal es utilizar un punto de montaje en la raíz, como /mnt/almacenamiento o /media/multimedia.

Asignar permisos correctos (Formato Linux: ext4 / btrfs)

Si tus discos tienen formato de Linux, ejecuta estos comandos para garantizar lectura:

Bash

# Permisos 755 a todas las carpetas (para poder entrar y leerlas)
sudo find /mnt/almacenamiento -type d -exec chmod 755 {} +

# Permisos 644 a todos los archivos multimedia
sudo find /mnt/almacenamiento -type f -exec chmod 644 {} +

Montaje automático en /etc/fstab 📌

Para que tus discos duros secundarios o externos no desaparezcan al reiniciar el equipo, agrégalos a tu archivo de montajes permanente.

  1. Identifica el UUID de tu disco:

Bash

lsblk -f
  1. Abre el archivo de configuración:

Bash

sudo nano /etc/fstab
  1. Añade la línea correspondiente al final del archivo:
  • Para discos en formato ext4:

Plaintext

UUID=tu-uuid-aqui   /mnt/almacenamiento   ext4   defaults,noatime   0   2
  • Para discos en formato NTFS (discos que usabas en Windows):

Plaintext

UUID=tu-uuid-aqui   /mnt/almacenamiento   ntfs-3g   uid=plex,gid=plex,dmask=022,fmask=133,windows_names   0   0

Guarda los cambios con Ctrl + O y sal con Ctrl + X.

6. Primer Acceso y Reclamar el Servidor 🌐

¡Es momento de entrar a la interfaz web y vincular tu cuenta de Plex!

  1. Abre tu navegador web e ingresa a la siguiente dirección:Plaintexthttp://localhost:32400/web
  2. Inicia sesión con tu cuenta de Plex (o regístrate gratis si aún no tienes una).
  3. Sigue el asistente de bienvenida: asígnale un nombre a tu servidor (ejemplo: Servidor-CachyOS) y marca la casilla para permitir el acceso a tus medios fuera del hogar si lo requieres.
  4. Añade tus bibliotecas: Selecciona si vas a añadir Películas, Series o Música y navega hasta la ruta de tus carpetas (ej. /mnt/almacenamiento/peliculas).

7. Optimización y Transcodificación por Hardware ⚙️

La transcodificación ocurre cuando el dispositivo donde reproduces el video no soporta el formato nativo del archivo (por ejemplo, reproducir un archivo 4K HEVC en un navegador web antiguo).

Si tienes una suscripción activa a Plex Pass, puedes transferir esta carga pesada del procesador a tu tarjeta gráfica integrada o dedicada:

Tipo de GráficaPaquetes necesarios en CachyOSParámetro en Plex
Intel (QuickSync)intel-media-driver y libva-intel-driverAjustes > Transcodificador > Usar aceleración por hardware
AMD (Radeon / APU)mesa y libva-mesa-driverAjustes > Transcodificador > Usar aceleración por hardware
NVIDIA (GeForce)nvidia-utils y nvidia-settingsAjustes > Transcodificador > Usar aceleración por hardware

Para asegurarte de que el usuario plex puede interactuar directamente con la GPU en una instalación nativa, agrégalo al grupo de video y render:

Bash

sudo usermod -aG video,render plex
sudo systemctl restart plexmediaserver.service

8. Configuración del Firewall y Acceso Remoto 🛡️

Si tienes activado un cortafuegos local (como ufw o firewalld), asegúrate de habilitar los puertos clave de Plex para que tus smart TVs y dispositivos móviles en la red local puedan comunicarse sin bloqueos:

Bash

# Si usas UFW:
sudo ufw allow 32400/tcp comment 'Plex Web & Media'
sudo ufw allow 1900/udp comment 'Plex DLNA'
sudo ufw allow 5353/udp comment 'Plex Discovery'
sudo ufw reload

9. Preguntas Frecuentes (FAQ) ❓

¿Plex es completamente gratuito?

Sí. Puedes ver todo tu contenido en red local, organizar bibliotecas con carátulas automáticas y reproducir en Smart TVs de forma 100% gratuita. Funciones avanzadas como la transcodificación por hardware o las descargas sin conexión requieren la suscripción opcional Plex Pass.

¿Cómo actualizo Plex en CachyOS?

Si instalaste mediante el método nativo (AUR), se actualizará automáticamente cada vez que actualices el sistema con paru -Syu o yay -Syu. Si usas Docker, basta con ejecutar docker compose pull y luego docker compose up -d.

¿Puedo acceder a mis películas desde fuera de mi casa?

Sí. En la sección Ajustes > Acceso Remoto de Plex puedes habilitar esta opción. Si tu router cuenta con UPnP funcionará automáticamente; de lo contrario, solo necesitas abrir y redirigir el puerto 32400 en el panel de control de tu router hacia la IP local de tu servidor.

Conclusión 🏁

Montar tu servidor Plex en CachyOS combina lo mejor de dos mundos: la inmensa versatilidad del ecosistema Arch Linux y la potencia de un kernel optimizado al milímetro para exprimir cada ciclo de tu hardware.

Siguiendo esta guía ya cuentas con un centro multimedia sólido, rápido y accesible desde cualquier rincón de tu hogar. ¡Prepara las palomitas y a disfrutar de tus contenidos favoritos! 🍿🎉

🔧 PHP + SAP HANA ODBC: solución cuando odbc_fetch_array() no devuelve todos los registros

Entrada fija

¿Te ha pasado que una consulta en SAP HANA devuelve cientos de registros correctamente, pero al consumirla desde PHP mediante ODBC solamente recibes uno?

Eso fue exactamente lo que ocurrió en este caso: una consulta en SAP HANA tenía 902 registros, pero desde PHP, al incluir la descripción del artículo OITM."ItemName", odbc_fetch_array() solamente recuperaba 1 registro.

Después de varias pruebas se pudo determinar que no era un problema de memoria, SQL, JOIN, PHP ni del while.

La solución fue configurar correctamente el controlador SAP HANA ODBC para manejar los caracteres mediante UTF-8:

CHAR_AS_UTF8=true

manteniendo:

EnableArrayFetch=1

La configuración se aplicó tanto en Linux Mint como en Windows 10.


🚨 El problema

La consulta original era similar a:

SELECT
    a."ItemCode",
    b."ItemName",
    a."Price",
    a."PriceList",
    c."ListName"
FROM ITM1 a
INNER JOIN OITM b
    ON a."ItemCode" = b."ItemCode"
INNER JOIN OPLN c
    ON a."PriceList" = c."ListNum"
WHERE a."PriceList" = 1
  AND IFNULL(a."Price", 0) > 0;

En SAP HANA la consulta contenía 902 artículos con precio.

Sin embargo, PHP solamente recibía:

1 registro

y no aparecía ningún error ODBC.

El código PHP era completamente normal:

while ($row = odbc_fetch_array($stmt)) {

    $data[] = [
        'ItemCode'  => $row['ItemCode'],
        'ItemName'  => $row['ItemName'],
        'Price'     => (float) $row['Price'],
        'PriceList' => (int) $row['PriceList'],
        'ListName'  => $row['ListName'],
    ];
}

🔍 Primero: comprobar si realmente existen los registros

Antes de culpar a PHP u ODBC, se comprobó directamente en HANA:

SELECT COUNT(*) AS "Total"
FROM ITM1
WHERE "PriceList" = 1
  AND IFNULL("Price", 0) > 0;

Resultado:

902

Por lo tanto, los datos sí existían.


🧪 Diagnóstico paso a paso

Para encontrar el problema se fue simplificando la consulta.

1️⃣ Solamente ITM1

SELECT
    "ItemCode",
    "Price",
    "PriceList"
FROM ITM1
WHERE "PriceList" = 1
  AND IFNULL("Price", 0) > 0;

Desde PHP:

TOTAL: 902

ITM1 funcionaba correctamente.


2️⃣ Agregar el JOIN con OITM

Se añadió:

INNER JOIN OITM b
    ON a."ItemCode" = b."ItemCode"

pero solamente se recuperó el código:

SELECT
    a."ItemCode",
    b."ItemCode"
FROM ITM1 a
INNER JOIN OITM b
    ON a."ItemCode" = b."ItemCode"
WHERE a."PriceList" = 1
  AND IFNULL(a."Price", 0) > 0;

Resultado:

TOTAL: 902

✅ El JOIN con OITM también funcionaba.


⚠️ 3️⃣ Agregar ItemName

El problema apareció cuando se añadió:

b."ItemName"

La consulta:

SELECT
    a."ItemCode",
    b."ItemName"
FROM ITM1 a
INNER JOIN OITM b
    ON a."ItemCode" = b."ItemCode"
WHERE a."PriceList" = 1
  AND IFNULL(a."Price", 0) > 0;

Desde PHP solamente devolvía:

TOTAL: 1

🎯 Aquí quedó localizado el problema.

No era el JOIN.

No era ITM1.

No era OPLN.

No era memoria.

El comportamiento aparecía específicamente al recuperar el contenido de:

OITM."ItemName"

🧠 Una pista importante: los caracteres especiales

Durante las pruebas también apareció algo muy revelador.

En SAP HANA el texto era:

REV 14±2

pero PHP recibía:

REV 14±2

Eso indicaba claramente un problema de codificación de caracteres entre:

SAP HANA
   ↓
HDBODBC
   ↓
PHP
   ↓
JSON
   ↓
DataTables

Además, el problema no generaba un error ODBC tradicional.

Por eso era especialmente difícil de localizar.


🐧 Solución en Linux Mint

Primero se comprobó la configuración de unixODBC:

odbcinst -j

La salida mostraba:

DRIVERS............: /etc/odbcinst.ini
SYSTEM DATA SOURCES: /etc/odbc.ini
USER DATA SOURCES..: /home/usuario/.odbc.ini

El DSN utilizado estaba en:

/etc/odbc.ini

La configuración original era:

[mi_dsn_hana]
Driver=SAP HANA
ServerNode=SERVIDOR_HANA:30015

Se añadió:

CHAR_AS_UTF8=true

Quedando:

[mi_dsn_hana]
Driver=SAP HANA
ServerNode=SERVIDOR_HANA:30015
CHAR_AS_UTF8=true

El driver utilizado estaba definido en:

/etc/odbcinst.ini

con:

[HANA_ODBC]
Description=SAP HANA ODBC Driver
Driver=/ruta/al/cliente-hana/libodbcHDB.so

🔎 Comandos útiles para localizar ODBC en Linux

Para saber dónde están los archivos:

odbcinst -j

Para ver el DSN:

cat /etc/odbc.ini

Para ver los drivers:

cat /etc/odbcinst.ini

Para buscar configuraciones relacionadas con HANA:

grep -RniE "HDB|HANA|CHAR_AS_UTF8|char_as_utf8|ServerNode|Driver" \
/etc/odbc.ini \
/etc/odbcinst.ini \
~/.odbc.ini 2>/dev/null

Para listar los DSN:

odbcinst -q -s

🪟 Solución en Windows 10

En Windows se comprobó primero la arquitectura de PHP:

php -i | findstr /I "Architecture"

Resultado:

Architecture => x64

Por lo tanto se utilizó el administrador ODBC de 64 bits:

C:\Windows\System32\odbcad32.exe

El DSN utilizado era:

mi_dsn_hana

y estaba registrado en:

HKLM\SOFTWARE\ODBC\ODBC.INI\mi_dsn_hana

Al consultar el registro:

reg query "HKLM\SOFTWARE\ODBC\ODBC.INI\mi_dsn_hana" /s

se encontró, entre otros valores:

Driver              C:\Program Files\SAP\hdbclient\libodbcHDB.dll
Host                SERVIDOR_HANA
PortNumber          30015
EnableArrayFetch    1
ArrayFetchSize      5000

💾 Antes de modificar el registro: hacer respaldo

Siempre es recomendable guardar una copia del DSN.

reg export "HKLM\SOFTWARE\ODBC\ODBC.INI\mi_dsn_hana" "%USERPROFILE%\Desktop\mi_dsn_hana-backup.reg"

Windows responderá:

La operación se completó correctamente.

Así se dispone de un archivo de respaldo en el escritorio.


⚙️ Agregar CHAR_AS_UTF8 en Windows

Se agregó directamente al registro:

reg add "HKLM\SOFTWARE\ODBC\ODBC.INI\mi_dsn_hana" /v CHAR_AS_UTF8 /t REG_SZ /d true /f

Para comprobarlo:

reg query "HKLM\SOFTWARE\ODBC\ODBC.INI\mi_dsn_hana" /v CHAR_AS_UTF8

El resultado esperado es:

CHAR_AS_UTF8    REG_SZ    true

✅ Configuración aplicada correctamente.


🔄 Reiniciar Apache

Después de modificar el DSN, es importante reiniciar Apache/XAMPP para que PHP cree una nueva conexión ODBC.

Desde XAMPP:

Stop Apache
Start Apache

O, si Apache está instalado como servicio:

net stop Apache2.4
net start Apache2.4

El nombre del servicio puede variar según la instalación.


⚙️ ¿Qué pasó con EnableArrayFetch?

El DSN de Windows ya tenía:

EnableArrayFetch=1

y:

ArrayFetchSize=5000

Durante las pruebas se decidió mantenerlo activado.

La configuración final quedó:

CHAR_AS_UTF8=true
EnableArrayFetch=1

Esto mismo se mantuvo tanto en Linux como en Windows.

No fue necesario desactivar EnableArrayFetch.


💻 La función PHP no necesitó cambios especiales

Una vez solucionada la configuración del ODBC, la consulta PHP puede seguir siendo una consulta normal:

static public function ctrMostrarListaPrecio($conn, int $id)
{
    $sql = '
        SELECT
            a."ItemCode",
            b."ItemName",
            a."Price",
            a."PriceList",
            c."ListName"
        FROM ITM1 a
        INNER JOIN OITM b
            ON a."ItemCode" = b."ItemCode"
        INNER JOIN OPLN c
            ON a."PriceList" = c."ListNum"
        WHERE a."PriceList" = ?
          AND IFNULL(a."Price", 0) > 0
    ';

    $stmt = odbc_prepare($conn, $sql);

    if (!$stmt) {
        throw new Exception(
            'Error ODBC prepare: ' . odbc_errormsg($conn)
        );
    }

    if (!odbc_execute($stmt, [$id])) {
        throw new Exception(
            'Error ODBC execute: ' . odbc_errormsg($conn)
        );
    }

    $data = [];

    while ($row = odbc_fetch_array($stmt)) {

        $data[] = [
            'ItemCode'  => $row['ItemCode'],
            'ItemName'  => $row['ItemName'],
            'Price'     => (float) $row['Price'],
            'PriceList' => (int) $row['PriceList'],
            'ListName'  => $row['ListName'],
        ];
    }

    return $data;
}

La solución estuvo en la configuración del HDBODBC, no en cambiar la consulta.


🧪 Otra prueba importante: comprobar si era memoria

También se revisó la memoria de PHP:

echo memory_get_usage(true);

Durante las pruebas se obtuvo aproximadamente:

2097152 bytes

Y el pico:

2097152 bytes

No hubo incremento importante al procesar los registros.

Por lo tanto:

❌ No era falta de memoria.

❌ No era que 902 registros fueran demasiados.

❌ No era el while.

❌ No era odbc_prepare().

❌ No era odbc_execute().

❌ No era el JOIN.

✅ El comportamiento estaba relacionado con el tratamiento de caracteres por HDBODBC.


🛠️ Diagnóstico recomendado para futuros problemas

Cuando PHP y SAP HANA devuelvan menos registros de los esperados, no hay que asumir inmediatamente que el problema está en SQL.

Una buena estrategia es ir agregando las columnas progresivamente.

Primero:

SELECT
    "ItemCode"
FROM ITM1
WHERE "PriceList" = 1;

Después:

SELECT
    a."ItemCode",
    b."ItemCode"
FROM ITM1 a
INNER JOIN OITM b
    ON a."ItemCode" = b."ItemCode"
WHERE a."PriceList" = 1;

Después:

SELECT
    a."ItemCode",
    b."ItemName"
FROM ITM1 a
INNER JOIN OITM b
    ON a."ItemCode" = b."ItemCode"
WHERE a."PriceList" = 1;

De esta forma puedes identificar exactamente qué columna provoca el comportamiento.

En este caso:

ITM1                         → 902
ITM1 + OITM.ItemCode         → 902
ITM1 + OITM.ItemName         → 1

Ese pequeño experimento permitió descubrir rápidamente que había que investigar el tratamiento del campo de texto.


📌 Configuración final

Después de todas las pruebas, la configuración que quedó funcionando fue:

CHAR_AS_UTF8=true
EnableArrayFetch=1

Linux Mint

Archivo:

/etc/odbc.ini

Configuración:

[mi_dsn_hana]
Driver=SAP HANA
ServerNode=SERVIDOR_HANA:30015
CHAR_AS_UTF8=true

Windows 10

Registro:

HKLM\SOFTWARE\ODBC\ODBC.INI\mi_dsn_hana

Valor:

CHAR_AS_UTF8    REG_SZ    true

Manteniendo:

EnableArrayFetch    REG_SZ    1

✅ Conclusión

El problema parecía inicialmente un problema de PHP porque:

while ($row = odbc_fetch_array($stmt))

solamente recuperaba un registro.

Sin embargo, las pruebas demostraron que SAP HANA sí tenía 902 registros y que ODBC podía recorrerlos correctamente mientras no se solicitara directamente el contenido de ItemName.

La pista definitiva fue que los textos con caracteres especiales aparecían alterados, por ejemplo:

14±2

se recibía como:

14±2

La corrección fue configurar el controlador de SAP HANA para trabajar con UTF-8:

CHAR_AS_UTF8=true

manteniendo:

EnableArrayFetch=1

La configuración fue aplicada tanto en Linux Mint como en Windows 10.

💡 Moraleja: cuando PHP + ODBC + SAP HANA devuelve menos filas de las esperadas, especialmente al trabajar con campos NVARCHAR o textos con caracteres especiales, conviene revisar primero la configuración del HDBODBC antes de modificar la consulta o asumir que existe un problema de memoria.


🚀 Resumen rápido

Linux

sudo cp /etc/odbc.ini /etc/odbc.ini.bak
sudo nano /etc/odbc.ini

Agregar:

CHAR_AS_UTF8=true

Windows 10

Respaldar:

reg export "HKLM\SOFTWARE\ODBC\ODBC.INI\mi_dsn_hana" "%USERPROFILE%\Desktop\mi_dsn_hana-backup.reg"

Agregar:

reg add "HKLM\SOFTWARE\ODBC\ODBC.INI\mi_dsn_hana" /v CHAR_AS_UTF8 /t REG_SZ /d true /f

Comprobar:

reg query "HKLM\SOFTWARE\ODBC\ODBC.INI\mi_dsn_hana" /v CHAR_AS_UTF8

Resultado esperado:

CHAR_AS_UTF8    REG_SZ    true

Configuración final:

CHAR_AS_UTF8=true
EnableArrayFetch=1

🔧 PHP + SAP HANA + ODBC + UTF-8: un pequeño parámetro del driver puede hacer toda la diferencia.

SAP Business One Service Layer: por qué el PATCH no elimina roles de un empleado (y cómo solucionarlo)

Entrada fija

Si estás integrando SAP Business One Service Layer con una aplicación propia en PHP o CodeIgniter 4 para gestionar empleados y sus roles, es muy probable que en algún momento te topes con este comportamiento extraño: haces un PATCH a EmployeesInfo quitando un rol del arreglo EmployeeRolesInfoLines, Service Layer te responde 204 (éxito), pero al consultar de nuevo el empleado… el rol sigue ahí.

No es un bug de tu código. Es un comportamiento documentado (pero poco conocido) de cómo Service Layer maneja las colecciones hijas en las peticiones PATCH. En este post te explico la causa exacta y la solución con un ejemplo completo en PHP.

El síntoma

Un flujo típico para quitar un rol asignado a un empleado se ve así:

  1. Haces GET a EmployeesInfo(empID) y traes la colección EmployeeRolesInfoLines.
  2. Filtras en tu código el rol que quieres eliminar.
  3. Mandas un PATCH de vuelta con el arreglo ya sin ese rol.
  4. Service Layer responde HTTP 204 No Content — es decir, “todo salió bien”.
  5. Vuelves a consultar el empleado… y el rol que “eliminaste” sigue en la lista.

El código no marca ningún error. El log de tu aplicación dice que la operación fue exitosa. Y sin embargo, en SAP no pasó nada.

La causa real: cómo funciona PATCH en Service Layer

Aquí está la clave que casi nadie documenta claramente: PATCH en SAP Business One Service Layer nunca elimina elementos de una colección hija por el simple hecho de omitirlos del arreglo.

Por definición, PATCH es una actualización parcial: aplica los cambios que le mandas y conserva silenciosamente todo lo que no esté presente en el payload. Si en tu arreglo EmployeeRolesInfoLines ya no incluyes el rol que querías borrar, Service Layer no lo interpreta como “bórralo” — simplemente lo ignora y lo deja como estaba.

Este mismo comportamiento se ha reportado en la comunidad de desarrolladores de SAP al trabajar con líneas de documentos (DocumentLines en órdenes de venta), y aplica exactamente igual a cualquier colección hija expuesta por Service Layer, incluyendo los roles de un empleado.

La solución: el header B1S-ReplaceCollectionsOnPatch

Service Layer sí tiene una forma de decirle “trata este arreglo como el reemplazo completo de la colección, no como una actualización parcial”: el header HTTP B1S-ReplaceCollectionsOnPatch: true.

Al incluir este header en tu petición PATCH, cualquier elemento que no esté presente en el arreglo que envías sí se elimina de la colección hija en SAP. Es exactamente el comportamiento que necesitas para dar de baja un rol.

⚠️ Importante antes de usarlo

Este header cambia el comportamiento para todas las colecciones hijas incluidas en ese PATCH, no solo la que te interesa. Si tu payload incluyera más de una colección hija, cualquiera que no mandes completa corre el riesgo de perder elementos. La recomendación es:

  • Usarlo únicamente en los endpoints donde manipulas directamente EmployeeRolesInfoLines (agregar/quitar roles).
  • No incluirlo en el PATCH general de datos del empleado (nombre, departamento, estatus), donde no estás tocando colecciones hijas.

Ejemplo completo en PHP (CodeIgniter 4)

Así queda la función completa para eliminar un rol de un empleado, con el flujo GET → filtrar → PATCH con el header correcto:

php

public function removeEmployeeRole($empID, $roleID) {
    helper('auth');
    $userName = user()->username;
    $empID = (int) $empID;
    $roleID = (int) $roleID;

    if ($empID <= 0 || $roleID <= 0) {
        return $this->respond(['status' => 400, 'message' => 'Faltan datos'], 400);
    }

    $dataSL = $this->serviceLayerModel->first();
    if (empty($dataSL)) {
        return $this->respond(['status' => 500, 'message' => 'No hay configuración Service Layer'], 500);
    }

    try {
        $conexionSap = $this->serviceLayerController->login(
                $dataSL['url'],
                $dataSL['port'],
                $dataSL['password'],
                $dataSL['username'],
                $dataSL['companyDB']
        );
    } catch (\Exception $e) {
        return $this->respond(['status' => 500, 'message' => 'Error login SL: ' . $e->getMessage()], 500);
    }

    if (empty($conexionSap->SessionId)) {
        return $this->respond(['status' => 500, 'message' => 'No se obtuvo SessionId'], 500);
    }

    $cookie = "B1SESSION=" . $conexionSap->SessionId . "; ROUTEID=.node1";
    $slRoot = rtrim($dataSL['url'], '/');
    if (stripos($slRoot, '/b1s/v1') === false) {
        $slRoot .= '/b1s/v1';
    } else {
        $pos = stripos($slRoot, '/b1s/v1');
        $slRoot = substr($slRoot, 0, $pos) . '/b1s/v1';
    }

    $getHeaders = [
        "Accept: application/json",
        "Content-Type: application/json",
        "User-Agent: PHP",
        "B1S-CaseInsensitive: true"
    ];

    // Header clave: le dice a Service Layer que reemplace por completo
    // la colección hija, en vez de solo actualizar/agregar elementos
    $patchHeaders = array_merge($getHeaders, [
        "B1S-ReplaceCollectionsOnPatch: true"
    ]);

    // 1) GET de los roles actuales
    $getUrl = $slRoot . "/EmployeesInfo({$empID})?" . http_build_query([
        '$select' => 'EmployeeID,EmployeeRolesInfoLines'
    ]);

    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL => $getUrl,
        CURLOPT_PORT => $dataSL['port'],
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_COOKIE => $cookie,
        CURLOPT_SSL_VERIFYHOST => false,
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_HTTPHEADER => $getHeaders,
        CURLOPT_TIMEOUT => 60
    ]);
    $getResp = curl_exec($ch);
    $getErr = curl_error($ch);
    $getHttp = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($getErr || $getHttp < 200 || $getHttp >= 300) {
        return $this->respond([
            'status' => 500,
            'message' => 'Error al obtener roles actuales: ' . ($getErr ?: "HTTP $getHttp: $getResp")
        ], 500);
    }

    $current = json_decode($getResp, true);
    $roles = $current['EmployeeRolesInfoLines'] ?? [];

    // 2) Filtrar quitando el rol indicado
    $newRoles = array_values(array_filter($roles, function ($r) use ($roleID) {
        return (int) ($r['RoleID'] ?? 0) !== $roleID;
    }));

    if (count($newRoles) === count($roles)) {
        return $this->respond([
            'status' => 404,
            'message' => 'El empleado no tiene asignado ese rol'
        ], 404);
    }

    // 3) PATCH con la colección ya sin ese rol + header de reemplazo total
    $patchUrl = $slRoot . "/EmployeesInfo({$empID})";
    $payload = ['EmployeeRolesInfoLines' => $newRoles];

    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL => $patchUrl,
        CURLOPT_PORT => $dataSL['port'],
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => 'PATCH',
        CURLOPT_POSTFIELDS => json_encode($payload),
        CURLOPT_COOKIE => $cookie,
        CURLOPT_SSL_VERIFYHOST => false,
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_HTTPHEADER => $patchHeaders,
        CURLOPT_TIMEOUT => 60
    ]);
    $resp = curl_exec($ch);
    $err = curl_error($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($err) {
        return $this->respond(['status' => 500, 'message' => 'cURL Error: ' . $err], 500);
    }

    if ($httpCode < 200 || $httpCode >= 300) {
        $body = json_decode($resp, true);
        return $this->respond(['status' => $httpCode, 'message' => 'Error al eliminar', 'body' => $body], $httpCode);
    }

    $this->log->save([
        "description" => "Eliminación de rol ID '$roleID' del empleado $empID (vía SL, EmployeesInfo/EmployeeRolesInfoLines)",
        "user" => $userName
    ]);

    // Normalizado a 200 siempre en éxito, sin importar si SAP regresó 204
    return $this->respond(['status' => 200, 'message' => 'Rol eliminado correctamente'], 200);
}

Puntos clave para recordar

  • PATCH en Service Layer nunca borra por omisión. Si un elemento de una colección hija no aparece en el arreglo que envías, se conserva tal cual.
  • B1S-ReplaceCollectionsOnPatch: true convierte ese comportamiento en un reemplazo completo: lo que no incluyas en el arreglo, se elimina.
  • El patrón correcto para editar colecciones hijas (agregar, actualizar o quitar) sigue siendo GET → modificar en tu código → PATCH con la colección completa — la diferencia está en agregar este header cuando el objetivo es que también se eliminen elementos.
  • Aplica este header únicamente en los endpoints que manipulan la colección específica; no lo agregues de forma global a todos tus PATCH contra EmployeesInfo.
  • Un 204 No Content de Service Layer confirma que la petición fue válida, no que hizo lo que tú esperabas — siempre vale la pena verificar el resultado real, sobre todo mientras ajustas la lógica de colecciones hijas.

Si estás integrando otros módulos de SAP B1 vía Service Layer (órdenes de venta, líneas de documento, direcciones de socios de negocio), este mismo principio aplica: cualquier colección hija (DocumentLines, Addresses, ContactEmployees, etc.) se comporta igual ante un PATCH normal.

📱 ¿Qué datos entregas al registrar tu línea Telcel? INE, CURP, selfie, biométricos y privacidad

Entrada fija

🚨 Registrar tu línea celular ya implica entregar datos personales: esto es lo que debes saber

A partir de los nuevos procesos de registro de usuarios de telefonía móvil, muchas personas tienen una pregunta importante:

🤔 ¿Qué información obtiene Telcel cuando registro mi línea y qué puede hacer con esos datos?

La preocupación es comprensible. Para registrar una línea pueden solicitarse datos de identificación, como el nombre completo y la CURP, así como una identificación oficial. En el caso del registro remoto, Telcel informa que puede solicitarse una prueba de vida o selfie para autenticar a la persona y validar la identificación proporcionada.

Pero el registro de una línea no debe analizarse únicamente desde el punto de vista del trámite.

También es importante preguntarse:

  • 🪪 ¿Qué datos personales estoy proporcionando?
  • 📷 ¿Qué ocurre con mi identificación?
  • 🤳 ¿Para qué sirve la selfie o prueba de vida?
  • 🖐️ ¿Telcel puede tratar datos biométricos?
  • 🏛️ ¿Se pueden validar datos ante el INE?
  • 📡 ¿Qué otros datos puede obtener Telcel después de que uso la línea?
  • 🔐 ¿Puede ver mis fotos y archivos personales?
  • 📢 ¿Puede utilizar mis datos para publicidad?
  • ⚖️ ¿Qué derechos tengo sobre mi información?

En este artículo analizamos el proceso tomando como referencia la información oficial publicada por Telcel sobre el registro de líneas y su Aviso de Privacidad vigente.


📲 ¿Qué necesitas para registrar una línea Telcel?

Según la información oficial publicada por Telcel para el registro de usuarios de telefonía móvil, al realizar el trámite se solicita una identificación oficial vigente que contenga fotografía y CURP.

Entre los documentos mencionados se encuentran:

  • 🪪 Credencial para votar del INE.
  • 🛂 Pasaporte vigente.
  • 🌎 En determinados casos aplicables a personas extranjeras, documentación y CURP correspondientes.

Además, Telcel señala que se proporciona:

  • 👤 Nombre completo.
  • 🔢 CURP.

Si realizas el registro mediante la modalidad remota, también puede solicitarse una prueba de vida o selfie para autenticar tu identidad y validar la identificación presentada.

Esto significa que el registro puede involucrar información mucho más amplia que simplemente asociar un nombre con un número telefónico.


🪪 ¿Qué información personal puede tener Telcel sobre ti?

El Aviso de Privacidad de Clientes de Telcel establece diferentes categorías de datos personales que pueden ser tratados para la prestación de sus servicios.

Entre ellas se encuentran:

  • 🪪 Datos de identificación.
  • 🔐 Datos de autenticación.
  • 📞 Datos de contacto.
  • 💳 Datos patrimoniales y financieros.
  • 🧾 Datos fiscales.
  • 👥 Datos demográficos.
  • 📍 Datos de ubicación.
  • 📡 Información técnica del dispositivo.
  • 🌐 Datos de red.
  • 📊 Datos inferidos.
  • 🛍️ Preferencias de consumo.
  • 🖐️ Datos biométricos, dependiendo del contexto y del tratamiento.

Telcel también publica información complementaria donde explica ejemplos de datos que pueden estar incluidos dentro de estas categorías, como nombre, apellidos, RFC, CURP, fecha de nacimiento, fotografía, firma y datos biométricos, entre otros.

Por eso, cuando registras una línea, no solamente debes pensar en el número telefónico: estás estableciendo una relación de servicio que puede requerir distintos datos para identificación, autenticación, seguridad y cumplimiento de obligaciones.


🤳 ¿Qué pasa con la selfie o prueba de vida?

Uno de los puntos que puede generar más dudas es el registro remoto.

Telcel indica que, si eliges la modalidad remota, puede solicitarse una prueba de vida mediante selfie para autenticarte y validar la identificación oficial proporcionada.

La finalidad principal de este proceso es comprobar que:

  • 👤 La persona que realiza el trámite existe físicamente.
  • 🪪 Coincide con la identidad presentada.
  • 🛡️ Se reduzca el riesgo de fraude o robo de identidad.

Sin embargo, una imagen del rostro utilizada para verificar identidad puede involucrar características biométricas dependiendo de la tecnología y del tratamiento realizado.

El Aviso de Privacidad de Telcel señala expresamente que puede tratar datos biométricos relacionados con huellas dactilares y características del rostro que sean proporcionados voluntariamente para actividades de verificación de identidad, prevención de fraude y operaciones relacionadas con sus servicios.

Esto no significa necesariamente que cualquier fotografía sea automáticamente utilizada como un registro biométrico permanente. El tratamiento concreto depende del proceso utilizado. Pero sí significa que el tema de la verificación facial y biométrica merece atención cuando realizas un trámite de identificación.


🖐️ ¿Telcel puede utilizar huellas y datos biométricos?

El Aviso de Privacidad de Clientes de Telcel establece que los datos biométricos pueden considerarse datos personales sensibles dependiendo del contexto.

Entre los datos mencionados se encuentran:

  • 🖐️ Huellas dactilares.
  • 🙂 Características del rostro.

La finalidad indicada incluye actividades como:

  • Verificación de identidad.
  • Prevención de fraudes.
  • Prevención del robo de identidad.
  • Autenticación para servicios.
  • Operaciones futuras realizadas ante Telcel.

También se establece la posibilidad de verificar ante el Instituto Nacional Electoral (INE) la calidad de los datos contenidos en la Credencial para Votar, incluyendo datos biométricos, conforme a las finalidades descritas en el aviso.

Esta es una de las razones por las que resulta importante leer el aviso de privacidad antes de entregar una identificación o realizar un proceso de autenticación facial.


🏛️ ¿Telcel puede verificar información con el INE?

De acuerdo con su Aviso de Privacidad, Telcel contempla como finalidad primaria:

verificar ante el Instituto Nacional Electoral la calidad de los datos contenidos en la Credencial para Votar, incluyendo datos biométricos.

También contempla transferencias relacionadas con el INE para estos procesos de validación y autenticación de identidad.

En términos simples, cuando utilizas tu credencial para votar en un proceso de identificación, el aviso contempla mecanismos para verificar la información proporcionada.

Esto es importante porque muchas personas piensan que entregar una identificación únicamente significa que un empleado observa físicamente el documento.

Los procesos modernos pueden incluir mecanismos tecnológicos de validación y autenticación, especialmente cuando se trata de prevenir registros fraudulentos o robo de identidad.


🔐 ¿Registrar una línea significa que Telcel puede entrar a mi celular?

No.

Este punto debe quedar muy claro.

Registrar una línea con tu identificación, CURP y otros datos necesarios para validar tu identidad no significa que Telcel reciba acceso automático al contenido almacenado dentro de tu teléfono.

El registro de la línea y el contenido de tu dispositivo son cosas diferentes.

Por ejemplo, registrar tu línea no significa automáticamente que Telcel pueda abrir:

  • 🖼️ Tu galería.
  • 📁 Tus documentos.
  • 🎥 Tus vídeos.
  • 🎵 Tu música almacenada.
  • 🔑 Tus contraseñas.
  • 💬 Tus conversaciones privadas.

El acceso directo a este tipo de información depende de factores diferentes, como las aplicaciones instaladas y los permisos otorgados dentro del sistema operativo.


📸 Entonces, ¿Telcel puede ver mis fotos?

No simplemente por registrar tu línea.

Entregar tu identificación o una selfie para un proceso de autenticación no significa que Telcel tenga acceso completo a toda tu galería.

Una selfie utilizada para verificar identidad es diferente de obtener permiso para navegar por todas las fotografías almacenadas en tu dispositivo.

Para que una aplicación instalada pueda acceder directamente a fotos, vídeos o archivos, normalmente necesita permisos específicos otorgados por Android.

Por eso es importante diferenciar:

🤳 Selfie para registro

Puede utilizarse para autenticar tu identidad durante el proceso.

🖼️ Acceso a la galería

Es un permiso relacionado con el sistema operativo y las aplicaciones instaladas.

Una cosa no implica automáticamente la otra.


📁 ¿Y mis archivos personales?

La misma lógica aplica a tus archivos.

El hecho de tener una línea registrada no permite automáticamente al operador abrir documentos almacenados en:

  • 📂 Descargas.
  • 📄 Documentos.
  • 🖼️ Imágenes.
  • 🎬 Vídeos.
  • 🎵 Música.

Android cuenta con mecanismos de permisos para controlar el acceso de las aplicaciones a este tipo de información.

Por eso, si utilizas aplicaciones relacionadas con Telcel, puedes revisar directamente qué permisos tienen.

Busca:

⚙️ Configuración → Aplicaciones → Nombre de la aplicación → Permisos

Ahí puedes comprobar si una aplicación tiene acceso a:

  • Fotos y vídeos.
  • Archivos.
  • Ubicación.
  • Cámara.
  • Micrófono.
  • Contactos.
  • Teléfono.
  • SMS.

Google explica que Android permite revisar y modificar los permisos otorgados a las aplicaciones desde la configuración del dispositivo.


📡 Después del registro: ¿qué información puede obtener Telcel por el uso del servicio?

Aquí es donde el Aviso de Privacidad cobra especial importancia.

Una vez que utilizas una línea y los servicios de telecomunicaciones, Telcel puede tratar información relacionada con la prestación de esos servicios.

El aviso menciona, entre otros:

  • 📡 Información técnica y de ubicación del dispositivo.
  • 🌐 Datos de la red.
  • 📍 Datos de ubicación.
  • 📊 Datos inferidos.
  • 🛒 Preferencias de consumo.

Esto no debe confundirse con acceso completo al almacenamiento del teléfono.

Por ejemplo:

Saber información técnica relacionada con una conexión no es lo mismo que abrir directamente la carpeta de fotos del usuario.

La diferencia entre los datos generados por el uso de la red y el contenido almacenado dentro del dispositivo es fundamental para entender la privacidad.


🧠 ¿Qué significa que puedan generar datos “inferidos”?

El Aviso de Privacidad también menciona los llamados datos inferidos.

En términos sencillos, son conclusiones o información generada a partir de otros datos disponibles.

Por ejemplo, mediante análisis de información pueden elaborarse:

  • 📊 Perfiles de consumo.
  • 🛍️ Preferencias comerciales.
  • 💳 Evaluaciones relacionadas con comportamiento crediticio.
  • 📈 Segmentaciones.
  • 🎯 Ofertas personalizadas.

El aviso contempla análisis y estudios relacionados con el comportamiento de consumo, así como elaboración de perfiles crediticios para determinar elegibilidad, nivel de riesgo o condiciones aplicables para productos y servicios. También contempla tratamientos automatizados de datos para estas finalidades.


💳 ¿Pueden consultar información relacionada con mi comportamiento crediticio?

Dependiendo del servicio contratado y de las obligaciones relacionadas, el Aviso de Privacidad contempla:

  • Monitoreo del comportamiento crediticio.
  • Elaboración de perfiles crediticios.
  • Evaluación de elegibilidad y nivel de riesgo.
  • Relación con sociedades de información crediticia.
  • Transferencias necesarias conforme a las finalidades y obligaciones aplicables.

Esto puede ser especialmente relevante cuando solicitas:

  • 📱 Un equipo financiado.
  • 📃 Un plan de renta.
  • 💰 Productos o servicios sujetos a evaluación crediticia.

No necesariamente aplica de la misma manera a todos los usuarios ni a todos los tipos de servicio, pero forma parte de las categorías y finalidades descritas en el aviso.


📢 ¿Pueden utilizar mis datos para publicidad?

El Aviso de Privacidad distingue entre finalidades primarias y finalidades secundarias.

Las finalidades primarias están relacionadas con proporcionar el servicio, verificar identidad, prevenir fraude, realizar facturación, cumplir obligaciones y otras actividades necesarias.

Las finalidades secundarias incluyen actividades como:

  • 📣 Envío de promociones.
  • 🎁 Ofertas personalizadas.
  • 🛍️ Información sobre productos y servicios.
  • 📊 Segmentación.
  • 🧠 Perfilamiento.
  • 📈 Predicciones y análisis para fines comerciales.

El aviso también contempla determinadas transferencias a empresas del grupo y, bajo ciertas condiciones y mecanismos de oposición, a socios comerciales o terceros para fines relacionados con productos y servicios.


✋ ¿Puedo decir que no quiero publicidad?

Sí existen mecanismos para limitar determinados tratamientos relacionados con finalidades secundarias.

El Aviso de Privacidad de Telcel señala que la negativa al uso de datos para finalidades secundarias no debe ser motivo para negar los servicios que solicitas o contratas.

También establece procedimientos para ejercer derechos relacionados con tus datos personales y para limitar determinados usos o divulgaciones.

Esto es importante:

📱 Puedes necesitar registrar tu línea para cumplir con el proceso aplicable, pero eso no significa necesariamente que debas aceptar recibir publicidad personalizada para poder utilizar el servicio.


⚖️ Tus Derechos ARCO: ¿qué puedes pedir?

Como titular de datos personales puedes ejercer los conocidos como Derechos ARCO:

🅰️ Acceso

Puedes solicitar conocer qué datos personales tienen sobre ti y cómo son utilizados.

✏️ Rectificación

Puedes pedir la corrección de información incorrecta, incompleta o desactualizada.

🗑️ Cancelación

Puedes solicitar la eliminación de datos cuando resulte legalmente procedente.

✋ Oposición

Puedes oponerte al uso de tus datos para determinadas finalidades.

La legislación mexicana exige que los avisos de privacidad informen, entre otros aspectos, la identidad del responsable, los datos tratados, las finalidades, los mecanismos para limitar el uso de los datos y los procedimientos para ejercer los derechos correspondientes.

Telcel publica en su Aviso de Privacidad los mecanismos para contactar a su Departamento de Datos Personales y ejercer los derechos relacionados con el tratamiento de la información.


🔍 ¿Qué deberías revisar antes de registrar tu línea?

Antes de realizar cualquier proceso de registro, considera estos puntos:

1️⃣ Lee qué datos te están solicitando

Pregunta si se requiere:

  • INE.
  • CURP.
  • Pasaporte.
  • Selfie.
  • Prueba de vida.
  • Huella u otro mecanismo de autenticación.

2️⃣ Pregunta para qué se utilizarán

Un proceso de identificación puede tener finalidades relacionadas con:

  • Seguridad.
  • Prevención de fraude.
  • Autenticación.
  • Cumplimiento normativo.

3️⃣ Consulta el Aviso de Privacidad

El Aviso de Privacidad es el documento que explica qué categorías de datos se tratan y para qué finalidades.

4️⃣ Diferencia entre registro y acceso al teléfono

Entregar tu identificación para registrar una línea no equivale a entregar acceso a tu galería o archivos personales.

5️⃣ Revisa los permisos de las aplicaciones

Si tienes apps de Telcel instaladas, comprueba qué permisos tienen realmente en tu dispositivo.


🛡️ Conclusión: registrar tu línea implica identificarte, no entregar el control completo de tu teléfono

El registro de una línea móvil implica proporcionar información personal para asociar la línea con una persona y realizar procesos de identificación y autenticación.

Según la información publicada por Telcel, el proceso puede requerir identificación oficial, nombre completo y CURP y, en la modalidad remota, una prueba de vida o selfie para validar la identidad.

Por su parte, el Aviso de Privacidad de Telcel contempla el tratamiento de múltiples categorías de información, incluyendo datos de identificación, contacto, ubicación, red, preferencias de consumo y, en determinados contextos, datos biométricos como huellas dactilares y características del rostro.

Sin embargo, hay una diferencia fundamental que todos los usuarios deberían conocer:

📱 Registrar tu línea con tu INE, CURP o una selfie no significa automáticamente que Telcel pueda entrar a tu celular, revisar tu galería, abrir tus archivos o consultar libremente todo lo que tienes instalado.

La información utilizada para registrar y autenticar una línea forma parte de un proceso diferente al acceso al contenido almacenado en el dispositivo.

La mejor recomendación es mantenerse informado, revisar el Aviso de Privacidad vigente, conocer qué permisos tienen las aplicaciones instaladas y ejercer los derechos disponibles cuando sea necesario.


📚 Fuentes oficiales

Cómo instalar todas las extensiones de PHP 8.3 en CachyOS para que Composer funcione de una vez

Entrada fija

Si acabas de instalar PHP 8.3 en CachyOS (o cualquier derivado de Arch) desde AUR y te encontraste con una cascada interminable de errores de composer update pidiendo extensiones que “deberían venir incluidas”, esta guía es para ti. Documentando el proceso completo que seguí para dejar funcionando un proyecto CodeIgniter 4 con dependencias de facturación electrónica (CFDI).

Leer Mas: Cómo instalar todas las extensiones de PHP 8.3 en CachyOS para que Composer funcione de una vez

El problema: PHP en Arch viene troceado en paquetes AUR separados

A diferencia de otras distros donde php trae casi todo integrado, en Arch/CachyOS el paquete php83 del AUR está dividido en subpaquetes independientes por extensión (php83-dom, php83-xsl, php83-mysql, etc.), todos derivados del mismo pkgbase. Esto significa dos cosas importantes:

  1. Ninguna extensión “viene por defecto” — hay que instalarlas explícitamente.
  2. Como comparten pkgbase, instalar una sola extensión nueva obliga a recompilar PHP completo, junto con todas las extensiones que ya tenías.

Síntoma inicial: Composer ni siquiera arranca

PHP Warning:  PHP Startup: Unable to load dynamic library 'phar'...
PHP's phar extension is missing. Composer requires it to run.

Sin phar, Composer no corre. Punto de partida obligado.

Los errores en cadena de composer update

Una vez con phar instalado, cada corrida de composer update revela otra extensión faltante:

- phpcfdi/cfdi-to-json require ext-dom * -> it is missing from your system.
- eclipxe/cfdiutils require ext-xsl * -> it is missing from your system.

Composer te va soltando las dependencias una por una, no de golpe — así que si vas resolviendo extensión por extensión, terminas recompilando PHP completo varias veces por la naturaleza del pkgbase compartido.

La solución: instalar todo en un solo lote, desatendido

En vez de ir corrigiendo extensión por extensión (y recompilar PHP 5-6 veces), la jugada es instalar de una sola vez todas las extensiones que un stack típico de CI4 + CFDI (facturación electrónica) va a necesitar:

yay -S --noconfirm --answerdiff None --answerclean All --removemake --cleanafter \
  php83-xsl php83-soap php83-bcmath php83-simplexml php83-tokenizer php83-fileinfo \
  php83-ctype php83-dom php83-xml php83-xmlreader php83-xmlwriter php83-iconv

Qué hace cada flag

FlagFunción
--noconfirmSalta el prompt de “¿Instalar? [SI]/no”
--answerdiff NoneEvita que te pregunte si quieres ver diffs del PKGBUILD
--answerclean AllLimpia directorios de build previos sin preguntar
--removemakeBorra dependencias de compilación (make) una vez terminado
--cleanafterLimpia los archivos temporales de compilación al finalizar

Con esto, yay corre de principio a fin sin pedir intervención manual, y como todas las extensiones comparten pkgbase, PHP se recompila una sola vez con todo el set incluido — en vez de una recompilación completa por cada extensión suelta.

Por qué justo estas extensiones

Si trabajas con librerías de facturación electrónica mexicana (CFDI) vía Composer (eclipxe/cfdiutils, phpcfdi/cfditopdf, etc.), este es el patrón típico de requisitos:

  • xsl, dom, xml, xmlreader, xmlwriter, simplexml — parseo y transformación de los XML del CFDI/timbrado.
  • soap — comunicación con PACs (Proveedores Autorizados de Certificación) para timbrado.
  • bcmath — cálculos de precisión decimal en montos, impuestos y totales.
  • tokenizer, ctype, fileinfo, iconv — requisitos base de CodeIgniter 4 y de muchos paquetes Composer modernos.

Verificación final

Una vez terminada la instalación:

php83 -m | grep -Ei 'dom|xsl|soap|bcmath|xml|tokenizer|ctype|fileinfo|iconv'
composer update

Si composer update resuelve sin errores de ext-* faltante, ya está: tu entorno CachyOS queda listo para correr CodeIgniter 4 con dependencias de facturación electrónica sin más sorpresas.

Bonus: evita recompilar cada vez que necesites otra extensión

Si en el futuro te falta una extensión nueva y no quieres esperar otra compilación completa del pkgbase de PHP, vale la pena activar Chaotic-AUR, un repositorio de binarios precompilados para paquetes de AUR (incluyendo todo el árbol php83-*):

sudo pacman-key --recv-key 3056513887B78AEB --keyserver keyserver.ubuntu.com
sudo pacman-key --lsign-key 3056513887B78AEB
sudo pacman -U 'https://cdn-mirror.chaotic.cx/chaotic-aur/chaotic-keyring.pkg.tar.zst' \
               'https://cdn-mirror.chaotic.cx/chaotic-aur/chaotic-mirrorlist.pkg.tar.zst'

Y agregando al final de /etc/pacman.conf:

[chaotic-aur]
Include = /etc/pacman.d/chaotic-mirrorlist

Con eso, la próxima extensión que necesites se instala en segundos vía pacman, sin pasar por makepkg.


Resumen para el que tenga prisa: en CachyOS/Arch, PHP viene fragmentado por extensión en AUR bajo un mismo pkgbase. En vez de ir instalando una por una según te las va pidiendo Composer, identifica de una vez el set completo que necesita tu stack (CI4 + CFDI, en mi caso) e instálalo todo junto con yay -S --noconfirm --answerdiff None --answerclean All --removemake --cleanafter <paquetes>. Te ahorras varias recompilaciones completas del core de PHP.

¿Qué es Navidrome y Cómo Instalarlo Nativamente en CachyOS / Arch Linux 🎵

Entrada fija

Si eres amante de la música y prefieres mantener el control de tu propia colección de archivos MP3, FLAC o WAV, seguro te has topado con este dilema: ¿cómo escuchar tu música local en el celular o la laptop sin andar pasando archivos por USB? 📁📲

Aquí es donde entra Navidrome, una de las mejores herramientas de código abierto para transformar tu PC en tu propio servidor de streaming estilo Spotify. 🎧✨

En este artículo te explicamos qué es, para qué sirve y los comandos paso a paso para instalarlo nativamente en CachyOS (o cualquier sistema basado en Arch Linux).

🚀 ¿Qué es Navidrome?

Navidrome es un servidor de medios y reproductor de música de código abierto, ultraligero y muy rápido. Está diseñado para permitirte explorar y escuchar tu colección de música almacenada en tu computadora o servidor desde cualquier lugar a través de un navegador web o aplicaciones móviles. 🌐🎶

Está escrito en Go, lo que significa que consume muy poca memoria RAM y CPU, rindiendo a la perfección tanto en tu PC de escritorio como en una laptop o Raspberry Pi.

💡 ¿Para qué sirve y por qué deberías usarlo?

  • Centralizar tu música: Guardas tu colección en tu disco duro y la escuchas en todos tus dispositivos.
  • Escuchar en el celular sin gastar almacenamiento: Transmites tus canciones por Wi-Fi o internet en lugar de saturar la memoria de tu teléfono. 📱
  • Compatibilidad con apps móviles: Es compatible con la API de Subsonic, lo que te permite usar clientes como Symfonium o Subtracks en Android, y Amperfy en iOS.
  • Privacidad total: Tus hábitos de escucha son 100% privados y ningún servicio te va a eliminar canciones por derechos de autor. 🛡️
  • Transcodificación en tiempo real: Si tienes archivos FLAC pesados, puede convertirlos a MP3 al vuelo para no gastar tus datos móviles. 📶

🛠️ Guía de Instalación Nativa en CachyOS / Arch Linux

Si usas CachyOS, la forma más limpia de tener Navidrome es mediante una instalación nativa con systemd. A continuación tienes el paso a paso en terminal:

1. Instalar Navidrome desde AUR

Usa el helper paru (incluido por defecto en CachyOS) para compilar e instalar el paquete binario:

Bash

paru -S navidrome-bin

2. Crear carpetas y ajustar permisos

Creamos la carpeta donde Navidrome guardará su base de datos y le asignamos los permisos al usuario de sistema navidrome:

Bash

# Crear directorio de datos
sudo mkdir -p /var/lib/navidrome

# Asignar propietario al usuario de navidrome
sudo chown -R navidrome:navidrome /var/lib/navidrome

También debemos dar permisos de lectura para que Navidrome pueda acceder a la carpeta donde guardas tu música (ajusta si la tienes en tu /home):

Bash

chmod o+rx /home/$USER
chmod -R o+rX /home/$USER/Musica

3. Configurar el archivo navidrome.toml

Abre el archivo de configuración con el editor de texto nano:

Bash

sudo nano /etc/navidrome/navidrome.toml

Agrega o modifica los siguientes parámetros (asegúrate de cambiar tu_usuario por tu nombre de usuario real en CachyOS):

Ini, TOML

# Ruta a tu colección de música
MusicFolder = "/home/tu_usuario/Musica"

# Ruta donde se guardará la base de datos
DataFolder = "/var/lib/navidrome"

# Puerto de red predeterminado
Port = 4533

# Escaneo automático de nuevos archivos cada hora
ScanSchedule = "@every 1h"

# Idioma por defecto
DefaultLanguage = "es"

Tip: Guarda los cambios presionando Ctrl + O, confirma con Enter y sal con Ctrl + X.

4. Activar el servicio Systemd

Habilita el servicio para que Navidrome inicie automáticamente con tu sistema operativo:

Bash

sudo systemctl enable --now navidrome

Para verificar que todo está funcionando correctamente:

Bash

sudo systemctl status navidrome

🌐 Primer acceso y configuración inicial

  1. Abre tu navegador e ingresa a: http://localhost:4533
  2. La primera pantalla te pedirá crear una cuenta de administrador (asigna tu usuario y contraseña).
  3. ¡Listo! Navidrome comenzará a escanear tu carpeta de música de forma automática. 🚀

📌 Conclusión

Instalar Navidrome de forma nativa en CachyOS es sumamente rápido y eficiente. Con un consumo de recursos casi nulo y una integración perfecta con systemd, tendrás tu propia plataforma de música privada accesible desde cualquier dispositivo. ¡Toma el control de tus archivos digitales hoy mismo! 🎧🔥

🎵 Cómo organizar tu música en Linux y crear tu propio Spotify con Picard y Navidrome

Entrada fija

¿Tienes cientos o miles de canciones desordenadas en carpetas? 😵‍💫🎶
¿Archivos con nombres como Track01.mp3, Audio_023.flac o canciones sin portada ni información?

En Linux podemos solucionar este problema de una forma sencilla utilizando MusicBrainz Picard para identificar y organizar nuestra música y Navidrome para crear nuestro propio servidor de música. 🐧🎧

El resultado: una biblioteca musical ordenada y accesible desde la computadora, celular o navegador. 📱💻

🎼 1. Organiza tu música con MusicBrainz Picard

El primer paso es tener correctamente identificadas nuestras canciones.

Para esto podemos utilizar MusicBrainz Picard, una herramienta gratuita que utiliza la base de datos de MusicBrainz para reconocer nuestros archivos y completar automáticamente sus metadatos.

Con Picard podemos obtener información como:

  • 🎤 Artista
  • 💿 Álbum
  • 🎵 Nombre de la canción
  • 📅 Año
  • 🎼 Género
  • 🔢 Número de pista
  • 🖼️ Portada del álbum
  • 💽 Información del disco

Esto es especialmente útil cuando tenemos una colección antigua de MP3, FLAC u otros formatos y queremos convertirla en una biblioteca musical bien organizada.

📂 Una estructura ordenada

Por ejemplo, podemos terminar con una estructura similar a:

Música/
├── Pink Floyd/
│   └── The Dark Side of the Moon/
│       ├── 01 - Speak to Me.flac
│       ├── 02 - Breathe.flac
│       └── 03 - On the Run.flac
│
├── Queen/
│   └── A Night at the Opera/
│       ├── 01 - Death on Two Legs.flac
│       └── 02 - Lazing on a Sunday Afternoon.flac
│
└── Metallica/
    └── Black Album/
        ├── 01 - Enter Sandman.flac
        └── 02 - Sad but True.flac

🎯 La ventaja es que posteriormente aplicaciones como Navidrome pueden utilizar estos metadatos para mostrar correctamente artistas, álbumes, géneros y canciones.


🏷️ 2. Picard: etiquetas y organización automática

Una vez que agregamos nuestra música a MusicBrainz Picard, el programa analiza las canciones y busca coincidencias en la base de datos.

Podemos revisar la información encontrada y después guardar los cambios. 💾

Así evitamos tener que editar manualmente cientos de canciones.

✅ El flujo sería:

🎵 Música desordenada
⬇️
🔎 MusicBrainz Picard
⬇️
🏷️ Etiquetas correctas
⬇️
📂 Archivos organizados
⬇️
🎧 Navidrome
⬇️
📱 Escuchar nuestra música desde cualquier dispositivo


🎧 3. Instala Navidrome y crea tu propio servidor de música

Una vez que nuestra biblioteca está organizada, podemos utilizar Navidrome.

Navidrome es un servidor de música que nos permite acceder a nuestra colección desde diferentes dispositivos mediante una interfaz web y clientes compatibles.

En lugar de depender exclusivamente de una plataforma de streaming, podemos tener nuestra propia biblioteca almacenada en nuestro servidor. 🖥️🎶

Por ejemplo:

Servidor Linux
      │
      ├── 🎵 Música
      │
      └── 🎧 Navidrome
             │
       ┌─────┼─────┐
       ↓     ↓     ↓
     📱      💻     🌐
   Celular   PC    Navegador

Esto resulta especialmente interesante si ya tienes una gran colección de música comprada, descargada legalmente o digitalizada desde tus propios discos.


🟢 4. ¿Navidrome puede ser una alternativa a Spotify?

Sí, pero son conceptos diferentes. 😉

Spotify es un servicio de streaming con un enorme catálogo disponible mediante su plataforma.

Navidrome, en cambio, está pensado para reproducir tu propia colección de música desde tu servidor.

🟢 Con Navidrome tienes:

✅ Tu propia biblioteca musical
✅ Control sobre tus archivos
✅ Organización mediante metadatos
✅ Acceso desde navegador
✅ Acceso desde dispositivos móviles mediante clientes compatibles
✅ Soporte para diferentes formatos de audio
✅ Sin depender de un catálogo externo para tu música
✅ Posibilidad de alojarlo en tu propio servidor Linux

🔵 Con Spotify tienes:

🎵 Un enorme catálogo de música
🔎 Búsqueda de artistas y canciones
📻 Recomendaciones y playlists
🌐 Servicio administrado por Spotify
📱 Aplicaciones oficiales para diferentes dispositivos

Por eso, Navidrome no busca reemplazar completamente a Spotify, sino ofrecer una alternativa para quienes quieren tener su propia biblioteca musical bajo su control.


🔥 5. ¿Por qué utilizar Picard + Navidrome?

La combinación es muy interesante:

🏷️ MusicBrainz Picard

Se encarga de identificar, etiquetar y organizar nuestra música.

🎧 Navidrome

Se encarga de servir y reproducir esa biblioteca desde nuestro servidor.

Es decir:

Picard organiza tu música. Navidrome te permite disfrutarla. 🎶

Y todo esto puede funcionar perfectamente dentro de un servidor Linux. 🐧


💻 6. Una biblioteca musical completamente organizada

Después de realizar todo el proceso podemos tener algo parecido a:

/home/usuario/Música/
│
├── Artista 1/
│   ├── Álbum 1/
│   └── Álbum 2/
│
├── Artista 2/
│   ├── Álbum 1/
│   └── Álbum 2/
│
└── Artista 3/
    └── Álbum 1/

Navidrome leerá la información de los archivos y podremos navegar por:

🎤 Artistas
💿 Álbumes
🎵 Canciones
🎼 Géneros
⭐ Favoritos
📋 Listas de reproducción


📱 7. Escucha tu música desde el celular

Una de las partes más interesantes de tener Navidrome es poder acceder a nuestra biblioteca desde otros dispositivos.

Por ejemplo:

🖥️ PC → Navidrome
📱 Celular → Cliente compatible
💻 Laptop → Navegador
🌐 Otros dispositivos → Acceso al servidor

Así podemos convertir una computadora o servidor Linux en nuestro centro personal de música. 🎶🐧


🔐 8. Tu música bajo tu control

Una de las principales ventajas de este enfoque es que tú decides dónde almacenar tu biblioteca y cómo administrarla.

Puedes utilizar:

💽 Disco duro
🖥️ PC vieja
🗄️ Servidor casero
☁️ Servidor remoto

Y si configuras correctamente el acceso remoto y la seguridad, también puedes acceder a tu biblioteca cuando estés fuera de casa. 🌎📱


🚀 Conclusión

Si tienes una colección grande de música y quieres dejar atrás el caos de carpetas y archivos mal nombrados, MusicBrainz Picard + Navidrome es una excelente combinación para Linux. 🐧🎵

Picard se encarga de identificar y organizar tus canciones.

Navidrome convierte esa biblioteca en tu propio servicio de música.

Y aunque no reemplaza directamente el enorme catálogo de Spotify, sí puede ser una excelente alternativa para quienes quieren disfrutar de su propia colección musical desde cualquier dispositivo.

🎵 Tu música.
📂 Tu biblioteca.
🖥️ Tu servidor.
🔐 Tu control.

#Linux #Navidrome #MusicBrainzPicard #Picard #Spotify #Musica #LinuxMint #ServidorLinux #SelfHosting #MusicaDigital #FLAC #MP3 #BibliotecaMusical #OpenSource #LinuxServer

📸 Cómo organizar fotos recuperadas con PhotoRec por año y mes en Linux

Entrada fija

¿Recuperaste miles de fotografías con PhotoRec y ahora tienes cientos de carpetas recup_dir.* llenas de archivos con nombres como f123456789.jpg? 😵‍💫

No necesitas organizarlas manualmente. En este tutorial vamos a utilizar ExifTool + Bash para leer automáticamente la fecha de las fotografías y organizarlas en carpetas por año y mes. 📅📸

🔎 ¿Qué hace este script?

El script analiza automáticamente las carpetas recuperadas por PhotoRec y realiza las siguientes tareas:

  • 📸 Busca fotografías recuperadas.
  • 🎥 Busca videos recuperados.
  • 📅 Lee la fecha original almacenada en los metadatos EXIF.
  • 🔎 Si no encuentra DateTimeOriginal, intenta utilizar CreateDate.
  • 📁 Crea automáticamente carpetas por año y mes.
  • ❓ Envía las fotografías sin fecha a SinFecha.
  • ❓ Envía los videos sin fecha a SinFecha.
  • 🔄 Evita sobrescribir archivos que tengan el mismo nombre.
  • 📝 Guarda un registro de todos los archivos movidos.
  • 🧹 Elimina las carpetas de recuperación que quedan vacías.

📂 Antes de organizar

Después de utilizar PhotoRec normalmente tendremos una estructura parecida a esta:

recup_dir.1/
recup_dir.2/
recup_dir.3/
recup_dir.4/
recup_dir.5/
...

Dentro de estas carpetas PhotoRec puede haber recuperado miles de archivos con nombres genéricos.

✨ Resultado final

Después de ejecutar el script, la información quedará organizada de esta manera:

Organizado/
├── Fotos/
│   ├── 2010/
│   │   ├── 01/
│   │   ├── 02/
│   │   └── 12/
│   ├── 2011/
│   ├── 2012/
│   ├── 2020/
│   └── SinFecha/
│
└── Videos/
    ├── 2010/
    │   ├── 01/
    │   └── 08/
    ├── 2011/
    └── SinFecha/

📸 Ejemplo

Supongamos que PhotoRec recuperó una fotografía con el nombre:

recup_dir.502/f268968512.jpg

Si ExifTool encuentra que la fotografía fue tomada en julio de 2018, el archivo será movido automáticamente a:

Organizado/Fotos/2018/07/f268968512.jpg

De esta forma podemos transformar una recuperación desordenada en una biblioteca mucho más fácil de administrar. 🚀

🛠️ Instalar ExifTool

En Linux Mint, Ubuntu y otras distribuciones basadas en Debian podemos instalar ExifTool con:

sudo apt update
sudo apt install exiftool

Podemos comprobar que está instalado con:

exiftool -ver

💻 Crear el script

Primero debemos entrar en la carpeta donde tenemos las carpetas recup_dir.*.

nano organizar_recuperados.sh

Después pegamos el siguiente código:

#!/bin/bash

DEST="$(pwd)/Organizado"
LOG="$(pwd)/organizar.log"

mkdir -p "$DEST/Fotos/SinFecha"
mkdir -p "$DEST/Videos/SinFecha"

echo "==================================" &gt; "$LOG"
echo " ORGANIZACIÓN DE ARCHIVOS" &gt;&gt; "$LOG"
echo " Inicio: $(date)" &gt;&gt; "$LOG"
echo "==================================" &gt;&gt; "$LOG"

mover() {
    local origen="$1"
    local carpeta="$2"

    mkdir -p "$carpeta"

    local nombre
    nombre=$(basename "$origen")

    local base="${nombre%.*}"
    local ext="${nombre##*.}"

    if [[ "$base" == "$ext" ]]; then
        ext=""
    else
        ext=".$ext"
    fi

    local destino="$carpeta/$nombre"
    local i=1

    while [[ -e "$destino" ]]; do
        destino="$carpeta/${base}_$i$ext"
        ((i++))
    done

    mv "$origen" "$destino"

    echo "$origen -&gt; $destino" &gt;&gt; "$LOG"
}

##################################
# FOTOS
##################################

echo
echo "=================================="
echo "        ORGANIZANDO FOTOS"
echo "=================================="
echo

echo "Contando fotos..."

TOTAL=$(find recup_dir.* -type f \( \
    -iname "*.jpg" -o \
    -iname "*.jpeg" -o \
    -iname "*.png" -o \
    -iname "*.bmp" -o \
    -iname "*.gif" -o \
    -iname "*.webp" -o \
    -iname "*.heic" -o \
    -iname "*.tif" -o \
    -iname "*.tiff" \
\) | wc -l)

echo "Fotos encontradas: $TOTAL"

N=0

find recup_dir.* -type f \( \
    -iname "*.jpg" -o \
    -iname "*.jpeg" -o \
    -iname "*.png" -o \
    -iname "*.bmp" -o \
    -iname "*.gif" -o \
    -iname "*.webp" -o \
    -iname "*.heic" -o \
    -iname "*.tif" -o \
    -iname "*.tiff" \
\) -print0 |

while IFS= read -r -d '' f
do

    ((N++))

    printf "\rFotos: %d / %d" "$N" "$TOTAL"

    fecha=$(exiftool -m -s3 -DateTimeOriginal "$f" 2&gt;/dev/null)

    if [[ -z "$fecha" || "$fecha" == "0000:00:00 00:00:00" ]]; then
        fecha=$(exiftool -m -s3 -CreateDate "$f" 2&gt;/dev/null)
    fi

    if [[ -n "$fecha" && "$fecha" != "0000:00:00 00:00:00" ]]; then

        año="${fecha:0:4}"
        mes="${fecha:5:2}"

        mover "$f" "$DEST/Fotos/$año/$mes"

    else

        mover "$f" "$DEST/Fotos/SinFecha"

    fi

done

echo
echo

##################################
# VIDEOS
##################################

echo "=================================="
echo "        ORGANIZANDO VIDEOS"
echo "=================================="
echo

echo "Contando videos..."

TOTAL=$(find recup_dir.* -type f \( \
    -iname "*.mp4" -o \
    -iname "*.mov" -o \
    -iname "*.3gp" -o \
    -iname "*.avi" -o \
    -iname "*.mkv" -o \
    -iname "*.mts" -o \
    -iname "*.m2ts" -o \
    -iname "*.wmv" -o \
    -iname "*.asf" -o \
    -iname "*.mpeg" -o \
    -iname "*.mpg" -o \
    -iname "*.vob" -o \
    -iname "*.webm" -o \
    -iname "*.flv" -o \
    -iname "*.m4v" \
\) | wc -l)

echo "Videos encontrados: $TOTAL"

N=0

find recup_dir.* -type f \( \
    -iname "*.mp4" -o \
    -iname "*.mov" -o \
    -iname "*.3gp" -o \
    -iname "*.avi" -o \
    -iname "*.mkv" -o \
    -iname "*.mts" -o \
    -iname "*.m2ts" -o \
    -iname "*.wmv" -o \
    -iname "*.asf" -o \
    -iname "*.mpeg" -o \
    -iname "*.mpg" -o \
    -iname "*.vob" -o \
    -iname "*.webm" -o \
    -iname "*.flv" -o \
    -iname "*.m4v" \
\) -print0 |

while IFS= read -r -d '' f
do

    ((N++))

    printf "\rVideos: %d / %d" "$N" "$TOTAL"

    fecha=$(exiftool -m -s3 -MediaCreateDate "$f" 2&gt;/dev/null)

    if [[ -z "$fecha" || "$fecha" == "0000:00:00 00:00:00" ]]; then
        fecha=$(exiftool -m -s3 -CreateDate "$f" 2&gt;/dev/null)
    fi

    if [[ -n "$fecha" && "$fecha" != "0000:00:00 00:00:00" ]]; then

        año="${fecha:0:4}"
        mes="${fecha:5:2}"

        mover "$f" "$DEST/Videos/$año/$mes"

    else

        mover "$f" "$DEST/Videos/SinFecha"

    fi

done

echo
echo

##################################
# LIMPIEZA
##################################

echo "Eliminando carpetas de recuperación vacías..."

find recup_dir.* -type d -empty -delete

echo
echo "=================================="
echo "          FINALIZADO"
echo "=================================="
echo

echo "Fotos y videos organizados en:"
echo "$DEST"

echo
echo "Registro:"
echo "$LOG"

echo
echo "Fin: $(date)" &gt;&gt; "$LOG"

▶️ Dar permisos y ejecutar

Una vez guardado el archivo, le damos permisos de ejecución:

chmod +x organizar_recuperados.sh

Y lo ejecutamos:

./organizar_recuperados.sh

El programa mostrará el progreso mientras analiza las fotografías y videos recuperados.

📝 Registro de archivos

El script crea un archivo llamado:

organizar.log

Este archivo contiene información de los archivos que fueron movidos y su ubicación final. Es muy útil para comprobar qué hizo el script.

⚠️ ¿Qué pasa con las fotos que no tienen fecha?

No todas las fotografías recuperadas por PhotoRec conservan sus metadatos EXIF. Esto puede ocurrir especialmente cuando el archivo fue recuperado parcialmente o cuando los metadatos ya habían sido eliminados.

Cuando no se encuentra una fecha válida, la fotografía se coloca en:

Organizado/Fotos/SinFecha/

Lo mismo ocurre con los videos:

Organizado/Videos/SinFecha/

💡 Consejo importante antes de recuperar archivos

Si estás recuperando información importante con PhotoRec, evita trabajar directamente sobre el disco donde se encuentran los archivos eliminados. Lo ideal es recuperar los archivos hacia otro disco para evitar sobrescribir información que todavía podría recuperarse. 💾

🚀 ¿Qué podemos hacer después?

Una vez que las fotografías estén organizadas por fecha, podemos utilizar herramientas como Digikam para administrar grandes colecciones de fotografías y Czkawka para localizar archivos duplicados.

Para música recuperada, una estrategia similar consiste en utilizar MusicBrainz Picard para identificar canciones y corregir sus metadatos, y posteriormente utilizar Navidrome para convertir la colección en una biblioteca musical accesible desde el navegador o el teléfono. 🎵📱

🏁 Conclusión

Con unas cuantas herramientas gratuitas y de código abierto podemos transformar una recuperación desordenada de PhotoRec en una biblioteca organizada automáticamente.

PhotoRec → ExifTool → Organización por fecha → Czkawka/DigiKam → Biblioteca organizada 📸💾🐧

Este método resulta especialmente útil cuando se han recuperado miles de fotografías y videos y queremos volver a construir nuestra colección personal de forma rápida y ordenada. 🚀

Cómo resolver “Error while downloading the document file to be converted” en OnlyOffice + Nextcloud tras actualizar el certificado

Entrada fija

Si acabas de renovar o cambiar el certificado SSL de tu servidor Nextcloud y ahora OnlyOffice Document Server (corriendo en Docker) dejó de funcionar mostrando el mensaje:

Error when trying to connect (Error occurred in the document service: Error while downloading the document file to be converted.)

este artículo documenta el diagnóstico completo y la solución que aplicamos en nuestro entorno (Docker, versión de Document Server 9.3.1.10).

El síntoma

Al intentar guardar la configuración de conexión entre la app de OnlyOffice en Nextcloud y el Document Server, Nextcloud devuelve el error de conversión de documento, sin más detalle en la interfaz.

Paso 1: Revisar los logs del contenedor de OnlyOffice

El primer paso —y el más importante— es ir directo al log del contenedor Docker, ya que la interfaz web no muestra el detalle técnico real:

sudo docker logs <container_id> --tail 100 | grep -i "downloadFile\|error\|CERT"

En nuestro caso, el log mostró claramente la causa:

error downloadFile:url=https://tu-dominio:444/index.php/apps/onlyoffice/empty?doc=...
code:DEPTH_ZERO_SELF_SIGNED_CERT;connect:undefined
Error: self-signed certificate

El diagnóstico

El código DEPTH_ZERO_SELF_SIGNED_CERT confirma que el problema es de confianza SSL, no de red, permisos ni JWT. El contenedor de OnlyOffice, al intentar descargar el archivo desde Nextcloud por HTTPS para convertirlo, rechaza el certificado porque es autofirmado (o le falta la cadena intermedia) y no forma parte de su almacén de certificados de confianza (CA store) interno.

Esto es un efecto colateral típico después de renovar o cambiar un certificado: aunque el navegador lo acepte (o lo tengas configurado para ignorarlo), el motor Node.js que corre dentro del contenedor de OnlyOffice valida los certificados de forma independiente y estricta.

La solución

Existen dos rutas posibles:

Opción A — Confiar en el certificado (recomendada si seguirá siendo autofirmado)

  1. Extraer el certificado servido en el puerto correspondiente:
echo | openssl s_client -connect tu-dominio:444 -servername tu-dominio 2>/dev/null | openssl x509 -outform PEM > cert.crt
  1. Copiarlo al contenedor y actualizar el almacén de confianza:
sudo docker cp cert.crt <container_id>:/usr/local/share/ca-certificates/cert.crt
sudo docker exec <container_id> update-ca-certificates
sudo docker restart <container_id>

Opción B — Deshabilitar la verificación estricta (solución que aplicamos)

Se edita el archivo de configuración del Document Server dentro del contenedor:

sudo docker exec -it <container_id> bash
nano /etc/onlyoffice/documentserver/local.json

Y se agrega la siguiente sección dentro de services.CoAuthoring:

"services": {
  "CoAuthoring": {
    "requestDefaults": {
      "rejectUnauthorized": false
    },
    ...
  }
}

Después de guardar el archivo, es indispensable reiniciar el contenedor para que los servicios internos (docservice, converter, nginx) carguen la nueva configuración:

sudo docker restart <container_id>

Tras el reinicio, la conexión entre Nextcloud y OnlyOffice vuelve a funcionar con normalidad.

Nota importante sobre seguridad

rejectUnauthorized: false desactiva la validación de certificados SSL para todas las peticiones salientes del Document Server, no solo hacia tu instancia de Nextcloud. Es una solución práctica y válida si el certificado en cuestión seguirá siendo autofirmado por diseño (por ejemplo, en una red interna), pero si en el futuro migras a un certificado válido emitido por una autoridad reconocida (como Let’s Encrypt), lo recomendable es revertir este valor a true para restaurar la verificación estricta y protegerte de posibles ataques de intermediario (man-in-the-middle) en esa conexión.

Resumen rápido

PasoAcción
1Revisar logs del contenedor con docker logs filtrando por downloadFile y CERT
2Confirmar el código de error (DEPTH_ZERO_SELF_SIGNED_CERT = problema de certificado)
3Editar local.json agregando rejectUnauthorized: false en requestDefaults
4Reiniciar el contenedor con docker restart
5Migrar a un certificado válido a futuro y revertir el ajuste (opcional, recomendado)

Documentado a partir de un caso real de integración Nextcloud + OnlyOffice Document Server 9.3.1.10 en Docker.

🔐 Solución definitiva: Error en ONLYOFFICE Docs al renovar certificado SSL en Nextcloud (certificado autofirmado)

Entrada fija

¿Tu integración de ONLYOFFICE con Nextcloud dejó de funcionar después de renovar el certificado SSL? Aparece el error: “Error when trying to connect (Error occurred in the document service: Error while downloading the document file to be converted.)” No te preocupes, aquí tienes la guía paso a paso para resolverlo de forma definitiva, tanto si usas certificado autofirmado como si quieres migrar a Let’s Encrypt.


📌 Índice

  1. Diagnóstico del problema
  2. Renovar el certificado en Nextcloud (Snap)
  3. Configurar Apache para el puerto 4445 (si aplica)
  4. Solución de confianza SSL en el contenedor ONLYOFFICE
  5. Configurar la integración en Nextcloud
  6. Automatizar renovaciones futuras
  7. Conclusión y recomendaciones finales

1. 🔍 Diagnóstico del problema

El error se debe a que el contenedor de ONLYOFFICE Document Server no confía en el nuevo certificado que presenta Nextcloud al intentar descargar el archivo a convertir. En los logs del contenedor aparece:

error downloadFile:url=https://gusadrive.dyndns.org:444/... code:DEPTH_ZERO_SELF_SIGNED_CERT

Para confirmar el diagnóstico, revisa los logs de tu contenedor:

sudo docker ps   # Identifica el nombre del contenedor (ej. reverent_torvalds)
sudo docker logs  --tail 100 | grep -i "downloadFile\|error\|CERT"

2. 🔄 Renovar el certificado en Nextcloud (Snap)

Si aún no has renovado tu certificado autofirmado, sigue estos pasos. Si ya lo hiciste, pasa al paso 3.

a) Generar un nuevo certificado autofirmado para el dominio:

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
    -keyout /var/snap/nextcloud/current/certs/custom/key.pem \
    -out /var/snap/nextcloud/current/certs/custom/cert.pem \
    -subj "/CN=gusadrive.dyndns.org"

b) Crear el archivo chain.pem (necesario para Nextcloud Snap):

sudo cp /var/snap/nextcloud/current/certs/custom/cert.pem /var/snap/nextcloud/current/certs/custom/chain.pem

c) Instalar el certificado en Nextcloud Snap:

sudo nextcloud.enable-https custom \
    /var/snap/nextcloud/current/certs/custom/cert.pem \
    /var/snap/nextcloud/current/certs/custom/key.pem \
    /var/snap/nextcloud/current/certs/custom/chain.pem

d) Reiniciar Nextcloud:

sudo snap restart nextcloud

3. 🌐 Configurar Apache para el puerto 4445 (si aplica)

Si tienes un VirtualHost de Apache que expone el panel de ONLYOFFICE en el puerto 4445, actualiza la configuración.

a) Localiza el VirtualHost:

sudo grep -r "4445" /etc/apache2/sites-enabled/

b) Edita el archivo (ej. /etc/apache2/sites-available/onlyoffice.conf) y apunta a los nuevos certificados:

<VirtualHost *:4445>
    ServerName gusadrive.dyndns.org
    SSLEngine on
    SSLCertificateFile "/etc/apache2/ssl/onlyoffice.crt"
    SSLCertificateKeyFile "/etc/apache2/ssl/onlyoffice.key"
    ...
</VirtualHost>

c) Copia los certificados a la ruta especificada:

sudo mkdir -p /etc/apache2/ssl
sudo cp /var/snap/nextcloud/current/certs/custom/cert.pem /etc/apache2/ssl/onlyoffice.crt
sudo cp /var/snap/nextcloud/current/certs/custom/key.pem /etc/apache2/ssl/onlyoffice.key

d) Habilita el sitio y reinicia Apache:

sudo a2ensite onlyoffice.conf
sudo systemctl restart apache2

4. 🐳 Solución de confianza SSL en el contenedor ONLYOFFICE

Tienes dos opciones para que el contenedor confíe en el certificado autofirmado de Nextcloud.

✅ Opción A (Recomendada para producción): Agregar el certificado al almacén de CA del contenedor

1. Copia el certificado al contenedor:

sudo docker cp /var/snap/nextcloud/current/certs/custom/cert.pem <nombre_contenedor>:/usr/local/share/ca-certificates/nextcloud.crt

2. Actualiza el almacén de CA dentro del contenedor:

sudo docker exec <nombre_contenedor> update-ca-certificates

3. Reinicia el contenedor:

sudo docker restart <nombre_contenedor>

4. Verifica que el certificado se haya agregado:

sudo docker exec <nombre_contenedor> ls -la /usr/local/share/ca-certificates/

⚠️ Opción B (Solución temporal / pruebas): Deshabilitar la verificación SSL en ONLYOFFICE

Esta opción es más rápida pero reduce la seguridad (el contenedor no validará certificados en ninguna conexión saliente).

1. Entra al contenedor:

sudo docker exec -it <nombre_contenedor> bash

2. Edita el archivo /etc/onlyoffice/documentserver/local.json y agrega la siguiente sección (si no existe):

{
  "services": {
    "CoAuthoring": {
      "requestDefaults": {
        "rejectUnauthorized": false
      }
    }
  }
}

3. Guarda, sal del contenedor y reinícialo:

sudo docker restart <nombre_contenedor>

5. ⚙️ Configurar la integración en Nextcloud

Ve a Configuración → ONLYOFFICE → Servidor de documentos en Nextcloud y asegura estos valores:

  • URL del servidor de documentos: http://localhost:8085/ (con barra final).
  • Clave secreta (JWT): Debe coincidir con la generada en ONLYOFFICE. Obténla con: sudo docker exec <nombre_contenedor> sudo documentserver-jwt-status.sh
  • Configuración avanzada (JSON):
    • Si usaste la Opción A, no necesitas nada extra.
    • Si usaste la Opción B, agrega: { "rejectUnauthorized": false }

Guarda los cambios.


6. 🔁 Automatizar renovaciones futuras (para certificado autofirmado)

Crea un script que se ejecute mensualmente para regenerar el certificado e instalarlo tanto en Nextcloud como en el contenedor.

Script de ejemplo (/root/renew_selfsigned.sh):

#!/bin/bash
# Regenerar certificado autofirmado
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
    -keyout /var/snap/nextcloud/current/certs/custom/key.pem \
    -out /var/snap/nextcloud/current/certs/custom/cert.pem \
    -subj "/CN=gusadrive.dyndns.org"

cp /var/snap/nextcloud/current/certs/custom/cert.pem /var/snap/nextcloud/current/certs/custom/chain.pem

# Instalar en Nextcloud
nextcloud.enable-https custom \
    /var/snap/nextcloud/current/certs/custom/cert.pem \
    /var/snap/nextcloud/current/certs/custom/key.pem \
    /var/snap/nextcloud/current/certs/custom/chain.pem

snap restart nextcloud

# Copiar al contenedor de ONLYOFFICE
docker cp /var/snap/nextcloud/current/certs/custom/cert.pem <nombre_contenedor>:/usr/local/share/ca-certificates/nextcloud.crt
docker exec <nombre_contenedor> update-ca-certificates
docker restart <nombre_contenedor>

Programa en cron (diario a las 3 AM, primer día de mes):

sudo crontab -e
# Añadir la línea:
0 3 1 * * /root/renew_selfsigned.sh >> /var/log/renew_cert.log 2>&1

7. 🎯 Conclusión y recomendaciones finales

  • El error “Error while downloading the document file” después de renovar un certificado autofirmado en Nextcloud se debe a que el contenedor de ONLYOFFICE no confía en ese certificado.
  • Opción A (recomendada): Agregar el certificado al almacén de CA del contenedor y actualizar las CA. Es segura y permite mantener la verificación SSL activa.
  • Opción B (temporal): Deshabilitar la verificación SSL en ONLYOFFICE editando local.json. Más rápida pero menos segura.
  • Recomendación a largo plazo: Utilizar un certificado de Let’s Encrypt con validación DNS para evitar este problema de raíz y simplificar las renovaciones.

Notas adicionales:

  • La comunicación entre Nextcloud y ONLYOFFICE puede hacerse por HTTP interno (http://localhost:8085) para evitar SSL por completo (válido si ambos servicios corren en el mismo servidor).
  • Asegura que el token JWT coincida exactamente entre ambos lados; un token incorrecto dará error 403.
  • Los logs del contenedor son la mejor herramienta para depurar: sudo docker logs <nombre> --tail 50 -f.

¿Te ha sido útil esta guía? Déjanos un comentario si tienes dudas o comparte tu experiencia. Si necesitas ayuda adicional, no dudes en contactarnos.

Página 1 de 14

Creado con WordPress & Tema de Anders Norén