Merge pull request 'mpd' (#5) from mpd into main

Reviewed-on: #5
This commit is contained in:
asaril 2023-05-21 20:54:43 +02:00
commit a7dad655df
3 changed files with 90 additions and 10 deletions

17
poetry.lock generated
View file

@ -299,6 +299,21 @@ files = [
{file = "pyflakes-3.0.1.tar.gz", hash = "sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd"}, {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]] [[package]]
name = "rpi-gpio" name = "rpi-gpio"
version = "0.7.1" version = "0.7.1"
@ -354,4 +369,4 @@ files = [
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.9" python-versions = "^3.9"
content-hash = "5f10ea01a98ffb96107cc03228a3164fc600ce76ac56ed249700e5a581083f1e" content-hash = "b90de4dbcb9039b01369909dd0a6cf26b2346671b8907ccbbe5bbea6a06a6182"

View file

@ -10,6 +10,7 @@ python = "^3.9"
spidev = "^3.6" spidev = "^3.6"
mfrc522 = "^0.0.7" mfrc522 = "^0.0.7"
pydantic = "^1.10.7" pydantic = "^1.10.7"
python-mpd2 = "^3.1.0"
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]

View file

@ -14,7 +14,7 @@ from dataclasses import dataclass
from mfrc522.SimpleMFRC522 import SimpleMFRC522 from mfrc522.SimpleMFRC522 import SimpleMFRC522
from pydantic import BaseModel from pydantic import BaseModel
from random import randrange from random import randrange
from mpd import MPDClient
import RPi.GPIO as GPIO import RPi.GPIO as GPIO
@ -79,6 +79,10 @@ class Renderer(ABC):
def is_playing(self) -> bool: def is_playing(self) -> bool:
pass pass
@abstractmethod
def close(self) -> None:
pass
class Player: class Player:
reader: SimpleMFRC522 reader: SimpleMFRC522
@ -194,7 +198,7 @@ class Player:
status_file.write(self.current_title.status.json(indent=2)) status_file.write(self.current_title.status.json(indent=2))
self.current_title = None self.current_title = None
def process(self): def process(self) -> None:
tag_id: Optional[int] = self.read_burst() tag_id: Optional[int] = self.read_burst()
# current_tag = self.current_title.tag_id if self.current_title else None # current_tag = self.current_title.tag_id if self.current_title else None
@ -219,7 +223,7 @@ class Player:
self.advance() self.advance()
self.start_playing() 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}") log.info(f"tag detected: {tag_id:x}")
cfg = self.get_title_config(tag_id) cfg = self.get_title_config(tag_id)
if not cfg: if not cfg:
@ -243,11 +247,14 @@ class Player:
): ):
self.start_time = time.time() self.start_time = time.time()
def tag_removed(self): def tag_removed(self) -> None:
if self.current_title is not None: if self.current_title is not None:
log.info(f"tag removed: {self.current_title.tag_id:x}") log.info(f"tag removed: {self.current_title.tag_id:x}")
self.stop_playing() self.stop_playing()
def close(self) -> None:
self.renderer.close()
class DebugRenderer(Renderer): class DebugRenderer(Renderer):
def __init__(self) -> None: def __init__(self) -> None:
@ -275,16 +282,73 @@ class DebugRenderer(Renderer):
def is_playing(self) -> bool: def is_playing(self) -> bool:
return (self.start != 0) and (self.get_time() - self.offset < 10) 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") or f.endswith(".flac"))])
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: def main(media_path: str, renderer_type: str) -> None:
if renderer_type == "dummy": if renderer_type == "dummy":
renderer = DebugRenderer() renderer = DebugRenderer()
elif renderer_type == "mpd":
renderer = MpdRenderer()
else: else:
renderer = DebugRenderer() renderer = DebugRenderer()
player = Player(media_path=media_path, renderer=renderer) player = Player(media_path=media_path, renderer=renderer)
while True: log.info('sleepywaves ready.')
player.process() try:
time.sleep(1) while True:
player.process()
time.sleep(1)
finally:
player.close()
if __name__ == "__main__": if __name__ == "__main__":
@ -302,8 +366,8 @@ if __name__ == "__main__":
) )
parser.add_argument( parser.add_argument(
"--renderer", "--renderer",
choices=("dummy"), choices=("dummy", "mpd"),
default="dummy", default="mpd",
help="media renderer to use as backend", help="media renderer to use as backend",
) )