2.6.1: las actualizaciones automáticas, apagadas por defecto

El programa no sale a la red al arrancar salvo que alguien encienda el
interruptor en Ajustes. Hasta la 2.6.0 el actualizador escribía
«auto: true» él solo en config.json sin que nadie lo eligiera: al arrancar
se apaga; lo que se encienda desde Ajustes queda marcado como elegido y se
respeta.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Este commit está contenido en:
Labstream
2026-09-25 05:57:48 -05:00
padre 1151320bf2
commit bcaa80df12
Se han modificado 6 ficheros con 32 adiciones y 14 borrados

Ver fichero

@@ -568,6 +568,12 @@ manejador, la barra de tareas refleja escaneo, lectura de clips, cola, asistente
de versión con su tiempo estimado, y la estimación de ProRes (por tasa nominal) y la copia de audio 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. (`-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.
Probado el 9 sep 2026 sobre una copia de ensayo: plan → aplicar → deshacer → volver a aplicar deja el árbol 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ó 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: con Resolve Studio 21.1 pero no pudo abrir proyecto porque Resolve estaba en el Gestor de proyectos:

Ver fichero

@@ -45,7 +45,7 @@ RE_SHA = re.compile(r"^[0-9a-fA-F]{64}$")
def _cfg(): def _cfg():
c = O.CONFIG.setdefault("actualizaciones", {}) c = O.CONFIG.setdefault("actualizaciones", {})
c.setdefault("url", URL_DEFECTO) c.setdefault("url", URL_DEFECTO)
c.setdefault("auto", True) c.setdefault("auto", False) # apagado salvo que alguien lo encienda en Ajustes
return c return c

Ver fichero

@@ -1,19 +1,19 @@
{ {
"nombre": "OrganiLAB", "nombre": "OrganiLAB",
"version": "2.6.0", "version": "2.6.1",
"builtAt": "2026-09-25T01:54:23.000Z", "builtAt": "2026-09-25T02:11:07.000Z",
"archivo": "OrganizadorLabstream-portatil-2.6.0.zip", "archivo": "OrganizadorLabstream-portatil-2.6.1.zip",
"size": 198765260, "size": 198766191,
"sha256": "67efa6f70d9c13a6dc98251243af5802d65c912e456b45184adb967983604e44", "sha256": "8823149160b68f7c1bc4f0e70e66de05183a1df5373ddbbdba8b3ed9f473ad6d",
"app": { "app": {
"archivo": "OrganizadorLabstream-app-2.6.0.zip", "archivo": "OrganizadorLabstream-app-2.6.1.zip",
"size": 14945501, "size": 14946432,
"sha256": "aca84360a8b7918926c0cc47253407013ac3e142f93ba744f66d58173eb4df32", "sha256": "b86022cd0d5f6e5fa20c662f70107e5b8f23868c40db5106a7dabe2ac3aa9346",
"url": "/api/herramientas/OrganizadorLabstream-app-2.6.0.zip" "url": "/api/herramientas/OrganizadorLabstream-app-2.6.1.zip"
}, },
"notes": "", "notes": "",
"firma": { "firma": {
"alg": "rsa2048-pkcs1v15-sha256", "alg": "rsa2048-pkcs1v15-sha256",
"valor": "3b71582c420ab85f2650a008caa6e5977613bc836e45ec0240bd44228a06f111f8ff4d410ad903e65fbb2b654343ddf0260d7066d25655e49ef436e9077a392173978acd00617fbb675a317b9e055986777b5c4fd222fe4841df15b2dcef0aca409f39dc4416f59e747c7119577ea742a1cbd369206af33cd0e477875aafce48fff1ec1216d32d4547db50987bfb7ecb0f290c7154c1dbc5361a791cc21d6f9b65f5b05df3fcf8e8ba41f62e8efe0e584570ed3a6773e08363e460b46f46a138f20cdfb3ad21f13c2fad09bee5f18066390e8129f308ff477b82868b8b8d83e2c08a5a901a4a9fd355a5a8ba5526d24c4071222bf86b1dbfcd33ccc63adc6c7c" "valor": "982d481cefe1f7383ae6575c891644553beb64c11dd21cf6d37b951fedb10abc34f7d867f44eec4983f203ae0fdb45ee38b484b8afef8b41f621a3c5820cc643cc19eeb9b8c297ae43baf7ac44a913a962f1bc8b5efed189662e91685ad3a4689c4c0d23f6975e8ef2886c9d8126f4d5f8a64f822d891729661e793e962ab0a20fba68fe4f503462ae6d6d7bf2b5cb16abf2eac57b8026d61a84b09d12500c6b19e85fd22eddb13956e4d45a322cd96b0274791ba7e05488f297f955fc4af048a66a0efe376e8476366f506a46a8435373b799c46d4540ec2c9547f275b19287c04f10a8d44b05df6555678b46e99fb76d1b54e8da82433067dd787afda35fc8"
} }
} }

Ver fichero

@@ -37,7 +37,7 @@ import actualizador
asistente.O = sys.modules[__name__] asistente.O = sys.modules[__name__]
actualizador.O = sys.modules[__name__] actualizador.O = sys.modules[__name__]
VERSION = "2.6.0" VERSION = "2.6.1"
CONGELADO = getattr(sys, "frozen", False) 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 SIN_VENTANA = getattr(subprocess, "CREATE_NO_WINDOW", 0) # ffmpeg/ffprobe/net sin abrir consolas negras # empaquetado como .exe con PyInstaller
@@ -251,6 +251,11 @@ for k, v in R.DICCIONARIO_SEMILLA.items(): # palabras nuevas de la semilla, si
DICC["carpetas"].setdefault(k, v) DICC["carpetas"].setdefault(k, v)
guardar_json(DICC_PATH, DICC) guardar_json(DICC_PATH, DICC)
_act = CONFIG.get("actualizaciones")
if isinstance(_act, dict) and _act.get("auto") is True and not _act.get("elegido"):
_act["auto"] = False
guardar_json(CONFIG_PATH, CONFIG)
PLANTILLAS = cargar_json(PLANTILLAS_PATH, R.PLANTILLAS) PLANTILLAS = cargar_json(PLANTILLAS_PATH, R.PLANTILLAS)
for t, d in R.PLANTILLAS.items(): for t, d in R.PLANTILLAS.items():
PLANTILLAS.setdefault(t, d) PLANTILLAS.setdefault(t, d)
@@ -3942,6 +3947,8 @@ class Manejador(BaseHTTPRequestHandler):
for k, v in d.items(): for k, v in d.items():
if k in permitidas and isinstance(v, dict): 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]}) CONFIG.setdefault(k, {}).update({kk: vv for kk, vv in v.items() if kk in permitidas[k]})
if isinstance(d.get("actualizaciones"), dict) and "auto" in d["actualizaciones"]:
CONFIG["actualizaciones"]["elegido"] = True # lo decidió una persona, no un valor por defecto
guardar_json(CONFIG_PATH, CONFIG) guardar_json(CONFIG_PATH, CONFIG)
return self._json({"ok": True, "config": CONFIG}) return self._json({"ok": True, "config": CONFIG})
if ruta == "/api/diccionario": if ruta == "/api/diccionario":
@@ -4417,7 +4424,7 @@ def main():
url = f"http://127.0.0.1:{PUERTO}/" url = f"http://127.0.0.1:{PUERTO}/"
if sys.stdout: if sys.stdout:
print(f"OrganiLAB {VERSION} en {url} (Ctrl+C para cerrar)") print(f"OrganiLAB {VERSION} en {url} (Ctrl+C para cerrar)")
if CONGELADO and CONFIG.get("actualizaciones", {}).get("auto", True): if CONGELADO and CONFIG.get("actualizaciones", {}).get("auto") is True:
actualizador.comprobar_en_segundo_plano() actualizador.comprobar_en_segundo_plano()
if "--sin-navegador" in sys.argv: # solo el servidor (desarrollo / vista previa) if "--sin-navegador" in sys.argv: # solo el servidor (desarrollo / vista previa)
try: try:

Ver fichero

@@ -364,6 +364,11 @@ class Servidor(unittest.TestCase):
self.assertEqual(c, 200) self.assertEqual(c, 200)
self.assertEqual(self.get("/api/estado")["raices"], []) self.assertEqual(self.get("/api/estado")["raices"], [])
self.assertEqual(self.post("/api/raiz/quitar", {"raiz": self.raiz})[0], 409) self.assertEqual(self.post("/api/raiz/quitar", {"raiz": self.raiz})[0], 409)
# 6. actualizaciones automáticas: apagadas por defecto; encenderlas deja constancia de que fue a mano
act = self.get("/api/estado")["config"].get("actualizaciones") or {}
self.assertIsNot(act.get("auto"), True)
c, r = self.post("/api/config", {"actualizaciones": {"auto": True}})
self.assertTrue(r["config"]["actualizaciones"]["auto"] and r["config"]["actualizaciones"]["elegido"])
if __name__ == "__main__": if __name__ == "__main__":

Ver fichero

@@ -1247,7 +1247,7 @@ $('#bitSoloRaiz').onchange = () => cargarBit().catch(e => aviso(e.message, 'bad'
let AJ = null, CLI_ABIERTO = null; let AJ = null, CLI_ABIERTO = null;
function pintarAjustes(){ function pintarAjustes(){
const ac = $('#actAuto'); const ac = $('#actAuto');
ac.checked = (ESTADO.config.actualizaciones || {}).auto !== false; ac.checked = (ESTADO.config.actualizaciones || {}).auto === true;
ac.onchange = () => api('/api/config', {actualizaciones: {auto: ac.checked}}).then(cargarEstado).then(() => aviso(ac.checked ? 'Al arrancar consultará si hay versión nueva.' : 'Ya no sale a la red al arrancar.', 'ok')).catch(e => aviso(e.message, 'bad')); ac.onchange = () => api('/api/config', {actualizaciones: {auto: ac.checked}}).then(cargarEstado).then(() => aviso(ac.checked ? 'Al arrancar consultará si hay versión nueva.' : 'Ya no sale a la red al arrancar.', 'ok')).catch(e => aviso(e.message, 'bad'));
if (!AJ) { if (!AJ) {
const c = ESTADO.config; AJ = {clientes: []}; const c = ESTADO.config; AJ = {clientes: []};