Adjust receiver protocol to accommodate config
This commit is contained in:
parent
09fe3b3e6c
commit
04859b8c8b
5 changed files with 32 additions and 21 deletions
|
@ -10,15 +10,15 @@ from .mpd.listener import MpdStateListener
|
|||
from .song_receiver import (
|
||||
Receiver,
|
||||
choose_loop_factory,
|
||||
import_receiver,
|
||||
construct_receiver,
|
||||
)
|
||||
|
||||
|
||||
async def listen(
|
||||
config: Config, listener: MpdStateListener, receiver_types: Iterable[type[Receiver]]
|
||||
config: Config, listener: MpdStateListener, receivers: Iterable[Receiver]
|
||||
) -> None:
|
||||
await listener.start(config.mpd)
|
||||
receivers = (rec(listener, config) for rec in receiver_types)
|
||||
await asyncio.gather(*(rec.start(listener) for rec in receivers))
|
||||
await listener.loop(receivers)
|
||||
|
||||
|
||||
|
@ -28,11 +28,11 @@ def main() -> None:
|
|||
print(config)
|
||||
|
||||
listener = MpdStateListener(config.cache)
|
||||
receiver_types = tuple(import_receiver(rec) for rec in config.receivers)
|
||||
receivers = tuple(construct_receiver(rec_config) for rec_config in config.receivers)
|
||||
factory = choose_loop_factory(receivers)
|
||||
|
||||
factory = choose_loop_factory(receiver_types)
|
||||
asyncio.run(
|
||||
listen(config, listener, receiver_types),
|
||||
listen(config, listener, receivers),
|
||||
loop_factory=factory.make_loop,
|
||||
debug=True,
|
||||
)
|
||||
|
|
|
@ -21,7 +21,7 @@ class BaseReceiverConfig(Protocol):
|
|||
|
||||
@dataclass(slots=True)
|
||||
class CocoaReceiverConfig(BaseReceiverConfig):
|
||||
kind: Literal["cocoa"] = "cocoa"
|
||||
kind: Literal["cocoa"] = field(default="cocoa", repr=False)
|
||||
|
||||
|
||||
ReceiverConfig = Annotated[
|
||||
|
|
|
@ -83,8 +83,7 @@ class MpdStateListener(Player):
|
|||
|
||||
if status["state"] == "stop":
|
||||
print("Nothing playing")
|
||||
for r in self.receivers:
|
||||
r.update(None)
|
||||
await self.update(None)
|
||||
return
|
||||
|
||||
art = await self.art_cache.get_cached_artwork(current)
|
||||
|
@ -93,8 +92,10 @@ class MpdStateListener(Player):
|
|||
|
||||
song = mpd_current_to_song(status, current, to_artwork(art))
|
||||
rprint(song)
|
||||
for r in self.receivers:
|
||||
r.update(song)
|
||||
await self.update(song)
|
||||
|
||||
async def update(self, song: Song | None) -> None:
|
||||
await asyncio.gather(*(r.update(song) for r in self.receivers))
|
||||
|
||||
async def get_art(self, file: str) -> bytes | None:
|
||||
picture = await self.readpicture(file)
|
||||
|
|
|
@ -37,7 +37,7 @@ from MediaPlayer import (
|
|||
MPRemoteCommandHandlerStatusSuccess,
|
||||
)
|
||||
|
||||
from ...config.model import Config
|
||||
from ...config.model import CocoaReceiverConfig
|
||||
from ...player import Player
|
||||
from ...song import PlaybackState, Song
|
||||
from ...song_receiver import LoopFactory, Receiver
|
||||
|
@ -146,7 +146,10 @@ class CocoaNowPlayingReceiver(Receiver):
|
|||
def loop_factory(cls) -> LoopFactory[CoreFoundationEventLoop]:
|
||||
return CocoaLoopFactory()
|
||||
|
||||
def __init__(self, player: Player, config: Config):
|
||||
def __init__(self, config: CocoaReceiverConfig):
|
||||
pass
|
||||
|
||||
async def start(self, player: Player) -> None:
|
||||
self.cmd_center = MPRemoteCommandCenter.sharedCommandCenter()
|
||||
self.info_center = MPNowPlayingInfoCenter.defaultCenter()
|
||||
|
||||
|
@ -184,7 +187,7 @@ class CocoaNowPlayingReceiver(Receiver):
|
|||
# unpause with remote commands.
|
||||
self.info_center.setPlaybackState_(MPMusicPlaybackStatePlaying)
|
||||
|
||||
def update(self, song: Song | None) -> None:
|
||||
async def update(self, song: Song | None) -> None:
|
||||
if song:
|
||||
self.info_center.setNowPlayingInfo_(song_to_media_item(song))
|
||||
self.info_center.setPlaybackState_(playback_state_to_cocoa(song.state))
|
||||
|
|
|
@ -3,7 +3,7 @@ from dataclasses import dataclass
|
|||
from importlib import import_module
|
||||
from typing import Generic, Iterable, Literal, Protocol, TypeVar, cast
|
||||
|
||||
from .config.model import BaseReceiverConfig, Config
|
||||
from .config.model import BaseReceiverConfig
|
||||
from .player import Player
|
||||
from .song import Song
|
||||
from .tools.types import not_none
|
||||
|
@ -20,10 +20,12 @@ class LoopFactory(Generic[T], Protocol):
|
|||
|
||||
|
||||
class Receiver(Protocol):
|
||||
def __init__(self, player: Player, config: Config) -> None: ...
|
||||
def __init__(self, config: BaseReceiverConfig): ...
|
||||
@classmethod
|
||||
def loop_factory(cls) -> LoopFactory[AbstractEventLoop]: ...
|
||||
def update(self, song: Song | None) -> None: ...
|
||||
|
||||
async def start(self, player: Player) -> None: ...
|
||||
async def update(self, song: Song | None) -> None: ...
|
||||
|
||||
|
||||
class ReceiverModule(Protocol):
|
||||
|
@ -42,8 +44,8 @@ class DefaultLoopFactory(LoopFactory[AbstractEventLoop]):
|
|||
|
||||
@dataclass
|
||||
class IncompatibleReceiverError(Exception):
|
||||
a: type[Receiver]
|
||||
b: type[Receiver]
|
||||
a: Receiver
|
||||
b: Receiver
|
||||
|
||||
|
||||
def import_receiver(config: BaseReceiverConfig) -> type[Receiver]:
|
||||
|
@ -53,13 +55,18 @@ def import_receiver(config: BaseReceiverConfig) -> type[Receiver]:
|
|||
return mod.receiver
|
||||
|
||||
|
||||
def construct_receiver(config: BaseReceiverConfig) -> Receiver:
|
||||
cls = import_receiver(config)
|
||||
return cls(config)
|
||||
|
||||
|
||||
def choose_loop_factory(
|
||||
receivers: Iterable[type[Receiver]],
|
||||
receivers: Iterable[Receiver],
|
||||
) -> LoopFactory[AbstractEventLoop]:
|
||||
"""Given the desired receivers, determine which asyncio event loop implementation will support all of them. Will raise an IncompatibleReceiverError if no such implementation exists."""
|
||||
|
||||
chosen_fac: LoopFactory[AbstractEventLoop] = DefaultLoopFactory()
|
||||
chosen_rec: type[Receiver] | None = None
|
||||
chosen_rec: Receiver | None = None
|
||||
|
||||
for rec in receivers:
|
||||
fac = rec.loop_factory()
|
||||
|
|
Loading…
Reference in a new issue