1.7.0: recorrido paso a paso, sugerencias en Por nombrar, stock por antigüedad, Convertidor con formatos y GPU/CPU, respaldo por lotes, barra de tareas corregida
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Este commit está contenido en:
185
organizador.py
185
organizador.py
@@ -33,7 +33,7 @@ import actualizador
|
||||
asistente.O = sys.modules[__name__]
|
||||
actualizador.O = sys.modules[__name__]
|
||||
|
||||
VERSION = "1.6.3"
|
||||
VERSION = "1.7.0"
|
||||
|
||||
CONGELADO = getattr(sys, "frozen", False)
|
||||
SIN_VENTANA = getattr(subprocess, "CREATE_NO_WINDOW", 0) # ffmpeg/ffprobe/net sin abrir consolas negras # empaquetado como .exe con PyInstaller
|
||||
@@ -101,6 +101,7 @@ CONFIG_DEFECTO = {
|
||||
"meses_minimos": 3,
|
||||
"min_mb": 300,
|
||||
"perfil": "equilibrado",
|
||||
"formato": "h265_10bit",
|
||||
"chroma": "420",
|
||||
"color": "rec709",
|
||||
"salida": "junto", # junto = al lado del original con sufijo _10bit ; espejo = _Archivo/<ruta>
|
||||
@@ -117,6 +118,68 @@ PERFILES = {
|
||||
"maxima": {"bpp": 0.14, "cq": 21, "nombre": "Máxima calidad"},
|
||||
}
|
||||
|
||||
# Formatos de salida del convertidor. gpu/cpu = codificador de ffmpeg que lo hace; se usa la GPU si está
|
||||
# disponible y si no la CPU. bpp_mult escala el bitrate objetivo del perfil (H.265 10 bits = 1.0).
|
||||
# ProRes no va por bitrate: mbps_1080p30 es su peso aproximado a 1080p 30 fps para estimar.
|
||||
FORMATOS = {
|
||||
"h265_10bit": {"nombre": "MP4 H.265 10 bits · archivo (recomendado)", "ext": ".mp4", "codec": "hevc", "bits": 10, "sufijo": "_10bit",
|
||||
"gpu": "hevc_nvenc", "cpu": "libx265", "bpp_mult": 1.0, "que": "unas 10 veces más ligero que el original, sin perder calidad visible; el que usa el respaldo"},
|
||||
"h265_ligero": {"nombre": "MP4 H.265 8 bits · ligero para compartir", "ext": ".mp4", "codec": "hevc", "bits": 8, "sufijo": "_ligero",
|
||||
"gpu": "hevc_nvenc", "cpu": "libx265", "bpp_mult": 0.55, "que": "para enviar por WhatsApp o Drive; pierde latitud de color"},
|
||||
"h264": {"nombre": "MP4 H.264 8 bits · compatible con todo", "ext": ".mp4", "codec": "h264", "bits": 8, "sufijo": "_h264",
|
||||
"gpu": "h264_nvenc", "cpu": "libx264", "bpp_mult": 1.5, "que": "se abre en cualquier equipo o televisor; pesa más que H.265"},
|
||||
"prores_proxy": {"nombre": "MOV ProRes Proxy · edición ligera", "ext": ".mov", "codec": "prores", "bits": 10, "sufijo": "_proxy",
|
||||
"cpu": "prores_ks", "prores": 0, "mbps_1080p30": 45, "que": "para editar suave en Resolve o Premiere; luego se reenlaza al original"},
|
||||
"prores_lt": {"nombre": "MOV ProRes 422 LT · edición", "ext": ".mov", "codec": "prores", "bits": 10, "sufijo": "_LT",
|
||||
"cpu": "prores_ks", "prores": 1, "mbps_1080p30": 102, "que": "calidad de edición; pesa bastante"},
|
||||
"prores_hq": {"nombre": "MOV ProRes 422 HQ · máster", "ext": ".mov", "codec": "prores", "bits": 10, "sufijo": "_HQ",
|
||||
"cpu": "prores_ks", "prores": 3, "mbps_1080p30": 220, "que": "entrega o máster; pesa mucho"},
|
||||
}
|
||||
_MOTORES = {"ts": 0, "datos": None}
|
||||
|
||||
|
||||
def motores():
|
||||
"""Qué codificadores hay: GPU NVIDIA (NVENC) y CPU. Se prueba de verdad (un clip de 3 cuadros), no solo
|
||||
por la lista de ffmpeg, porque la lista incluye nvenc aunque no haya tarjeta NVIDIA."""
|
||||
if _MOTORES["datos"] and time.time() - _MOTORES["ts"] < 600:
|
||||
return _MOTORES["datos"]
|
||||
ff = ruta_herramienta("ffmpeg")
|
||||
out = {"gpu": {"nombre": "", "hevc": False, "h264": False}, "cpu": {"libx265": False, "libx264": False, "prores_ks": False}, "formatos": {}, "ffmpeg": bool(ff)}
|
||||
disponibles = set()
|
||||
if ff:
|
||||
try:
|
||||
r = subprocess.run([ff, "-hide_banner", "-encoders"], capture_output=True, text=True, timeout=20, creationflags=SIN_VENTANA)
|
||||
for linea in r.stdout.splitlines():
|
||||
partes = linea.split()
|
||||
if len(partes) >= 2 and partes[0][:1] in ("V", "A") and len(partes[0]) == 6:
|
||||
disponibles.add(partes[1])
|
||||
except Exception: # noqa
|
||||
pass
|
||||
for k in ("libx265", "libx264", "prores_ks"):
|
||||
out["cpu"][k] = k in disponibles
|
||||
for k, enc in (("hevc", "hevc_nvenc"), ("h264", "h264_nvenc")):
|
||||
if enc in disponibles:
|
||||
try:
|
||||
r = subprocess.run([ff, "-hide_banner", "-loglevel", "error", "-f", "lavfi", "-i", "testsrc=size=256x144:rate=30",
|
||||
"-frames:v", "3", "-c:v", enc, "-f", "null", "-"], capture_output=True, text=True, timeout=40, creationflags=SIN_VENTANA)
|
||||
out["gpu"][k] = r.returncode == 0
|
||||
except Exception: # noqa
|
||||
pass
|
||||
try:
|
||||
r = subprocess.run(["nvidia-smi", "--query-gpu=name", "--format=csv,noheader"], capture_output=True, text=True, timeout=10, creationflags=SIN_VENTANA)
|
||||
out["gpu"]["nombre"] = (r.stdout or "").strip().splitlines()[0] if r.returncode == 0 and r.stdout.strip() else ""
|
||||
except Exception: # noqa
|
||||
pass
|
||||
for k, f in FORMATOS.items():
|
||||
m = None
|
||||
if f.get("gpu") and out["gpu"].get(f["codec"]):
|
||||
m = "gpu"
|
||||
elif f.get("cpu") and out["cpu"].get(f["cpu"]):
|
||||
m = "cpu"
|
||||
out["formatos"][k] = m # None = no se puede con este ffmpeg
|
||||
_MOTORES.update(ts=time.time(), datos=out)
|
||||
return out
|
||||
|
||||
|
||||
def cargar_json(ruta, defecto):
|
||||
try:
|
||||
@@ -234,7 +297,7 @@ def init_db():
|
||||
);
|
||||
""")
|
||||
con.commit()
|
||||
for alter in ("ALTER TABLE archivos ADD COLUMN es_stock INTEGER DEFAULT 0",):
|
||||
for alter in ("ALTER TABLE archivos ADD COLUMN es_stock INTEGER DEFAULT 0", "ALTER TABLE trabajos ADD COLUMN formato TEXT DEFAULT 'h265_10bit'"):
|
||||
try:
|
||||
con.execute(alter)
|
||||
con.commit()
|
||||
@@ -1350,7 +1413,19 @@ def kbps_objetivo(ancho, alto, fps, perfil):
|
||||
return max(1500, int(ancho * alto * fps * bpp / 1000))
|
||||
|
||||
|
||||
def candidatos(raiz, meses, perfil, min_mb, incluir_exportados=False):
|
||||
def estimar_bytes(f, perfil, formato):
|
||||
"""peso aproximado de la salida para un archivo del inventario"""
|
||||
fm = FORMATOS.get(formato, FORMATOS["h265_10bit"])
|
||||
dur = f["dur"] or 0
|
||||
if fm.get("mbps_1080p30"):
|
||||
pix = (f["ancho"] or 1920) * (f["alto"] or 1080) * (f["fps"] or 30)
|
||||
return int(fm["mbps_1080p30"] * 1e6 / 8 * dur * pix / (1920 * 1080 * 30))
|
||||
obj = kbps_objetivo(f["ancho"] or 1920, f["alto"] or 1080, f["fps"], perfil) * fm.get("bpp_mult", 1.0)
|
||||
return int(obj * 1000 / 8 * dur) + int(256000 / 8 * dur)
|
||||
|
||||
|
||||
def candidatos(raiz, meses, perfil, min_mb, incluir_exportados=False, formato="h265_10bit"):
|
||||
fm = FORMATOS.get(formato, FORMATOS["h265_10bit"])
|
||||
con = db()
|
||||
limite = time.time() - int(meses) * 30.4 * 86400
|
||||
filas = con.execute("SELECT * FROM archivos WHERE raiz = ? AND analizado = 1 AND es_proxy = 0 AND bytes >= ? ORDER BY bytes DESC",
|
||||
@@ -1365,16 +1440,18 @@ def candidatos(raiz, meses, perfil, min_mb, incluir_exportados=False):
|
||||
motivo_no = "stock de Envato: mejor borrarlo (se vuelve a descargar)"
|
||||
elif f["alfa"]:
|
||||
motivo_no = "tiene canal alfa (HEVC lo perdería)"
|
||||
elif f["codec"] in ("hevc", "av1") and f["kbps"] and f["kbps"] <= kbps_objetivo(f["ancho"], f["alto"], f["fps"], perfil) * 1.3:
|
||||
elif fm["codec"] == "hevc" and f["codec"] in ("hevc", "av1") and f["kbps"] and f["kbps"] <= kbps_objetivo(f["ancho"], f["alto"], f["fps"], perfil) * fm.get("bpp_mult", 1.0) * 1.3:
|
||||
motivo_no = "ya está en HEVC/AV1 eficiente"
|
||||
elif motor == "resolve" and formato != "h265_10bit":
|
||||
motivo_no = "los BRAW van por Resolve y solo salen a H.265 10 bits"
|
||||
elif f["mtime"] > limite:
|
||||
motivo_no = f"tiene menos de {meses} meses"
|
||||
elif f["contexto"] == "EXPORTADOS" and not incluir_exportados:
|
||||
motivo_no = "es un exportado / master"
|
||||
elif not f["ancho"] or not f["dur"]:
|
||||
motivo_no = "no se pudo leer (ffprobe)"
|
||||
obj = kbps_objetivo(f["ancho"] or 1920, f["alto"] or 1080, f["fps"], perfil)
|
||||
est = int(obj * 1000 / 8 * (f["dur"] or 0)) + int(256000 / 8 * (f["dur"] or 0))
|
||||
obj = int(kbps_objetivo(f["ancho"] or 1920, f["alto"] or 1080, f["fps"], perfil) * fm.get("bpp_mult", 1.0))
|
||||
est = estimar_bytes(f, perfil, formato)
|
||||
out.append({
|
||||
"ruta": f["ruta"], "rel": os.path.relpath(f["ruta"], raiz), "bytes": f["bytes"], "codec": f["codec"], "perfil": f["perfil"],
|
||||
"pix_fmt": f["pix_fmt"], "res": f"{f['ancho']}x{f['alto']}", "fps": f["fps"], "dur": f["dur"], "kbps": f["kbps"],
|
||||
@@ -1384,16 +1461,21 @@ def candidatos(raiz, meses, perfil, min_mb, incluir_exportados=False):
|
||||
return out
|
||||
|
||||
|
||||
def salida_para(ruta, raiz):
|
||||
def salida_para(ruta, raiz, formato="h265_10bit"):
|
||||
o = CONFIG["optimizar"]
|
||||
fm = FORMATOS.get(formato, FORMATOS["h265_10bit"])
|
||||
base, _ = os.path.splitext(ruta)
|
||||
sufijo = o.get("sufijo", "_10bit") if formato == "h265_10bit" else fm["sufijo"]
|
||||
if o.get("salida") == "espejo":
|
||||
rel = os.path.relpath(base, raiz)
|
||||
return os.path.join(raiz, "_Archivo", rel + ".mp4")
|
||||
return base + o.get("sufijo", "_10bit") + ".mp4"
|
||||
return os.path.join(raiz, "_Archivo", rel + fm["ext"])
|
||||
return base + sufijo + fm["ext"]
|
||||
|
||||
|
||||
def encolar(rutas, perfil, chroma, color, raiz):
|
||||
def encolar(rutas, perfil, chroma, color, raiz, formato="h265_10bit"):
|
||||
if formato not in FORMATOS:
|
||||
formato = "h265_10bit"
|
||||
fm = FORMATOS[formato]
|
||||
con = db()
|
||||
ids = []
|
||||
with con:
|
||||
@@ -1401,18 +1483,20 @@ def encolar(rutas, perfil, chroma, color, raiz):
|
||||
f = con.execute("SELECT * FROM archivos WHERE ruta = ?", (r,)).fetchone()
|
||||
if not f:
|
||||
continue
|
||||
ya = con.execute("SELECT id FROM trabajos WHERE ruta = ? AND estado IN ('pendiente','corriendo','listo','verificado')", (r,)).fetchone()
|
||||
ya = con.execute("SELECT id FROM trabajos WHERE ruta = ? AND formato = ? AND estado IN ('pendiente','corriendo','listo','verificado')", (r, formato)).fetchone()
|
||||
if ya:
|
||||
continue
|
||||
salida = salida_para(r, raiz)
|
||||
motor = "resolve" if f["ext"] == ".braw" else "ffmpeg"
|
||||
if motor == "resolve" and formato != "h265_10bit":
|
||||
continue # los BRAW solo salen por Resolve a H.265 10 bits
|
||||
salida = salida_para(r, raiz, formato)
|
||||
# el mismo clip en MP4 y MOV daría la misma salida: el segundo pisaría al primero. No se encola.
|
||||
otro = con.execute("SELECT id FROM trabajos WHERE salida = ? AND ruta != ? AND estado IN ('pendiente','corriendo','listo','verificado')", (salida, r)).fetchone()
|
||||
if otro or os.path.exists(salida):
|
||||
continue
|
||||
motor = "resolve" if f["ext"] == ".braw" else "ffmpeg"
|
||||
kb = kbps_objetivo(f["ancho"] or 1920, f["alto"] or 1080, f["fps"], perfil)
|
||||
cur = con.execute("INSERT INTO trabajos (ruta, salida, motor, perfil, chroma, color, kbps, estado, bytes_in, creado, raiz) VALUES (?,?,?,?,?,?,?,?,?,?,?)",
|
||||
(r, salida, motor, perfil, chroma, color, kb, "pendiente", f["bytes"], time.time(), raiz))
|
||||
kb = int(kbps_objetivo(f["ancho"] or 1920, f["alto"] or 1080, f["fps"], perfil) * fm.get("bpp_mult", 1.0))
|
||||
cur = con.execute("INSERT INTO trabajos (ruta, salida, motor, perfil, chroma, color, kbps, estado, bytes_in, creado, raiz, formato) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)",
|
||||
(r, salida, motor, perfil, chroma, color, kb, "pendiente", f["bytes"], time.time(), raiz, formato))
|
||||
ids.append(cur.lastrowid)
|
||||
con.close()
|
||||
return ids
|
||||
@@ -1440,18 +1524,45 @@ def correr_ffmpeg(t):
|
||||
cq = PERFILES.get(t["perfil"], PERFILES["equilibrado"])["cq"]
|
||||
maxrate = int(t["kbps"] * 1.8)
|
||||
salida = t["salida"]
|
||||
formato = (t["formato"] if "formato" in t.keys() else None) or "h265_10bit"
|
||||
fm = FORMATOS.get(formato, FORMATOS["h265_10bit"])
|
||||
motor = motores()["formatos"].get(formato)
|
||||
if not motor:
|
||||
set_trabajo(t["id"], estado="error", log=f"este ffmpeg no puede producir {fm['nombre']} (ni por GPU ni por CPU)")
|
||||
return
|
||||
os.makedirs(os.path.dirname(salida), exist_ok=True)
|
||||
tmp = salida + ".parcial.mp4"
|
||||
cmd = [ruta_herramienta("ffmpeg"), "-hide_banner", "-nostdin", "-y", "-i", t["ruta"], "-map", "0:v:0", "-map", "0:a?",
|
||||
"-c:v", "hevc_nvenc",
|
||||
"-pix_fmt", "p210le" if chroma == "422" else "p010le",
|
||||
"-profile:v", "rext" if chroma == "422" else "main10",
|
||||
"-preset", "p6", "-tune", "hq", "-rc", "vbr", "-cq", str(cq), "-b:v", "0",
|
||||
"-maxrate", f"{maxrate}k", "-bufsize", f"{maxrate * 2}k",
|
||||
"-spatial-aq", "1", "-temporal-aq", "1", "-aq-strength", "8", "-rc-lookahead", "32",
|
||||
"-bf", "3", "-b_ref_mode", "middle", "-g", str(int(round(fps * 2))),
|
||||
"-tag:v", "hvc1", "-map_metadata", "0", "-movflags", "+faststart"]
|
||||
if f and f["acodec"] == "aac":
|
||||
tmp = salida + ".parcial" + fm["ext"]
|
||||
gop = str(int(round(fps * 2)))
|
||||
cmd = [ruta_herramienta("ffmpeg"), "-hide_banner", "-nostdin", "-y", "-i", t["ruta"], "-map", "0:v:0", "-map", "0:a?"]
|
||||
if fm["codec"] == "prores":
|
||||
cmd += ["-c:v", "prores_ks", "-profile:v", str(fm["prores"]), "-pix_fmt", "yuv422p10le", "-vendor", "apl0", "-qscale:v", "9"]
|
||||
elif motor == "gpu":
|
||||
diez = fm["bits"] == 10
|
||||
cmd += ["-c:v", fm["gpu"],
|
||||
"-pix_fmt", ("p210le" if chroma == "422" else "p010le") if diez else "yuv420p",
|
||||
"-preset", "p6", "-tune", "hq", "-rc", "vbr", "-cq", str(cq), "-b:v", "0",
|
||||
"-maxrate", f"{maxrate}k", "-bufsize", f"{maxrate * 2}k",
|
||||
"-spatial-aq", "1", "-temporal-aq", "1", "-aq-strength", "8", "-rc-lookahead", "32",
|
||||
"-bf", "3", "-b_ref_mode", "middle", "-g", gop]
|
||||
if fm["codec"] == "hevc":
|
||||
cmd += ["-profile:v", ("rext" if chroma == "422" else "main10") if diez else "main", "-tag:v", "hvc1"]
|
||||
else:
|
||||
cmd += ["-profile:v", "high"]
|
||||
else:
|
||||
diez = fm["bits"] == 10
|
||||
cmd += ["-c:v", fm["cpu"], "-preset", "medium", "-crf", str(cq - 2),
|
||||
"-pix_fmt", ("yuv422p10le" if chroma == "422" else "yuv420p10le") if diez else "yuv420p",
|
||||
"-maxrate", f"{maxrate}k", "-bufsize", f"{maxrate * 2}k", "-g", gop]
|
||||
if fm["codec"] == "hevc":
|
||||
cmd += ["-tag:v", "hvc1"]
|
||||
if diez:
|
||||
cmd += ["-profile:v", "main422-10" if chroma == "422" else "main10"]
|
||||
cmd += ["-map_metadata", "0"]
|
||||
if fm["ext"] == ".mp4":
|
||||
cmd += ["-movflags", "+faststart"]
|
||||
if fm["codec"] == "prores":
|
||||
cmd += ["-c:a", "pcm_s16le"]
|
||||
elif f and f["acodec"] == "aac":
|
||||
cmd += ["-c:a", "copy"]
|
||||
else:
|
||||
cmd += ["-c:a", "aac", "-b:a", "320k"]
|
||||
@@ -1677,9 +1788,10 @@ def verificar(ids):
|
||||
problemas = []
|
||||
if dur_src and abs(info["dur"] - dur_src) > tol:
|
||||
problemas.append(f"duración {info['dur']:.2f}s vs original {dur_src:.2f}s")
|
||||
if info["codec"] != "hevc":
|
||||
problemas.append(f"códec {info['codec']}")
|
||||
if "10" not in info["pix_fmt"]:
|
||||
fm = FORMATOS.get((t["formato"] if "formato" in t.keys() else None) or "h265_10bit", FORMATOS["h265_10bit"])
|
||||
if info["codec"] != fm["codec"]:
|
||||
problemas.append(f"códec {info['codec']} (se esperaba {fm['codec']})")
|
||||
if fm["bits"] == 10 and "10" not in info["pix_fmt"]:
|
||||
problemas.append(f"no es 10 bits ({info['pix_fmt']})")
|
||||
if os.path.getsize(t["salida"]) < 100000:
|
||||
problemas.append("archivo demasiado pequeño")
|
||||
@@ -1704,6 +1816,9 @@ def reemplazar(ids):
|
||||
if not t or t["estado"] != "verificado":
|
||||
res.append({"id": id_, "ok": False, "motivo": "solo se reemplazan trabajos verificados"})
|
||||
continue
|
||||
if ((t["formato"] if "formato" in t.keys() else "") or "").startswith("prores"):
|
||||
res.append({"id": id_, "ok": False, "motivo": "ProRes es un formato de edición: queda junto al original, no lo reemplaza"})
|
||||
continue
|
||||
if not os.path.exists(t["salida"]) or os.path.getsize(t["salida"]) < 1024:
|
||||
res.append({"id": id_, "ok": False, "motivo": "el MP4 convertido ya no está donde se verificó; el original se queda"})
|
||||
set_trabajo(id_, estado="error", log="la salida verificada desapareció antes de reemplazar")
|
||||
@@ -2217,7 +2332,7 @@ def estado_general():
|
||||
"hechos": COLA["hechos"], "total": total_tanda, "inicio": COLA["inicio"]},
|
||||
"aplicando": APLICANDO, "asistente": asistente.ESTADO,
|
||||
"respaldo": {k: v for k, v in RESPALDO.items() if k != "errores"} | {"errores_n": len(RESPALDO.get("errores") or [])},
|
||||
"cubetas": R.CUBETAS, "tipos": R.TIPOS_CLIENTE, "perfiles": PERFILES, "plantillas": PLANTILLAS}
|
||||
"cubetas": R.CUBETAS, "tipos": R.TIPOS_CLIENTE, "perfiles": PERFILES, "formatos": {k: {"nombre": v["nombre"], "que": v["que"], "ext": v["ext"]} for k, v in FORMATOS.items()}, "plantillas": PLANTILLAS}
|
||||
|
||||
|
||||
def estado_carpeta(ruta):
|
||||
@@ -2387,7 +2502,9 @@ class Manejador(BaseHTTPRequestHandler):
|
||||
if ruta == "/api/optimizar/candidatos":
|
||||
o = CONFIG["optimizar"]
|
||||
return self._json({"candidatos": candidatos(os.path.normpath(q["raiz"]), q.get("meses", o["meses_minimos"]), q.get("perfil", o["perfil"]),
|
||||
q.get("min_mb", o["min_mb"]), q.get("exportados") == "1")})
|
||||
q.get("min_mb", o["min_mb"]), q.get("exportados") == "1", q.get("formato", o.get("formato", "h265_10bit")))})
|
||||
if ruta == "/api/optimizar/motores":
|
||||
return self._json(motores())
|
||||
if ruta == "/api/optimizar/cola":
|
||||
con = db()
|
||||
filas = [dict(r) for r in con.execute("SELECT * FROM trabajos ORDER BY id DESC LIMIT 500").fetchall()]
|
||||
@@ -2451,7 +2568,7 @@ class Manejador(BaseHTTPRequestHandler):
|
||||
return self._json({"ok": True})
|
||||
if ruta == "/api/config":
|
||||
# solo ajustes de uso; las rutas de herramientas y la URL de actualización se cambian a mano en config.json
|
||||
permitidas = {"optimizar": {"meses_minimos", "min_mb", "perfil", "chroma", "color", "salida", "sufijo"}, "respaldo": {"destino"}}
|
||||
permitidas = {"optimizar": {"meses_minimos", "min_mb", "perfil", "formato", "chroma", "color", "salida", "sufijo"}, "respaldo": {"destino"}}
|
||||
for k, v in d.items():
|
||||
if k in permitidas and isinstance(v, dict):
|
||||
CONFIG.setdefault(k, {}).update({kk: vv for kk, vv in v.items() if kk in permitidas[k]})
|
||||
@@ -2527,7 +2644,7 @@ class Manejador(BaseHTTPRequestHandler):
|
||||
return self._json({"lanzado": True})
|
||||
if ruta == "/api/optimizar/encolar":
|
||||
o = CONFIG["optimizar"]
|
||||
ids = encolar(d.get("rutas", []), d.get("perfil", o["perfil"]), d.get("chroma", o["chroma"]), d.get("color", o["color"]), os.path.normpath(d["raiz"]))
|
||||
ids = encolar(d.get("rutas", []), d.get("perfil", o["perfil"]), d.get("chroma", o["chroma"]), d.get("color", o["color"]), os.path.normpath(d["raiz"]), d.get("formato", o.get("formato", "h265_10bit")))
|
||||
if d.get("iniciar"):
|
||||
iniciar_cola()
|
||||
return self._json({"ids": ids})
|
||||
|
||||
Referencia en una nueva incidencia
Block a user