[WIP] API adaptations for music.mpd

This commit is contained in:
Fabio Manganiello 2024-04-03 22:44:29 +02:00
parent 4e8c6dd435
commit c3015bc687
Signed by: blacklight
GPG key ID: D90FBA7F76362774
2 changed files with 116 additions and 21 deletions

View file

@ -333,6 +333,15 @@ class MusicMopidyPlugin(RunnablePlugin):
:return: .. schema:: mopidy.MopidyStatusSchema :return: .. schema:: mopidy.MopidyStatusSchema
""" """
# Note: stop could be interpreted both as "stop the playback" and "stop
# the plugin". If the stop event is set, we assume that the user wants
# to stop the plugin.
if self.should_stop():
if self._client:
self._client.stop()
return None
return self._exec_with_status({'method': 'core.playback.stop'}) return self._exec_with_status({'method': 'core.playback.stop'})
@action @action

View file

@ -116,6 +116,33 @@ class MusicMpdPlugin(MusicPlugin, RunnablePlugin):
return None, error return None, error
@staticmethod
def _dump_directory(item: dict):
item['type'] = 'directory'
item['uri'] = item['name'] = item['directory']
return item
@staticmethod
def _dump_playlist(item: dict):
item['type'] = 'playlist'
item['uri'] = item['name'] = item['playlist']
item['last_modified'] = item.pop('last-modified', None)
return item
@staticmethod
def _dump_track(item: dict, pos: Optional[int] = None):
item['type'] = 'track'
item['uri'] = item['file']
for attr in ('time', 'track', 'disc'):
item[attr] = int(item[attr]) if item.get(attr) is not None else None
if 'pos' in item:
item['playlist_pos'] = int(item.pop('pos'))
elif pos is not None:
item['playlist_pos'] = pos
return item
@action @action
def play(self, resource: Optional[str] = None, **__): def play(self, resource: Optional[str] = None, **__):
""" """
@ -169,6 +196,15 @@ class MusicMpdPlugin(MusicPlugin, RunnablePlugin):
@action @action
def stop(self, *_, **__): # type: ignore def stop(self, *_, **__): # type: ignore
"""Stop playback""" """Stop playback"""
# Note: stop could be interpreted both as "stop the playback" and "stop
# the plugin". If the stop event is set, we assume that the user wants
# to stop the plugin.
if self.should_stop():
if self.client:
self.client.disconnect()
return None
return self._exec('stop') return self._exec('stop')
@action @action
@ -344,17 +380,44 @@ class MusicMpdPlugin(MusicPlugin, RunnablePlugin):
self._exec('rm', p) self._exec('rm', p)
@action @action
def move(self, from_pos, to_pos): def move(
self,
start: Optional[int] = None,
end: Optional[int] = None,
position: Optional[int] = None,
from_pos: Optional[int] = None,
to_pos: Optional[int] = None,
):
""" """
Move the playlist item in position <from_pos> to position <to_pos> Move the playlist items from the positions ``start`` to ``end`` to the
new position ``position``.
:param from_pos: Track current position You can pass either:
:type from_pos: int
:param to_pos: Track new position - ``start``, ``end`` and ``position`` to move a slice of tracks
:type to_pos: int from ``start`` to ``end`` to the new position ``position``.
- ``from_pos`` and ``to_pos`` to move a single track from
``from_pos`` to ``to_pos``.
.. note: Positions are 0-based (i.e. the first track has position 0).
:param start: Start position of the selection.
:param end: End position of the selection.
:param position: New position.
:param from_pos: Alias for ``start`` - it only works with one track at
the time.
:param to_pos: Alias for ``position`` - it only works with one track at
the time.
""" """
return self._exec('move', from_pos, to_pos) assert (start is not None and end is not None and position is not None) or (
from_pos is not None and to_pos is not None
), 'Specify either (start, end, position) or (from_pos, to_pos)'
if from_pos is not None and to_pos is not None:
return self._exec('move', from_pos, to_pos)
chunk = start if start == end else f'{start}:{end}'
return self._exec('move', chunk, position)
@classmethod @classmethod
def _parse_resource(cls, resource): def _parse_resource(cls, resource):
@ -546,7 +609,10 @@ class MusicMpdPlugin(MusicPlugin, RunnablePlugin):
}, },
] ]
""" """
return self._exec('playlistinfo', return_status=False) return [
self._dump_track(track, pos=i) # type: ignore
for i, track in enumerate(self._exec('playlistinfo', return_status=False))
]
@action @action
def get_playlists(self, *_, **__): def get_playlists(self, *_, **__):
@ -558,11 +624,11 @@ class MusicMpdPlugin(MusicPlugin, RunnablePlugin):
output = [ output = [
{ {
"playlist": "Rock", "playlist": "Rock",
"last-modified": "2018-06-25T21:28:19Z" "last_modified": "2018-06-25T21:28:19Z"
}, },
{ {
"playlist": "Jazz", "playlist": "Jazz",
"last-modified": "2018-06-24T22:28:29Z" "last_modified": "2018-06-24T22:28:29Z"
}, },
{ {
# ... # ...
@ -573,22 +639,27 @@ class MusicMpdPlugin(MusicPlugin, RunnablePlugin):
playlists: list = self._exec( # type: ignore playlists: list = self._exec( # type: ignore
'listplaylists', return_status=False 'listplaylists', return_status=False
) )
return sorted(playlists, key=lambda p: p['playlist'])
return sorted(
[self._dump_playlist(pl) for pl in playlists], key=lambda p: p['playlist']
)
@action @action
def get_playlist(self, playlist: str, *_, with_tracks: bool = False, **__): def get_playlist(self, playlist: str, *_, **__):
""" """
List the information (and, optionally, the items) for the specified playlist. Get the tracks in a playlist.
:param playlist: Name of the playlist :param playlist: Name of the playlist
:param with_tracks: If True then the list of tracks in the playlist will
be returned as well (default: False).
""" """
return self._exec( return [
'listplaylistinfo' if with_tracks else 'listplaylist', self._dump_track(track) # type: ignore
playlist, for track in self._exec(
return_status=False, 'listplaylistinfo', # if with_tracks else 'listplaylist',
) playlist,
return_status=False,
)
if track
]
@action @action
def add_to_playlist( def add_to_playlist(
@ -663,12 +734,27 @@ class MusicMpdPlugin(MusicPlugin, RunnablePlugin):
:param uri: URI to browse (default: root directory). :param uri: URI to browse (default: root directory).
""" """
return ( resp: dict = ( # type: ignore
self._exec('lsinfo', uri, return_status=False) self._exec('lsinfo', uri, return_status=False)
if uri if uri
else self._exec('lsinfo', return_status=False) else self._exec('lsinfo', return_status=False)
) )
ret = []
for item in resp:
if item.get('directory'):
item = self._dump_directory(item)
elif item.get('playlist'):
item = self._dump_playlist(item)
elif item.get('file'):
item = self._dump_track(item)
else:
continue
ret.append(item)
return ret
@action @action
def plchanges(self, version: int): def plchanges(self, version: int):
""" """