Convertir: horario y pausa si edito, aligerar solo lo viejo, aviso de Windows, resumen de la tanda con CSV, y marcar con criterio

Las tres propuestas que faltaban del lienzo:
- La cola respeta un horario (espera entre clip y clip) y espera si Resolve, Premiere o After Effects
  están usando la tarjeta (nvidia-smi pmon). La pasada automática puede meter en cola lo de más de N
  meses hasta un tope de GB. Al acabar, un aviso de Windows con la identidad del programa.
- Cada tanda deja un resumen en la bitácora (op tanda): clips, pesos, tiempo, nota, fallos, por
  carpeta. Sale en Convertir con «Exportar CSV» y «Abrir la carpeta», y en Historial cuenta clips.
- Barra de marcar con criterio (tamaño, cámara, mes, antigüedad) y buscador.

Pruebas: probar 19, prueba_orden 33, prueba_funcional 32 (nueva: resumen de la tanda), prueba_ventana 18.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Este commit está contenido en:
Labstream
2026-10-12 14:29:49 -05:00
padre d38c51bd73
commit ad6efef792
Se han modificado 4 ficheros con 418 adiciones y 20 borrados

Ver fichero

@@ -383,6 +383,25 @@ def p_comparar():
return 'dos cuadros JPEG y nota VMAF %s sobre %d cuadros (%.0f s)' % (r['vmaf'], r['cuadros'], r['seg'])
def p_tanda():
# al acabar la cola queda el resumen de la tanda: clips, pesos, tiempo; y se exporta en CSV
u = get('/api/optimizar/cola')['cola']['ultima']
assert u and u['clips'] >= 1 and u['bytes_in'] > u['bytes_out'] > 0 and u['lote'].startswith('tanda-'), u
assert IDS['trabajo'] in u['ids'] and u['raiz'].lower() == RAIZ.lower(), u
r = urllib.request.urlopen(BASE + '/api/optimizar/tanda.csv' + q(lote=u['lote']), timeout=60)
csv_ = r.read().decode('utf-8-sig')
assert r.headers.get('Content-Type', '').startswith('text/csv') and csv_.startswith('clip;carpeta;estado') and 'reemplazado' in csv_, csv_[:200]
lotes = get('/api/bitacora')['lotes']
l = next((x for x in lotes if x['lote'] == u['lote']), None)
assert l and l['tanda']['clips'] == u['clips'], l
# el horario: fuera de él la cola espera (se comprueba la regla, no esperando de verdad)
c, r2 = post('/api/config', {'optimizar': {'horario': {'activo': True, 'desde': '20:00', 'hasta': '07:00'}, 'pausar_si_edito': False, 'avisar': False}})
assert c == 200 and r2['config']['optimizar']['horario']['desde'] == '20:00'
c, r3 = post('/api/config', {'optimizar': {'horario': {'activo': False, 'desde': '20:00', 'hasta': '07:00'}}})
assert c == 200 and not r3['config']['optimizar']['horario']['activo']
return 'resumen de %d clip(s), %s, CSV con %d líneas, y en Historial' % (u['clips'], u['lote'], csv_.count('\n'))
def p_braw():
m = get('/api/optimizar/motores')['braw']
if not BRAW:
@@ -552,7 +571,7 @@ for nombre, fn in (('Interfaz sin nada externo', p_estatico), ('Registrar carpet
('Historial y papelera', p_historial), ('Repetidos', p_repetidos), ('Stock viejo', p_stock),
('Carpetas vacías', p_vacias), ('Mapa interactivo', p_mapa), ('Colores en Windows', p_colores),
('Motores de conversión', p_motores), ('Leer clips (ffprobe)', p_analizar),
('Convertir, verificar, reemplazar', p_convertir), ('Comparar original y convertido', p_comparar), ('Convertir un BRAW', p_braw), ('Control de la cola', p_cola_control),
('Convertir, verificar, reemplazar', p_convertir), ('Comparar original y convertido', p_comparar), ('Resumen de la tanda', p_tanda), ('Convertir un BRAW', p_braw), ('Control de la cola', p_cola_control),
('Respaldar', p_respaldo), ('Asistente / hacer de una vez', p_asistente),
('Pieza nueva', p_pieza), ('Bandeja de entrada y tarjeta', p_entrada), ('Orden automático', p_automatico),
('Arrastrar y buscar carpeta', p_soltar_y_buscar), ('Actualizaciones', p_actualizacion_offline),