comparison sat/plugins/plugin_misc_radiocol.py @ 4037:524856bd7b19

massive refactoring to switch from camelCase to snake_case: historically, Libervia (SàT before) was using camelCase as allowed by PEP8 when using a pre-PEP8 code, to use the same coding style as in Twisted. However, snake_case is more readable and it's better to follow PEP8 best practices, so it has been decided to move on full snake_case. Because Libervia has a huge codebase, this ended with a ugly mix of camelCase and snake_case. To fix that, this patch does a big refactoring by renaming every function and method (including bridge) that are not coming from Twisted or Wokkel, to use fully snake_case. This is a massive change, and may result in some bugs.
author Goffi <goffi@goffi.org>
date Sat, 08 Apr 2023 13:54:42 +0200
parents be6d91572633
children
comparison
equal deleted inserted replaced
4036:c4464d7ae97b 4037:524856bd7b19
63 # Maximum number of songs in the queue (the song being currently played doesn't count) 63 # Maximum number of songs in the queue (the song being currently played doesn't count)
64 QUEUE_LIMIT = 2 64 QUEUE_LIMIT = 2
65 65
66 66
67 class Radiocol(object): 67 class Radiocol(object):
68 def inheritFromRoomGame(self, host): 68 def inherit_from_room_game(self, host):
69 global RoomGame 69 global RoomGame
70 RoomGame = host.plugins["ROOM-GAME"].__class__ 70 RoomGame = host.plugins["ROOM-GAME"].__class__
71 self.__class__ = type( 71 self.__class__ = type(
72 self.__class__.__name__, (self.__class__, RoomGame, object), {} 72 self.__class__.__name__, (self.__class__, RoomGame, object), {}
73 ) 73 )
74 74
75 def __init__(self, host): 75 def __init__(self, host):
76 log.info(_("Radio collective initialization")) 76 log.info(_("Radio collective initialization"))
77 self.inheritFromRoomGame(host) 77 self.inherit_from_room_game(host)
78 RoomGame._init_( 78 RoomGame._init_(
79 self, 79 self,
80 host, 80 host,
81 PLUGIN_INFO, 81 PLUGIN_INFO,
82 (NC_RADIOCOL, RADIOC_TAG), 82 (NC_RADIOCOL, RADIOC_TAG),
87 "playing_time": 0, 87 "playing_time": 0,
88 "to_delete": {}, 88 "to_delete": {},
89 }, 89 },
90 ) 90 )
91 self.host = host 91 self.host = host
92 host.bridge.addMethod( 92 host.bridge.add_method(
93 "radiocolLaunch", 93 "radiocol_launch",
94 ".plugin", 94 ".plugin",
95 in_sign="asss", 95 in_sign="asss",
96 out_sign="", 96 out_sign="",
97 method=self._prepareRoom, 97 method=self._prepare_room,
98 async_=True, 98 async_=True,
99 ) 99 )
100 host.bridge.addMethod( 100 host.bridge.add_method(
101 "radiocolCreate", 101 "radiocol_create",
102 ".plugin", 102 ".plugin",
103 in_sign="sass", 103 in_sign="sass",
104 out_sign="", 104 out_sign="",
105 method=self._createGame, 105 method=self._create_game,
106 ) 106 )
107 host.bridge.addMethod( 107 host.bridge.add_method(
108 "radiocolSongAdded", 108 "radiocol_song_added",
109 ".plugin", 109 ".plugin",
110 in_sign="sss", 110 in_sign="sss",
111 out_sign="", 111 out_sign="",
112 method=self._radiocolSongAdded, 112 method=self._radiocol_song_added,
113 async_=True, 113 async_=True,
114 ) 114 )
115 host.bridge.addSignal( 115 host.bridge.add_signal(
116 "radiocolPlayers", ".plugin", signature="ssass" 116 "radiocol_players", ".plugin", signature="ssass"
117 ) # room_jid, referee, players, profile 117 ) # room_jid, referee, players, profile
118 host.bridge.addSignal( 118 host.bridge.add_signal(
119 "radiocolStarted", ".plugin", signature="ssasais" 119 "radiocol_started", ".plugin", signature="ssasais"
120 ) # room_jid, referee, players, [QUEUE_TO_START, QUEUE_LIMIT], profile 120 ) # room_jid, referee, players, [QUEUE_TO_START, QUEUE_LIMIT], profile
121 host.bridge.addSignal( 121 host.bridge.add_signal(
122 "radiocolSongRejected", ".plugin", signature="sss" 122 "radiocol_song_rejected", ".plugin", signature="sss"
123 ) # room_jid, reason, profile 123 ) # room_jid, reason, profile
124 host.bridge.addSignal( 124 host.bridge.add_signal(
125 "radiocolPreload", ".plugin", signature="ssssssss" 125 "radiocol_preload", ".plugin", signature="ssssssss"
126 ) # room_jid, timestamp, filename, title, artist, album, profile 126 ) # room_jid, timestamp, filename, title, artist, album, profile
127 host.bridge.addSignal( 127 host.bridge.add_signal(
128 "radiocolPlay", ".plugin", signature="sss" 128 "radiocol_play", ".plugin", signature="sss"
129 ) # room_jid, filename, profile 129 ) # room_jid, filename, profile
130 host.bridge.addSignal( 130 host.bridge.add_signal(
131 "radiocolNoUpload", ".plugin", signature="ss" 131 "radiocol_no_upload", ".plugin", signature="ss"
132 ) # room_jid, profile 132 ) # room_jid, profile
133 host.bridge.addSignal( 133 host.bridge.add_signal(
134 "radiocolUploadOk", ".plugin", signature="ss" 134 "radiocol_upload_ok", ".plugin", signature="ss"
135 ) # room_jid, profile 135 ) # room_jid, profile
136 136
137 def __create_preload_elt(self, sender, song_added_elt): 137 def __create_preload_elt(self, sender, song_added_elt):
138 preload_elt = copy.deepcopy(song_added_elt) 138 preload_elt = copy.deepcopy(song_added_elt)
139 preload_elt.name = "preload" 139 preload_elt.name = "preload"
141 preload_elt["timestamp"] = str(time.time()) 141 preload_elt["timestamp"] = str(time.time())
142 # attributes filename, title, artist, album, length have been copied 142 # attributes filename, title, artist, album, length have been copied
143 # XXX: the frontend should know the temporary directory where file is put 143 # XXX: the frontend should know the temporary directory where file is put
144 return preload_elt 144 return preload_elt
145 145
146 def _radiocolSongAdded(self, referee_s, song_path, profile): 146 def _radiocol_song_added(self, referee_s, song_path, profile):
147 return self.radiocolSongAdded(jid.JID(referee_s), song_path, profile) 147 return self.radiocol_song_added(jid.JID(referee_s), song_path, profile)
148 148
149 def radiocolSongAdded(self, referee, song_path, profile): 149 def radiocol_song_added(self, referee, song_path, profile):
150 """This method is called by libervia when a song has been uploaded 150 """This method is called by libervia when a song has been uploaded
151 @param referee (jid.JID): JID of the referee in the room (room userhost + '/' + nick) 151 @param referee (jid.JID): JID of the referee in the room (room userhost + '/' + nick)
152 @param song_path (unicode): absolute path of the song added 152 @param song_path (unicode): absolute path of the song added
153 @param profile_key (unicode): %(doc_profile_key)s 153 @param profile_key (unicode): %(doc_profile_key)s
154 @return: a Deferred instance 154 @return: a Deferred instance
172 song = actual_song 172 song = actual_song
173 else: 173 else:
174 song = OggVorbis(song_path) 174 song = OggVorbis(song_path)
175 except (OggVorbisHeaderError, HeaderNotFoundError): 175 except (OggVorbisHeaderError, HeaderNotFoundError):
176 # this file is not ogg vorbis nor mp3, we reject it 176 # this file is not ogg vorbis nor mp3, we reject it
177 self.deleteFile(song_path) # FIXME: same host trick (see note above) 177 self.delete_file(song_path) # FIXME: same host trick (see note above)
178 return defer.fail( 178 return defer.fail(
179 exceptions.DataError( 179 exceptions.DataError(
180 D_( 180 D_(
181 "The uploaded file has been rejected, only Ogg Vorbis and MP3 songs are accepted." 181 "The uploaded file has been rejected, only Ogg Vorbis and MP3 songs are accepted."
182 ) 182 )
198 ] = ( 198 ] = (
199 song_path 199 song_path
200 ) # FIXME: works only because of the same host trick, see the note under the docstring 200 ) # FIXME: works only because of the same host trick, see the note under the docstring
201 return self.send(referee, ("", "song_added"), attrs, profile=profile) 201 return self.send(referee, ("", "song_added"), attrs, profile=profile)
202 202
203 def playNext(self, room_jid, profile): 203 def play_next(self, room_jid, profile):
204 """"Play next song in queue if exists, and put a timer 204 """"Play next song in queue if exists, and put a timer
205 which trigger after the song has been played to play next one""" 205 which trigger after the song has been played to play next one"""
206 # TODO: songs need to be erased once played or found invalids 206 # TODO: songs need to be erased once played or found invalids
207 # ==> unlink done the Q&D way with the same host trick (see above) 207 # ==> unlink done the Q&D way with the same host trick (see above)
208 radio_data = self.games[room_jid] 208 radio_data = self.games[room_jid]
209 if len(radio_data["players"]) == 0: 209 if len(radio_data["players"]) == 0:
210 log.debug(_("No more participants in the radiocol: cleaning data")) 210 log.debug(_("No more participants in the radiocol: cleaning data"))
211 radio_data["queue"] = [] 211 radio_data["queue"] = []
212 for filename in radio_data["to_delete"]: 212 for filename in radio_data["to_delete"]:
213 self.deleteFile(filename, radio_data) 213 self.delete_file(filename, radio_data)
214 radio_data["to_delete"] = {} 214 radio_data["to_delete"] = {}
215 queue = radio_data["queue"] 215 queue = radio_data["queue"]
216 if not queue: 216 if not queue:
217 # nothing left to play, we need to wait for uploads 217 # nothing left to play, we need to wait for uploads
218 radio_data["playing"] = None 218 radio_data["playing"] = None
226 if not radio_data["upload"] and len(queue) < QUEUE_LIMIT: 226 if not radio_data["upload"] and len(queue) < QUEUE_LIMIT:
227 # upload is blocked and we now have resources to get more, we reactivate it 227 # upload is blocked and we now have resources to get more, we reactivate it
228 self.send(room_jid, ("", "upload_ok"), profile=profile) 228 self.send(room_jid, ("", "upload_ok"), profile=profile)
229 radio_data["upload"] = True 229 radio_data["upload"] = True
230 230
231 reactor.callLater(length, self.playNext, room_jid, profile) 231 reactor.callLater(length, self.play_next, room_jid, profile)
232 # we wait more than the song length to delete the file, to manage poorly reactive networks/clients 232 # we wait more than the song length to delete the file, to manage poorly reactive networks/clients
233 reactor.callLater( 233 reactor.callLater(
234 length + 90, self.deleteFile, filename, radio_data 234 length + 90, self.delete_file, filename, radio_data
235 ) # FIXME: same host trick (see above) 235 ) # FIXME: same host trick (see above)
236 236
237 def deleteFile(self, filename, radio_data=None): 237 def delete_file(self, filename, radio_data=None):
238 """ 238 """
239 Delete a previously uploaded file. 239 Delete a previously uploaded file.
240 @param filename: filename to delete, or full filepath if radio_data is None 240 @param filename: filename to delete, or full filepath if radio_data is None
241 @param radio_data: current game data 241 @param radio_data: current game data
242 @return: True if the file has been deleted 242 @return: True if the file has been deleted
261 return True 261 return True
262 262
263 def room_game_cmd(self, mess_elt, profile): 263 def room_game_cmd(self, mess_elt, profile):
264 from_jid = jid.JID(mess_elt["from"]) 264 from_jid = jid.JID(mess_elt["from"])
265 room_jid = from_jid.userhostJID() 265 room_jid = from_jid.userhostJID()
266 nick = self.host.plugins["XEP-0045"].getRoomNick(room_jid, profile) 266 nick = self.host.plugins["XEP-0045"].get_room_nick(room_jid, profile)
267 267
268 radio_elt = mess_elt.firstChildElement() 268 radio_elt = mess_elt.firstChildElement()
269 radio_data = self.games[room_jid] 269 radio_data = self.games[room_jid]
270 if "queue" in radio_data: 270 if "queue" in radio_data:
271 queue = radio_data["queue"] 271 queue = radio_data["queue"]
272 272
273 from_referee = self.isReferee(room_jid, from_jid.resource) 273 from_referee = self.is_referee(room_jid, from_jid.resource)
274 to_referee = self.isReferee(room_jid, jid.JID(mess_elt["to"]).user) 274 to_referee = self.is_referee(room_jid, jid.JID(mess_elt["to"]).user)
275 is_player = self.isPlayer(room_jid, nick) 275 is_player = self.is_player(room_jid, nick)
276 for elt in radio_elt.elements(): 276 for elt in radio_elt.elements():
277 if not from_referee and not (to_referee and elt.name == "song_added"): 277 if not from_referee and not (to_referee and elt.name == "song_added"):
278 continue # sender must be referee, expect when a song is submitted 278 continue # sender must be referee, expect when a song is submitted
279 if not is_player and (elt.name not in ("started", "players")): 279 if not is_player and (elt.name not in ("started", "players")):
280 continue # user is in the room but not playing 280 continue # user is in the room but not playing
285 ): # new game created and/or players list updated 285 ): # new game created and/or players list updated
286 players = [] 286 players = []
287 for player in elt.elements(): 287 for player in elt.elements():
288 players.append(str(player)) 288 players.append(str(player))
289 signal = ( 289 signal = (
290 self.host.bridge.radiocolStarted 290 self.host.bridge.radiocol_started
291 if elt.name == "started" 291 if elt.name == "started"
292 else self.host.bridge.radiocolPlayers 292 else self.host.bridge.radiocol_players
293 ) 293 )
294 signal( 294 signal(
295 room_jid.userhost(), 295 room_jid.userhost(),
296 from_jid.full(), 296 from_jid.full(),
297 players, 297 players,
298 [QUEUE_TO_START, QUEUE_LIMIT], 298 [QUEUE_TO_START, QUEUE_LIMIT],
299 profile, 299 profile,
300 ) 300 )
301 elif elt.name == "preload": # a song is in queue and must be preloaded 301 elif elt.name == "preload": # a song is in queue and must be preloaded
302 self.host.bridge.radiocolPreload( 302 self.host.bridge.radiocol_preload(
303 room_jid.userhost(), 303 room_jid.userhost(),
304 elt["timestamp"], 304 elt["timestamp"],
305 elt["filename"], 305 elt["filename"],
306 elt["title"], 306 elt["title"],
307 elt["artist"], 307 elt["artist"],
308 elt["album"], 308 elt["album"],
309 elt["sender"], 309 elt["sender"],
310 profile, 310 profile,
311 ) 311 )
312 elif elt.name == "play": 312 elif elt.name == "play":
313 self.host.bridge.radiocolPlay( 313 self.host.bridge.radiocol_play(
314 room_jid.userhost(), elt["filename"], profile 314 room_jid.userhost(), elt["filename"], profile
315 ) 315 )
316 elif elt.name == "song_rejected": # a song has been refused 316 elif elt.name == "song_rejected": # a song has been refused
317 self.host.bridge.radiocolSongRejected( 317 self.host.bridge.radiocol_song_rejected(
318 room_jid.userhost(), elt["reason"], profile 318 room_jid.userhost(), elt["reason"], profile
319 ) 319 )
320 elif elt.name == "no_upload": 320 elif elt.name == "no_upload":
321 self.host.bridge.radiocolNoUpload(room_jid.userhost(), profile) 321 self.host.bridge.radiocol_no_upload(room_jid.userhost(), profile)
322 elif elt.name == "upload_ok": 322 elif elt.name == "upload_ok":
323 self.host.bridge.radiocolUploadOk(room_jid.userhost(), profile) 323 self.host.bridge.radiocol_upload_ok(room_jid.userhost(), profile)
324 elif elt.name == "song_added": # a song has been added 324 elif elt.name == "song_added": # a song has been added
325 # FIXME: we are KISS for the proof of concept: every song is added, to a limit of 3 in queue. 325 # FIXME: we are KISS for the proof of concept: every song is added, to a limit of 3 in queue.
326 # Need to manage some sort of rules to allow peoples to send songs 326 # Need to manage some sort of rules to allow peoples to send songs
327 if len(queue) >= QUEUE_LIMIT: 327 if len(queue) >= QUEUE_LIMIT:
328 # there are already too many songs in queue, we reject this one 328 # there are already too many songs in queue, we reject this one
346 346
347 self.send(room_jid, preload_elt, profile=profile) 347 self.send(room_jid, preload_elt, profile=profile)
348 if not radio_data["playing"] and len(queue) == QUEUE_TO_START: 348 if not radio_data["playing"] and len(queue) == QUEUE_TO_START:
349 # We have not started playing yet, and we have QUEUE_TO_START 349 # We have not started playing yet, and we have QUEUE_TO_START
350 # songs in queue. We can now start the party :) 350 # songs in queue. We can now start the party :)
351 self.playNext(room_jid, profile) 351 self.play_next(room_jid, profile)
352 else: 352 else:
353 log.error(_("Unmanaged game element: %s") % elt.name) 353 log.error(_("Unmanaged game element: %s") % elt.name)
354 354
355 def getSyncDataForPlayer(self, room_jid, nick): 355 def get_sync_data_for_player(self, room_jid, nick):
356 game_data = self.games[room_jid] 356 game_data = self.games[room_jid]
357 elements = [] 357 elements = []
358 if game_data["playing"]: 358 if game_data["playing"]:
359 preload = copy.deepcopy(game_data["playing"]) 359 preload = copy.deepcopy(game_data["playing"])
360 current_time = game_data["playing_time"] + 1 if self.testing else time.time() 360 current_time = game_data["playing_time"] + 1 if self.testing else time.time()