salida en app v3
This commit is contained in:
@@ -27,7 +27,6 @@
|
|||||||
"msx",
|
"msx",
|
||||||
"msx2",
|
"msx2",
|
||||||
"n64",
|
"n64",
|
||||||
"nds",
|
|
||||||
"neogeo",
|
"neogeo",
|
||||||
"neogeocd",
|
"neogeocd",
|
||||||
"nes",
|
"nes",
|
||||||
@@ -35,7 +34,6 @@
|
|||||||
"ngpc",
|
"ngpc",
|
||||||
"pcengine",
|
"pcengine",
|
||||||
"pcenginecd",
|
"pcenginecd",
|
||||||
"psp",
|
|
||||||
"psx",
|
"psx",
|
||||||
"satellaview",
|
"satellaview",
|
||||||
"saturn",
|
"saturn",
|
||||||
|
|||||||
+113
-47
@@ -13,7 +13,7 @@ class DirectorySelectorApp:
|
|||||||
def __init__(self, root):
|
def __init__(self, root):
|
||||||
self.root = root
|
self.root = root
|
||||||
self.root.title("Selector de Directorios ES-DE / ROMs")
|
self.root.title("Selector de Directorios ES-DE / ROMs")
|
||||||
self.root.geometry("700x650")
|
self.root.geometry("700x700")
|
||||||
|
|
||||||
# Variables de rutas
|
# Variables de rutas
|
||||||
self.path_esde_src = tk.StringVar()
|
self.path_esde_src = tk.StringVar()
|
||||||
@@ -34,7 +34,7 @@ class DirectorySelectorApp:
|
|||||||
# ---------------------------
|
# ---------------------------
|
||||||
tk.Label(root, text="Directorios encontrados en ROMs:", font=("Arial", 11)).pack(pady=(15, 5))
|
tk.Label(root, text="Directorios encontrados en ROMs:", font=("Arial", 11)).pack(pady=(15, 5))
|
||||||
|
|
||||||
self.listbox = tk.Listbox(root, selectmode=tk.MULTIPLE, height=15)
|
self.listbox = tk.Listbox(root, selectmode=tk.MULTIPLE, height=10)
|
||||||
self.listbox.pack(fill="both", expand=True, padx=10)
|
self.listbox.pack(fill="both", expand=True, padx=10)
|
||||||
|
|
||||||
# ---------------------------
|
# ---------------------------
|
||||||
@@ -52,12 +52,33 @@ class DirectorySelectorApp:
|
|||||||
command=self.run_robocopy).pack(pady=10)
|
command=self.run_robocopy).pack(pady=10)
|
||||||
|
|
||||||
# ---------------------------
|
# ---------------------------
|
||||||
# PANEL DE LOG
|
# LABELS DE ESTADO
|
||||||
# ---------------------------
|
# ---------------------------
|
||||||
tk.Label(root, text="Progreso:", font=("Arial", 11)).pack(pady=(5, 0))
|
status_frame = tk.Frame(root, bg="#2a2a2a", relief="sunken", bd=2)
|
||||||
|
status_frame.pack(fill="x", padx=10, pady=5)
|
||||||
|
|
||||||
self.log = tk.Text(root, height=10, state="disabled", bg="#111", fg="#0f0")
|
self.label_system = tk.Label(status_frame, text="Sistema: -",
|
||||||
self.log.pack(fill="both", expand=False, padx=10, pady=5)
|
font=("Arial", 10, "bold"),
|
||||||
|
bg="#2a2a2a", fg="#00ff00", anchor="w")
|
||||||
|
self.label_system.pack(fill="x", padx=10, pady=3)
|
||||||
|
|
||||||
|
self.label_phase = tk.Label(status_frame, text="Fase: -",
|
||||||
|
font=("Arial", 10),
|
||||||
|
bg="#2a2a2a", fg="#00aaff", anchor="w")
|
||||||
|
self.label_phase.pack(fill="x", padx=10, pady=3)
|
||||||
|
|
||||||
|
self.label_current = tk.Label(status_frame, text="Archivo: -",
|
||||||
|
font=("Arial", 9),
|
||||||
|
bg="#2a2a2a", fg="#ffaa00", anchor="w")
|
||||||
|
self.label_current.pack(fill="x", padx=10, pady=3)
|
||||||
|
|
||||||
|
# ---------------------------
|
||||||
|
# RESUMEN
|
||||||
|
# ---------------------------
|
||||||
|
tk.Label(root, text="Resumen:", font=("Arial", 11)).pack(pady=(10, 5))
|
||||||
|
|
||||||
|
self.summary_text = tk.Text(root, height=6, state="disabled", bg="#f0f0f0", fg="#000")
|
||||||
|
self.summary_text.pack(fill="both", expand=False, padx=10, pady=5)
|
||||||
|
|
||||||
# Evento de cierre
|
# Evento de cierre
|
||||||
self.root.protocol("WM_DELETE_WINDOW", self.on_close)
|
self.root.protocol("WM_DELETE_WINDOW", self.on_close)
|
||||||
@@ -105,13 +126,33 @@ class DirectorySelectorApp:
|
|||||||
messagebox.showerror("Error", f"No se pudo leer la ruta:\n{e}")
|
messagebox.showerror("Error", f"No se pudo leer la ruta:\n{e}")
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
# LOG
|
# ACTUALIZACIÓN DE LABELS Y RESUMEN
|
||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
def append_log(self, text):
|
def append_summary(self, text):
|
||||||
self.log.configure(state="normal")
|
self.summary_text.configure(state="normal")
|
||||||
self.log.insert(tk.END, text + "\n")
|
self.summary_text.insert(tk.END, text + "\n")
|
||||||
self.log.see(tk.END)
|
self.summary_text.see(tk.END)
|
||||||
self.log.configure(state="disabled")
|
self.summary_text.configure(state="disabled")
|
||||||
|
|
||||||
|
def clear_summary(self):
|
||||||
|
self.summary_text.configure(state="normal")
|
||||||
|
self.summary_text.delete(1.0, tk.END)
|
||||||
|
self.summary_text.configure(state="disabled")
|
||||||
|
|
||||||
|
def update_status_system(self, text):
|
||||||
|
self.label_system.config(text=text)
|
||||||
|
self.root.update_idletasks()
|
||||||
|
|
||||||
|
def update_status_phase(self, text):
|
||||||
|
self.label_phase.config(text=text)
|
||||||
|
self.root.update_idletasks()
|
||||||
|
|
||||||
|
def update_status_current(self, text):
|
||||||
|
# Limitar longitud para que no se salga de la ventana
|
||||||
|
if len(text) > 80:
|
||||||
|
text = "..." + text[-77:]
|
||||||
|
self.label_current.config(text=text)
|
||||||
|
self.root.update_idletasks()
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
# EJECUTAR ROBOCOPY (HILO)
|
# EJECUTAR ROBOCOPY (HILO)
|
||||||
@@ -125,7 +166,7 @@ class DirectorySelectorApp:
|
|||||||
selected = [self.listbox.get(i) for i in self.listbox.curselection()]
|
selected = [self.listbox.get(i) for i in self.listbox.curselection()]
|
||||||
|
|
||||||
if not selected:
|
if not selected:
|
||||||
self.append_log("❌ No hay sistemas seleccionados.")
|
self.append_summary("❌ No hay sistemas seleccionados.")
|
||||||
return
|
return
|
||||||
|
|
||||||
esde_src = self.path_esde_src.get()
|
esde_src = self.path_esde_src.get()
|
||||||
@@ -134,54 +175,68 @@ class DirectorySelectorApp:
|
|||||||
roms_dst = self.path_roms_dst.get()
|
roms_dst = self.path_roms_dst.get()
|
||||||
|
|
||||||
if not all([esde_src, roms_src, esde_dst, roms_dst]):
|
if not all([esde_src, roms_src, esde_dst, roms_dst]):
|
||||||
self.append_log("❌ ERROR: Debes configurar todas las rutas antes de continuar.")
|
self.append_summary("❌ ERROR: Debes configurar todas las rutas antes de continuar.")
|
||||||
return
|
return
|
||||||
|
|
||||||
self.append_log("=" * 60)
|
self.clear_summary()
|
||||||
self.append_log("🚀 INICIANDO PROCESO DE COPIA")
|
self.append_summary("=" * 60)
|
||||||
self.append_log(f"📦 Total de sistemas a procesar: {len(selected)}")
|
self.append_summary("🚀 INICIANDO PROCESO DE COPIA")
|
||||||
self.append_log("=" * 60)
|
self.append_summary(f"📦 Total de sistemas a procesar: {len(selected)}")
|
||||||
|
self.append_summary("=" * 60)
|
||||||
|
|
||||||
|
total_systems = len(selected)
|
||||||
|
|
||||||
for idx, system in enumerate(selected, 1):
|
for idx, system in enumerate(selected, 1):
|
||||||
self.append_log(f"\n{'=' * 60}")
|
# Actualizar label de sistema
|
||||||
self.append_log(f"🎮 SISTEMA [{idx}/{len(selected)}]: {system.upper()}")
|
self.update_status_system(f"Sistema: {idx}/{total_systems} - {system.upper()}")
|
||||||
self.append_log("=" * 60)
|
|
||||||
|
self.append_summary(f"\n🎮 SISTEMA [{idx}/{total_systems}]: {system.upper()}")
|
||||||
|
|
||||||
# ROMs
|
# ROMs
|
||||||
self.append_log(f"\n📁 [1/3] Copiando ROMs...")
|
self.update_status_phase("Fase: [1/3] Copiando ROMs...")
|
||||||
|
self.append_summary(" 📁 [1/3] Copiando ROMs...")
|
||||||
self.launch_robocopy_with_log(
|
self.launch_robocopy_with_log(
|
||||||
os.path.join(roms_src, system),
|
os.path.join(roms_src, system),
|
||||||
os.path.join(roms_dst, system)
|
os.path.join(roms_dst, system)
|
||||||
)
|
)
|
||||||
|
|
||||||
# ES-DE gamelists
|
# ES-DE gamelists
|
||||||
self.append_log(f"\n📋 [2/3] Copiando gamelists...")
|
self.update_status_phase("Fase: [2/3] Copiando gamelists...")
|
||||||
|
self.append_summary(" 📋 [2/3] Copiando gamelists...")
|
||||||
self.launch_robocopy_with_log(
|
self.launch_robocopy_with_log(
|
||||||
os.path.join(esde_src, "gamelists", system),
|
os.path.join(esde_src, "gamelists", system),
|
||||||
os.path.join(esde_dst, "gamelists", system)
|
os.path.join(esde_dst, "gamelists", system)
|
||||||
)
|
)
|
||||||
|
|
||||||
# ES-DE downloaded_media
|
# ES-DE downloaded_media
|
||||||
self.append_log(f"\n🖼️ [3/3] Copiando media...")
|
self.update_status_phase("Fase: [3/3] Copiando media...")
|
||||||
|
self.append_summary(" 🖼️ [3/3] Copiando media...")
|
||||||
self.launch_robocopy_with_log(
|
self.launch_robocopy_with_log(
|
||||||
os.path.join(esde_src, "downloaded_media", system),
|
os.path.join(esde_src, "downloaded_media", system),
|
||||||
os.path.join(esde_dst, "downloaded_media", system)
|
os.path.join(esde_dst, "downloaded_media", system)
|
||||||
)
|
)
|
||||||
|
|
||||||
self.append_log(f"\n✅ Sistema '{system}' completado")
|
self.append_summary(f" ✅ Sistema '{system}' completado\n")
|
||||||
|
|
||||||
self.append_log("\n" + "=" * 60)
|
# Limpiar labels al finalizar
|
||||||
self.append_log("🎉 PROCESO COMPLETADO EXITOSAMENTE")
|
self.update_status_system("Sistema: ✅ COMPLETADO")
|
||||||
self.append_log("=" * 60)
|
self.update_status_phase("Fase: -")
|
||||||
|
self.update_status_current("Archivo: -")
|
||||||
|
|
||||||
|
self.append_summary("=" * 60)
|
||||||
|
self.append_summary("🎉 PROCESO COMPLETADO EXITOSAMENTE")
|
||||||
|
self.append_summary("=" * 60)
|
||||||
|
|
||||||
def launch_robocopy_with_log(self, src, dst):
|
def launch_robocopy_with_log(self, src, dst):
|
||||||
if not os.path.isdir(src):
|
if not os.path.isdir(src):
|
||||||
self.append_log(f" ⚠️ Carpeta no existe (omitido): {os.path.basename(src)}")
|
self.append_summary(f" ⚠️ Carpeta no existe (omitido)")
|
||||||
|
self.update_status_current("Archivo: (carpeta no existe)")
|
||||||
return
|
return
|
||||||
|
|
||||||
os.makedirs(dst, exist_ok=True)
|
os.makedirs(dst, exist_ok=True)
|
||||||
|
|
||||||
cmd = ["robocopy", src, dst, "/MIR", "/NP", "/NDL", "/NFL"]
|
# Quitar /NFL y /NDL para ver los archivos en tiempo real
|
||||||
|
cmd = ["robocopy", src, dst, "/MIR", "/NP"]
|
||||||
|
|
||||||
process = subprocess.Popen(
|
process = subprocess.Popen(
|
||||||
cmd,
|
cmd,
|
||||||
@@ -199,39 +254,48 @@ class DirectorySelectorApp:
|
|||||||
for line in process.stdout:
|
for line in process.stdout:
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
|
|
||||||
|
# Actualizar label con el archivo actual
|
||||||
|
if line and not line.startswith("---") and not line.startswith("Total"):
|
||||||
|
# Si la línea parece un archivo siendo copiado
|
||||||
|
if len(line) > 5 and not any(x in line for x in ["Files :", "Dirs :", "Bytes :", "Speed :", "Times :"]):
|
||||||
|
self.update_status_current(f"Archivo: {line}")
|
||||||
|
|
||||||
# Extraer información relevante del output de robocopy
|
# Extraer información relevante del output de robocopy
|
||||||
if "Files :" in line and "Copied" in line:
|
if "Files :" in line:
|
||||||
parts = line.split()
|
parts = line.split()
|
||||||
try:
|
try:
|
||||||
copied_idx = parts.index("Copied")
|
total_idx = parts.index("Files")
|
||||||
if copied_idx + 1 < len(parts):
|
if total_idx + 2 < len(parts):
|
||||||
files_copied = int(parts[copied_idx + 1])
|
files_copied = int(parts[total_idx + 2])
|
||||||
except (ValueError, IndexError):
|
except (ValueError, IndexError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
elif "Dirs :" in line and "Copied" in line:
|
elif "Dirs :" in line:
|
||||||
parts = line.split()
|
parts = line.split()
|
||||||
try:
|
try:
|
||||||
copied_idx = parts.index("Copied")
|
total_idx = parts.index("Dirs")
|
||||||
if copied_idx + 1 < len(parts):
|
if total_idx + 2 < len(parts):
|
||||||
dirs_copied = int(parts[copied_idx + 1])
|
dirs_copied = int(parts[total_idx + 2])
|
||||||
except (ValueError, IndexError):
|
except (ValueError, IndexError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
elif "Bytes :" in line and "Copied" in line:
|
elif "Bytes :" in line:
|
||||||
parts = line.split()
|
parts = line.split()
|
||||||
try:
|
try:
|
||||||
copied_idx = parts.index("Copied")
|
bytes_idx = parts.index("Bytes")
|
||||||
if copied_idx + 1 < len(parts):
|
if bytes_idx + 2 < len(parts):
|
||||||
bytes_str = parts[copied_idx + 1].replace(",", "")
|
bytes_str = parts[bytes_idx + 2].replace(",", "").replace(".", "")
|
||||||
total_bytes = int(bytes_str)
|
# Extraer solo números
|
||||||
|
bytes_str = ''.join(c for c in bytes_str if c.isdigit())
|
||||||
|
if bytes_str:
|
||||||
|
total_bytes = int(bytes_str)
|
||||||
except (ValueError, IndexError):
|
except (ValueError, IndexError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
process.wait()
|
process.wait()
|
||||||
|
|
||||||
# Convertir bytes a formato legible
|
# Convertir bytes a formato legible
|
||||||
if total_bytes > 0:
|
if files_copied > 0 or dirs_copied > 0:
|
||||||
if total_bytes < 1024:
|
if total_bytes < 1024:
|
||||||
size_str = f"{total_bytes} B"
|
size_str = f"{total_bytes} B"
|
||||||
elif total_bytes < 1024**2:
|
elif total_bytes < 1024**2:
|
||||||
@@ -241,9 +305,11 @@ class DirectorySelectorApp:
|
|||||||
else:
|
else:
|
||||||
size_str = f"{total_bytes/(1024**3):.2f} GB"
|
size_str = f"{total_bytes/(1024**3):.2f} GB"
|
||||||
|
|
||||||
self.append_log(f" ✓ {files_copied} archivos, {dirs_copied} carpetas ({size_str})")
|
self.append_summary(f" ✓ {files_copied} archivos, {dirs_copied} carpetas ({size_str})")
|
||||||
else:
|
else:
|
||||||
self.append_log(f" ✓ Sin cambios (ya sincronizado)")
|
self.append_summary(f" ✓ Sin cambios (ya sincronizado)")
|
||||||
|
|
||||||
|
self.update_status_current("Archivo: -")
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
# PERSISTENCIA
|
# PERSISTENCIA
|
||||||
@@ -298,4 +364,4 @@ class DirectorySelectorApp:
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
root = tk.Tk()
|
root = tk.Tk()
|
||||||
app = DirectorySelectorApp(root)
|
app = DirectorySelectorApp(root)
|
||||||
root.mainloop()
|
root.mainloop()
|
||||||
Reference in New Issue
Block a user