| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- # -*- coding: utf-8 -*-
- """
- Music Extension Points.
- Extension Points für Musikquellen, Decoder und Ausgabeziele.
- """
- from abc import abstractmethod
- from typing import Any, AsyncIterator, TYPE_CHECKING
- from trixy_core.plugins.extensions.extension import Extension
- from trixy_core.plugins.extensions.extension_point import ExtensionPoint, get_global_registry
- if TYPE_CHECKING:
- from trixy_core.music.sources.base import MusicSource
- from trixy_core.music.formats.base import AudioDecoder
- # Extension Point IDs
- MUSIC_SOURCE_POINT = "music.source"
- MUSIC_DECODER_POINT = "music.decoder"
- MUSIC_OUTPUT_POINT = "music.output"
- class MusicSourceExtension(Extension["MusicSource"]):
- """
- Extension für Musikquellen.
- Ermöglicht Plugins, neue Musikquellen hinzuzufügen:
- - Streaming-Dienste (Spotify, Amazon Music, Tidal, Deezer)
- - Cloud-Speicher (Google Drive, Dropbox)
- - Netzwerk-Shares (SMB, WebDAV)
- - Podcast-Feeds
- - Internet-Radio-Verzeichnisse
- Beispiel:
- class SpotifySourceExtension(MusicSourceExtension):
- def __init__(self, plugin_name: str):
- super().__init__(
- "spotify_source",
- "Spotify",
- plugin_name,
- source_type="spotify",
- )
- async def create_instance(self, config):
- return SpotifySource(
- client_id=config["client_id"],
- client_secret=config["client_secret"],
- )
- """
- def __init__(
- self,
- extension_id: str,
- name: str,
- plugin_name: str = "",
- source_type: str = "",
- description: str = "",
- ) -> None:
- """
- Initialisiert die MusicSource Extension.
- Args:
- extension_id: Eindeutige ID
- name: Anzeigename
- plugin_name: Plugin-Name
- source_type: Quellen-Typ (z.B. "spotify", "amazon")
- description: Beschreibung
- """
- super().__init__(extension_id, name, plugin_name)
- self._info.description = description
- self._info.extension_point = MUSIC_SOURCE_POINT
- self._info.metadata["source_type"] = source_type
- @property
- def source_type(self) -> str:
- """Quellen-Typ."""
- return self._info.metadata.get("source_type", "")
- @abstractmethod
- async def create_instance(self, config: dict[str, Any]) -> "MusicSource":
- """Erstellt die MusicSource-Instanz."""
- pass
- class MusicDecoderExtension(Extension["AudioDecoder"]):
- """
- Extension für Audio-Decoder.
- Ermöglicht Plugins, neue Audio-Formate zu unterstützen:
- - Proprietäre Formate (MQA, DSD)
- - Kompressionsformate (AC3, DTS)
- - Spezielle Codecs
- Beispiel:
- class MQADecoderExtension(MusicDecoderExtension):
- def __init__(self, plugin_name: str):
- super().__init__(
- "mqa_decoder",
- "MQA Decoder",
- plugin_name,
- formats=["mqa"],
- extensions=[".mqa"],
- )
- async def create_instance(self, config):
- return MQADecoder()
- """
- def __init__(
- self,
- extension_id: str,
- name: str,
- plugin_name: str = "",
- formats: list[str] | None = None,
- extensions: list[str] | None = None,
- mime_types: list[str] | None = None,
- description: str = "",
- ) -> None:
- """
- Initialisiert die AudioDecoder Extension.
- Args:
- extension_id: Eindeutige ID
- name: Anzeigename
- plugin_name: Plugin-Name
- formats: Unterstützte Format-Namen
- extensions: Dateiendungen (z.B. [".mqa"])
- mime_types: MIME-Types
- description: Beschreibung
- """
- super().__init__(extension_id, name, plugin_name)
- self._info.description = description
- self._info.extension_point = MUSIC_DECODER_POINT
- self._info.metadata["formats"] = formats or []
- self._info.metadata["extensions"] = extensions or []
- self._info.metadata["mime_types"] = mime_types or []
- @property
- def formats(self) -> list[str]:
- """Unterstützte Formate."""
- return self._info.metadata.get("formats", [])
- @property
- def file_extensions(self) -> list[str]:
- """Unterstützte Dateiendungen."""
- return self._info.metadata.get("extensions", [])
- @abstractmethod
- async def create_instance(self, config: dict[str, Any]) -> "AudioDecoder":
- """Erstellt die AudioDecoder-Instanz."""
- pass
- class MusicOutputExtension(Extension):
- """
- Extension für Ausgabeziele.
- Ermöglicht Plugins, neue Ausgabeziele hinzuzufügen:
- - Chromecast/Google Cast
- - AirPlay
- - Sonos
- - Bluetooth-Lautsprecher
- - DLNA/UPnP
- Beispiel:
- class ChromecastOutputExtension(MusicOutputExtension):
- def __init__(self, plugin_name: str):
- super().__init__(
- "chromecast_output",
- "Google Chromecast",
- plugin_name,
- output_type="chromecast",
- )
- async def create_instance(self, config):
- return ChromecastOutput()
- """
- def __init__(
- self,
- extension_id: str,
- name: str,
- plugin_name: str = "",
- output_type: str = "",
- description: str = "",
- ) -> None:
- """
- Initialisiert die MusicOutput Extension.
- Args:
- extension_id: Eindeutige ID
- name: Anzeigename
- plugin_name: Plugin-Name
- output_type: Ausgabe-Typ
- description: Beschreibung
- """
- super().__init__(extension_id, name, plugin_name)
- self._info.description = description
- self._info.extension_point = MUSIC_OUTPUT_POINT
- self._info.metadata["output_type"] = output_type
- @property
- def output_type(self) -> str:
- """Ausgabe-Typ."""
- return self._info.metadata.get("output_type", "")
- def setup_music_extension_points() -> dict[str, ExtensionPoint]:
- """
- Richtet alle Music Extension Points ein.
- Returns:
- Dict mit allen erstellten Extension Points
- """
- registry = get_global_registry()
- points = {}
- # Musikquellen
- points[MUSIC_SOURCE_POINT] = registry.create_point(
- id=MUSIC_SOURCE_POINT,
- name="Musikquellen",
- description="Erweiterung um neue Musikquellen (Spotify, Amazon, etc.)",
- category="music",
- allows_multiple=True,
- )
- # Audio-Decoder
- points[MUSIC_DECODER_POINT] = registry.create_point(
- id=MUSIC_DECODER_POINT,
- name="Audio-Decoder",
- description="Erweiterung um neue Audio-Formate",
- category="music",
- allows_multiple=True,
- )
- # Ausgabeziele
- points[MUSIC_OUTPUT_POINT] = registry.create_point(
- id=MUSIC_OUTPUT_POINT,
- name="Ausgabeziele",
- description="Erweiterung um neue Ausgabeziele (Chromecast, AirPlay, etc.)",
- category="music",
- allows_multiple=True,
- )
- return points
- def get_music_sources() -> list["MusicSource"]:
- """Holt alle registrierten Musikquellen."""
- registry = get_global_registry()
- point = registry.get_point(MUSIC_SOURCE_POINT)
- if point:
- return point.get_all_instances()
- return []
- def get_music_decoders() -> list["AudioDecoder"]:
- """Holt alle registrierten Decoder."""
- registry = get_global_registry()
- point = registry.get_point(MUSIC_DECODER_POINT)
- if point:
- return point.get_all_instances()
- return []
|