2020# You should have received a copy of the GNU General Public License
2121# along with SmartHomeNG If not, see <http://www.gnu.org/licenses/>.
2222#########################################################################
23+ from __future__ import annotations
24+ from typing import Any , Tuple
2325
2426import builtins
2527import os
2628import sys
29+ import re
2730
2831if __name__ == '__main__' :
2932 builtins .SDP_standalone = True
@@ -40,7 +43,8 @@ class SmartPluginWebIf():
4043else :
4144 builtins .SDP_standalone = False
4245
43- from lib .model .sdp .globals import (CUSTOM_SEP , PLUGIN_ATTR_NET_HOST , PLUGIN_ATTR_RECURSIVE , PLUGIN_ATTR_CMD_CLASS , PLUGIN_ATTR_CONNECTION , PLUGIN_ATTR_CONN_TERMINATOR )
46+ from lib .model .sdp .globals import (CUSTOM_SEP , PLUGIN_ATTR_NET_HOST , PLUGIN_ATTR_RECURSIVE , PLUGIN_ATTR_CMD_CLASS ,
47+ PLUGIN_ATTR_CONNECTION , PLUGIN_ATTR_CONN_TERMINATOR )
4448from lib .model .smartdeviceplugin import SmartDevicePlugin , Standalone
4549from lib .model .sdp .command import SDPCommandParseStr
4650
@@ -50,7 +54,7 @@ class SmartPluginWebIf():
5054class lms (SmartDevicePlugin ):
5155 """ Device class for Logitech Mediaserver/Squeezebox function. """
5256
53- PLUGIN_VERSION = '1.6 .0'
57+ PLUGIN_VERSION = '2.0 .0'
5458
5559 def _set_device_defaults (self ):
5660 self .custom_commands = 1
@@ -75,10 +79,17 @@ def _set_device_defaults(self):
7579 self ._parameters ['web_host' ] = host
7680 else :
7781 self ._parameters ['web_host' ] = f'http://{ host } '
82+ self ._parameters ['CURRENT_LIST_ID' ] = {}
7883
7984 def on_connect (self , by = None ):
80- self .logger .debug ("Activating listen mode after connection." )
85+ self .logger .debug (f "Activating listen mode after connection." )
8186 self .send_command ('server.listenmode' , True )
87+ self .logger .debug (f"Subscribing all players to playlist changes." )
88+ for player in self ._custom_values .get (1 ):
89+ if player == '-' :
90+ continue
91+ else :
92+ self .send_command ('player.info.player.status_subscribe' + CUSTOM_SEP + player , True )
8293
8394 def _transform_send_data (self , data = None , ** kwargs ):
8495 if isinstance (data , dict ):
@@ -88,23 +99,79 @@ def _transform_send_data(self, data=None, **kwargs):
8899
89100 def _transform_received_data (self , data ):
90101 # fix weird representation of MAC address (%3A = :), etc.
91- return urllib .parse .unquote_plus (data )
102+ data_temp = data .replace ("%20" , "PPLACEHOLDERR" )
103+ data = urllib .parse .unquote (data_temp )
104+ data = data .replace ("PPLACEHOLDERR" , "%20" )
105+ return data
92106
93- def _process_additional_data (self , command , data , value , custom , by ):
107+ def _process_additional_data (self , command : str , data : Any , value : Any , custom : int , by : str | None = None ):
94108
95109 def trigger_read (command ):
96110 self .send_command (command + CUSTOM_SEP + custom )
97111
112+ if command == f'server.newclient' :
113+ self .logger .debug (f"Got new client connection { command } , re-reading players" )
114+ self .send_command ('server.players' )
115+
116+ if command == f'server.players' :
117+ self .logger .debug (f"Got command players { command } data { data } value { value } by { by } " )
118+ for player in self ._custom_values .get (1 ):
119+ if player == '-' :
120+ continue
121+ elif player in value .keys ():
122+ self ._dispatch_callback ('player.info.player.modelname' + CUSTOM_SEP + player , value [player ].get ('modelname' ), by )
123+ self ._dispatch_callback ('player.info.player.firmware' + CUSTOM_SEP + player , value [player ].get ('firmware' ), by )
124+
125+ if command == f'database.rescan.running' and value is False :
126+ self .logger .debug (f"Got command rescan not running, { command } data { data } value { value } by { by } " )
127+ self ._dispatch_callback ('database.rescan.progress' , "" , by )
128+
129+ if command == f'server.playlists.delete' :
130+ self .logger .debug (f"Got command delete playlist { command } , re-reading playlists" )
131+ self .send_command ('server.playlists.available' )
132+
133+ if command == f'server.syncgroups.members' and data :
134+ def find_player_index (target , mac_list ):
135+ for index , item in enumerate (mac_list ):
136+ if re .search (rf'\b{ re .escape (target )} \b' , item ):
137+ return index # Return the index where the match is found
138+ return - 1
139+
140+ self .logger .debug (f"Got command syncgroups { command } data { data } value { value } by { by } " )
141+ for player in self ._custom_values .get (1 ):
142+ idx = find_player_index (player , value )
143+ if idx >= 0 :
144+ synced = value [idx ].split ("," )
145+ synced .remove (player )
146+ self .logger .debug (f"Updating syncstatus of player { player } to { synced } " )
147+ self ._dispatch_callback ('player.control.sync_status' + CUSTOM_SEP + player , synced , by )
148+ else :
149+ self ._dispatch_callback ('player.control.sync_status' + CUSTOM_SEP + player , [], by )
150+ self ._dispatch_callback ('player.control.sync' + CUSTOM_SEP + player , '-' , by )
151+
98152 if not custom :
99153 return
100154
101- if command == f'player.info.playlists.names{ CUSTOM_SEP } { custom } ' :
102- self .logger .debug (f"Got command playlist names { command } data { data } value { value } custom { custom } by { by } " )
103- trigger_read ('player.playlist.id' )
104- trigger_read ('player.playlist.name' )
155+ if command == f'player.playlist.rename_current{ CUSTOM_SEP } { custom } ' :
156+ self .logger .debug (f"Got command rename_current { command } , re-reading playlists" )
157+ self .send_command ('server.playlists.available' )
158+
159+ if command == f'player.playlist.delete_current{ CUSTOM_SEP } { custom } ' :
160+ self .logger .debug (f"Got command delete_current { command } , re-reading playlists" )
161+ self .send_command ('server.playlists.available' )
162+
163+ if command == f'player.playlist.save{ CUSTOM_SEP } { custom } ' :
164+ self .logger .debug (f"Got command save playlist { command } , re-reading playlists" )
165+ self .send_command ('server.playlists.available' )
166+
167+ if command == f'player.playlist.clear{ CUSTOM_SEP } { custom } ' :
168+ self .logger .debug (f"Got command playlist clear { command } " )
169+ trigger_read ('player.info.player.status' )
170+
171+ if command == f'player.playlist.tracks{ CUSTOM_SEP } { custom } ' :
172+ self .logger .debug (f"Got command playlist tracks, most likely because playlist was changed. Check modified { command } " )
173+ trigger_read ('player.playlist.modified' )
105174
106- if command == 'playlist.rename' :
107- trigger_read ('info.playlists.names' )
108175 # set alarm
109176 if command == f'player.control.alarms{ CUSTOM_SEP } { custom } ' :
110177 return
@@ -123,7 +190,7 @@ def trigger_read(command):
123190 self .logger .error (f"Error setting alarm: { e } " )
124191
125192 # set album art URL
126- if command == f'player.info.album{ CUSTOM_SEP } { custom } ' :
193+ if command == f'player.info.currentsong. album{ CUSTOM_SEP } { custom } ' :
127194 self .logger .debug (f"Got command album { command } data { data } value { value } custom { custom } by { by } " )
128195 host = self ._parameters ['web_host' ]
129196 port = self ._parameters ['web_port' ]
@@ -132,7 +199,7 @@ def trigger_read(command):
132199 else :
133200 url = f'{ host } :{ port } /music/current/cover.jpg?player={ custom } '
134201 self .logger .debug (f"Setting albumarturl to { url } " )
135- self ._dispatch_callback ('player.info.albumarturl' + CUSTOM_SEP + custom , url , by )
202+ self ._dispatch_callback ('player.info.player. albumarturl' + CUSTOM_SEP + custom , url , by )
136203
137204 # set playlist ID
138205 if command == f'player.playlist.load{ CUSTOM_SEP } { custom } ' :
@@ -142,41 +209,34 @@ def trigger_read(command):
142209
143210 if command == f'player.playlist.id{ CUSTOM_SEP } { custom } ' :
144211 self .logger .debug (f"Got command id { command } data { data } value { value } custom { custom } by { by } " )
212+ self ._parameters ['CURRENT_LIST_ID' ][custom ] = value
145213 trigger_read ('player.playlist.name' )
214+ trigger_read ('player.playlist.url' )
146215
147216 if command == f'player.control.sync{ CUSTOM_SEP } { custom } ' :
148217 self .logger .debug (f"Got command sync { command } data { data } value { value } custom { custom } by { by } " )
149- trigger_read ('server.syncgroups.members' )
218+ self . send_command ('server.syncgroups.members' )
150219
151220 # update on new song
152- if command == f'player.info.title{ CUSTOM_SEP } { custom } ' :
221+ if command == f'player.info.currentsong. title{ CUSTOM_SEP } { custom } ' :
153222 # trigger_read('player.control.playmode')
154223 # trigger_read('player.playlist.index')
155- trigger_read ('player.info.duration' )
156- trigger_read ('player.info.album' )
157- trigger_read ('player.info.artist' )
158- trigger_read ('player.info.genre' )
159- trigger_read ('player.info.path' )
224+ trigger_read ('player.info.currentsong. duration' )
225+ trigger_read ('player.info.currentsong. album' )
226+ trigger_read ('player.info.currentsong. artist' )
227+ trigger_read ('player.info.currentsong. genre' )
228+ trigger_read ('player.info.currentsong. path' )
160229
161230 # update on new song
162231 if command == f'player.control.playpause{ CUSTOM_SEP } { custom } ' and value :
163232 trigger_read ('player.control.playmode' )
164- trigger_read ('player.info.duration' )
165- trigger_read ('player.info.album' )
166- trigger_read ('player.info.artist' )
167- trigger_read ('player.info.genre' )
168- trigger_read ('player.info.path' )
233+ self .read_all_commands ('player.info.currentsong' + CUSTOM_SEP + custom )
169234
170235 # update on new song
171236 if command == f'player.playlist.index{ CUSTOM_SEP } { custom } ' :
172237 self .logger .debug (f"Got command index { command } data { data } value { value } custom { custom } by { by } " )
173238 trigger_read ('player.control.playmode' )
174- trigger_read ('player.info.duration' )
175- trigger_read ('player.info.album' )
176- trigger_read ('player.info.artist' )
177- trigger_read ('player.info.genre' )
178- trigger_read ('player.info.path' )
179- trigger_read ('player.info.title' )
239+ self .read_all_commands ('player.info.currentsong' + CUSTOM_SEP + custom )
180240
181241 # update current time info
182242 if command in [f'player.control.forward{ CUSTOM_SEP } { custom } ' , f'player.control.rewind{ CUSTOM_SEP } { custom } ' ]:
0 commit comments