| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- # -*- coding: utf-8 -*-
- """
- Basisklasse für Trixy-Plugins.
- Plugins erweitern diese Klasse und implementieren ihre Funktionalität.
- """
- import json
- from abc import ABC, abstractmethod
- from pathlib import Path
- from typing import Any, TYPE_CHECKING
- from trixy_core.utils.debug import pdebug, perror, pinfo
- if TYPE_CHECKING:
- from trixy_core.application import IApplication
- class TrixyPlugin(ABC):
- """
- Abstrakte Basisklasse für alle Trixy-Plugins.
- Ein Plugin muss in einem eigenen Verzeichnis unter ./plugins/ liegen
- und folgende Struktur haben:
- - main.py: Plugin-Klasse die TrixyPlugin erweitert
- - config.json: Plugin-Konfiguration
- Attribute:
- NAME: Eindeutiger Plugin-Name
- VERSION: Plugin-Version
- DESCRIPTION: Kurze Beschreibung
- AUTHOR: Autor des Plugins
- """
- NAME: str = ""
- VERSION: str = "1.0.0"
- DESCRIPTION: str = ""
- AUTHOR: str = ""
- def __init__(
- self,
- application: "IApplication",
- plugin_path: Path,
- config: dict[str, Any] | None = None
- ) -> None:
- """
- Initialisiert das Plugin.
- Args:
- application: Referenz zur Hauptanwendung
- plugin_path: Pfad zum Plugin-Verzeichnis
- config: Optionale Konfiguration
- """
- self._application = application
- self._plugin_path = plugin_path
- self._config: dict[str, Any] = config or {}
- self._enabled = True
- @property
- def application(self) -> "IApplication":
- """Gibt die Anwendungsreferenz zurück."""
- return self._application
- @property
- def plugin_path(self) -> Path:
- """Gibt den Plugin-Pfad zurück."""
- return self._plugin_path
- @property
- def config(self) -> dict[str, Any]:
- """Gibt die Plugin-Konfiguration zurück."""
- return self._config
- @config.setter
- def config(self, value: dict[str, Any]) -> None:
- """Setzt die Plugin-Konfiguration."""
- self._config = value
- @property
- def enabled(self) -> bool:
- """Ist das Plugin aktiviert?"""
- return self._enabled
- @enabled.setter
- def enabled(self, value: bool) -> None:
- """Aktiviert oder deaktiviert das Plugin."""
- self._enabled = value
- @property
- def name(self) -> str:
- """Gibt den Plugin-Namen zurück."""
- return self.NAME or self.__class__.__name__
- def is_enabled(self) -> bool:
- """Prüft, ob das Plugin aktiviert ist."""
- return self._enabled
- def get_config_value(self, key: str, default: Any = None) -> Any:
- """
- Gibt einen Konfigurationswert zurück.
- Args:
- key: Schlüssel (unterstützt Punkt-Notation: "section.key")
- default: Standardwert
- Returns:
- Konfigurationswert oder default
- """
- keys = key.split(".")
- value = self._config
- for k in keys:
- if isinstance(value, dict) and k in value:
- value = value[k]
- else:
- return default
- return value
- def set_config_value(self, key: str, value: Any) -> None:
- """
- Setzt einen Konfigurationswert.
- Args:
- key: Schlüssel (unterstützt Punkt-Notation)
- value: Zu setzender Wert
- """
- keys = key.split(".")
- config = self._config
- for k in keys[:-1]:
- if k not in config:
- config[k] = {}
- config = config[k]
- config[keys[-1]] = value
- def reload_config(self) -> bool:
- """
- Lädt die Konfiguration neu aus der Datei.
- Returns:
- True bei Erfolg
- """
- config_path = self._plugin_path / "config.json"
- if not config_path.exists():
- pdebug(f"Keine config.json für Plugin: {self.name}")
- return False
- try:
- with open(config_path, "r", encoding="utf-8") as f:
- self._config = json.load(f)
- pinfo(f"Plugin-Konfiguration neu geladen: {self.name}")
- return True
- except Exception as e:
- perror(f"Fehler beim Laden der Plugin-Konfiguration: {e}")
- return False
- def save_config(self) -> bool:
- """
- Speichert die Konfiguration in die Datei.
- Returns:
- True bei Erfolg
- """
- config_path = self._plugin_path / "config.json"
- try:
- with open(config_path, "w", encoding="utf-8") as f:
- json.dump(self._config, f, indent=2, ensure_ascii=False)
- pinfo(f"Plugin-Konfiguration gespeichert: {self.name}")
- return True
- except Exception as e:
- perror(f"Fehler beim Speichern der Plugin-Konfiguration: {e}")
- return False
- @abstractmethod
- async def on_load(self) -> None:
- """
- Wird aufgerufen, wenn das Plugin geladen wird.
- Hier sollten Event-Handler registriert und
- Initialisierungen durchgeführt werden.
- """
- pass
- @abstractmethod
- async def on_unload(self) -> None:
- """
- Wird aufgerufen, wenn das Plugin entladen wird.
- Hier sollten Ressourcen freigegeben werden.
- """
- pass
- async def on_enable(self) -> None:
- """Wird aufgerufen, wenn das Plugin aktiviert wird."""
- pass
- async def on_disable(self) -> None:
- """Wird aufgerufen, wenn das Plugin deaktiviert wird."""
- pass
- async def on_config_change(self, old_config: dict[str, Any]) -> None:
- """
- Wird aufgerufen, wenn sich die Konfiguration ändert.
- Args:
- old_config: Vorherige Konfiguration
- """
- pass
- def get_config_tool_tabs(self) -> list[dict[str, Any]]:
- """
- Gibt zusaetzliche Tabs fuer das Config-Tool zurueck.
- Plugins koennen diese Methode ueberschreiben, um benutzerdefinierte
- Tabs in der Plugin-Detailansicht des Config-Tools anzubieten.
- Returns:
- Liste von Tab-Definitionen, z.B.:
- [{"title": "Test", "description": "TTS-Test Seite"}]
- """
- return []
- def __repr__(self) -> str:
- return f"<Plugin {self.name} v{self.VERSION} enabled={self._enabled}>"
|