From ae91ed44c4083fbe70584c9184dc0e642e4adb2f Mon Sep 17 00:00:00 2001 From: Asaril Date: Mon, 15 May 2023 03:26:18 +0200 Subject: [PATCH] add mpd --- poetry.lock | 17 +++++++++- pyproject.toml | 1 + src/sleepywaves.py | 82 +++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 90 insertions(+), 10 deletions(-) diff --git a/poetry.lock b/poetry.lock index 32f792f..b577a46 100644 --- a/poetry.lock +++ b/poetry.lock @@ -299,6 +299,21 @@ files = [ {file = "pyflakes-3.0.1.tar.gz", hash = "sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd"}, ] +[[package]] +name = "python-mpd2" +version = "3.1.0" +description = "A Python MPD client library" +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "python-mpd2-3.1.0.tar.gz", hash = "sha256:f33c2cdb0d6baa74a36724f38c1c4a099a7ce2c8ec4a2bb7192150a5855df476"}, + {file = "python_mpd2-3.1.0-py2.py3-none-any.whl", hash = "sha256:c4d44a54e88a675f7301fdb11a1bd31165a6f51a664dd41e8137e92f7b02ebfb"}, +] + +[package.extras] +twisted = ["Twisted"] + [[package]] name = "rpi-gpio" version = "0.7.1" @@ -354,4 +369,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "5f10ea01a98ffb96107cc03228a3164fc600ce76ac56ed249700e5a581083f1e" +content-hash = "b90de4dbcb9039b01369909dd0a6cf26b2346671b8907ccbbe5bbea6a06a6182" diff --git a/pyproject.toml b/pyproject.toml index 29f0b07..bcdf981 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,6 +10,7 @@ python = "^3.9" spidev = "^3.6" mfrc522 = "^0.0.7" pydantic = "^1.10.7" +python-mpd2 = "^3.1.0" [tool.poetry.group.dev.dependencies] diff --git a/src/sleepywaves.py b/src/sleepywaves.py index 5bcc2fd..a488659 100644 --- a/src/sleepywaves.py +++ b/src/sleepywaves.py @@ -14,7 +14,7 @@ from dataclasses import dataclass from mfrc522.SimpleMFRC522 import SimpleMFRC522 from pydantic import BaseModel from random import randrange - +from mpd import MPDClient import RPi.GPIO as GPIO @@ -79,6 +79,10 @@ class Renderer(ABC): def is_playing(self) -> bool: pass + @abstractmethod + def close(self) -> None: + pass + class Player: reader: SimpleMFRC522 @@ -194,7 +198,7 @@ class Player: status_file.write(self.current_title.status.json(indent=2)) self.current_title = None - def process(self): + def process(self) -> None: tag_id: Optional[int] = self.read_burst() # current_tag = self.current_title.tag_id if self.current_title else None @@ -219,7 +223,7 @@ class Player: self.advance() self.start_playing() - def tag_detected(self, tag_id: int): + def tag_detected(self, tag_id: int) -> None: log.info(f"tag detected: {tag_id:x}") cfg = self.get_title_config(tag_id) if not cfg: @@ -243,11 +247,14 @@ class Player: ): self.start_time = time.time() - def tag_removed(self): + def tag_removed(self) -> None: if self.current_title is not None: log.info(f"tag removed: {self.current_title.tag_id:x}") self.stop_playing() + def close(self) -> None: + self.renderer.close() + class DebugRenderer(Renderer): def __init__(self) -> None: @@ -275,16 +282,73 @@ class DebugRenderer(Renderer): def is_playing(self) -> bool: return (self.start != 0) and (self.get_time() - self.offset < 10) + def close(self) -> None: + log.debug("DebugRenderer: close()") + + +class MpdRenderer(Renderer): + def __init__(self) -> None: + super().__init__() + + self.mpd = MPDClient() # type:ignore + self.mpd.timeout = 10 + self.mpd.connect("/var/run/mpd/socket") + self.mpd.clear() + self.mpd.single(1) + self.mpd.consume(1) + + # self.start: int = 0 + # self.offset: int = 0 + + def get_tracks(self, path: str) -> list[str]: + all_files = os.listdir(path) + return sorted([f for f in all_files if f.endswith(".mp3")]) + + def play(self, path: str, from_time: int) -> None: + log.info(f"MpdRenderer: play({path}, {from_time})") + self.mpd.clear() + self.mpd.add(f"file://{path}") + self.mpd.play() + if from_time != 0: + self.mpd.seekcur(from_time) + # self.start = int(time.time()) + # self.offset = from_time + + def get_time(self) -> int: + # return int(time.time()) - self.start + self.offset + return int(float(self.mpd.status()["elapsed"])) + + def stop(self) -> None: + log.info("MpdRenderer: stop()") + self.mpd.stop() + self.mpd.clear() + # self.start = 0 + # self.offset = 0 + + def is_playing(self) -> bool: + return self.mpd.status()["state"] == "play" + # return (self.start != 0) and (self.get_time() - self.offset < 10) + + def close(self) -> None: + self.mpd.close() + self.mpd.disconnect() + def main(media_path: str, renderer_type: str) -> None: if renderer_type == "dummy": renderer = DebugRenderer() + elif renderer_type == "mpd": + renderer = MpdRenderer() else: renderer = DebugRenderer() player = Player(media_path=media_path, renderer=renderer) - while True: - player.process() - time.sleep(1) + log.info('sleepywaves ready.') + try: + while True: + player.process() + time.sleep(1) + finally: + player.close() if __name__ == "__main__": @@ -302,8 +366,8 @@ if __name__ == "__main__": ) parser.add_argument( "--renderer", - choices=("dummy"), - default="dummy", + choices=("dummy", "mpd"), + default="mpd", help="media renderer to use as backend", )