Insta geht wieder, wegen dem Domain Umzug
Dieser Commit ist enthalten in:
@ -1,13 +1,18 @@
|
|||||||
{
|
{
|
||||||
"permissions": {
|
"permissions": {
|
||||||
"allow": [
|
"allow": [
|
||||||
"Bash(python3:*)"
|
"Bash(python3:*)",
|
||||||
|
"Bash(tree:*)",
|
||||||
|
"Bash(git -C /mnt/a/GiTea/AccountForger log --oneline)",
|
||||||
|
"Bash(cat:*)",
|
||||||
|
"Bash(sqlite3:*)",
|
||||||
|
"Bash(find:*)"
|
||||||
],
|
],
|
||||||
"deny": [],
|
"deny": [],
|
||||||
|
"ask": [],
|
||||||
"defaultMode": "acceptEdits",
|
"defaultMode": "acceptEdits",
|
||||||
"additionalDirectories": [
|
"additionalDirectories": [
|
||||||
"/mnt/a/GiTea/Styleguide"
|
"/mnt/a/GiTea/Styleguide"
|
||||||
],
|
]
|
||||||
"ask": []
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,9 +5,9 @@
|
|||||||
## Project Overview
|
## Project Overview
|
||||||
|
|
||||||
- **Path**: `A:\GiTea\AccountForger`
|
- **Path**: `A:\GiTea\AccountForger`
|
||||||
- **Files**: 1393 files
|
- **Files**: 1394 files
|
||||||
- **Size**: 257.7 MB
|
- **Size**: 257.7 MB
|
||||||
- **Last Modified**: 2025-11-16 22:31
|
- **Last Modified**: 2025-11-27 19:34
|
||||||
|
|
||||||
## Technology Stack
|
## Technology Stack
|
||||||
|
|
||||||
@ -21,13 +21,13 @@
|
|||||||
|
|
||||||
```
|
```
|
||||||
check_rotation_system.py
|
check_rotation_system.py
|
||||||
|
CLAUDE.md
|
||||||
CLAUDE_PROJECT_README.md
|
CLAUDE_PROJECT_README.md
|
||||||
debug_video_issue.py
|
debug_video_issue.py
|
||||||
init
|
init
|
||||||
install_requirements.py
|
install_requirements.py
|
||||||
main.py
|
main.py
|
||||||
package.json
|
package.json
|
||||||
README.md
|
|
||||||
application/
|
application/
|
||||||
│ ├── __init__.py
|
│ ├── __init__.py
|
||||||
│ ├── services/
|
│ ├── services/
|
||||||
@ -436,3 +436,6 @@ This project is managed with Claude Project Manager. To work with this project:
|
|||||||
- README updated on 2025-11-09 21:00:06
|
- README updated on 2025-11-09 21:00:06
|
||||||
- README updated on 2025-11-16 22:31:39
|
- README updated on 2025-11-16 22:31:39
|
||||||
- README updated on 2025-11-16 22:32:35
|
- README updated on 2025-11-16 22:32:35
|
||||||
|
- README updated on 2025-11-27 19:33:36
|
||||||
|
- README updated on 2025-11-27 19:34:18
|
||||||
|
- README updated on 2025-11-27 19:41:04
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"imap_server": "imap.ionos.de",
|
"imap_server": "imap.ionos.de",
|
||||||
"imap_port": 993,
|
"imap_port": 993,
|
||||||
"imap_user": "info@z5m7q9dk3ah2v1plx6ju.com",
|
"imap_user": "info@z5m7q9dk3ah2v1plx6ju.com",
|
||||||
"imap_pass": "GZsg9:66@a@M%etP"
|
"imap_pass": "GZsg9:66@a@M%etP"
|
||||||
}
|
}
|
||||||
@ -277,6 +277,37 @@ class BasePlatformController(QObject):
|
|||||||
"""
|
"""
|
||||||
generator_tab = self.get_generator_tab()
|
generator_tab = self.get_generator_tab()
|
||||||
generator_tab.set_running(False)
|
generator_tab.set_running(False)
|
||||||
|
|
||||||
# Standard-Implementierung - kann von Unterklassen erweitert werden
|
# Standard-Implementierung - kann von Unterklassen erweitert werden
|
||||||
self.logger.info(f"Account erfolgreich erstellt für {self.platform_name}")
|
self.logger.info(f"Account erfolgreich erstellt für {self.platform_name}")
|
||||||
|
|
||||||
|
def stop_account_creation(self):
|
||||||
|
"""
|
||||||
|
Stoppt die Account-Erstellung (Default-Implementierung).
|
||||||
|
|
||||||
|
Diese Methode kann von Unterklassen überschrieben werden für spezielle Anforderungen.
|
||||||
|
Sie stellt sicher dass:
|
||||||
|
1. Der Process Guard freigegeben wird
|
||||||
|
2. Der Worker-Thread gestoppt wird
|
||||||
|
3. Die UI zurückgesetzt wird
|
||||||
|
4. Dialoge geschlossen werden
|
||||||
|
"""
|
||||||
|
# Guard-Freigabe (wichtig: VOR Worker-Stop)
|
||||||
|
from utils.process_guard import get_guard
|
||||||
|
guard = get_guard()
|
||||||
|
if guard.is_locked():
|
||||||
|
guard.end(success=False)
|
||||||
|
self.logger.info("Guard freigegeben bei Stop (BaseController)")
|
||||||
|
|
||||||
|
# Worker stoppen falls vorhanden
|
||||||
|
if self.worker_thread and self.worker_thread.isRunning():
|
||||||
|
self.worker_thread.stop()
|
||||||
|
generator_tab = self.get_generator_tab()
|
||||||
|
generator_tab.add_log(f"{self.platform_name}-Account-Erstellung wurde abgebrochen")
|
||||||
|
generator_tab.set_running(False)
|
||||||
|
generator_tab.set_progress(0)
|
||||||
|
|
||||||
|
# Forge-Dialog schließen falls vorhanden
|
||||||
|
if hasattr(self, 'forge_dialog') and self.forge_dialog:
|
||||||
|
self.forge_dialog.close()
|
||||||
|
self.forge_dialog = None
|
||||||
@ -283,6 +283,24 @@ class BaseAccountCreationWorkerThread(QThread):
|
|||||||
return save_result
|
return save_result
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
"""Stoppt den Thread"""
|
"""
|
||||||
|
Stoppt den Thread sauber mit Guard-Freigabe.
|
||||||
|
|
||||||
|
WICHTIG: Guard wird SOFORT freigegeben, da terminate() den finally-Block überspringt.
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
self.running = False
|
self.running = False
|
||||||
|
|
||||||
|
# Guard SOFORT freigeben bevor terminate()
|
||||||
|
# Grund: terminate() überspringt den finally-Block in run()
|
||||||
|
from utils.process_guard import get_guard
|
||||||
|
guard = get_guard()
|
||||||
|
if guard.is_locked():
|
||||||
|
guard.end(success=False)
|
||||||
|
logger.info("Guard freigegeben bei Worker-Stop (vor terminate)")
|
||||||
|
|
||||||
|
# Jetzt Thread beenden
|
||||||
self.terminate()
|
self.terminate()
|
||||||
|
self.wait(2000) # Warte max 2 Sekunden auf sauberes Ende
|
||||||
|
|||||||
@ -287,7 +287,15 @@ class FacebookController(BasePlatformController):
|
|||||||
self.forge_dialog = None
|
self.forge_dialog = None
|
||||||
|
|
||||||
def stop_account_creation(self):
|
def stop_account_creation(self):
|
||||||
"""Stoppt die Facebook-Account-Erstellung."""
|
"""Stoppt die Facebook-Account-Erstellung mit Guard-Freigabe."""
|
||||||
|
# Guard-Freigabe (wichtig: VOR Worker-Stop)
|
||||||
|
from utils.process_guard import get_guard
|
||||||
|
guard = get_guard()
|
||||||
|
if guard.is_locked():
|
||||||
|
guard.end(success=False)
|
||||||
|
self.logger.info("Guard freigegeben bei Facebook Stop")
|
||||||
|
|
||||||
|
# Worker stoppen
|
||||||
if self.worker_thread and self.worker_thread.isRunning():
|
if self.worker_thread and self.worker_thread.isRunning():
|
||||||
self.worker_thread.stop()
|
self.worker_thread.stop()
|
||||||
generator_tab = self.get_generator_tab()
|
generator_tab = self.get_generator_tab()
|
||||||
|
|||||||
@ -198,16 +198,25 @@ class GmailController(BasePlatformController):
|
|||||||
logger.info(f"[GMAIL] start_account_creation abgeschlossen")
|
logger.info(f"[GMAIL] start_account_creation abgeschlossen")
|
||||||
|
|
||||||
def stop_account_creation(self):
|
def stop_account_creation(self):
|
||||||
"""Stoppt die laufende Account-Erstellung"""
|
"""Stoppt die laufende Account-Erstellung mit Guard-Freigabe"""
|
||||||
logger.info("[GMAIL] Stoppe Account-Erstellung")
|
logger.info("[GMAIL] Stoppe Account-Erstellung")
|
||||||
|
|
||||||
|
# Guard-Freigabe (wichtig: VOR Worker-Stop)
|
||||||
|
from utils.process_guard import get_guard
|
||||||
|
guard = get_guard()
|
||||||
|
if guard.is_locked():
|
||||||
|
guard.end(success=False)
|
||||||
|
logger.info("Guard freigegeben bei Gmail Stop")
|
||||||
|
|
||||||
|
# Worker stoppen
|
||||||
if self.worker_thread and self.worker_thread.isRunning():
|
if self.worker_thread and self.worker_thread.isRunning():
|
||||||
self.worker_thread.stop()
|
self.worker_thread.stop()
|
||||||
self.worker_thread.wait()
|
self.worker_thread.wait()
|
||||||
|
|
||||||
|
# Dialog schließen
|
||||||
if hasattr(self, 'forge_dialog') and self.forge_dialog:
|
if hasattr(self, 'forge_dialog') and self.forge_dialog:
|
||||||
self.forge_dialog.close()
|
self.forge_dialog.close()
|
||||||
|
|
||||||
# UI zurücksetzen
|
# UI zurücksetzen
|
||||||
generator_tab = self.get_generator_tab()
|
generator_tab = self.get_generator_tab()
|
||||||
generator_tab.set_running(False)
|
generator_tab.set_running(False)
|
||||||
|
|||||||
@ -269,14 +269,22 @@ class InstagramController(BasePlatformController):
|
|||||||
self.forge_dialog.show()
|
self.forge_dialog.show()
|
||||||
|
|
||||||
def stop_account_creation(self):
|
def stop_account_creation(self):
|
||||||
"""Stoppt die Instagram-Account-Erstellung."""
|
"""Stoppt die Instagram-Account-Erstellung mit Guard-Freigabe."""
|
||||||
|
# Guard-Freigabe (wichtig: VOR Worker-Stop)
|
||||||
|
from utils.process_guard import get_guard
|
||||||
|
guard = get_guard()
|
||||||
|
if guard.is_locked():
|
||||||
|
guard.end(success=False)
|
||||||
|
self.logger.info("Guard freigegeben bei Instagram Stop")
|
||||||
|
|
||||||
|
# Worker stoppen
|
||||||
if self.worker_thread and self.worker_thread.isRunning():
|
if self.worker_thread and self.worker_thread.isRunning():
|
||||||
self.worker_thread.stop()
|
self.worker_thread.stop()
|
||||||
generator_tab = self.get_generator_tab()
|
generator_tab = self.get_generator_tab()
|
||||||
generator_tab.add_log("Account-Erstellung wurde abgebrochen")
|
generator_tab.add_log("Account-Erstellung wurde abgebrochen")
|
||||||
generator_tab.set_running(False)
|
generator_tab.set_running(False)
|
||||||
generator_tab.set_progress(0)
|
generator_tab.set_progress(0)
|
||||||
|
|
||||||
# Forge-Dialog schließen falls vorhanden
|
# Forge-Dialog schließen falls vorhanden
|
||||||
if hasattr(self, 'forge_dialog') and self.forge_dialog:
|
if hasattr(self, 'forge_dialog') and self.forge_dialog:
|
||||||
self.forge_dialog.close()
|
self.forge_dialog.close()
|
||||||
|
|||||||
@ -131,14 +131,22 @@ class OkRuController(BasePlatformController):
|
|||||||
self.forge_dialog.show()
|
self.forge_dialog.show()
|
||||||
|
|
||||||
def stop_account_creation(self):
|
def stop_account_creation(self):
|
||||||
"""Stoppt die OK.ru-Account-Erstellung."""
|
"""Stoppt die OK.ru-Account-Erstellung mit Guard-Freigabe."""
|
||||||
|
# Guard-Freigabe (wichtig: VOR Worker-Stop)
|
||||||
|
from utils.process_guard import get_guard
|
||||||
|
guard = get_guard()
|
||||||
|
if guard.is_locked():
|
||||||
|
guard.end(success=False)
|
||||||
|
self.logger.info("Guard freigegeben bei OK.ru Stop")
|
||||||
|
|
||||||
|
# Worker stoppen
|
||||||
if self.worker_thread and self.worker_thread.isRunning():
|
if self.worker_thread and self.worker_thread.isRunning():
|
||||||
self.worker_thread.stop()
|
self.worker_thread.stop()
|
||||||
generator_tab = self.get_generator_tab()
|
generator_tab = self.get_generator_tab()
|
||||||
generator_tab.add_log("Account-Erstellung wurde abgebrochen")
|
generator_tab.add_log("Account-Erstellung wurde abgebrochen")
|
||||||
generator_tab.set_running(False)
|
generator_tab.set_running(False)
|
||||||
generator_tab.set_progress(0)
|
generator_tab.set_progress(0)
|
||||||
|
|
||||||
# Forge-Dialog schließen falls vorhanden
|
# Forge-Dialog schließen falls vorhanden
|
||||||
if hasattr(self, 'forge_dialog') and self.forge_dialog:
|
if hasattr(self, 'forge_dialog') and self.forge_dialog:
|
||||||
self.forge_dialog.close()
|
self.forge_dialog.close()
|
||||||
|
|||||||
@ -273,14 +273,22 @@ class TikTokController(BasePlatformController):
|
|||||||
self.forge_dialog.show()
|
self.forge_dialog.show()
|
||||||
|
|
||||||
def stop_account_creation(self):
|
def stop_account_creation(self):
|
||||||
"""Stoppt die TikTok-Account-Erstellung."""
|
"""Stoppt die TikTok-Account-Erstellung mit Guard-Freigabe."""
|
||||||
|
# Guard-Freigabe (wichtig: VOR Worker-Stop)
|
||||||
|
from utils.process_guard import get_guard
|
||||||
|
guard = get_guard()
|
||||||
|
if guard.is_locked():
|
||||||
|
guard.end(success=False)
|
||||||
|
self.logger.info("Guard freigegeben bei TikTok Stop")
|
||||||
|
|
||||||
|
# Worker stoppen
|
||||||
if self.worker_thread and self.worker_thread.isRunning():
|
if self.worker_thread and self.worker_thread.isRunning():
|
||||||
self.worker_thread.stop()
|
self.worker_thread.stop()
|
||||||
generator_tab = self.get_generator_tab()
|
generator_tab = self.get_generator_tab()
|
||||||
generator_tab.add_log("Account-Erstellung wurde abgebrochen")
|
generator_tab.add_log("Account-Erstellung wurde abgebrochen")
|
||||||
generator_tab.set_running(False)
|
generator_tab.set_running(False)
|
||||||
generator_tab.set_progress(0)
|
generator_tab.set_progress(0)
|
||||||
|
|
||||||
# Forge-Dialog schließen falls vorhanden
|
# Forge-Dialog schließen falls vorhanden
|
||||||
if hasattr(self, 'forge_dialog') and self.forge_dialog:
|
if hasattr(self, 'forge_dialog') and self.forge_dialog:
|
||||||
self.forge_dialog.close()
|
self.forge_dialog.close()
|
||||||
|
|||||||
@ -271,14 +271,22 @@ class XController(BasePlatformController):
|
|||||||
self.forge_dialog.show()
|
self.forge_dialog.show()
|
||||||
|
|
||||||
def stop_account_creation(self):
|
def stop_account_creation(self):
|
||||||
"""Stoppt die X-Account-Erstellung."""
|
"""Stoppt die X-Account-Erstellung mit Guard-Freigabe."""
|
||||||
|
# Guard-Freigabe (wichtig: VOR Worker-Stop)
|
||||||
|
from utils.process_guard import get_guard
|
||||||
|
guard = get_guard()
|
||||||
|
if guard.is_locked():
|
||||||
|
guard.end(success=False)
|
||||||
|
self.logger.info("Guard freigegeben bei X Stop")
|
||||||
|
|
||||||
|
# Worker stoppen
|
||||||
if self.worker_thread and self.worker_thread.isRunning():
|
if self.worker_thread and self.worker_thread.isRunning():
|
||||||
self.worker_thread.stop()
|
self.worker_thread.stop()
|
||||||
generator_tab = self.get_generator_tab()
|
generator_tab = self.get_generator_tab()
|
||||||
generator_tab.add_log("Account-Erstellung wurde abgebrochen")
|
generator_tab.add_log("Account-Erstellung wurde abgebrochen")
|
||||||
generator_tab.set_running(False)
|
generator_tab.set_running(False)
|
||||||
generator_tab.set_progress(0)
|
generator_tab.set_progress(0)
|
||||||
|
|
||||||
# Forge-Dialog schließen falls vorhanden
|
# Forge-Dialog schließen falls vorhanden
|
||||||
if hasattr(self, 'forge_dialog') and self.forge_dialog:
|
if hasattr(self, 'forge_dialog') and self.forge_dialog:
|
||||||
self.forge_dialog.close()
|
self.forge_dialog.close()
|
||||||
|
|||||||
@ -129,18 +129,18 @@ class SessionController(QObject):
|
|||||||
self.login_failed.emit(account_id, str(e))
|
self.login_failed.emit(account_id, str(e))
|
||||||
|
|
||||||
def _cancel_login(self, account_id: str):
|
def _cancel_login(self, account_id: str):
|
||||||
"""Bricht den Login-Prozess ab"""
|
"""Bricht den Login-Prozess ab mit Guard-Freigabe"""
|
||||||
logger.info(f"Login für Account {account_id} wurde abgebrochen")
|
logger.info(f"Login für Account {account_id} wurde abgebrochen")
|
||||||
|
|
||||||
# Feature 5: Guard freigeben bei Cancel
|
# Guard IMMER freigeben bei Cancel (einfacher + robuster)
|
||||||
# HINWEIS: Worker Thread gibt Guard in seinem finally-Block frei
|
# Doppelte Freigabe ist kein Problem (wird von ProcessGuard ignoriert)
|
||||||
# Nur freigeben wenn Worker noch nicht gestartet (Guard locked aber kein Worker)
|
|
||||||
from utils.process_guard import get_guard
|
from utils.process_guard import get_guard
|
||||||
guard = get_guard()
|
guard = get_guard()
|
||||||
if guard.is_locked() and not (hasattr(self, 'login_worker') and self.login_worker and self.login_worker.isRunning()):
|
if guard.is_locked():
|
||||||
logger.warning("Guard war locked aber Worker nicht aktiv - gebe Guard frei")
|
|
||||||
guard.end(success=False)
|
guard.end(success=False)
|
||||||
|
logger.info("Guard freigegeben bei Login-Cancel")
|
||||||
|
|
||||||
|
# Dialog schließen
|
||||||
if hasattr(self, 'login_dialog') and self.login_dialog:
|
if hasattr(self, 'login_dialog') and self.login_dialog:
|
||||||
self.login_dialog.close()
|
self.login_dialog.close()
|
||||||
self.login_dialog = None
|
self.login_dialog = None
|
||||||
|
|||||||
Binäre Datei nicht angezeigt.
@ -15,6 +15,7 @@ from email.header import decode_header
|
|||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
from utils.text_similarity import TextSimilarity
|
from utils.text_similarity import TextSimilarity
|
||||||
|
from config.paths import PathConfig
|
||||||
|
|
||||||
logger = logging.getLogger("email_handler")
|
logger = logging.getLogger("email_handler")
|
||||||
|
|
||||||
@ -22,8 +23,8 @@ class EmailHandler:
|
|||||||
"""
|
"""
|
||||||
Handler für den Zugriff auf E-Mail-Dienste und den Abruf von Bestätigungscodes.
|
Handler für den Zugriff auf E-Mail-Dienste und den Abruf von Bestätigungscodes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
CONFIG_FILE = os.path.join("config", "email_config.json")
|
CONFIG_FILE = os.path.join(PathConfig.CONFIG_DIR, "email_config.json")
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Initialisiert den EmailHandler und lädt die Konfiguration."""
|
"""Initialisiert den EmailHandler und lädt die Konfiguration."""
|
||||||
|
|||||||
@ -31,6 +31,7 @@ class ProcessGuard:
|
|||||||
# Konfiguration
|
# Konfiguration
|
||||||
MAX_FAILURES = 3
|
MAX_FAILURES = 3
|
||||||
PAUSE_DURATION_HOURS = 1
|
PAUSE_DURATION_HOURS = 1
|
||||||
|
LOCK_TIMEOUT_MINUTES = 10 # Auto-Unlock nach 10 Minuten bei hängenden Prozessen
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Initialisiert den Process Guard."""
|
"""Initialisiert den Process Guard."""
|
||||||
@ -38,6 +39,7 @@ class ProcessGuard:
|
|||||||
self._is_locked = False
|
self._is_locked = False
|
||||||
self._current_process = None
|
self._current_process = None
|
||||||
self._current_platform = None
|
self._current_platform = None
|
||||||
|
self._lock_started_at = None # Timestamp für Auto-Timeout
|
||||||
|
|
||||||
# Error Tracking
|
# Error Tracking
|
||||||
self._failure_count = 0
|
self._failure_count = 0
|
||||||
@ -95,6 +97,7 @@ class ProcessGuard:
|
|||||||
self._is_locked = True
|
self._is_locked = True
|
||||||
self._current_process = process_type
|
self._current_process = process_type
|
||||||
self._current_platform = platform
|
self._current_platform = platform
|
||||||
|
self._lock_started_at = datetime.now() # Timestamp für Auto-Timeout
|
||||||
logger.info(f"Process locked: {process_type} ({platform})")
|
logger.info(f"Process locked: {process_type} ({platform})")
|
||||||
|
|
||||||
def end(self, success: bool):
|
def end(self, success: bool):
|
||||||
@ -109,6 +112,7 @@ class ProcessGuard:
|
|||||||
self._is_locked = False
|
self._is_locked = False
|
||||||
self._current_process = None
|
self._current_process = None
|
||||||
self._current_platform = None
|
self._current_platform = None
|
||||||
|
self._lock_started_at = None # Timestamp zurücksetzen
|
||||||
|
|
||||||
# Fehler-Tracking
|
# Fehler-Tracking
|
||||||
if success:
|
if success:
|
||||||
@ -133,6 +137,7 @@ class ProcessGuard:
|
|||||||
self._is_locked = False
|
self._is_locked = False
|
||||||
self._current_process = None
|
self._current_process = None
|
||||||
self._current_platform = None
|
self._current_platform = None
|
||||||
|
self._lock_started_at = None # Timestamp zurücksetzen
|
||||||
self._load_pause_state()
|
self._load_pause_state()
|
||||||
|
|
||||||
if self._is_paused():
|
if self._is_paused():
|
||||||
@ -143,12 +148,31 @@ class ProcessGuard:
|
|||||||
|
|
||||||
def is_locked(self) -> bool:
|
def is_locked(self) -> bool:
|
||||||
"""
|
"""
|
||||||
Gibt zurück ob aktuell ein Prozess läuft.
|
Gibt zurück ob aktuell ein Prozess läuft (mit Auto-Timeout-Check).
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
True wenn ein Prozess aktiv ist
|
True wenn ein Prozess aktiv ist
|
||||||
"""
|
"""
|
||||||
return self._is_locked
|
if not self._is_locked:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Auto-Timeout-Check: Unlock bei hängenden Prozessen
|
||||||
|
if self._lock_started_at:
|
||||||
|
elapsed_minutes = (datetime.now() - self._lock_started_at).total_seconds() / 60
|
||||||
|
|
||||||
|
if elapsed_minutes > self.LOCK_TIMEOUT_MINUTES:
|
||||||
|
logger.warning(
|
||||||
|
f"⏰ AUTO-TIMEOUT: Lock nach {int(elapsed_minutes)} Minuten freigegeben. "
|
||||||
|
f"Prozess: {self._current_process} ({self._current_platform})"
|
||||||
|
)
|
||||||
|
# Lock automatisch freigeben
|
||||||
|
self._is_locked = False
|
||||||
|
self._current_process = None
|
||||||
|
self._current_platform = None
|
||||||
|
self._lock_started_at = None
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
def is_paused(self) -> bool:
|
def is_paused(self) -> bool:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -11,7 +11,7 @@ from PyQt5.QtWidgets import (
|
|||||||
QLabel, QPushButton, QStackedWidget, QTabWidget,
|
QLabel, QPushButton, QStackedWidget, QTabWidget,
|
||||||
QAction, QMessageBox
|
QAction, QMessageBox
|
||||||
)
|
)
|
||||||
from PyQt5.QtCore import Qt, pyqtSignal, QSize, QFile
|
from PyQt5.QtCore import Qt, pyqtSignal, QSize, QFile, QTimer
|
||||||
from PyQt5.QtGui import QIcon, QFont, QPixmap
|
from PyQt5.QtGui import QIcon, QFont, QPixmap
|
||||||
from localization.language_manager import LanguageManager
|
from localization.language_manager import LanguageManager
|
||||||
|
|
||||||
@ -114,6 +114,14 @@ class MainWindow(QMainWindow):
|
|||||||
# Verbinde Signale
|
# Verbinde Signale
|
||||||
self.connect_signals()
|
self.connect_signals()
|
||||||
|
|
||||||
|
# Timer für periodische Guard-Status-Prüfung des Zurück-Buttons
|
||||||
|
self.guard_check_timer = QTimer()
|
||||||
|
self.guard_check_timer.timeout.connect(self._update_back_button_state)
|
||||||
|
self.guard_check_timer.start(1000) # Alle 1 Sekunde prüfen
|
||||||
|
|
||||||
|
# Initiale Button-Status-Prüfung
|
||||||
|
self._update_back_button_state()
|
||||||
|
|
||||||
def connect_signals(self):
|
def connect_signals(self):
|
||||||
"""Verbindet die internen Signale."""
|
"""Verbindet die internen Signale."""
|
||||||
# Platform-Selector-Signal verbinden
|
# Platform-Selector-Signal verbinden
|
||||||
@ -267,6 +275,37 @@ class MainWindow(QMainWindow):
|
|||||||
"""Setzt eine Nachricht in der Statusleiste."""
|
"""Setzt eine Nachricht in der Statusleiste."""
|
||||||
self.statusBar().showMessage(message)
|
self.statusBar().showMessage(message)
|
||||||
|
|
||||||
|
def _update_back_button_state(self):
|
||||||
|
"""
|
||||||
|
Aktualisiert den Status des Zurück-Buttons basierend auf ProcessGuard.
|
||||||
|
|
||||||
|
Deaktiviert den Zurück-Button wenn ein Prozess läuft oder Pause aktiv ist,
|
||||||
|
um zu verhindern dass User während Account-Erstellung/Login navigieren.
|
||||||
|
"""
|
||||||
|
from utils.process_guard import get_guard
|
||||||
|
guard = get_guard()
|
||||||
|
|
||||||
|
# Prüfe ob blockiert
|
||||||
|
is_locked = guard.is_locked()
|
||||||
|
is_paused = guard.is_paused()
|
||||||
|
is_blocked = is_locked or is_paused
|
||||||
|
|
||||||
|
# Button entsprechend setzen (nur wenn auf Platform-View)
|
||||||
|
if self.stacked_widget.currentWidget() == self.platform_container:
|
||||||
|
self.back_button.setEnabled(not is_blocked)
|
||||||
|
|
||||||
|
# Tooltip setzen
|
||||||
|
if is_blocked:
|
||||||
|
status_msg = guard.get_status_message()
|
||||||
|
self.back_button.setToolTip(f"⚠ {status_msg}")
|
||||||
|
else:
|
||||||
|
# Reset Tooltip
|
||||||
|
if self.language_manager:
|
||||||
|
tooltip = self.language_manager.get_text("buttons.back", "↩ Zurück")
|
||||||
|
else:
|
||||||
|
tooltip = "↩ Zurück"
|
||||||
|
self.back_button.setToolTip(tooltip)
|
||||||
|
|
||||||
def add_log_widget(self, text_widget):
|
def add_log_widget(self, text_widget):
|
||||||
"""Fügt einen GUI-Handler zum Logger hinzu."""
|
"""Fügt einen GUI-Handler zum Logger hinzu."""
|
||||||
add_gui_handler(logger, text_widget)
|
add_gui_handler(logger, text_widget)
|
||||||
|
|||||||
In neuem Issue referenzieren
Einen Benutzer sperren