Skip to content

Commit

Permalink
Merge pull request #996 from onkelandy/lms
Browse files Browse the repository at this point in the history
LMS: command improvements, rename some items/commands
  • Loading branch information
onkelandy authored Jan 24, 2025
2 parents 962ab8c + ea38eb0 commit 514f733
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 44 deletions.
33 changes: 25 additions & 8 deletions lms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,9 @@ def _transform_send_data(self, data=None, **kwargs):

def _transform_received_data(self, data):
# fix weird representation of MAC address (%3A = :), etc.
data_temp = data.replace("%20", "PPLACEHOLDERR")
data_temp = data.replace("%20", "PPLACcCEHOLDERR")
data = urllib.parse.unquote(data_temp)
data = data.replace("PPLACEHOLDERR", "%20")
data = data.replace("PPLACcCEHOLDERR", "%20")
return data

def _process_additional_data(self, command: str, data: Any, value: Any, custom: int, by: str | None = None):
Expand All @@ -110,7 +110,16 @@ def trigger_read(command):
self.send_command(command + CUSTOM_SEP + custom)

if command == f'server.newclient':
self.logger.debug(f"Got new client connection {command}, re-reading players")
self.logger.debug(f"Got new client connection {command}, re-reading players.")
self.send_command('server.players')
if value in self._custom_values.get(1):
self.logger.debug(f"Subscribing to updates: {value}")
self.send_command('player.info.player.status_subscribe' + CUSTOM_SEP + value, True)
self.read_all_commands('player.info.currentsong' + CUSTOM_SEP + value)
self.read_all_commands('player.control' + CUSTOM_SEP + value)

if command == f'server.forgetclient':
self.logger.debug(f"Got forget client connection {command}: {value}, re-reading players")
self.send_command('server.players')

if command == f'server.players':
Expand Down Expand Up @@ -152,6 +161,14 @@ def find_player_index(target, mac_list):
if not custom:
return

if command == f'player.info.player.connected{CUSTOM_SEP}{custom}':
self.logger.debug(f"Got client (dis)connection {command}: {value}, re-reading players")
self.send_command('server.players')

if command == f'player.info.player.name{CUSTOM_SEP}{custom}':
self.logger.debug(f"Got name {command}: {value}, re-reading players")
self.send_command('server.players')

if command == f'player.playlist.rename_current{CUSTOM_SEP}{custom}':
self.logger.debug(f"Got command rename_current {command}, re-reading playlists")
self.send_command('server.playlists.available')
Expand Down Expand Up @@ -204,14 +221,14 @@ def find_player_index(target, mac_list):
# set playlist ID
if command == f'player.playlist.load{CUSTOM_SEP}{custom}':
self.logger.debug(f"Got command load {command} data {data} value {value} custom {custom} by {by}")
trigger_read('player.playlist.id')
trigger_read('player.playlist.current_id')
trigger_read('player.control.playmode')

if command == f'player.playlist.id{CUSTOM_SEP}{custom}':
if command == f'player.playlist.current_id{CUSTOM_SEP}{custom}':
self.logger.debug(f"Got command id {command} data {data} value {value} custom {custom} by {by}")
self._parameters['CURRENT_LIST_ID'][custom] = value
trigger_read('player.playlist.name')
trigger_read('player.playlist.url')
trigger_read('player.playlist.current_name')
trigger_read('player.playlist.current_url')

if command == f'player.control.sync{CUSTOM_SEP}{custom}':
self.logger.debug(f"Got command sync {command} data {data} value {value} custom {custom} by {by}")
Expand All @@ -225,7 +242,7 @@ def find_player_index(target, mac_list):
trigger_read('player.info.currentsong.album')
trigger_read('player.info.currentsong.artist')
trigger_read('player.info.currentsong.genre')
trigger_read('player.info.currentsong.path')
trigger_read('player.info.currentsong.file_path')

# update on new song
if command == f'player.control.playpause{CUSTOM_SEP}{custom}' and value:
Expand Down
23 changes: 12 additions & 11 deletions lms/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
'members': {'read': True, 'write': False, 'read_cmd': 'syncgroups ?', 'item_type': 'list', 'dev_datatype': 'LMSSyncmembers', 'reply_pattern': r'^syncgroups\s?(.*)?$', 'custom_disabled': True, 'item_attrs': {'initial': True}},
'names': {'read': True, 'write': False, 'read_cmd': 'syncgroups ?', 'item_type': 'list', 'dev_datatype': 'LMSSyncnames', 'reply_pattern': r'^syncgroups\s?(.*)?$', 'custom_disabled': True, 'item_attrs': {'initial': False}},
},
'newclient': {'read': True, 'write': False, 'item_type': 'str', 'dev_datatype': 'str', 'reply_pattern': r'^({CUSTOM_PATTERN1}) client new$', 'custom_disabled': True},
'newclient': {'read': True, 'write': False, 'item_type': 'str', 'dev_datatype': 'str', 'reply_pattern': [r'^({CUSTOM_PATTERN1}) client new$', r'^({CUSTOM_PATTERN1}) client reconnect$'], 'custom_disabled': True},
'forgetclient': {'read': True, 'write': False, 'item_type': 'str', 'dev_datatype': 'str', 'reply_pattern': r'^({CUSTOM_PATTERN1}) client forget$', 'custom_disabled': True},
'players': {'read': True, 'write': False, 'read_cmd': 'players 0 100', 'item_type': 'dict', 'dev_datatype': 'LMSPlayers', 'reply_pattern': r'^players 0 100 (.*)', 'custom_disabled': True, 'item_attrs': {'initial': True, 'item_template': 'players'}},
'playlists': {
'available': {'read': True, 'write': False, 'read_cmd': 'playlists 0 1000 tags:u', 'item_type': 'dict', 'dev_datatype': 'LMSPlaylists', 'reply_pattern': r'^playlists 0 1000(?: tags:[u,s])? (.*)', 'custom_disabled': True, 'item_attrs': {'initial': True, 'item_template': 'playlists'}},
Expand Down Expand Up @@ -48,8 +49,8 @@
},
'player_plugins': {
'customskip': {
'active': {'read': True, 'write': True, 'item_type': 'str', 'write_cmd': '{CUSTOM_ATTR1} customskip setfilter {VALUE}.cs.xml', 'read_cmd': '{CUSTOM_ATTR1} playerpref plugin.customskip3:filter ?', 'reply_pattern': [r'^{CUSTOM_PATTERN1} prefset plugin.customskip3 filter (.*).cs.xml$', r'^{CUSTOM_PATTERN1} prefset plugin.customskip3 filter (0)$', r'{CUSTOM_PATTERN1} playerpref plugin.customskip3:filter (.*).cs.xml'], 'dev_datatype': 'str', 'item_attrs': {'initial': True}},
'remove': {'read': False, 'write': True, 'item_type': 'bool', 'write_cmd': '{CUSTOM_ATTR1} customskip clearfilter', 'dev_datatype': 'str'},
'active_filter': {'read': True, 'write': True, 'item_type': 'str', 'write_cmd': '{CUSTOM_ATTR1} customskip setfilter {VALUE}.cs.xml', 'read_cmd': '{CUSTOM_ATTR1} playerpref plugin.customskip3:filter ?', 'reply_pattern': [r'^{CUSTOM_PATTERN1} prefset plugin.customskip3 filter (.*).cs.xml$', r'^{CUSTOM_PATTERN1} prefset plugin.customskip3 filter (0)$', r'{CUSTOM_PATTERN1} playerpref plugin.customskip3:filter (.*).cs.xml'], 'dev_datatype': 'str', 'item_attrs': {'initial': True}},
'remove_filter': {'read': False, 'write': True, 'item_type': 'bool', 'write_cmd': '{CUSTOM_ATTR1} customskip clearfilter', 'dev_datatype': 'str'},
},
},
'player': {
Expand All @@ -59,7 +60,7 @@
'playpause': {'read': True, 'write': True, 'item_type': 'bool', 'write_cmd': '{CUSTOM_ATTR1} {VALUE}', 'dev_datatype': 'LMSPlay', 'reply_pattern': [r'^{CUSTOM_PATTERN1} (?:playlist\s)?(play|pause)(?:\s3)?$', r'^{CUSTOM_PATTERN1} pause (0|1)'], 'item_attrs': {'enforce': True}},
'stop': {'read': True, 'write': True, 'item_type': 'bool', 'write_cmd': '{CUSTOM_ATTR1} {VALUE}', 'dev_datatype': 'LMSStop', 'reply_pattern': [r'^{CUSTOM_PATTERN1} (?:playlist\s)?(stop)$', r'^{CUSTOM_PATTERN1} (?:playlist\s)?(play|pause)(?:\s3)?$'], 'item_attrs': {'enforce': True}},
'mute': {'read': True, 'write': True, 'read_cmd': '{CUSTOM_ATTR1} mixer muting ?', 'item_type': 'bool', 'write_cmd': '{CUSTOM_ATTR1} mixer muting {RAW_VALUE:01}', 'dev_datatype': 'LMSonoff', 'reply_pattern': [r'^{CUSTOM_PATTERN1} mixer muting$', r'^{CUSTOM_PATTERN1} (?:mixer muting|prefset server mute) (\d)'], 'item_attrs': {'initial': True, 'enforce': True}},
'volume': {'read': True, 'write': True, 'read_cmd': '{CUSTOM_ATTR1} mixer volume ?', 'item_type': 'num', 'write_cmd': '{CUSTOM_ATTR1} mixer volume {VALUE}', 'dev_datatype': 'str', 'reply_pattern': [r'^{CUSTOM_PATTERN1} (?:mixer volume |prefset server volume )(\-?\d{1,3})', r'^{CUSTOM_PATTERN1} status(?:.*)mixer volume:([^\s]+)']},
'volume': {'read': True, 'write': True, 'read_cmd': '{CUSTOM_ATTR1} mixer volume ?', 'item_type': 'num', 'write_cmd': '{CUSTOM_ATTR1} mixer volume {VALUE}', 'dev_datatype': 'str', 'reply_pattern': [r'^{CUSTOM_PATTERN1} (?:mixer volume |prefset server volume )(\-?\d{1,3})', r'^{CUSTOM_PATTERN1} status(?:.*)mixer volume:([^\s]+)'], 'item_attrs': {'initial': True}},
'volume_fading': {'read': False, 'write': True, 'item_type': 'num', 'write_cmd': '{CUSTOM_ATTR1} mixer volume {VALUE}', 'dev_datatype': 'str', 'item_attrs': {'item_template': 'volume_fading'}},
'volume_low': {'read': False, 'write': True, 'item_type': 'num', 'write_cmd': '{CUSTOM_ATTR1} mixer volume {VALUE}', 'dev_datatype': 'str', 'send_retries': 0, 'item_attrs': {'attributes': {'cache': True, 'enforce_updates': True, 'initial_value': 60}}},
'volume_high': {'read': False, 'write': True, 'item_type': 'num', 'write_cmd': '{CUSTOM_ATTR1} mixer volume {VALUE}', 'dev_datatype': 'str', 'send_retries': 0, 'item_attrs': {'attributes': {'cache': True, 'enforce_updates': True, 'initial_value': 80}}},
Expand All @@ -82,12 +83,12 @@
'playlist': {
'rename_current': {'read': False, 'write': True, 'item_type': 'str', 'write_cmd': '{CUSTOM_ATTR1} playlists rename playlist_id:{CUSTOM_PARAM1:CURRENT_LIST_ID} newname:{VALUE}', 'dev_datatype': 'str', 'reply_pattern': r'^{CUSTOM_PATTERN1} playlists rename playlist_id:\d+\s+newname:([^\s]+)(?:\s+overwritten_playlist_id:\d+)?$', 'item_attrs': {'enforce': True}},
'delete_current': {'read': False, 'write': True, 'write_cmd': '{CUSTOM_ATTR1} playlists delete playlist_id:{CUSTOM_PARAM1:CURRENT_LIST_ID}', 'item_type': 'bool', 'dev_datatype': 'LMSDeletePlaylist', 'reply_pattern': r'^{CUSTOM_PATTERN1} playlists delete playlist_id:(\d+)', 'send_retries': 0, 'item_attrs': {'enforce': True, 'attributes': {'remark': 'Be careful, instantly deletes the current playlist!'}}},
'repeat': {'read': True, 'write': True, 'read_cmd': '{CUSTOM_ATTR1} playlist repeat ?', 'item_type': 'str', 'write_cmd': '{CUSTOM_ATTR1} playlist repeat {VALUE}', 'dev_datatype': 'str', 'reply_pattern': [r'^{CUSTOM_PATTERN1} prefset server repeat {LOOKUP}$', r'^{CUSTOM_PATTERN1} playlist repeat {LOOKUP}$', r'^{CUSTOM_PATTERN1} status(?:.*)playlist repeat:{LOOKUP}$'], 'lookup': 'REPEAT', 'item_attrs': {'initial': True, 'attributes': {'remark': '0 = Off, 1 = Song, 2 = Playlist'}, 'lookup_item': True}},
'shuffle': {'read': True, 'write': True, 'read_cmd': '{CUSTOM_ATTR1} playlist shuffle ?', 'item_type': 'str', 'write_cmd': '{CUSTOM_ATTR1} playlist shuffle {VALUE}', 'dev_datatype': 'str', 'reply_pattern': [r'^{CUSTOM_PATTERN1} prefset server shuffle {LOOKUP}$', r'^{CUSTOM_PATTERN1} playlist shuffle {LOOKUP}$', r'^{CUSTOM_PATTERN1} status(?:.*)playlist shuffle:{LOOKUP}$'], 'lookup': 'SHUFFLE', 'item_attrs': {'initial': True, 'attributes': {'remark': '0 = Off, 1 = Song, 2 = Album'}, 'lookup_item': True}},
'repeat': {'read': True, 'write': True, 'read_cmd': '{CUSTOM_ATTR1} playlist repeat ?', 'item_type': 'str', 'write_cmd': '{CUSTOM_ATTR1} playlist repeat {VALUE}', 'dev_datatype': 'str', 'reply_pattern': [r'^{CUSTOM_PATTERN1} prefset server repeat {LOOKUP}$', r'^{CUSTOM_PATTERN1} playlist repeat {LOOKUP}$', r'^{CUSTOM_PATTERN1} status(?:.*)playlist repeat:{LOOKUP}$'], 'lookup': 'REPEAT', 'item_attrs': {'initial': True, 'attributes': {'initial_value': 'OFF', 'remark': '0 = Off, 1 = Song, 2 = Playlist'}, 'lookup_item': True}},
'shuffle': {'read': True, 'write': True, 'read_cmd': '{CUSTOM_ATTR1} playlist shuffle ?', 'item_type': 'str', 'write_cmd': '{CUSTOM_ATTR1} playlist shuffle {VALUE}', 'dev_datatype': 'str', 'reply_pattern': [r'^{CUSTOM_PATTERN1} prefset server shuffle {LOOKUP}$', r'^{CUSTOM_PATTERN1} playlist shuffle {LOOKUP}$', r'^{CUSTOM_PATTERN1} status(?:.*)playlist shuffle:{LOOKUP}$'], 'lookup': 'SHUFFLE', 'item_attrs': {'initial': True, 'attributes': {'initial_value': 'OFF', 'remark': '0 = Off, 1 = Song, 2 = Album'}, 'lookup_item': True}},
'index': {'read': True, 'write': True, 'read_cmd': '{CUSTOM_ATTR1} playlist index ?', 'write_cmd': '{CUSTOM_ATTR1} playlist index {VALUE}', 'item_type': 'str', 'dev_datatype': 'str', 'reply_pattern': [r'^{CUSTOM_PATTERN1} playlist (?:index|newsong .*) (\d+)$', r'^{CUSTOM_PATTERN1} status(?:.*)playlist_cur_index:(\d*[^\s]+)', r'^{CUSTOM_PATTERN1} prefset server currentSong (\d+)$', r'^{CUSTOM_PATTERN1} playlist jump (\d+)']},
'name': {'read': True, 'write': True, 'read_cmd': '{CUSTOM_ATTR1} playlist name ?', 'write_cmd': '{CUSTOM_ATTR1} playlist name {VALUE}', 'item_type': 'str', 'dev_datatype': 'str', 'reply_pattern': [r'^{CUSTOM_PATTERN1} playlistcontrol cmd:load playlist_name:(.*) count:(?:\d+)$', r'^{CUSTOM_PATTERN1} playlist name (.*[^?])', r'^{CUSTOM_PATTERN1} playlist playlistsinfo id:(?:\d+) name:(.*) modified:']},
'url': {'read': True, 'write': False, 'read_cmd': '{CUSTOM_ATTR1} playlist playlistsinfo url', 'item_type': 'str', 'dev_datatype': 'str', 'reply_pattern': r'^{CUSTOM_PATTERN1} playlist playlistsinfo (?:url\s)?id:(?:\d+) name:(?:.*) modified:(?:0|1) url:(.*)'},
'id': {'read': True, 'write': True, 'read_cmd': '{CUSTOM_ATTR1} playlist playlistsinfo', 'write_cmd': '{CUSTOM_ATTR1} playlistcontrol cmd:load playlist_id:{VALUE}', 'item_type': 'num', 'dev_datatype': 'str', 'reply_pattern': [r'^{CUSTOM_PATTERN1} (?:playlist playlistsinfo |playlistcontrol cmd:load playlist_)id:(\d+)', r'^{CUSTOM_PATTERN1} playlist loadtracks playlist.id=(\d+)\s'], 'item_attrs': {'initial': True}},
'current_name': {'read': True, 'write': True, 'read_cmd': '{CUSTOM_ATTR1} playlist name ?', 'write_cmd': '{CUSTOM_ATTR1} playlist name {VALUE}', 'item_type': 'str', 'dev_datatype': 'str', 'reply_pattern': [r'^{CUSTOM_PATTERN1} playlistcontrol cmd:load playlist_name:(.*) count:(?:\d+)$', r'^{CUSTOM_PATTERN1} playlist name (.*[^?])', r'^{CUSTOM_PATTERN1} playlist playlistsinfo id:(?:\d+) name:(.*) modified:']},
'current_url': {'read': True, 'write': False, 'read_cmd': '{CUSTOM_ATTR1} playlist playlistsinfo url', 'item_type': 'str', 'dev_datatype': 'str', 'reply_pattern': r'^{CUSTOM_PATTERN1} playlist playlistsinfo (?:url\s)?id:(?:\d+) name:(?:.*) modified:(?:0|1) url:(.*)'},
'current_id': {'read': True, 'write': True, 'read_cmd': '{CUSTOM_ATTR1} playlist playlistsinfo', 'write_cmd': '{CUSTOM_ATTR1} playlistcontrol cmd:load playlist_id:{VALUE}', 'item_type': 'num', 'dev_datatype': 'str', 'reply_pattern': [r'^{CUSTOM_PATTERN1} (?:playlist playlistsinfo |playlistcontrol cmd:load playlist_)id:(\d+)', r'^{CUSTOM_PATTERN1} playlist loadtracks playlist.id=(\d+)\s'], 'item_attrs': {'initial': True}},
'save': {'read': True, 'write': True, 'write_cmd': '{CUSTOM_ATTR1} playlist save {VALUE}', 'item_type': 'str', 'dev_datatype': 'str', 'reply_pattern': r'^{CUSTOM_PATTERN1} playlist save (.*)', 'item_attrs': {'enforce': True}},
'load': {'read': True, 'write': True, 'write_cmd': '{CUSTOM_ATTR1} playlistcontrol cmd:load playlist_name:{VALUE}', 'item_type': 'str', 'dev_datatype': 'str', 'reply_pattern': [r'^{CUSTOM_PATTERN1} playlistcontrol cmd:load playlist_name:(.*) count:(?:\d+)', r'^{CUSTOM_PATTERN1} playlist resume (.*)', r'^{CUSTOM_PATTERN1} playlist loadtracks playlist.name:(.*)\s'], 'item_attrs': {'enforce': True}},
'loadalbum': {'read': True, 'write': True, 'write_cmd': '{CUSTOM_ATTR1} playlist loadalbum {VALUE}', 'item_type': 'str', 'dev_datatype': 'str', 'reply_pattern': r'^{CUSTOM_PATTERN1} playlist loadalbum (.*)', 'item_attrs': {'enforce': True, 'attributes': {'remark': '<Genre> <Artist> <Album>. You can use * for any of the entries. Spaces need to be replaced by %20'}}},
Expand Down Expand Up @@ -115,7 +116,7 @@
'ip': {'read': True, 'write': False, 'read_cmd': '{CUSTOM_ATTR1} ip ?', 'item_type': 'str', 'dev_datatype': 'str', 'reply_pattern': [r'^{CUSTOM_PATTERN1} ip (.*)', r'^{CUSTOM_PATTERN1} status(?:.*)player_ip:([^:\s]+)']},
'modelname': {'read': False, 'write': False, 'item_type': 'str', 'dev_datatype': 'str'},
'firmware': {'read': False, 'write': False, 'item_type': 'str', 'dev_datatype': 'str'},
'name': {'read': True, 'write': True, 'read_cmd': '{CUSTOM_ATTR1} name ?', 'write_cmd': '{CUSTOM_ATTR1} name {VALUE}', 'item_type': 'str', 'dev_datatype': 'str', 'reply_pattern': [r'^{CUSTOM_PATTERN1} name (.*)', r'^{CUSTOM_PATTERN1} status(?:.*)player_name:([^\s]+)']},
'name': {'read': True, 'write': True, 'read_cmd': '{CUSTOM_ATTR1} name ?', 'write_cmd': '{CUSTOM_ATTR1} name {VALUE}', 'item_type': 'str', 'dev_datatype': 'str', 'reply_pattern': [r'^{CUSTOM_PATTERN1} prefset server playername (.*)', r'^{CUSTOM_PATTERN1} name (.*)', r'^{CUSTOM_PATTERN1} status(?:.*)player_name:([^\s]+)']},
'signalstrength': {'read': True, 'write': False, 'read_cmd': '{CUSTOM_ATTR1} signalstrength ?', 'item_type': 'num', 'dev_datatype': 'str', 'reply_pattern': [r'^{CUSTOM_PATTERN1} signalstrength (\d+)', r'^{CUSTOM_PATTERN1} status(?:.*)signalstrength:([^\s]+)']},
'albumarturl': {'read': True, 'write': False, 'item_type': 'str', 'dev_datatype': 'str', 'reply_pattern': '^(https?://.*)', 'item_attrs': {'attributes': {'remark': 'This item gets automatically defined and overwritten based on (web_)host and web_port'}}}
},
Expand All @@ -124,7 +125,7 @@
'artist': {'read': True, 'write': False, 'read_cmd': '{CUSTOM_ATTR1} artist ?', 'item_type': 'str', 'dev_datatype': 'LMSConvertSpaces', 'reply_pattern': r'^{CUSTOM_PATTERN1} artist (.*)'},
'album': {'read': True, 'write': False, 'read_cmd': '{CUSTOM_ATTR1} album ?', 'item_type': 'str', 'dev_datatype': 'LMSConvertSpaces', 'reply_pattern': r'^{CUSTOM_PATTERN1} album (.*)'},
'title': {'read': True, 'write': False, 'read_cmd': '{CUSTOM_ATTR1} current_title ?', 'item_type': 'str', 'dev_datatype': 'LMSConvertSpaces', 'reply_pattern': [r'^{CUSTOM_PATTERN1} (?:current_title|playlist newsong) (.*?)(?:\s\d+)?$', r'^{CUSTOM_PATTERN1} status(?:.*)title:([^\s]+)'], 'item_attrs': {'initial': True}},
'path': {'read': True, 'write': False, 'read_cmd': '{CUSTOM_ATTR1} path ?', 'item_type': 'str', 'dev_datatype': 'str', 'reply_pattern': [r'^{CUSTOM_PATTERN1} path (.*)', r'^{CUSTOM_PATTERN1} playlist open (.*)', r'^{CUSTOM_PATTERN1} playlist play (.*)']},
'file_path': {'read': True, 'write': False, 'read_cmd': '{CUSTOM_ATTR1} path ?', 'item_type': 'str', 'dev_datatype': 'str', 'reply_pattern': [r'^{CUSTOM_PATTERN1} path (.*)', r'^{CUSTOM_PATTERN1} playlist open (.*)', r'^{CUSTOM_PATTERN1} playlist play (.*)']},
'duration': {'read': True, 'write': False, 'read_cmd': '{CUSTOM_ATTR1} duration ?', 'item_type': 'num', 'dev_datatype': 'str', 'reply_pattern': r'^{CUSTOM_PATTERN1} duration (\d+)', 'item_attrs': {'item_template': 'duration'}},
}
}
Expand Down
Loading

0 comments on commit 514f733

Please sign in to comment.