-
-
Notifications
You must be signed in to change notification settings - Fork 26
/
Copy pathmpris.py
134 lines (102 loc) Β· 3.44 KB
/
mpris.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
"""A module for interfacing with an MPRIS MediaPlayer2 over dbus."""
from dataclasses import dataclass
from enum import Enum, auto
import json
import os
import sys
import logging
from typing import List
import subprocess
from dasbus.connection import SessionMessageBus
from dasbus.client.proxy import disconnect_proxy
from amplipi import utils
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
sh = logging.StreamHandler(sys.stdout)
logger.addHandler(sh)
class CommandTypes(Enum):
PLAY = auto()
PAUSE = auto()
NEXT = auto()
PREVIOUS = auto()
@dataclass
class Metadata:
"""A data class for storing metadata on a song."""
artist: str = ''
title: str = ''
art_url: str = ''
album: str = ''
state: str = ''
connected: bool = False
state_changed_time: float = 0
# TODO: consider removing the script this starts and doing it all here since we no longer poll
class MPRIS:
"""A class for interfacing with an MPRIS MediaPlayer2 over dbus."""
def __init__(self, service_suffix, metadata_path) -> None:
self.mpris = SessionMessageBus().get_proxy(
service_name=f"org.mpris.MediaPlayer2.{service_suffix}",
object_path="/org/mpris/MediaPlayer2",
interface_name="org.mpris.MediaPlayer2.Player"
)
self.capabilities: List[CommandTypes] = []
self.service_suffix = service_suffix
self.metadata_path = metadata_path
self._closing = False
try:
child_args = [sys.executable,
f"{utils.get_folder('streams')}/MPRIS_metadata_reader.py",
self.service_suffix,
self.metadata_path]
self.metadata_process = subprocess.Popen(args=child_args, stdout=sys.stdout, stderr=sys.stderr)
except Exception as e:
logger.exception(f'Exception starting MPRIS metadata process: {e}')
def play(self) -> None:
"""Plays."""
self.mpris.Play()
def pause(self) -> None:
"""Pauses."""
self.mpris.Pause()
def next(self) -> None:
"""Skips song."""
self.mpris.Next()
def previous(self) -> None:
"""Goes back a song."""
self.mpris.Previous()
def play_pause(self) -> None:
"""Plays or pauses depending on current state."""
self.mpris.PlayPause()
def get_capabilities(self) -> List[CommandTypes]:
"""Returns a list of supported commands."""
if len(self.capabilities) == 0:
if self.mpris.CanPlay:
self.capabilities.append(CommandTypes.PLAY)
if self.mpris.CanPause:
self.capabilities.append(CommandTypes.PAUSE)
if self.mpris.CanGoNext:
self.capabilities.append(CommandTypes.NEXT)
if self.mpris.CanGoPrevious:
self.capabilities.append(CommandTypes.PREVIOUS)
return self.capabilities
def close(self):
"""Closes the MPRIS object."""
if self.metadata_process:
self.metadata_process.terminate()
if self.metadata_process.wait(1) != 0:
logger.info('Failed to stop MPRIS metadata process, killing')
self.metadata_process.kill()
self.metadata_process.communicate()
self.metadata_process = None
if self.mpris:
logger.info('disconnecting proxy')
disconnect_proxy(self.mpris)
self.mpris = None
logger.info("mpris closed")
try:
os.remove(self.metadata_path)
except FileNotFoundError:
pass
except Exception as e:
logger.exception(f'Could not remove metadata file: {e}')
logger.info(f'Closed MPRIS {self.service_suffix}')
def __del__(self):
self.close()