La consola de la sesión ve y escribe una copia privada de HKEY_CURRENT_USER (la aplicación de escritorio de Claude está empaquetada). En el Windows de Munka la línea de Aplicaciones estuvo bien desde el primer momento. Queda escrito cómo comprobar el registro de verdad: lanzando a través del Explorador. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
764 líneas
60 KiB
Markdown
764 líneas
60 KiB
Markdown
# Organizador Labstream
|
||
|
||
Programa de Windows (Python, sin dependencias) para **inventariar, mapear, ordenar y optimizar** el material
|
||
de los clientes de Labstream repartido por los discos del estudio. Abre su propia ventana, se instala en el
|
||
menú Inicio y todo ocurre en este equipo.
|
||
|
||
```
|
||
organizador.py ← inventario + plan + cola de conversión, y el servidor local con que habla la interfaz
|
||
ventana.py ← la ventana de Windows del programa (marco Win32 + WebView2, solo ctypes)
|
||
instalar.py ← lo instala en su sitio (carpeta de programas del usuario), con accesos en Inicio y Escritorio y su línea en Aplicaciones
|
||
arranque.py ← cómo arranca el paquete: su .exe es el Python firmado, y esto le dice qué hacer
|
||
reglas.py ← cómo reconoce cámaras, carpetas, basura y las plantillas de estructura
|
||
resolve_bridge.py ← convierte BRAW a H.265 10 bits usando DaVinci Resolve Studio
|
||
actualizador.py ← busca versión nueva en Labstream OS (solo si se le pide) y la instala; firma.py la verifica
|
||
static/index.html ← la interfaz (Carpeta · Revisar y ordenar · Mapa · Convertidor · Respaldar · Historial · Ajustes · Manual)
|
||
static/manrope.woff2 ← la tipografía, para no pedirle nada a nadie fuera de este equipo
|
||
WebView2Loader.dll ← la entrada a WebView2 (Microsoft, firmada); lo único que viaja y no es de Python
|
||
datos/ ← inventario.sqlite, config.json, diccionario.json (lo aprendido), bitacora.jsonl
|
||
empaquetar.py ← arma el paquete: dist\OrganizadorLabstream\ con OrganizadorLabstream.exe y los dos zips
|
||
probar.py ← 19 pruebas sin abrir nada · prueba_funcional.py: las 26 funciones · prueba_ventana.py: la ventana de verdad
|
||
Iniciar.bat ← desde el código, con consola (para ver lo que imprime)
|
||
```
|
||
|
||
Nunca borra nada. Todo lo que sobra va a `_Para borrar` dentro de la misma raíz y cada movimiento queda en la
|
||
bitácora para poder deshacerlo.
|
||
|
||
---
|
||
|
||
## 1. Diagnóstico (9 sep 2026)
|
||
|
||
| Raíz | Archivos | Peso | BRAW | Stock Envato | Proxies | Basura | Duplicados |
|
||
|---|---|---|---|---|---|---|---|
|
||
| `Z:\Dermatologas\David Reyes` | 4 667 | 1,36 TB | 723 GB (53 %) | 464 GB | 4,5 GB | 301 archivos | 91 GB |
|
||
| `W:\Danney` | 24 967 | 3,14 TB | 1,18 TB (40 %) | — | — | 12 000 autoguardados de AE | — |
|
||
| `N:\` (Camilo Ortega) | 24 016 | 3,10 TB | — | — | 150 GB | 1 031 archivos | — |
|
||
|
||
Lo que se repite en todas:
|
||
|
||
- **El mismo cliente vive en hasta 12 sitios.** Camilo Ortega aparece en N:, K:, L:, M:, Q: y Z:. David Reyes
|
||
en Z:, K:, Q: y V:. Danney en W:, K: y Q:. Cada sitio con un nombre distinto (`David Reyes`, `DR. DAVID REYES`).
|
||
- **Dos sistemas de orden a la vez.** Danney tiene `2026/MM- Mes/NN- Pieza` y, al lado, `Nuevo Orden/` por
|
||
cámara y año con 1,8 TB. El mismo tipo de material está en los dos.
|
||
- **Los meses no se llaman igual:** `08-Agosto`, `09- Septiembre`, `10- octubre`, `02-marzo` (que es marzo
|
||
pero numerado 02), `04 -Mayo`, `05- MAYO`.
|
||
- **Material suelto en la raíz:** PSD de 2 GB, archivos «Recuperado», capturas de pantalla, un MP4 final.
|
||
- **Intermedios enormes que ya no hacen falta:** ProRes HQ vertical de 8 GB, prerenders QuickTime Animation
|
||
de 10 GB, proxies de Resolve/Premiere al lado del original.
|
||
- **Stock de Envato copiado dentro de cada pieza** (`Visual/Elements`): 464 GB en David Reyes, con
|
||
91 GB duplicados exactos.
|
||
- **Basura de sistema por todas partes:** `.DS_Store`, `Thumbs.db`, `.tmp` de Photoshop (uno de 1,2 GB),
|
||
`~lock~`, carpetas de autoguardado de After Effects.
|
||
|
||
## 2. Cómo organizarlo
|
||
|
||
### Cuatro tipos de cliente, cuatro plantillas
|
||
|
||
| Tipo | Quiénes | Estructura |
|
||
|---|---|---|
|
||
| **contenido** (mensual) | dermatólogas, marca personal | `AAAA / MM- Mes / NN- Pieza` + `00_Grabacion` por mes |
|
||
| **pauta** (anuncios) | Camilo Ortega, Jonathan, Malpraxis | `Campañas / AAAA_Campaña` + `Material / Grabaciones, Celular, IA` |
|
||
| **proyecto** (puntual) | Brigard, PepsiCo, Kingspan, Filarmónica… | `00_Brief 01_Material 02_Grabacion 03_Proyecto 04_Exportados` |
|
||
| **interno** | recursos de Labstream | `Musica Sonidos Stock LUTs Transiciones` compartidos |
|
||
|
||
### La carpeta canónica de un cliente de contenido
|
||
|
||
```
|
||
David Reyes/
|
||
├── 00_Marca/ logos, manual, fuentes, fondos, transiciones, intros
|
||
├── 01_Proyectos/ .drp .prproj .aep .psd de trabajo (Diseño/, Edicion/)
|
||
├── 2026/
|
||
│ ├── 03- Marzo/
|
||
│ │ ├── 00_Grabacion/ originales de cámara del mes, separados por fuente
|
||
│ │ │ ├── URSA_BRAW/ ├── SONY/ ├── OSMO/ ├── CELULAR/ └── AUDIO/
|
||
│ │ ├── 01- La isotretinoina/ ← una pieza: Guion, Visual, Audio, Portada, Export
|
||
│ │ ├── 02- El poder del ácido hialurónico/
|
||
│ │ ├── _Exportados/ masters del mes
|
||
│ │ └── _Portadas/
|
||
│ └── 08- Agosto/
|
||
├── Campañas/2026_Garnier/ trabajos de marca (Dove, Loreal, Isdin…)
|
||
├── _Apoyos/ tomas de apoyo reutilizables por tema
|
||
├── _Recursos/Musica Stock (mejor aún: en la biblioteca compartida del estudio)
|
||
├── _Documentos/ propuestas, referentes, brief
|
||
├── _Revisar/ lo que la app no supo ubicar
|
||
└── _Para borrar/ basura, proxies y originales ya convertidos (la app no borra; lo revisa y lo borra una persona)
|
||
```
|
||
|
||
Reglas que hacen que funcione:
|
||
|
||
1. **Un cliente, una carpeta, un disco.** Las únicas otras dos casas legítimas son `Entregas_LAB` (K:) y
|
||
`Exportados` (Q:), que ya gestiona Labstream OS.
|
||
2. **Los archivos no se renombran nunca; solo se mueven carpetas.** Resolve y Premiere re-enlazan por nombre.
|
||
3. **Dentro de una pieza no se toca.** El orden es de la raíz hasta el nivel de pieza.
|
||
4. **El mes es el de publicación, no el de rodaje.** Una `Grabación` de diciembre que alimenta piezas de marzo
|
||
vive en `03- Marzo/00_Grabacion`. Cuando no hay mes, la app usa la fecha del nombre del archivo
|
||
(Sony, DJI, Higgsfield, Envato y el MMDD de los clips Blackmagic) y solo al final la de modificación.
|
||
5. **Stock y música van a la biblioteca compartida**, no dentro de cada pieza.
|
||
6. **Los proxies se regeneran**: a `_Para borrar/proxies`. La basura de sistema, a `_Para borrar/basura`.
|
||
7. **Política de frío.** El BRAW de piezas ya publicadas y con más de 3 meses se convierte a H.265 10 bits;
|
||
el original va a `_Para borrar/originales`; una persona lo borra cuando comprueba que nadie lo echó de menos.
|
||
|
||
## 3. Cómo la app aprende
|
||
|
||
- **Diccionario.** La pestaña lista cada nombre de carpeta que aparece en la raíz («Grabado», «Render»,
|
||
«Julio music», «Nuevo Orden»…) con su peso. Le dices qué es (grabación, exportados, portadas, marca…) y
|
||
desde entonces esa palabra se reconoce en cualquier disco. Viene sembrado con ~200 palabras vistas en las
|
||
carpetas actuales, incluidos los errores de tecleo (`Elemnts`, `Visula`, `Calular pero de`).
|
||
- **Reglas exactas.** Si en el plan corriges el destino de una carpeta, se guarda como regla para ese cliente.
|
||
- **Alias de clientes.** `DR. DAVID REYES` = `David Reyes` = `Davids`. Con ellos la pestaña Mapa cruza todos
|
||
los discos y dice dónde vive cada cliente.
|
||
- Todo está en `datos/diccionario.json` y `datos/config.json`: texto plano, se puede editar a mano o versionar.
|
||
|
||
## 4. Optimizar material viejo (MP4 H.265 10 bits)
|
||
|
||
| Origen | Motor | Resultado medido |
|
||
|---|---|---|
|
||
| Sony XAVC-I 4K 60p 4:2:2 10 bits, 228 Mb/s | ffmpeg + NVENC (RTX 5080) | 671 MB → 24,6 MB (8,4 Mb/s) en 30 s, HEVC Main10 |
|
||
| Sony XAVC-I 4K 30p, 286 Mb/s | ffmpeg + NVENC | 286 → 9,6 Mb/s, 1,5× tiempo real |
|
||
| BRAW URSA 4.6K 30p, 567 Mb/s | DaVinci Resolve Studio (H.265 NVIDIA, Main10) | ≈ 31 Mb/s → unas 18 veces menos |
|
||
|
||
- **Perfiles:** ahorro / equilibrado / máxima. El bitrate objetivo sale del tamaño del cuadro y los fps
|
||
(≈ 0,085 bits por píxel y cuadro en «equilibrado»: 4K30 → 21 Mb/s, 4.6K30 → 31 Mb/s).
|
||
- **Croma:** 4:2:0 10 bits (Main10, se reproduce en todo) o 4:2:2 10 bits (Rext; la RTX 5080 lo codifica y
|
||
Resolve lo lee, pero muchos reproductores no).
|
||
- **BRAW:** pasa por Resolve porque ffmpeg no lo decodifica. El puente abre (o crea) el proyecto
|
||
«Labstream Archivo» con gestión de color a Rec.709 Gamma 2.4, importa los clips, monta una línea de
|
||
tiempo por resolución y renderiza «clips individuales». Si Resolve no deja cambiar de proyecto, trabaja en
|
||
un bin dentro del proyecto abierto y aplica la LUT Gen 5 Film → Video a cada clip. **Resolve debe estar
|
||
abierto con un proyecto, no en el Gestor de proyectos, y sin diálogos abiertos.**
|
||
- **Flujo:** Analizar (ffprobe) → Ver candidatos → Encolar → Verificar (duración, códec, 10 bits) →
|
||
Reemplazar (el original y su `.XML` de Sony van a `_Para borrar/originales`). La salida conserva la fecha
|
||
de modificación del original y se llama `nombre_10bit.mp4` junto al original.
|
||
- Se excluyen solos: lo que ya está en HEVC/AV1 eficiente (los iPhone en HDR, por ejemplo), lo que tiene
|
||
canal alfa, los exportados/masters (salvo que se marque «incluir exportados») y lo más reciente que N meses.
|
||
|
||
Estimación con los inventarios actuales: los 1,9 TB de BRAW de Danney y David Reyes quedarían en unos
|
||
110 GB; los intermedios ProRes/XAVC de más de 1 GB (≈ 1 TB entre los dos) en menos de 100 GB.
|
||
|
||
### Stock de Envato en proyectos viejos
|
||
|
||
Las tomas de Envato se vuelven a descargar con la suscripción: en piezas ya publicadas sobran. En la
|
||
pestaña Optimizar, «Buscar stock viejo» lista, agrupado por carpeta, todo lo que la app reconoce como
|
||
Envato (nombre `…-2026-01-22-22-34-00-utc` o carpeta `Elements`) en piezas de más de N meses. Se elige
|
||
video, música o imágenes. Va a `_Para borrar/stock` (reversible desde Bitácora); la app no lo borra nunca, eso lo hace una persona desde el Explorador. En David Reyes son 464 GB.
|
||
|
||
### Respaldo compacto (pestaña Respaldo)
|
||
|
||
Copia a otro disco una versión ligera de cada cliente para tenerla a mano:
|
||
|
||
- misma estructura de carpetas (`AAAA / MM- Mes / NN- Pieza`), y donde una carpeta mezcla tipos de medio se
|
||
separa en `Video`, `Audio`, `Imagenes`, `Diseño`, `Proyectos`, `Documentos`, `Fuentes`;
|
||
- los clips de cámara van en su versión **MP4 H.265 10 bits** (verificada) en lugar del original;
|
||
el BRAW/RAW que aún no se convirtió no se copia, y la pestaña lo lista para que se convierta antes;
|
||
- sin stock de Envato, sin proxies, sin basura, sin `_Para borrar`;
|
||
- deja `INDICE.csv` (ruta en el respaldo, ruta original, tipo, bytes, fecha), `_MAPA.md` (resumen por
|
||
carpeta y tipo) y `manifest.json` en la raíz del respaldo;
|
||
- es incremental: lo que ya está igual (tamaño y fecha) se salta, así se puede detener y retomar.
|
||
|
||
Orden recomendado por cliente: Ordenar → Optimizar (convertir BRAW e intermedios, verificar, reemplazar)
|
||
→ Buscar stock viejo → Respaldo → cuando el respaldo esté comprobado, una persona borra `_Para borrar` a mano.
|
||
|
||
## 5. Los discos
|
||
|
||
15 recursos compartidos en tres cajas (NAS Labstream 192.168.0.22, LabTem 192.168.0.40 y el Blackmagic
|
||
Cloud Store Mini 192.168.0.3). La pestaña Mapa los lista con su uso y marca en azul las carpetas que
|
||
reconoce como clientes. Propuesta de niveles:
|
||
|
||
| Nivel | Dónde | Qué |
|
||
|---|---|---|
|
||
| caliente | Cloud Store Mini (10G) | el mes en edición |
|
||
| trabajo | NAS Labstream (`labstream`, `Camilo Ortega`, `Medicina1`…) | el año en curso, una carpeta por cliente |
|
||
| entregas | `Entregas_LAB` y `Exportados` | lo maneja Labstream OS |
|
||
| frío | `temple`, `Datos`, `Nubes` | años anteriores ya optimizados a H.265 10 bits |
|
||
| recursos | `Recursos Audiovisuales`, `Sonidos` | música, stock, LUTs, transiciones compartidos |
|
||
|
||
Consolidar un cliente entre discos es una copia grande; conviene hacerla en el propio NAS
|
||
(`rsync` por SSH) y no desde el PC. La app ordena **dentro** de cada raíz; el cruce entre discos lo
|
||
muestra en el mapa para decidirlo.
|
||
|
||
## 6. Uso (interfaz 1.6)
|
||
|
||
1. Se abre desde el menú Inicio o el Escritorio (o con doble clic en `OrganizadorLabstream.exe`, en la carpeta
|
||
del programa). El paquete trae Python y ffmpeg dentro; para BRAW hace falta DaVinci Resolve Studio abierto
|
||
con scripting externo en *Local*. Desde el código: `py -3.12 organizador.py`, con Python 3.10+ y
|
||
ffmpeg/ffprobe en el PATH.
|
||
2. Suelta la carpeta del cliente en la barra lateral (o pega la ruta). Se registra y se escanea sola.
|
||
3. La vista **Carpeta** es el recorrido: cinco pasos con estado (hecho, en curso, listo, pendiente, bloqueado)
|
||
y un bloque «Siguiente» que dice qué toca y ofrece un solo botón principal. El **Asistente paso a paso**
|
||
sigue disponible desde ahí.
|
||
- **1 Escanear**: solo lee nombres y tamaños.
|
||
- **2 Revisar**: diagnóstico y carpetas que la app no reconoce (se nombran en un panel, al lado del plan).
|
||
- **3 Ordenar**: «Calcular» enseña qué va a pasar, agrupado por tipo (basura, grabación, piezas…), con
|
||
seguridad *seguro / revisar / dudoso*. «Aplicar» mueve dentro de la misma carpeta. Se deshace desde Historial.
|
||
- **4 Convertir a 10 bits**: tres bloques en orden: elegir clips, conversión en curso, verificar y reemplazar.
|
||
Abajo, el stock de Envato viejo.
|
||
- **5 Respaldar**: destino → Calcular → Copiar. Avisa si hay BRAW sin convertir.
|
||
4. **Historial**: cada cambio en palabras («Ordenó carpetas», «Apartó stock viejo») con su Deshacer, y lo que
|
||
hay en `_Para borrar`.
|
||
5. **Ajustes** (engranaje): carpetas registradas, clientes con alias, plantillas.
|
||
|
||
Las tareas largas (escaneo, lectura de clips, conversión, asistente, copia) se ven en la **barra inferior** desde
|
||
cualquier vista, con progreso y Detener; al terminar aparece un aviso. Un botón deshabilitado siempre dice al
|
||
lado por qué. Los errores del programa se muestran como aviso, no rompen la pantalla.
|
||
|
||
Cambios de seguridad de 1.5.0: el servidor local rechaza peticiones que no vengan de la propia página
|
||
(cabeceras Host/Origin y Content-Type), `/api/config` solo acepta ajustes de conversión y respaldo, ningún
|
||
destino puede salir de la carpeta del cliente, la carpeta `_Para borrar` ya no se vuelve a planificar como
|
||
basura, y no se encola una conversión cuya salida ya exista o esté reclamada por otro clip (MP4 y MOV del
|
||
mismo nombre). El plan se invalida al re-escanear.
|
||
|
||
Movimientos (1.5.0): si en el destino ya existe un archivo con el mismo nombre, **no se renombra con «(2)»**:
|
||
se deja donde está y sale en los errores del lote (Resolve y Premiere enlazan por nombre, y el XML de Sony
|
||
va emparejado con su clip). Solo dentro de `_Para borrar` y `Duplicados` se numera. Si un archivo está
|
||
bloqueado (abierto en un editor) o la copia entre discos queda incompleta, el original no se toca. El sidecar
|
||
Sony `C0001M01.XML` se reconoce como cámara.
|
||
|
||
Actualización automática (1.5.0): sigue funcionando igual para el usuario (aviso en la vista Carpeta →
|
||
«Actualizar ahora»), pero antes de instalar se exige que el manifiesto traiga versión con forma `1.2.3`,
|
||
nombre de zip simple, sha256 obligatorio y descarga en el mismo servidor https que el manifiesto. No se
|
||
actualiza con un escaneo, lectura, conversión, asistente o copia en marcha. El `.bat` espera a que se cierren
|
||
todas las ventanas de OrganiLAB, guarda copia de la versión actual en `actualizacion\previa`, instala y, si
|
||
la copia falla, restaura la anterior. `datos\` y `ffmpeg\` nunca se tocan.
|
||
|
||
1.5.1: los hilos de lectura de clips y de la cola de conversión ya no dejan la app «ocupada» si fallan; cada
|
||
«Reemplazar» es un lote propio (`optimizar-fecha`) que se deshace solo, y antes de mover el original comprueba
|
||
que el MP4 verificado siga ahí; «Deshacer» dice qué archivos no pudo devolver y por qué; una carpeta llamada
|
||
solo «3» bajo un año se propone como marzo con confianza media, no alta; el puente con Resolve, cuando no puede
|
||
abrir «Labstream Archivo» y usa el proyecto del editor, no toca sus ajustes ni su cola de render ni lo guarda,
|
||
y nunca pisa un MP4 que ya exista; las raíces de unidad (`N:\`) ya se consultan bien (mapa y respaldo).
|
||
|
||
### Publicar una versión
|
||
|
||
py -3.12 probar.py && py -3.12 prueba_funcional.py && py -3.12 prueba_ventana.py
|
||
py -3.12 empaquetar.py # construye dist\, los dos zips y manifiesto.json (NOTAS="..." para las notas)
|
||
py -3.12 prueba_ventana.py --paquete dist\OrganizadorLabstream # el paquete, arrancado por su .exe
|
||
bash publicar.sh # sube los zips al NAS, deja el manifiesto en GitHub y despliega el OS
|
||
|
||
`empaquetar.py` no deja salir un paquete con un binario sin firmar ni uno cuyo motor no arranque. Con
|
||
`SOLO_LOCAL=si` construye sin tocar el manifiesto del OS (para ensayar).
|
||
|
||
Cuando el OS sirve el manifiesto nuevo, cada copia instalada lo ve al abrirse (o al pulsar «Actualizar ahora»),
|
||
descarga el zip «app» (15 MB), comprueba el sha256 y se sustituye sola sin tocar `datos\` ni `ffmpeg\`.
|
||
|
||
1.5.2: «Juntar repetidos» comprueba el contenido (primer MB, centro y último) antes de apartar una copia
|
||
«idéntica»; si difiere, la deja y lo dice. El plan avisa cuando el destino ya tiene un archivo con ese nombre
|
||
(baja a «dudoso» y no se marca). El actualizador reintenta solo durante unos minutos si el OS responde 502/503
|
||
(pasa mientras se redespliega) en vez de fallar a la primera.
|
||
|
||
1.5.3: el recorrido de cinco pasos va fijo arriba en todas las vistas (con el paso de la vista actual
|
||
resaltado, «Volver a escanear» y el asistente siempre a mano; el paso 1 también re-escanea al hacer clic);
|
||
la página aprovecha pantallas anchas (hasta 1720 px); `_Para borrar`, `_Papelera` y `Duplicados` se muestran
|
||
como «apartado por la app», no como carpetas sin reconocer.
|
||
|
||
1.5.4: «Convertir a 10 bits» queda en tres pasos limpios: Buscar clips (lee y lista en un solo botón; los
|
||
criterios y la calidad están plegados en «Cambiar criterios»), Convertir (lista compacta con estado, sin
|
||
tabla de diez columnas) y Reemplazar. Cada clip se verifica solo al terminar, así que el paso «Verificar»
|
||
desaparece. El stock de Envato pasa a «Revisar y ordenar». Ajustes es una sola lista por cliente: tipo,
|
||
sus carpetas y otros nombres con que aparece; las plantillas quedan en «Avanzado». Confirmado que ffprobe
|
||
sí lee los BRAW (resolución, fps, duración), así que la vía Resolve es alcanzable desde la interfaz.
|
||
|
||
1.5.5: botón «Buscar actualizaciones» en la barra lateral (junto a la versión y la hora de la última
|
||
comprobación). Por comando, en PowerShell hay que dar la ruta completa del .exe con `&` (no está en el PATH):
|
||
|
||
& "C:\Users\Munka\Downloads\OrganizadorLabstream-portatil-1.4.1\OrganizadorLabstream\OrganizadorLabstream.exe" actualizar --si
|
||
|
||
(`--si` instala sin preguntar; el nombre de la carpeta portátil no cambia al actualizar, solo su contenido).
|
||
|
||
1.6.0, rediseño: el recorrido de cinco pasos vive en la barra lateral, colgando de la carpeta seleccionada
|
||
(punto de estado, dato corto, clic para ir al paso; el paso 1 re-escanea). Cada vista cabe en una pantalla:
|
||
«Revisar y ordenar» tiene pestañas internas (Qué hay · Qué va a pasar · Por nombrar con su número · Stock
|
||
viejo); «Convertir» es un solo panel con tres botones (Buscar clips, Convertir N, Reemplazar N) y una lista
|
||
única con el estado de cada clip; «Historial» es una línea de tiempo por día con lo apartado en _Para borrar
|
||
resumido arriba; «Ajustes» son tarjetas de cliente plegadas que se abren para editar. La ayuda queda en una
|
||
línea y un «?» despliega el resto. Texto 13,5 px, un solo botón lleno por pantalla, y la carpeta que está
|
||
trabajando parpadea en la barra lateral.
|
||
|
||
1.6.1: se puede desconectar una carpeta escaneada. Aparece una ✕ al pasar el ratón por la carpeta en la
|
||
barra lateral y un enlace «Desconectar» en la cabecera de «Carpeta». Solo la quita de la lista: no borra ni
|
||
mueve nada del disco. Una casilla opcional olvida también el inventario escaneado (si no se marca, al volver
|
||
a soltar la carpeta el escaneo anterior sigue ahí). No deja desconectar mientras esa carpeta se escanea,
|
||
se analiza, se le aplica el plan o tiene conversiones pendientes. Endpoint `POST /api/raiz/quitar
|
||
{raiz, datos}`; queda anotado en la bitácora como `raiz_quitada`.
|
||
|
||
1.6.2: el manifiesto de actualización va firmado. `firma.py` (RSA-2048 sin dependencias) firma
|
||
versión+archivo+sha256+tamaño al empaquetar con la clave privada de `%USERPROFILE%\.labstream\organizador-firma.json`
|
||
(haz copia de seguridad: sin ella no se pueden publicar versiones nuevas); la pública está incrustada en
|
||
`actualizador.py` y el .exe no instala nada que no cuadre con ella, aunque alguien cambiara el archivo en el
|
||
servidor. Los .exe anteriores (≤ 1.6.1) ignoran la firma y siguen actualizándose. La barra de tareas muestra el
|
||
tiempo restante estimado (≈ 4 min) a partir del avance. Corregido: tras aplicar el plan, «Moviendo» se quedaba
|
||
en la barra de tareas para siempre y bloqueaba desconectar la carpeta. Pruebas automáticas en `probar.py`
|
||
(reglas, firma, y un recorrido completo escanear → plan → aplicar → deshacer → desconectar sobre una copia
|
||
temporal): `py -3.12 probar.py`. Rendimiento medido sobre el inventario real (54 mil archivos): las consultas
|
||
con LIKE tardan menos de 10 ms; no hacía falta optimizar.
|
||
|
||
1.6.3: botón «Elegir carpeta…» (barra lateral, pantalla vacía y diálogo de añadir) que abre el selector de
|
||
carpetas de Windows, sin depender de soltar la carpeta ni de pegar la ruta. `POST /api/elegir-carpeta` lanza el
|
||
diálogo en un PowerShell aparte para no bloquear el servidor y devuelve la ruta (o nulo si se cancela).
|
||
|
||
1.7.0, recorrido paso a paso y convertidor:
|
||
- Arrastrar una carpeta a la ventana ya trae su ruta real: el puente WebView2 (`v.dom.document.events.drop`)
|
||
guarda lo soltado y la interfaz lo pide en `/api/soltado`; la búsqueda por nombre queda solo de reserva
|
||
(navegador externo).
|
||
- «Qué va a pasar» son ahora tres pasos en frases, cada uno con su botón Aplicar: 1 apartar basura y proxies,
|
||
2 ordenar por año y mes, 3 ordenar lo demás. Cada fila dice «X pasa a Y» y por qué en lenguaje llano; lo
|
||
dudoso queda sin marcar. Al aplicar un paso el plan se recalcula solo. Cada fila del plan trae `paso`.
|
||
- «Por nombrar» propone qué es cada carpeta mirando su contenido (clips de cámara, proyectos, música, fotos,
|
||
documentos, videos) y el parecido del nombre con el diccionario; botón «Sí, es …» por carpeta y «Aceptar las
|
||
sugerencias seguras» para todas las de confianza alta (≥ 90 % de un mismo tipo y ≥ 3 archivos).
|
||
- «Stock viejo» agrupa por antigüedad (más de 12, 6-12, 3-6, 1-3, menos de 1 mes) con casilla por tramo y
|
||
atajos 1/2/3/6/12 meses.
|
||
- «Deshacer» sale de la interfaz (confundía). Sigue existiendo por API/CLI para emergencias.
|
||
- «Desconectar» pasa a llamarse «Quitar de la lista» con explicación clara.
|
||
- «Convertidor» (antes «Convertir a 10 bits»): formatos MP4 H.265 10 bits, H.265 ligero, H.264, ProRes Proxy /
|
||
LT / HQ (`FORMATOS`), detección real de GPU NVIDIA (NVENC) y CPU en `/api/optimizar/motores` (se prueba
|
||
codificando 3 cuadros), cola tipo Media Encoder («Convirtiendo 2 de 3 · 47 %») y el mismo clip se puede
|
||
convertir a varios formatos. ProRes nunca reemplaza el original (es de edición). Columna `formato` en
|
||
`trabajos`.
|
||
- Respaldar por lotes: «solo lo de más de 3 / 6 / 12 meses» (`meses` en `/api/respaldo/plan`).
|
||
- Barra de tareas revisada: la conversión en curso llegaba como un id y la interfaz esperaba un objeto (salía
|
||
0 % sin nombre); ahora `estado.cola` trae `actual` (ruta, pct, raíz), `hechos` y `total`.
|
||
|
||
1.8.0, auditoría y red de seguridad. Tras revisar el código con cuatro pasadas y medir sobre el material real
|
||
(7,73 TB, 53.964 archivos):
|
||
- **Deshacer vuelve a la interfaz.** Al rediseñar el Historial en la 1.6.0 se quitaron los botones pero la app
|
||
seguía prometiendo en cuatro pantallas que «se deshace desde Historial». Ahora está en el Historial, en
|
||
«Últimos cambios» y en el aviso que sale al aplicar («Deshacer esto»).
|
||
- **«Elements» ya no convierte en stock lo que tenga dentro.** La marca solo la hereda una carpeta con nombre
|
||
completo de paquete de Envato; lo descargado se reconoce por el nombre del archivo. Medido: marcaba 1.713
|
||
archivos y 50,7 GB de material propio como desechable, que el respaldo excluye por defecto.
|
||
- **El plan contrasta el mes de la carpeta con la fecha de los archivos** (`_discrepa_mes`, `Plan.mes_real`).
|
||
Si no cuadran, baja a «probable», no se marca y sale un aviso arriba con los dos meses. 5 de las 10 carpetas
|
||
de mes con material fechable no contenían el mes que decían: son 727 GB. Los nombres Blackmagic no traen
|
||
año, así que en esos solo se compara el mes.
|
||
- **Un archivo bloqueado ya no corta el resto de su grupo** en `aplicar()`: cada archivo va por su cuenta y el
|
||
resumen dice cuántos fallaron de verdad (antes uno abierto en Resolve dejaba sin mover los 117 restantes).
|
||
- **Un escaneo interrumpido no reemplaza el inventario:** si hubo fallos de lectura y el recuento cae más de
|
||
un 10 % frente al anterior, se conserva el que había y se explica por qué.
|
||
- **Las uniones de carpeta de Windows no se recorren** (`_es_enlace`, `_id_carpeta`). Una circular dejaba el
|
||
escaneo dando vueltas sin fin: comprobado, un árbol de un archivo no terminaba en dos minutos.
|
||
- **Abrir una carpeta pasó de 8,83 s a 0,21 s:** `_resumen_carpetas` calcula de una sola pasada lo que antes
|
||
era una consulta por carpeta que recorría la tabla entera.
|
||
- **La papelera se llama igual en el disco que en pantalla.** Las plantillas guardadas con el nombre viejo
|
||
(`_Papelera`) se migran a `_Para borrar` al arrancar.
|
||
- Falsos positivos quitados: `.dat`, `.idx` y `.bak` ya no son basura de sistema, y una carpeta llamada
|
||
`Cache` a secas ya no son proxies. Las abreviaturas de mes («Mar», «May») bajan a confianza media.
|
||
- Convertidor: un clip ya convertido a un formato puede convertirse a otro (el filtro «en cola» miraba todos
|
||
los trabajos); los originales ya apartados no vuelven a salir como candidatos; en modo espejo cada formato
|
||
tiene su propio archivo; el temporal se borra si falla; y la cola no puede arrancar dos veces.
|
||
- Interfaz: los botones ya no vuelven a su etiqueta vieja pisando lo que la acción acaba de calcular, y las
|
||
rutas de Windows se recortan bien (soltar un archivo registraba el archivo como carpeta de cliente).
|
||
|
||
1.8.1, fase 2 de la auditoría:
|
||
- **Dos movimientos que acabarían en el mismo archivo se detectan antes de aplicar** (`Plan.marcar_colisiones`).
|
||
Caso real: dos carpetas de grabación genéricas del mismo mes van las dos a `00_Grabacion/SONY` y las dos
|
||
traen un `C0001.MP4`. Ahora salen sin marcar, en rojo, con un aviso que nombra las dos carpetas y el archivo
|
||
que choca. También se comprueba si el destino ya tiene un archivo con ese nombre en el disco (antes solo se
|
||
miraba en las filas de carpeta, no en los grupos de archivos); se revisan los 40 primeros de cada grupo para
|
||
no llenar la red de consultas.
|
||
- **Aplicar por pasos ya no degrada el inventario.** `actualizar_inventario` reescribe las filas de `carpetas`
|
||
con su ruta nueva en vez de borrarlas, y conserva la marca de basura/proxy heredada. Antes, como la interfaz
|
||
recalcula el plan sin volver a escanear, los pasos siguientes salían con «0 archivos · 0 B» y sin fecha.
|
||
Comprobado: tras aplicar el paso de fechas, la fila del paso 3 conserva sus 3 archivos y su peso.
|
||
|
||
1.9.0, convertidor y respaldo:
|
||
- **El análisis de clips va en paralelo** (`HILOS_ANALISIS = 8`), se puede detener y dice cuántos no se
|
||
pudieron leer. Cada lectura con ffprobe es sobre todo espera de red: 0,23 s por clip medidos en el NAS, así
|
||
que los 15.423 clips pendientes pasaban de la hora solo para poder empezar a convertir.
|
||
- **Los formatos ahora pesan de verdad distinto.** «Ligero para compartir» usaba el mismo perfil de calidad
|
||
que el de archivo y solo bajaba un techo de tasa que casi nunca se toca. Medido sobre el mismo clip:
|
||
archivo 14,3 MB, ligero 8,2 MB, H.264 18,3 MB.
|
||
- **ProRes ya no lleva cuantizador fijo:** con `-qscale` se saltaba la tasa del perfil y un «máster HQ» no
|
||
salía a tasa de HQ, que es justo lo que promete.
|
||
- **El croma 4:2:2 se prueba de verdad** al arrancar (`motores()["chroma422"]`). NVENC no lo admite antes de
|
||
Blackwell; si la tarjeta no puede, el trabajo va por CPU en vez de fallar, y la interfaz lo dice.
|
||
- **El audio multipista ya no rompe la conversión:** `-c:a copy` solo cuando hay una sola pista AAC. Con dos
|
||
pistas (cámaras de audio multipista) ffmpeg abortaba. Se guarda `pistas_audio` al analizar.
|
||
- **Raíces anidadas rechazadas:** registrar `N:\` y `N:\Camilo` dejaba a la interna sin inventario y su
|
||
respaldo copiaba cero archivos diciendo que había ido bien.
|
||
- **Respaldo incremental corregido:** compara con el archivo de origen tal como está ahora, no con lo que
|
||
decía el último escaneo. Antes, algo editado después de escanear no se volvía a copiar nunca.
|
||
- **El índice del respaldo se acumula** en vez de reescribirse con la última tanda, que es lo que hacía
|
||
inservible el respaldo por lotes.
|
||
- Interfaz: marcar una casilla del plan actualiza solo las cifras (antes repintaba la lista entera y se
|
||
perdía el foco); el buscador de Ajustes ya no borra lo que estabas editando; la lista de stock no salta al
|
||
principio en cada clic.
|
||
|
||
2.0.0, una sola lista por carpeta. La pantalla «Carpeta» deja de ser un resumen y pasa a ser la lista de
|
||
todo lo que se puede hacer ahora mismo, en orden, cada cosa con su cifra real y su botón: apartar basura y
|
||
proxies, decir qué son las carpetas que no reconoce, ordenar por fecha, ordenar lo demás, apartar stock
|
||
viejo, juntar repetidos, aligerar los clips y respaldar. Lo que ya está hecho aparece tachado con un visto.
|
||
Era la simplificación de fondo que salió de la auditoría: antes había que bajar tres niveles de navegación
|
||
(pestaña, sub-pestaña, paso) para saber qué faltaba en una carpeta.
|
||
|
||
Endpoint nuevo `GET /api/carpeta/acciones` (`acciones()`): todas las cifras salen de consultas baratas sobre
|
||
el inventario, así que tarda entre 0,04 y 0,23 s en las carpetas reales; el plan de orden solo se consulta si
|
||
ya estaba calculado, y si no el botón dice «Calcular». De paso se conecta a la interfaz la detección de
|
||
material repetido, que funcionaba por dentro pero no tenía dónde pulsarse, y `_gb` pasa a dar terabytes.
|
||
|
||
2.1.0, el asistente se fusiona con la lista. Había dos formas de hacer lo mismo: la lista de acciones y un
|
||
«Asistente paso a paso» que recorría lo mismo preguntando. Ahora hay una sola: encima de la lista sale
|
||
**«Hacer las N de una vez»**, que ejecuta seguidas las acciones que no necesitan que elijas nada (apartar
|
||
basura y proxies, ordenar por fecha, ordenar lo demás, apartar stock viejo, juntar repetidos) usando el mismo
|
||
motor que tenía el asistente. Se quedan fuera convertir y respaldar, que tienen su propio botón porque hay
|
||
que elegir. Lo dudoso nunca entra: se queda como está para que alguien lo mire.
|
||
|
||
Probado de punta a punta sobre un árbol de ensayo: 19 archivos antes y después, ninguno perdido, y en un solo
|
||
clic el material de cámara quedó repartido por mes y fuente, las piezas en su mes, la música en `_Recursos` y
|
||
la basura, los proxies y el stock viejo en `_Para borrar`. Endpoint `POST /api/acciones/hacer`; la lista de
|
||
acciones trae `automatico` (las que se pueden hacer solas) y el progreso del motor. De paso, las acciones de
|
||
ordenar dejan de contar como pendientes mientras no haya un plan calculado: después de ordenarlo todo la
|
||
lista seguía diciendo que faltaban dos cosas que en realidad ya no tenían nada.
|
||
|
||
2.2.0, la fecha de verdad manda y ya no hay que decidir nada a mano:
|
||
- **La fecha sale de lo más antiguo que sabe el disco** (`R.fecha_real`): al copiar en Windows la fecha de
|
||
creación pasa a ser la de la copia y la de modificación se conserva; al renderizar, las dos son nuevas.
|
||
Quedarse con la más antigua de las dos da siempre la mejor estimación de cuándo se grabó.
|
||
- **Un render hereda la fecha del original** (`R.base_derivado`, `_heredar_fechas`). «C0001_10bit.mp4» se
|
||
archiva en el mes en que se grabó «C0001.MP4», no en el mes en que se convirtió. Reconoce los sufijos
|
||
habituales (`_10bit`, `_ligero`, `_h264`, `_proxy`, `_LT`, `_HQ`, `_render`, `_export`, `_master`, `_final`)
|
||
y busca el original en la misma carpeta o, si el nombre es bastante propio y único, en toda la carpeta del
|
||
cliente. Si hay dos candidatos con el mismo nombre no hereda nada. Las conversiones que hace la propia app
|
||
ya conservaban la fecha del original, tanto por ffmpeg como por Resolve.
|
||
- **Cuando la carpeta y los archivos no coinciden, manda el archivo.** El nombre del clip lo pone la cámara y
|
||
la fecha la pone el disco; el nombre de la carpeta lo escribió una persona con prisa. Así el material se
|
||
archiva en el mes en que se grabó sin preguntarle nada a nadie, y el aviso ya no pide una decisión: dice lo
|
||
que la app hizo y por qué. En el material real, los 727 GB de las dos carpetas que mentían se resuelven
|
||
solos: lo de «02-marzo» va a diciembre de 2025 y lo de «08-Agosto» a abril de 2026.
|
||
|
||
2.2.1, el diálogo de añadir carpeta se explica solo. Al soltar una carpeta salían dos campos, «Cliente» y
|
||
«Tipo», sin decir para qué servían ni qué iba a pasar al confirmar, y el tipo se describía por a quién se le
|
||
hace («Contenido mensual (dermatólogas, marca personal): año / mes / pieza») en vez de por cómo queda
|
||
ordenado. Ahora cada campo es una pregunta en español con una línea debajo que dice qué hace, y el diálogo
|
||
enseña, con la plantilla de verdad del tipo elegido, las cuatro carpetas donde va a guardar el material:
|
||
|
||
```
|
||
V:\Galeano\2026\09- Septiembre\00_Grabacion\ lo que sale de la cámara
|
||
V:\Galeano\2026\09- Septiembre\Nombre de la pieza\ cada pieza, con su edición
|
||
V:\Galeano\2026\09- Septiembre\_Exportados\ lo que ya se entregó
|
||
V:\Galeano\_Recursos\Musica\ música y sonidos de siempre
|
||
```
|
||
|
||
El ejemplo se arma con `ESTADO.plantillas`, o sea que enseña exactamente lo que la app va a hacer y cambia
|
||
al cambiar el tipo. Además cierra un fallo: si el nombre que se escribe es un cliente que ya existe, se
|
||
preselecciona el tipo que ese cliente ya tiene; antes salía siempre «contenido», así que una segunda carpeta
|
||
de un cliente de pauta o de proyecto se podía registrar con la plantilla equivocada. Y el diálogo dice al
|
||
final que al confirmar solo lee y arma una lista: no mueve ni un archivo.
|
||
|
||
2.3.0, tres cosas para la reorganización:
|
||
|
||
**Los proyectos se separan por programa.** En una carpeta de cliente conviven `.prproj`, `.aep`, `.drp` y
|
||
`.psd`, y lo que cuesta es encontrarlos mezclados. La plantilla de proyectos pasa de `01_Proyectos/{nombre}`
|
||
a `01_Proyectos/{app}/{nombre}`, con `{app}` = el programa que abre el archivo (`R.APPS_PROYECTO`,
|
||
`R.app_proyecto`): Premiere, After Effects, DaVinci Resolve, Photoshop, Illustrator, InDesign, Audition,
|
||
Affinity, Figma y XD, Cinema 4D, Blender, Motion, Plantillas e Intercambio. Un proyecto que ya viene dentro
|
||
de su propia carpeta se queda con el nombre de esa carpeta; lo que se separa es lo suelto. Las plantillas
|
||
guardadas de una instalación anterior se migran solas si nadie las había tocado a mano. De paso entran
|
||
extensiones que caían en «otro» y acababan en `_Revisar`: `.sesx`, `.c4d`, `.blend`, `.motn`, `.aepx`,
|
||
`.aet`, `.prel`, `.idml`, `.psdt`, `.afpub`.
|
||
|
||
**Borrar carpetas vacías.** Ordenar deja huecos: repartida «Grabacion» por mes y por cámara, la carpeta
|
||
original se queda sin nada, y `quitar_vacias` solo limpiaba el camino de lo que se acababa de mover. Nueva
|
||
sub-pestaña en «Revisar y ordenar» y nuevo paso 5 en la lista de acciones. Los candidatos salen del
|
||
inventario (instantáneo) y cada uno se comprueba en el disco antes de enseñarlo y otra vez antes de
|
||
borrarlo; una carpeta que dejó de estar vacía se salta y se avisa. Solo sale la de más arriba de cada rama.
|
||
Los enlaces y las uniones de Windows no se tocan nunca, aunque parezcan vacíos. **Es lo único que la app
|
||
borra**, y solo porque no hay nada dentro que perder: cada carpeta queda en la bitácora como `rmdir` y
|
||
«Deshacer» las vuelve a crear con su nombre y las devuelve al inventario. No entra en «Hacer las N de una
|
||
vez»: hay que mirar la lista, porque una carpeta vacía llamada «03- Exfoliación química» es lo único que
|
||
queda de esa pieza. En el material real: 29 huecos en David Reyes y 40 en Camilo Ortega.
|
||
|
||
**Mapa.** Pestaña nueva con el árbol de carpetas que produce cada plantilla, armado con las plantillas de
|
||
verdad (`mapa_estructura`, `GET /api/estructura`), así que enseña exactamente lo que la app va a hacer. Las
|
||
carpetas variables van en cursiva; al tocar cualquiera, el panel de al lado dice qué guarda (derivado de
|
||
`ROL_A_CUBETA` y `R.ROL_QUE`, o sea que no se desfasa), cuánto material de eso hay hoy en la carpeta, y deja
|
||
cambiar el destino ahí mismo. En la carpeta de un programa sale el desglose: en David Reyes, Photoshop 10,6
|
||
GB, Affinity 10,3 GB, DaVinci Resolve 172 MB, Illustrator 146 MB, After Effects 736 KB. Abajo, «Sin carpeta
|
||
asignada» lista el material que no tiene dónde ir con ese tipo de trabajo y deja añadirle una carpeta.
|
||
`POST /api/plantillas` pasa a fusionar cubeta a cubeta: con `update()` de primer nivel, guardar una sola
|
||
plantilla borraba las otras diecinueve.
|
||
|
||
2.4.0, el mapa deja de ser un dibujo y pasa a ser la herramienta con la que se decide el orden:
|
||
|
||
**Cada carpeta lleva el color de lo que guarda** (`R.COLOR_CUBETA`, el mismo que ya usaba el gráfico de
|
||
peso). Una carpeta que mezcla tipos de distinto color se queda neutra; lo que cuelga de una con color
|
||
hereda el suyo, así una rama entera se lee de un vistazo.
|
||
|
||
**«¿Dónde va a parar este archivo?»** Se escribe el nombre de cualquier archivo, exista o no, y la app
|
||
dice qué es, de qué cámara o programa viene, de qué fecha, y en qué carpeta lo dejaría; el árbol
|
||
enciende el destino. Lo resuelve `donde_iria()` con el mismo clasificador que usa el escaneo, así que
|
||
no es una simulación aparte. Debajo salen nombres de archivo de verdad de la carpeta conectada para
|
||
probar con un clic. `GET /api/estructura/archivo`.
|
||
|
||
**Cambiarle el nombre a una carpeta.** Se toca una carpeta del árbol, se escribe otro nombre y el
|
||
cambio alcanza a **todas** las plantillas que pasan por ahí: renombrar `00_Grabacion` cambia también
|
||
`CELULAR`, que cuelga de ella. Si ya hay carpetas con ese nombre en el disco, dice cuántas y ofrece
|
||
renombrarlas también; es un movimiento normal, queda en la bitácora y se deshace desde Historial. Las
|
||
carpetas que nombra el material (el año, el mes, la pieza) no se pueden renombrar a mano, y los
|
||
nombres imposibles se rechazan. `POST /api/estructura/renombrar`, `GET /api/estructura/existen`.
|
||
De paso, `{anio}` y `{mes}` dejan de encajar con cualquier carpeta: solo con algo que de verdad parezca
|
||
un año o un mes («Efectos» salía como si fuera un año).
|
||
|
||
**Colores en el Explorador de Windows.** Windows no tiene «color de carpeta», pero sí icono por
|
||
carpeta. La app genera un `.ico` por color sin dependencias (el mismo codificador PNG/ICO del logo) en
|
||
`.organilab\iconos` dentro de la propia carpeta del cliente, y lo asigna con
|
||
`SHGetSetFolderCustomSettings`, que es la puerta que usa «Propiedades › Personalizar › Cambiar icono»:
|
||
escribe el `desktop.ini` como lo escribe Windows, marca la carpeta y refresca la caché de iconos.
|
||
Escribir el `desktop.ini` a mano no bastaba, y comprobarlo con `SHGetFileInfo` engaña, porque esa vía
|
||
no informa de la personalización ni cuando la ha puesto el propio Explorador; la comprobación buena es
|
||
releer con la misma API. La ruta del icono es relativa, así que los colores viajan con el disco.
|
||
Medido el 16-sep-2026: en C: se puede, en Z: solo con el atributo de sistema, y en W: el disco no lo
|
||
permite — en ese caso la app lo dice y no deja nada escrito. Se quita con un clic.
|
||
`POST /api/colores/pintar` y `/api/colores/quitar`.
|
||
|
||
La carpeta `.organilab` no se escanea ni se ordena, y los `desktop.ini` que pone la app no se cuentan
|
||
como basura: si no, el primer «apartar basura» se llevaba los colores por delante.
|
||
|
||
2.5.0, el material de cámara baja hasta el día de rodaje.
|
||
|
||
El año y el mes ya salían de la fecha de cada archivo desde la 2.2.0 (Danney se repartía solo en 54
|
||
meses distintos), pero dentro del mes seguía todo junto: en Camilo, un mes con **13 días de rodaje
|
||
distintos y 907 archivos** en la misma carpeta. Ahora la plantilla de grabación lleva `{dia}`
|
||
(`{anio}/{mes}/00_Grabacion/{dia}/{sub}`), con el día en la misma forma que los meses: `15- Viernes`,
|
||
el número delante para que ordene y el nombre detrás para saber de un vistazo si aquello fue un sábado
|
||
de rodaje.
|
||
|
||
**El día solo aparece cuando hace falta.** `Plan._dias_de_rodaje()` cuenta, mes a mes, en cuántos días
|
||
distintos se grabó algo en esa carpeta de cliente, y `dia_de()` devuelve cadena vacía cuando el mes
|
||
tuvo un solo rodaje: entonces la variable se lleva su propio segmento y la carpeta del día desaparece
|
||
sola. Medido sobre el material real: David Reyes solo la necesita en 1 de sus 8 meses, Danney en 36 de
|
||
57 y Camilo en 12 de 26. En el plan de los tres clientes salen 186 grupos por día y ninguna colisión.
|
||
|
||
**Un archivo de cámara suelto también se archiva por su propia fecha.** Dentro de una carpeta de
|
||
grabación el archivo ya mandaba sobre el nombre de la carpeta desde la 2.2.0, pero un clip traspapelado
|
||
fuera de ella se quedaba en el mes que dijera la carpeta: `plan_archivo` hacía `if mes: fm = mes` sin
|
||
mirar la fecha. Ahora usa la misma regla y el mismo aviso.
|
||
|
||
Probado sobre un árbol de ensayo con un marzo de tres rodajes y un mayo de uno solo: marzo se reparte
|
||
en `03- Martes`, `11- Miércoles` y `19- Jueves`, mayo se queda sin carpeta de día, y aplicar y deshacer
|
||
dejan el árbol exacto.
|
||
|
||
2.6.0, auditoría: 100 % local y las 26 funciones verificadas una a una.
|
||
|
||
**Qué sale a la red.** Se buscó toda llamada externa en el código: había dos. La tipografía Manrope se
|
||
pedía a Google en cada arranque (y sin red la página esperaba a que fallara); ahora viene con el
|
||
programa (`static/manrope.woff2`, 25 KB, servida como `font/woff2`). Lo otro es el comprobador de
|
||
versiones, que consulta Labstream OS al arrancar: sigue igual pero con un interruptor en Ajustes
|
||
(«al arrancar, consultar si hay versión nueva»); apagado, el programa no habla con nada fuera de este
|
||
equipo. El botón «Buscar actualizaciones» funciona a mano en cualquier caso. Todo lo demás —inventario,
|
||
plan, conversión, respaldo, colores, mapa— es local.
|
||
|
||
**Verificación función por función.** `smoke.py` (en la carpeta de trabajo de la sesión) levanta una
|
||
copia del programa sobre un cliente de ensayo con de todo (cámara de dos días, exportados, proyectos,
|
||
música, stock de Envato viejo, basura, proxies, dos repetidos, un hueco, un mes en minúsculas y un clip
|
||
de video de verdad) y ejercita las 26 funciones por su API en el orden en que las usaría una persona,
|
||
incluida una conversión real con ffmpeg (H.265 10 bits por GPU), verificación, reemplazo y una copia de
|
||
respaldo con su índice. Resultado: 26 de 26. Por el camino salieron cinco fallos de verdad:
|
||
|
||
- **Un mes en minúsculas nunca se normalizaba.** «10- octubre» → «10- Octubre» es un renombrado que
|
||
solo cambia mayúsculas; en Windows los dos nombres son el mismo, y tanto `Plan.agregar` como `mover`
|
||
lo tomaban por «ya está en su sitio» y lo descartaban sin decir nada. El plan prometía «meses con
|
||
nombre completo» que nunca ocurrían. Ahora se propone, se aplica (`os.rename` sí sabe) y `deshacer` lo
|
||
devuelve (antes decía «su sitio original ya está ocupado», porque `exists()` también miente ahí).
|
||
- **Las carpetas que crea el plan no entraban en el inventario** hasta el siguiente escaneo
|
||
(`00_Grabacion`, `_Para borrar\basura`…): «existen», las carpetas vacías y los colores no las veían.
|
||
`_recontar_carpetas` las da de alta tras cada movimiento y recuenta las tocadas, con totales de
|
||
subárbol como los del escaneo; las que se quedaron sin nada y desaparecieron se dan de baja.
|
||
- **Una fusión de carpetas se quedaba a medias.** Si al fusionar «Grabacion mañana» sobre
|
||
`00_Grabacion/SONY` un archivo tropezaba (ya existía, estaba abierto), el bucle cortaba ahí, los
|
||
demás no se intentaban y el aviso hablaba de uno solo. Ahora cada hijo va por su cuenta y el aviso
|
||
cuenta cuántos se quedaron.
|
||
- **«Viejo» significaba tres cosas.** El convertidor miraba la fecha de modificación con meses de 30,4
|
||
días; el stock y el respaldo, el mes de la pieza (o la fecha del archivo) por meses de calendario.
|
||
Un clip de un rodaje de 2024 re-exportado ayer no era «viejo» para convertir. Ahora la regla es una
|
||
(`es_viejo` + `limite_meses`); con 0 meses no se filtra por edad.
|
||
- **`/api/actualizacion` decía versión vacía** hasta la primera consulta: `ESTADO` del actualizador trae
|
||
`version: ""` y pisaba la real al mezclar los diccionarios.
|
||
|
||
Y tres menores: cada fila de archivos sueltos era de una sola carpeta de origen (antes juntaba varias y
|
||
ponía la del primero), el mes de un grupo de stock es el más repetido (no el del primer archivo), y se
|
||
quitan tres rutas que nadie llamaba (`/api/diagnostico`, `/api/asistente/estado`, `/api/tour-visto`).
|
||
|
||
Lo que se miró y está bien: los 52 endpoints que usa la interfaz existen, todos los botones tienen su
|
||
manejador, la barra de tareas refleja escaneo, lectura de clips, cola, asistente, respaldo y descarga
|
||
de versión con su tiempo estimado, y la estimación de ProRes (por tasa nominal) y la copia de audio
|
||
(`-c:a copy` solo con AAC de una pista) resisten los casos del ensayo.
|
||
|
||
2.6.1, las actualizaciones automáticas se apagan por defecto. El programa no sale a la red al arrancar
|
||
salvo que alguien encienda el interruptor en Ajustes; «Buscar actualizaciones» sigue a mano. Hasta la
|
||
2.6.0 el actualizador escribía `auto: true` él solo en `config.json` (no había interruptor, así que
|
||
nadie lo eligió): al arrancar la 2.6.1, ese valor se apaga; el que se encienda desde Ajustes queda
|
||
marcado como elegido y se respeta.
|
||
|
||
2.6.2, arranque en blanco. Munka abrió la app y se encontró dentro de la carpeta de Galeano, y preguntó
|
||
si era un caché: no lo era, es la única carpeta registrada en su `config.json` (la añadió el 16 de
|
||
septiembre y ese mismo día aplicó dos lotes sobre ella). Pero la pregunta destapó dos cosas de verdad:
|
||
|
||
- **Una instalación nueva no abría en blanco**: `CONFIG_DEFECTO` traía tres carpetas de fábrica (David
|
||
Reyes, Danney, Camilo) apuntando a Z:, W: y N:, así que en un equipo sin esos discos el programa
|
||
arrancaba con tres clientes «sin escanear» que nadie había puesto. Ahora `raices` viene vacía; lo
|
||
que sigue de serie es el diccionario de clientes y discos, que es
|
||
conocimiento del estudio, no estado. Prueba nueva: una copia recién hecha responde `raices: []`.
|
||
- **Al abrir, el desplegable caía solo en la primera carpeta registrada** (con una sola, en esa). Ahora
|
||
la primera opción está vacía y la portada enseña «Tus carpetas» —cada una con su último escaneo— para
|
||
entrar con un clic. Nada se abre solo.
|
||
- Y un fallo latente: un `config.json` ilegible (una coma de más al editarlo a mano) se sustituía por
|
||
los valores de fábrica y se guardaba encima, y las carpetas registradas y los clientes desaparecían sin
|
||
decir nada. Ahora se aparta en `config.json.roto-<fecha>` y se avisa en consola. Con prueba.
|
||
|
||
3.0.0, OrganiLAB pasa a ser un programa de Windows. Munka pidió que dejara de ser una aplicación web. Ventana
|
||
propia tenía desde hacía tiempo, pero prestada (pywebview sobre .NET), y lo que se repartía era un .exe de
|
||
PyInstaller sin firma que Smart App Control le bloqueaba en su propio equipo (15 y 25 de septiembre); desde
|
||
entonces lo abría por un acceso directo a Python. Cambian tres cosas:
|
||
|
||
**La ventana es de Windows y es nuestra** (`ventana.py`, solo ctypes). Un marco Win32 de verdad —clase
|
||
registrada, bucle de mensajes, icono, barra de título del color de la interfaz— y dentro WebView2, el
|
||
componente con que Windows pinta HTML, manejado por COM directamente. Fuera pywebview, pythonnet y
|
||
clr_loader, con sus tres binarios sin firmar (el día que Smart App Control parase uno, el programa acababa
|
||
en el navegador sin decir nada). Lo único que viaja y no es de Python es `WebView2Loader.dll`, de Microsoft
|
||
y firmada. Los IID y las posiciones de las tablas virtuales no están escritos de memoria: salen del
|
||
ensamblado `Microsoft.Web.WebView2.Core.dll`, que declara cada interfaz con sus métodos en orden. Con la
|
||
ventana vienen cosas que una página no puede tener:
|
||
|
||
- identidad en la barra de tareas (`Labstream.OrganiLAB`): es OrganiLAB, no «Python», y si se ancla vuelve
|
||
a abrir el programa;
|
||
- una sola copia abierta por carpeta de datos (un candado con nombre): abrirlo otra vez trae la ventana al
|
||
frente. Antes la segunda copia abría el navegador y, peor, daba por huérfanas las conversiones que la
|
||
primera tenía en marcha (`recuperar_huerfanas` corría antes de mirar si ya había otra);
|
||
- si el puerto 8765 lo tiene otro programa, toma uno libre en vez de abrir la página de ese otro;
|
||
- el selector de carpetas es el de Windows, modal sobre la ventana (antes, un PowerShell aparte que tardaba
|
||
un par de segundos y podía salir por detrás);
|
||
- las carpetas soltadas llegan con su ruta completa (`postMessageWithAdditionalObjects` → `ICoreWebView2File`);
|
||
- avance en el botón de la barra de tareas, y un parpadeo al terminar algo largo si se está en otra cosa;
|
||
- recuerda dónde y de qué tamaño se dejó (`datos\ventana.json`);
|
||
- cerrar con trabajo en marcha avisa de qué se está haciendo; la ventana se quita de la vista, el trabajo
|
||
sigue y el programa se cierra solo al acabar (abrirlo otra vez devuelve esa misma ventana);
|
||
- nada de navegador: sin menú de «Atrás / Recargar / Inspeccionar» (solo sale al escribir o con texto
|
||
seleccionado), sin F5, sin zoom, sin barra de estado, sin página de error de Edge y sin permisos; un
|
||
enlace hacia fuera se abre en el navegador del equipo, no dentro.
|
||
|
||
Si un Windows no tiene WebView2 (un Windows 10 sin Edge al día), la interfaz se abre en el navegador como
|
||
antes y el programa se va solo cuando esa página lleva tres minutos sin preguntar. Y si el motor se cae a
|
||
media sesión, la ventana lo monta de nuevo sola (probado matándolo a propósito).
|
||
|
||
**El .exe vuelve a abrir con Smart App Control** (`empaquetar.py`, `arranque.py`). El paquete ya no lleva
|
||
ningún binario propio. `OrganizadorLabstream.exe` es `pythonw.exe` —el intérprete, firmado por la Python
|
||
Software Foundation— con otro nombre, junto a su `python312.dll`, la librería estándar en un zip y los
|
||
módulos de extensión, todos firmados. Python importa `sitecustomize` al arrancar, y ese módulo
|
||
(`arranque.py`) es quien lanza el programa cuando al .exe no se le pasa un guion; con un `.py`, `-c` o `-m`
|
||
sigue siendo un intérprete normal, y así corre el puente de Resolve. Al empaquetar se le pregunta a Windows
|
||
por la firma de cada binario (`WinVerifyTrust`) y se arranca el motor del paquete: si algo no está firmado
|
||
o no arranca, no hay paquete. Probado aquí con Smart App Control bloqueando y todos los archivos marcados
|
||
como bajados de internet: abre con doble clic. El paquete de actualización baja de 15 a 12 MB. Las copias
|
||
de la 2.x dan el salto con su actualizador de siempre (el zip trae un `OrganizadorLabstream.exe`, que es lo
|
||
que exige); la carpeta `_internal` de PyInstaller que queda atrás la borra la 3.0 al arrancar. Ensayado
|
||
sobre una copia de la instalación de Munka con sus datos: abre, conserva su carpeta registrada, sus 19
|
||
clientes y sus ajustes. Y la actualización automática, de punta a punta con el formato nuevo: una 3.0.1 de
|
||
ensayo, firmada con la clave de verdad y servida en local, se descarga, se verifica, cierra el programa,
|
||
copia y lo vuelve a abrir en la versión nueva, con el .exe todavía firmado.
|
||
|
||
Lo que no tiene arreglo sin un certificado de firma propio: en el Explorador el .exe sale con el icono y el
|
||
nombre de Python (en Inicio, en el Escritorio y en la barra de tareas sale con los suyos), y los dos `.bat`
|
||
de arrastrar, si el zip viene de internet, Smart App Control los para; arrastrar la carpeta sobre el propio
|
||
.exe hace lo mismo.
|
||
|
||
**Se instala como un programa** (`instalar.py`). Acceso directo en el menú Inicio y en el Escritorio, con
|
||
la misma identidad que la ventana para que el acceso anclado y la ventana abierta sean un solo botón, y su
|
||
línea en Configuración › Aplicaciones. No copia nada ni pide permisos de administrador: da de alta el
|
||
programa donde está. La primera vez que se abre un paquete en un equipo lo ofrece, una sola vez; también
|
||
`OrganizadorLabstream.exe instalar` / `desinstalar`. Quitarlo borra los accesos y la línea, nunca la carpeta
|
||
ni los datos. Tras una actualización pone al día la versión que enseña Windows sin reponer un acceso que
|
||
alguien quitó.
|
||
|
||
En el equipo de Munka (4 oct 2026) la instalación se mudó de Descargas a su sitio definitivo,
|
||
`%LOCALAPPDATA%\Programs\OrganiLAB`: programa, `datos\` y `ffmpeg\` movidos dentro del mismo disco (377
|
||
archivos, las mismas huellas antes y después) y vuelta a dar de alta desde ahí. En Descargas solo queda la
|
||
2.6.2 apartada, con una nota. Y se comprobó con las herramientas de Windows, sin tocar ninguna, que la da por
|
||
segura: Smart App Control encendido y la app abre; 31 de los 33 binarios con firma válida (27 de la Python
|
||
Software Foundation, 4 de Microsoft); los otros dos son `ffmpeg.exe` y `ffprobe.exe`, que sus autores publican
|
||
sin firmar: son byte a byte los que instala winget (`Gyan.FFmpeg`), Smart App Control los deja correr y
|
||
Microsoft Defender, con las firmas del día, no encuentra nada en la carpeta.
|
||
|
||
Lo que sigue igual por dentro: las pantallas son las mismas (HTML) y hablan con el programa por un servidor
|
||
que solo escucha en 127.0.0.1 y rechaza lo que no venga de su propia página. Rehacer las siete pantallas
|
||
con controles clásicos de Windows sería otro programa.
|
||
|
||
**La red.** El motor arranca con las tareas de fondo apagadas, sin resolver ningún nombre de fuera de este
|
||
equipo y con un proxy que no existe: la interfaz no puede cargar nada externo ni por descuido. Medido un
|
||
minuto, proceso por proceso: el programa, cero conexiones hacia fuera; el motor de Edge, una, al arrancar,
|
||
a Microsoft 365 (`substrate.office.com`). Es su gestor de identidad (`oneauth.dll`) consultando el perfil
|
||
de la cuenta de Windows: lo hace el componente de Windows en cualquier programa que lo use —y lo hacía ya
|
||
con la ventana anterior—, no pasa por el proxy y ninguno de los interruptores probados (siete
|
||
combinaciones) lo apaga. OrganiLAB no manda ni recibe nada por ahí. De paso: usado por consola, el paquete
|
||
consultaba si había versión nueva aunque las actualizaciones automáticas estuvieran apagadas; ya no.
|
||
|
||
Pruebas: `probar.py` sube de 10 a 17 (accesos directos, alta y baja en Windows contra una clave de ensayo,
|
||
una sola copia, puerto ocupado, Windows sin WebView2, las tablas de la ventana, el arranque del paquete);
|
||
`prueba_funcional.py` sigue en 26 de 26; y `prueba_ventana.py`, nueva, abre la ventana de verdad y
|
||
comprueba 17 cosas desde el código y 8 más arrancando el paquete por su .exe.
|
||
|
||
3.1.0, instalar es instalar de verdad, y el manual va dentro.
|
||
|
||
**El programa se instala solo en su sitio.** En la 3.0 «instalar» daba de alta el programa donde estuviera la
|
||
carpeta, y la carpeta suele estar en Descargas, que es de donde se limpia: en el equipo de Munka hubo que
|
||
mudarla a mano. Ahora, la primera vez que se abre un paquete, la pregunta es «¿Instalar OrganiLAB en este
|
||
equipo?», y decir que sí lo copia a `%LOCALAPPDATA%\Programs\OrganiLAB` con sus datos y su ffmpeg, lo da de
|
||
alta desde ahí (Inicio, Escritorio, Aplicaciones), lo cierra y lo vuelve a abrir desde su sitio
|
||
(`instalar.poner`, `instalar.mudar`). Lo mismo hace `OrganizadorLabstream.exe instalar`. Detalles:
|
||
|
||
- Del origen no se borra ni se mueve nada. Queda `instalado-en.txt`, que dice adónde se fue y además hace
|
||
que abrir esa copia abra la instalada (`instalar.mudado`): no hay dos programas con dos juegos de datos.
|
||
- No viaja lo que es de la sesión abierta (`sesion.json`) ni lo que se rehace solo (el perfil del motor de la
|
||
ventana, `actualizacion\`, `__pycache__`). El inventario se copia con la copia de SQLite, que sale entera
|
||
y coherente aunque el programa esté abierto.
|
||
- Un destino que ya existe y no está vacío no se pisa. Si ya hay un OrganiLAB instalado en el equipo, lo
|
||
dice y no instala otro encima. Si falta sitio en el disco o la copia falla a medias, quita lo copiado y
|
||
el programa sigue funcionando desde donde estaba.
|
||
- Si el paquete ya está en su sitio, o se corre desde el código, instalar sigue siendo solo darlo de alta.
|
||
- Para probarlo sin tocar el Windows de verdad, `ORGANILAB_ENSAYO=<carpeta>` hace que el «equipo» sea esa
|
||
carpeta (programas, Inicio, Escritorio y una clave aparte del registro). `prueba_ventana.py --paquete` lo
|
||
usa para recorrer la instalación entera: abre desde unas «Descargas», acepta la oferta, espera a que se
|
||
reabra desde su sitio y comprueba que abrir la copia de origen abre la instalada.
|
||
|
||
**El puerto, para una sola copia.** Probando la instalación salió un fallo que venía de siempre:
|
||
`ThreadingHTTPServer` pide «reutilizar dirección», y en Windows eso deja que dos programas escuchen a la vez
|
||
en el mismo puerto; las peticiones van a cualquiera de los dos. Dos OrganiLAB con datos distintos (el
|
||
instalado y una copia suelta) se contestaban el uno por el otro sin que nada fallara a la vista, y la
|
||
detección de «ya hay uno abierto» por puerto ocupado no saltaba nunca. `ServidorLocal` pide el puerto en
|
||
exclusiva (`SO_EXCLUSIVEADDRUSE`); si está ocupado, la copia toma otro. La prueba del puerto ocupado usa
|
||
ahora un servidor como el de otro OrganiLAB, que es justo el caso que no fallaba cuando debía. Y las pruebas
|
||
con ventana cierran siempre las copias que abren, también cuando una comprobación falla.
|
||
|
||
**Manual.** Vista nueva en la interfaz, «Manual», junto a Ajustes: cada función del programa, qué hace y
|
||
cómo lo hace, en el orden de las pestañas (41 entradas en 12 apartados). Vive en `static/index.html`, así
|
||
que viaja con cada versión; una prueba comprueba que cada pestaña tiene su apartado.
|
||
|
||
Pruebas: `probar.py` 19 de 19, `prueba_funcional.py` 26 de 26, `prueba_ventana.py` 18 desde el código y,
|
||
con el paquete, 8 del arranque y 9 de la instalación.
|
||
|
||
3.1.1, poner al día el alta en Windows no reescribe lo que ya está bien. Tras una actualización,
|
||
`instalar.al_dia` reescribía los dos accesos directos aunque ya apuntaran a donde debían, y solo después
|
||
apuntaba la versión; ahora un acceso que ya abre lo que debe no se toca, uno que no se deja reescribir no
|
||
impide lo demás, y la versión se apunta siempre. Con prueba.
|
||
|
||
Lo que llevó a este cambio no era un fallo del programa sino de medida, y conviene dejarlo escrito para
|
||
quien mantenga esto desde Claude: **la consola de la sesión ve y escribe una copia privada de
|
||
`HKEY_CURRENT_USER`**, no el registro de verdad (la aplicación de escritorio de Claude es una aplicación
|
||
empaquetada, y Windows aparta en una copia lo que escriben ella y los procesos que lanza). Los archivos sí
|
||
son los de verdad. Consecuencias, vistas el 4 oct 2026:
|
||
|
||
- Tras actualizar la instalación de Munka, desde la consola «Aplicaciones» seguía diciendo la versión vieja;
|
||
en su Windows decía la nueva desde el primer momento. Se estuvo persiguiendo un fallo que no existía.
|
||
- El alta que se hizo desde la consola (`OrganizadorLabstream.exe instalar --si`) creó los accesos directos
|
||
de verdad, pero la línea de Aplicaciones solo en la copia privada. La de verdad se creó cuando Munka abrió
|
||
el programa y aceptó la oferta de instalarlo.
|
||
- Para ver o cambiar el registro de verdad desde una sesión, hay que lanzar la comprobación a través del
|
||
Explorador (`explorer.exe` sobre un `.bat` o un acceso directo): así el proceso nace fuera de la copia. Lo
|
||
mismo para probar el programa «como lo abre el usuario»: abierto desde la consola hereda la copia.
|
||
- Las pruebas que dan de alta en el registro (`probar.py`, `prueba_ventana.py`) no se ven afectadas: escriben
|
||
y leen en la misma copia, y además usan una clave de ensayo.
|
||
|
||
Probado el 9 sep 2026 sobre una copia de ensayo: plan → aplicar → deshacer → volver a aplicar deja el árbol
|
||
exacto; conversión ffmpeg verificada y reemplazo con original a `_Para borrar`. El puente de Resolve conectó
|
||
con Resolve Studio 21.1 pero no pudo abrir proyecto porque Resolve estaba en el Gestor de proyectos:
|
||
queda por probar con un proyecto abierto.
|