Files
fortunecookie/src/fortunecookie.py
T
darklithium ace4d9c43c fix: Last-State, Keks-Größe, Musik-Button
- Last-State speichert in .cache/fortunecookie.darklithium/music_enabled
- Geöffneter Keks: 36x28 gu (geschlossen: 32x24 gu)
- Musik-Button: 10x10 gu, x-large Icon, erst nach Init sichtbar
- Python ohne PySide2-Abhängigkeiten
- Properties vor Functions in QML

Fixes: PermissionError auf .config/, Icon-Flickern

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-02 03:27:35 +02:00

233 lines
6.9 KiB
Python

"""
Fortune Cookie v1.0 - Python Backend Module
Framework 1.7 Standard
Audio-Steuerung in QML (keine Qt-Python-Bindings benoetigt)
"""
import os
import random
import json
import platform
from pathlib import Path
# ============================================================================
# APP-METADATEN
# ============================================================================
APP_NAME = "fortunecookie"
APP_VERSION = "1.0.0"
MAINTAINER = "darklithium <dev@darklithium.de>"
# ============================================================================
# PLATTFORM-ERKENNUNG (Framework 1.7 Standard)
# ============================================================================
def get_platform():
"""Gibt die aktuelle Plattform zurueck (arm64/amd64)."""
machine = platform.machine().lower()
if "arm" in machine or "aarch" in machine:
return "arm64"
return "amd64"
# ============================================================================
# FORTUNE-LOGIK
# ============================================================================
# Globale Variablen
_current_fortune = ""
_fortunes = []
_initialized = False
# Musik-Status (wird dynamisch von Datei geladen)
# _music_enabled wird nicht als globale Variable gespeichert, sondern immer frisch geladen
def _init():
"""Initialisiert das Modul (wird beim ersten Aufruf ausgefuehrt)."""
global _fortunes, _initialized
if _initialized:
return True
# Lade Fortunes
_load_fortunes()
_initialized = True
return True
def _load_fortunes():
"""Laedt alle Sprueche aus assets/fortunes.json."""
global _fortunes
if _fortunes:
return
try:
# Versuche verschiedene Pfade
possible_paths = [
os.path.join(os.path.dirname(__file__), "..", "assets", "fortunes.json"),
os.path.join("assets", "fortunes.json"),
]
for fortunes_path in possible_paths:
if os.path.exists(fortunes_path):
with open(fortunes_path, "r", encoding="utf-8") as f:
data = json.load(f)
if isinstance(data, list):
_fortunes = data
elif isinstance(data, dict):
# Lade deutsche Sprüche, falls vorhanden, sonst englische
_fortunes = data.get("de", data.get("en", []))
elif isinstance(data, dict) and "fortunes" in data:
_fortunes = data.get("fortunes", [])
return
# Fallback: Standard-Sprueche
_fortunes = [
"Ein guter Tag beginnt mit einem Laecheln.",
"Das Glueck liegt in den kleinen Dingen.",
"Geduld ist eine Tugend.",
]
except Exception:
_fortunes = []
def _get_random_fortune():
"""Gibt einen zufaelligen Spruch zurueck."""
if not _fortunes:
_load_fortunes()
return random.choice(_fortunes) if _fortunes else "Keine Sprueche verfguebar."
def get_initial_fortune():
"""Gibt einen zufaelligen Spruch fuer den Start zurueck."""
_init()
global _current_fortune
_current_fortune = _get_random_fortune()
return _current_fortune
def open_fortune():
"""Oeffnet den Fortune Cookie (neuer Spruch)."""
_init()
global _current_fortune
# Neuer Spruch
_current_fortune = _get_random_fortune()
return True
def get_current_fortune():
"""Gibt den aktuellen Spruch zurueck."""
_init()
global _current_fortune
return _current_fortune
def get_new_fortune():
"""Gibt einen neuen Spruch zurueck (Cookie schliesst sich)."""
_init()
global _current_fortune
_current_fortune = _get_random_fortune()
return _current_fortune
# ============================================================================
# LAST-STATE SPEICHERUNG (Musik an/aus)
# ============================================================================
def _get_config_dir():
"""Gibt das Konfigurationsverzeichnis der App zurueck.
Click-Apps auf UBPorts haben eingeschraenkte Schreibrechte.
Verwendete Pfade:
- ~/.cache/<appname>/ (funktioniert in Click-Apps)
"""
try:
home = os.path.expanduser("~")
# Click-App-Pfad (funktioniert in der Sandbox)
app_name = "fortunecookie.darklithium"
cache_dir = os.path.join(home, ".cache", app_name)
os.makedirs(cache_dir, exist_ok=True)
return cache_dir
except Exception:
# Fallback
return os.path.join("/tmp", "fortunecookie")
def _get_music_state_file():
"""Gibt den Pfad zur Musik-Status-Datei zurueck."""
config_dir = _get_config_dir()
return os.path.join(config_dir, "music_enabled")
def _load_music_state():
"""Laedt den Musik-Status aus Datei (true/false)."""
try:
state_file = _get_music_state_file()
print(f"DEBUG: Loading music state from: {state_file}")
print(f"DEBUG: File exists: {os.path.exists(state_file)}")
if os.path.exists(state_file):
with open(state_file, "r") as f:
content = f.read().strip().lower()
print(f"DEBUG: File content: '{content}'")
result = content == "true"
print(f"DEBUG: Music enabled: {result}")
return result
else:
print("DEBUG: Music state file does not exist, using default: True")
except Exception as e:
print(f"WARN: Musik-Status nicht geladen: {e}")
import traceback
traceback.print_exc()
# Default: Musik an
return True
def _save_music_state(enabled):
"""Speichert den Musik-Status in Datei (true/false)."""
try:
config_dir = _get_config_dir()
os.makedirs(config_dir, exist_ok=True)
state_file = _get_music_state_file()
print(f"DEBUG: Saving music state {enabled} to: {state_file}")
with open(state_file, "w") as f:
f.write("true" if enabled else "false")
print(f"DEBUG: Successfully saved music state")
except Exception as e:
print(f"WARN: Musik-Status nicht gespeichert: {e}")
import traceback
traceback.print_exc()
def set_music_enabled(enabled):
"""Aktiviert/Deaktiviert die Musik und speichert den Status."""
_save_music_state(enabled)
return True
def get_music_enabled():
"""Gibt den Musik-Status zurueck (frisch von Datei geladen)."""
return _load_music_state()
# ============================================================================
# PLATTFORM-SPEZIFISCHE PFADERMITTLUNG
# ============================================================================
def get_asset_path(filename):
"""Gibt den Pfad zu einer Asset-Datei zurueck (funktioniert in Click & Desktop)."""
possible_paths = [
os.path.join(os.path.dirname(__file__), "..", "assets", filename),
os.path.join("assets", filename),
]
for path in possible_paths:
if os.path.exists(path):
return path
return os.path.join("assets", filename)