Skip to content

Commit 243a415

Browse files
committed
v1.6.14
1 parent ad266cd commit 243a415

File tree

3 files changed

+141
-9
lines changed

3 files changed

+141
-9
lines changed

config_manager.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,125 @@ def verify_safe_password(password):
7474

7575
input_hash = hashlib.sha256(password.encode('utf-8')).hexdigest()
7676
return input_hash == stored_hash
77+
import json
78+
import os
79+
import shutil
80+
81+
# Nombre del archivo de configuración
82+
CONFIG_FILENAME = "visagevault_config.json"
83+
84+
def get_config_path():
85+
"""
86+
Calcula la ruta del archivo de configuración siguiendo estándares.
87+
Prioridad:
88+
1. Carpeta local (si es portable/desarrollo).
89+
2. ~/.config/visagevault/ (si está instalado en Linux).
90+
"""
91+
base_dir = os.path.dirname(os.path.abspath(__file__))
92+
93+
# 1. MODO PORTABLE / DESARROLLO (Windows o ejecución local)
94+
# Si tenemos permiso de escritura en la carpeta del script, usamos esa.
95+
if os.access(base_dir, os.W_OK):
96+
return os.path.join(base_dir, CONFIG_FILENAME)
97+
98+
# 2. MODO INSTALADO (Linux / AUR / /usr/share)
99+
# Usamos el estándar XDG: ~/.config/visagevault/
100+
user_home = os.path.expanduser("~")
101+
config_dir = os.path.join(user_home, ".config", "visagevault")
102+
103+
# Crear la carpeta si no existe
104+
if not os.path.exists(config_dir):
105+
try:
106+
os.makedirs(config_dir, exist_ok=True)
107+
except OSError:
108+
# Fallback extremo: volver a home si falla crear .config
109+
return os.path.join(user_home, CONFIG_FILENAME)
110+
111+
target_config = os.path.join(config_dir, CONFIG_FILENAME)
112+
113+
# --- MIGRACIÓN AUTOMÁTICA ---
114+
# Si existe el archivo viejo en la raíz (~/visagevault_config.json)
115+
# y no existe el nuevo, lo movemos para no perder datos.
116+
old_config_path = os.path.join(user_home, CONFIG_FILENAME)
117+
if os.path.exists(old_config_path) and not os.path.exists(target_config):
118+
try:
119+
shutil.move(old_config_path, target_config)
120+
print(f"Configuración migrada de {old_config_path} a {target_config}")
121+
except Exception as e:
122+
print(f"Error migrando configuración: {e}")
123+
124+
return target_config
125+
126+
def load_config():
127+
config_path = get_config_path()
128+
if not os.path.exists(config_path):
129+
return {}
130+
try:
131+
with open(config_path, 'r') as f:
132+
return json.load(f)
133+
except (json.JSONDecodeError, IOError):
134+
return {}
135+
136+
def save_config(config_data):
137+
config_path = get_config_path()
138+
try:
139+
with open(config_path, 'w') as f:
140+
json.dump(config_data, f, indent=4)
141+
except IOError as e:
142+
print(f"Error guardando configuración en {config_path}: {e}")
143+
144+
# --- GETTERS Y SETTERS ESPECÍFICOS ---
145+
146+
def get_photo_directory():
147+
config = load_config()
148+
return config.get('photo_directory', "")
149+
150+
def set_photo_directory(path):
151+
config = load_config()
152+
config['photo_directory'] = path
153+
save_config(config)
154+
155+
def get_thumbnail_size():
156+
config = load_config()
157+
# Tamaño por defecto 128 si no existe
158+
return config.get('thumbnail_size', 128)
159+
160+
def set_thumbnail_size(size):
161+
config = load_config()
162+
config['thumbnail_size'] = size
163+
save_config(config)
164+
165+
def get_drive_folder_id():
166+
config = load_config()
167+
return config.get('drive_folder_id', None)
168+
169+
def set_drive_folder_id(folder_id):
170+
config = load_config()
171+
config['drive_folder_id'] = folder_id
172+
save_config(config)
173+
174+
# --- SEGURIDAD CAJA FUERTE ---
175+
176+
def get_safe_password_hash():
177+
config = load_config()
178+
return config.get('safe_password_hash', None)
179+
180+
def set_safe_password_hash(password_plain):
181+
import hashlib
182+
# Guardamos solo el hash SHA256, nunca la contraseña plana
183+
hash_object = hashlib.sha256(password_plain.encode())
184+
hex_dig = hash_object.hexdigest()
185+
186+
config = load_config()
187+
config['safe_password_hash'] = hex_dig
188+
save_config(config)
189+
190+
def verify_safe_password(password_plain):
191+
import hashlib
192+
stored_hash = get_safe_password_hash()
193+
if not stored_hash: return False
194+
195+
hash_object = hashlib.sha256(password_plain.encode())
196+
hex_dig = hash_object.hexdigest()
197+
198+
return hex_dig == stored_hash

drive_auth.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,11 @@ def get_service(self, silent=False):
6262
return build('drive', 'v3', credentials=self.creds)
6363

6464
def _perform_login(self):
65-
# Comprobación de seguridad por si olvidamos inyectar las claves
66-
if "BUILD_TIME" in self.CLIENT_CONFIG["installed"]["client_id"]:
67-
raise ValueError("Error: Las credenciales de Google no se inyectaron durante la compilación.")
65+
"""Login usando el diccionario incrustado en lugar de un archivo."""
6866

69-
flow = InstalledAppFlow.from_client_config(self.CLIENT_CONFIG, self.SCOPES)
67+
flow = InstalledAppFlow.from_client_config(
68+
self.CLIENT_CONFIG, self.SCOPES
69+
)
7070
self.creds = flow.run_local_server(port=0)
7171

7272
def has_credentials(self):

visagevault.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# ==============================================================================
22
# PROYECTO: VisageVault - Gestor de Fotografías Inteligente
3-
# VERSIÓN: 1.6.13
3+
# VERSIÓN: 1.6.14
44
# DERECHOS DE AUTOR: © 2025 Daniel Serrano Armenta
55
# ==============================================================================
66
#
@@ -676,7 +676,7 @@ def run(self):
676676
local_db.conn.close()
677677

678678
# =================================================================
679-
# CLASE OPTIMIZADA: CARGA DE CARAS CON CACHÉ DE DISCO
679+
# CLASE: FaceLoader (CORREGIDA PARA RUTAS LINUX)
680680
# =================================================================
681681
class FaceLoader(QRunnable):
682682
def __init__(self, signals: FaceLoaderSignals, face_id: int, photo_path: str, location_str: str):
@@ -685,12 +685,22 @@ def __init__(self, signals: FaceLoaderSignals, face_id: int, photo_path: str, lo
685685
self.face_id = face_id
686686
self.photo_path = photo_path
687687
self.location_str = location_str
688+
689+
# --- CORRECCIÓN DE RUTA ---
690+
# Detectar si estamos en modo sistema (Linux instalado) o portable
688691
base_dir = os.path.dirname(os.path.abspath(__file__))
689-
# visagevault_cache/face_cache
690-
self.cache_dir = os.path.join(base_dir, "visagevault_cache", "face_cache")
692+
693+
if os.access(base_dir, os.W_OK):
694+
# Modo Desarrollo / Windows
695+
self.cache_dir = os.path.join(base_dir, "visagevault_cache", "face_cache")
696+
else:
697+
# Modo Linux Instalado (AUR) -> Usar ~/.cache
698+
user_home = os.path.expanduser("~")
699+
self.cache_dir = os.path.join(user_home, ".cache", "visagevault", "face_cache")
700+
# --------------------------
691701

692702
if not os.path.exists(self.cache_dir):
693-
try: os.makedirs(self.cache_dir)
703+
try: os.makedirs(self.cache_dir, exist_ok=True)
694704
except: pass
695705

696706
self.cache_path = os.path.join(self.cache_dir, f"face_{self.face_id}.jpg")

0 commit comments

Comments
 (0)