| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- # -*- coding: utf-8 -*-
- """
- Crossfade-Plugin für Trixy.
- Ermöglicht nahtlose Übergänge zwischen Musik-Tracks durch
- Mischen des Track-Endes mit dem Anfang des nächsten Tracks.
- """
- from trixy_core.plugins import TrixyPlugin
- from trixy_core.utils.debug import pinfo, pdebug, perror, pwarn
- from plugins.crossfade.processor import CrossfadeProcessor, CrossfadeConfig
- class CrossfadePlugin(TrixyPlugin):
- """
- Crossfade-Plugin.
- Fügt der Audio-Pipeline einen Crossfade-Prozessor hinzu,
- der automatisch Übergänge zwischen Tracks mischt.
- """
- NAME = "crossfade"
- VERSION = "1.0.0"
- DESCRIPTION = "Nahtlose Übergänge zwischen Musik-Tracks"
- AUTHOR = "Trixy"
- def __init__(self, application, plugin_path, config=None):
- super().__init__(application, plugin_path, config)
- self._processor: CrossfadeProcessor | None = None
- async def on_load(self) -> None:
- """Wird beim Laden des Plugins aufgerufen."""
- pinfo(f"CrossfadePlugin: Lade Plugin v{self.VERSION}")
- # Konfiguration laden
- crossfade_config = CrossfadeConfig(
- duration_ms=self.get_config_value("crossfade_duration_ms", 5000),
- fade_curve=self.get_config_value("fade_curve", "linear"),
- min_track_duration_ms=self.get_config_value("min_track_duration_ms", 30000),
- prebuffer_duration_ms=self.get_config_value("prebuffer_duration_ms", 6000),
- enabled=self.get_config_value("enabled", True),
- )
- # Prozessor erstellen
- self._processor = CrossfadeProcessor(
- processor_id=f"{self.NAME}_processor",
- name="Crossfade",
- config=crossfade_config,
- )
- # Decoder-Registry setzen wenn verfügbar
- if self.application:
- try:
- # Versuche MusicPlayer zu finden
- from trixy_core.music.formats import get_default_registry
- registry = get_default_registry()
- self._processor.set_decoder_registry(registry)
- except Exception:
- pass
- pinfo(f"CrossfadePlugin: Geladen (Dauer: {crossfade_config.duration_ms}ms)")
- async def on_unload(self) -> None:
- """Wird beim Entladen des Plugins aufgerufen."""
- if self._processor:
- self._processor.reset()
- self._processor = None
- pdebug("CrossfadePlugin: Entladen")
- async def on_enable(self) -> None:
- """Wird beim Aktivieren aufgerufen."""
- pinfo("CrossfadePlugin: on_enable() aufgerufen")
- if self._processor:
- self._processor.enabled = True
- self._processor.config.enabled = True
- # Prozessor zur Pipeline hinzufügen
- self._register_processor()
- else:
- pwarn("CrossfadePlugin: Kein Processor vorhanden!")
- pinfo("CrossfadePlugin: Aktiviert")
- async def on_disable(self) -> None:
- """Wird beim Deaktivieren aufgerufen."""
- if self._processor:
- self._processor.enabled = False
- self._processor.config.enabled = False
- # Prozessor aus Pipeline entfernen
- self._unregister_processor()
- pinfo("CrossfadePlugin: Deaktiviert")
- async def on_config_change(self, old_config: dict) -> None:
- """Wird bei Konfigurationsänderungen aufgerufen."""
- if self._processor:
- self._processor.update_config(
- duration_ms=self.get_config_value("crossfade_duration_ms", 5000),
- fade_curve=self.get_config_value("fade_curve", "linear"),
- min_track_duration_ms=self.get_config_value("min_track_duration_ms", 30000),
- prebuffer_duration_ms=self.get_config_value("prebuffer_duration_ms", 6000),
- enabled=self.get_config_value("enabled", True),
- )
- pdebug("CrossfadePlugin: Konfiguration aktualisiert")
- def _register_processor(self) -> None:
- """Registriert Prozessor bei der Audio-Pipeline."""
- if not self._processor:
- return
- try:
- # MusicPlayer finden und Pipeline abrufen
- if self.application:
- # Server-Modus
- if hasattr(self.application, "services"):
- # Debug: Alle registrierten Services anzeigen
- all_services = list(self.application.services.services.keys())
- pdebug(f"CrossfadePlugin: Verfügbare Services: {all_services}")
- music_service = self.application.services.get_service("music_player")
- pdebug(f"CrossfadePlugin: music_player Service = {music_service}")
- if music_service and hasattr(music_service, "player"):
- player = music_service.player
- pdebug(f"CrossfadePlugin: Player = {player}")
- if player:
- pipeline = player.processing_pipeline
- pipeline.add(self._processor)
- pinfo("CrossfadePlugin: Prozessor zur Pipeline hinzugefügt")
- return
- else:
- pdebug("CrossfadePlugin: Player ist None")
- else:
- pdebug(f"CrossfadePlugin: Service hat kein 'player' Attribut")
- pdebug("CrossfadePlugin: Keine Pipeline gefunden, Prozessor nicht registriert")
- except Exception as e:
- perror(f"CrossfadePlugin: Fehler beim Registrieren: {e}")
- import traceback
- pdebug(traceback.format_exc())
- def _unregister_processor(self) -> None:
- """Entfernt Prozessor aus der Audio-Pipeline."""
- if not self._processor:
- return
- try:
- if self.application:
- if hasattr(self.application, "services"):
- music_service = self.application.services.get_service("music_player")
- if music_service and hasattr(music_service, "player"):
- pipeline = music_service.player.processing_pipeline
- pipeline.remove(self._processor.id)
- pdebug("CrossfadePlugin: Prozessor aus Pipeline entfernt")
- except Exception as e:
- perror(f"CrossfadePlugin: Fehler beim Entfernen: {e}")
- @property
- def processor(self) -> CrossfadeProcessor | None:
- """Zugriff auf den Crossfade-Prozessor."""
- return self._processor
- def get_stats(self) -> dict:
- """Liefert Statistiken."""
- if self._processor:
- return self._processor.get_config()
- return {}
|