Files
fortunecookie/src/fortunecookie.py
T
darklithium c4e7d4bd55 feat: phase 1 - einstellungen mit lautstärke und spruchlisten
- Settings.qml mit Lautstärke-Slidern für Musik und Knack-Geräusch
- Spruchlisten-Auswahl (classic, farmer_wisdom, unfortune)
- StackLayout für Navigation zwischen Hauptseite und Einstellungen
- Python: load_setting/save_setting für generische Einstellungen
- Python: Volume-Einstellungen und Spruchlisten-Verwaltung
- ASSET_REQUIREMENTS.md für Grafik-Spezifikationen
- JSON-Dateien: classic.json, farmer_wisdom.json, unfortune.json

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-02 21:26:41 +02:00

313 lines
9.5 KiB
Python

"""
Fortune Cookie v1.1 - Python Backend Module
Framework 1.8 Standard
Audio-Steuerung in QML (keine Qt-Python-Bindings benoetigt)
Last-State Speicherung mit Datei-basiertem Speicher
Einstellungen: Lautstaerke, Spruchlisten
"""
import os
import random
import json
import platform
# ============================================================================
# APP-METADATEN
# ============================================================================
APP_NAME = "fortunecookie"
APP_VERSION = "1.1.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-LISTEN VERWALTUNG
# ============================================================================
# Verfuegbare Spruchlisten
AVAILABLE_FORTUNE_LISTS = [
"classic", # Standard Glückskeks-Sprueche
"farmer_wisdom", # Bauernweisheiten
"unfortune", # Gothic/UNfortune-Sprueche
]
# Aktuelle Spruchliste (Standard: classic)
_current_fortune_list = "classic"
_current_fortune = ""
_fortunes = {}
_initialized = False
def _init():
"""Initialisiert das Modul (wird beim ersten Aufruf ausgefuehrt)."""
global _fortunes, _initialized, _current_fortune_list
if _initialized:
return True
# Lade alle Spruchlisten
_load_all_fortune_lists()
# Lade aktuelle Liste aus Einstellungen
_current_fortune_list = load_setting("fortune_list", default_value="classic")
if _current_fortune_list not in _fortunes:
_current_fortune_list = "classic"
_initialized = True
return True
def _load_all_fortune_lists():
"""Laedt alle verfuegbaren Spruchlisten."""
global _fortunes
if _fortunes:
return
try:
base_path = os.path.join(os.path.dirname(__file__), "..", "assets", "fortunes")
for list_name in AVAILABLE_FORTUNE_LISTS:
try:
json_path = os.path.join(base_path, f"{list_name}.json")
if os.path.exists(json_path):
with open(json_path, "r", encoding="utf-8") as f:
_fortunes[list_name] = json.load(f)
else:
# Fallback: Leere Liste
_fortunes[list_name] = []
except Exception as e:
print(f"WARN: Spruchliste {list_name} nicht geladen: {e}")
_fortunes[list_name] = []
except Exception as e:
print(f"ERROR: Spruchlisten nicht geladen: {e}")
# Fallback: Standard-Sprueche
_fortunes = {
"classic": [
"Ein guter Tag beginnt mit einem Laecheln.",
"Das Glueck liegt in den kleinen Dingen.",
"Geduld ist eine Tugend.",
],
"farmer_wisdom": [],
"unfortune": []
}
def _get_random_fortune():
"""Gibt einen zufaelligen Spruch aus der aktuellen Liste zurueck."""
global _current_fortune_list, _fortunes
_init()
if _current_fortune_list not in _fortunes or not _fortunes[_current_fortune_list]:
# Fallback auf classic
_current_fortune_list = "classic"
if not _fortunes.get("classic"):
return "Keine Sprueche verfguebar."
return random.choice(_fortunes[_current_fortune_list])
def get_initial_fortune():
"""Gibt einen zufaelligen Spruch fuer den Start zurueck."""
global _current_fortune
_init()
_current_fortune = _get_random_fortune()
return _current_fortune
def open_fortune():
"""Oeffnet den Fortune Cookie (neuer Spruch aus aktueller Liste)."""
global _current_fortune
_init()
_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)."""
global _current_fortune
_init()
_current_fortune = _get_random_fortune()
return _current_fortune
# ============================================================================
# EINSTELLUNGEN (Settings)
# ============================================================================
def _get_config_dir():
"""Gibt das Konfigurationsverzeichnis zurück (Click-App kompatibel)."""
try:
home = os.path.expanduser("~")
app_name = APP_NAME + ".darklithium"
cache_dir = os.path.join(home, ".cache", app_name)
os.makedirs(cache_dir, exist_ok=True)
return cache_dir
except Exception:
return os.path.join("/tmp", APP_NAME + "_config")
def _get_setting_file(setting_name):
"""Gibt den Pfad zu einer Einstellungsdatei zurück."""
return os.path.join(_get_config_dir(), f"{setting_name}.txt")
def load_setting(setting_name, default_value=None):
"""Laedt eine Einstellung aus einer Datei.
Args:
setting_name (str): Name der Einstellung
default_value: Standardwert, wenn Datei nicht existiert
Rückgabe:
Wert der Einstellung (Typ hängt von default_value ab)
"""
try:
setting_file = _get_setting_file(setting_name)
if os.path.exists(setting_file):
with open(setting_file, "r") as f:
content = f.read().strip()
# Try to convert to appropriate type
if default_value is not None:
if isinstance(default_value, bool):
return content.lower() == "true"
elif isinstance(default_value, int):
return int(content)
elif isinstance(default_value, float):
return float(content)
return content
except Exception as e:
print(f"WARN: Einstellung nicht geladen ({setting_name}): {e}")
return default_value
def save_setting(setting_name, value):
"""Speichert eine Einstellung in einer Datei.
Args:
setting_name (str): Name der Einstellung
value: Zu speichernder Wert (wird zu String konvertiert)
Rückgabe:
bool: True bei Erfolg
"""
try:
config_dir = _get_config_dir()
os.makedirs(config_dir, exist_ok=True)
setting_file = _get_setting_file(setting_name)
with open(setting_file, "w") as f:
f.write(str(value))
return True
except Exception as e:
print(f"WARN: Einstellung nicht gespeichert ({setting_name}): {e}")
return False
# ============================================================================
# LAUTSTÄRKE-EINSTELLUNGEN
# ============================================================================
def get_music_volume():
"""Gibt die Musik-Lautstärke zurück (0.0 - 1.0)."""
return float(load_setting("music_volume", default_value=0.5))
def set_music_volume(volume):
"""Setzt die Musik-Lautstärke (0.0 - 1.0)."""
# Clamp value between 0.0 and 1.0
volume = max(0.0, min(1.0, float(volume)))
return save_setting("music_volume", volume)
def get_crack_volume():
"""Gibt die Knack-Lautstärke zurück (0.0 - 1.0)."""
return float(load_setting("crack_volume", default_value=1.0))
def set_crack_volume(volume):
"""Setzt die Knack-Lautstärke (0.0 - 1.0)."""
volume = max(0.0, min(1.0, float(volume)))
return save_setting("crack_volume", volume)
# ============================================================================
# SPRUCHLISTEN-EINSTELLUNGEN
# ============================================================================
def get_fortune_lists():
"""Gibt die Liste der verfuegbaren Spruchlisten zurück."""
_init()
return AVAILABLE_FORTUNE_LISTS
def get_current_fortune_list():
"""Gibt den Namen der aktuellen Spruchliste zurück."""
_init()
return load_setting("fortune_list", default_value="classic")
def set_fortune_list(list_name):
"""Setzt die aktuelle Spruchliste.
Args:
list_name (str): Name der Spruchliste (classic, farmer_wisdom, unfortune)
Rückgabe:
bool: True bei Erfolg
"""
if list_name not in AVAILABLE_FORTUNE_LISTS:
return False
return save_setting("fortune_list", list_name)
# ============================================================================
# MUSIK EIN/AUS (Last-State)
# ============================================================================
def get_music_enabled():
"""Gibt zurück, ob Musik aktiviert ist (Last-State)."""
return load_setting("music_enabled", default_value=True)
def set_music_enabled(enabled):
"""Setzt den Musik-Status und speichert ihn persistent."""
return save_setting("music_enabled", bool(enabled))
# ============================================================================
# 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)