| 
														
															@@ -6,6 +6,7 @@ from typing import Optional, Iterator, Dict, List 
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															 import sys 
														 | 
														
														 | 
														
															 import sys 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 from itertools import cycle 
														 | 
														
														 | 
														
															 from itertools import cycle 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+from websockets.asyncio.server import ServerConnection 
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															 import chube_youtube 
														 | 
														
														 | 
														
															 import chube_youtube 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 from channel import Channel, Subscriber 
														 | 
														
														 | 
														
															 from channel import Channel, Subscriber 
														 | 
													
												
											
										
											
												
													
														 | 
														
															@@ -131,7 +132,10 @@ class Playback: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															     def set_song(self, song): 
														 | 
														
														 | 
														
															     def set_song(self, song): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         with self.lock: 
														 | 
														
														 | 
														
															         with self.lock: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															             self._song = song 
														 | 
														
														 | 
														
															             self._song = song 
														 | 
													
												
											
												
													
														| 
														 | 
														
															-            logger.debug("Playback %s: Set song to %d", self, song["id"]) 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+            if song is not None: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+                logger.debug("Playback %s: Set song to %d", self, song["id"]) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+            else: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+                logger.debug("Playback %s: finished last song", self) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															     def get_song(self): 
														 | 
														
														 | 
														
															     def get_song(self): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         with self.lock: 
														 | 
														
														 | 
														
															         with self.lock: 
														 | 
													
												
											
										
											
												
													
														 | 
														
															@@ -177,7 +181,7 @@ class Room: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 rooms: Dict[str, Room] = dict() 
														 | 
														
														 | 
														
															 rooms: Dict[str, Room] = dict() 
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															-async def request_state_processor(ws, _, path): 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+async def request_state_processor(ws: ServerConnection, _, path): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															     room = rooms[path] 
														 | 
														
														 | 
														
															     room = rooms[path] 
														 | 
													
												
											
												
													
														| 
														 | 
														
															     state = { 
														 | 
														
														 | 
														
															     state = { 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         "lists": room.chueue.as_lists(), 
														 | 
														
														 | 
														
															         "lists": room.chueue.as_lists(), 
														 | 
													
												
											
										
											
												
													
														 | 
														
															@@ -290,10 +294,10 @@ async def obtain_control_processor(ws, data, path): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															     await obtain_control(ws, room) 
														 | 
														
														 | 
														
															     await obtain_control(ws, room) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															-async def release_control_processor(ws, data, path): 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+async def release_control_processor(ws: ServerConnection, data, path): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															     room = rooms[path] 
														 | 
														
														 | 
														
															     room = rooms[path] 
														 | 
													
												
											
												
													
														| 
														 | 
														
															     if len(room.channel.subscribers) > 1: 
														 | 
														
														 | 
														
															     if len(room.channel.subscribers) > 1: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															-        await release_control(ws, room) 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+        await release_control(ws, False, room) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															     else: 
														 | 
														
														 | 
														
															     else: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         pass 
														 | 
														
														 | 
														
															         pass 
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
										
											
												
													
														 | 
														
															@@ -329,12 +333,12 @@ async def player_enabled_processor(ws, data, path): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															             if room.get_controller() is None: 
														 | 
														
														 | 
														
															             if room.get_controller() is None: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															                 await obtain_control(ws, room) 
														 | 
														
														 | 
														
															                 await obtain_control(ws, room) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															     else: 
														 | 
														
														 | 
														
															     else: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															-        await release_control(ws, room) 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+        await release_control(ws, False, room) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															 # TODO change OBTAIN_CONTROL en RELEASE_CONTROL to one message 
														 | 
														
														 | 
														
															 # TODO change OBTAIN_CONTROL en RELEASE_CONTROL to one message 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 # TODO There is some potential concurrent bug here, when the controller loses/releases control right before a song end. 
														 | 
														
														 | 
														
															 # TODO There is some potential concurrent bug here, when the controller loses/releases control right before a song end. 
														 | 
													
												
											
												
													
														| 
														 | 
														
															-async def obtain_control(ws, room: Room): 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+async def obtain_control(ws: ServerConnection, room: Room): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															     with room.controller_lock: 
														 | 
														
														 | 
														
															     with room.controller_lock: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         controller = room.get_controller() 
														 | 
														
														 | 
														
															         controller = room.get_controller() 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         if controller is None or controller.ws is not ws: 
														 | 
														
														 | 
														
															         if controller is None or controller.ws is not ws: 
														 | 
													
												
											
										
											
												
													
														 | 
														
															@@ -344,7 +348,7 @@ async def obtain_control(ws, room: Room): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															                 await controller.ws.send(make_message(Message.RELEASE_CONTROL)) 
														 | 
														
														 | 
														
															                 await controller.ws.send(make_message(Message.RELEASE_CONTROL)) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															-async def release_control(ws, room: Room): 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+async def release_control(ws: ServerConnection, ws_disconnected: bool, room: Room): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															     with room.controller_lock: 
														 | 
														
														 | 
														
															     with room.controller_lock: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         controller = room.get_controller() 
														 | 
														
														 | 
														
															         controller = room.get_controller() 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         if controller is not None and controller.ws is ws: 
														 | 
														
														 | 
														
															         if controller is not None and controller.ws is ws: 
														 | 
													
												
											
										
											
												
													
														 | 
														
															@@ -352,8 +356,8 @@ async def release_control(ws, room: Room): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															             room.set_controller(controller) 
														 | 
														
														 | 
														
															             room.set_controller(controller) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															             if controller is not None: 
														 | 
														
														 | 
														
															             if controller is not None: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															                 await controller.ws.send(make_message(Message.OBTAIN_CONTROL)) 
														 | 
														
														 | 
														
															                 await controller.ws.send(make_message(Message.OBTAIN_CONTROL)) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															-            # if ws.open: 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															-            await ws.send(make_message(Message.RELEASE_CONTROL)) 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+            if not ws_disconnected: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+                await ws.send(make_message(Message.RELEASE_CONTROL)) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															 async def on_connect(ws, path): 
														 | 
														
														 | 
														
															 async def on_connect(ws, path): 
														 | 
													
												
											
										
											
												
													
														 | 
														
															@@ -371,7 +375,7 @@ async def on_connect(ws, path): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 async def on_disconnect(ws, path): 
														 | 
														
														 | 
														
															 async def on_disconnect(ws, path): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															     room = rooms[path] 
														 | 
														
														 | 
														
															     room = rooms[path] 
														 | 
													
												
											
												
													
														| 
														 | 
														
															     room.channel.unsubscribe(ws) 
														 | 
														
														 | 
														
															     room.channel.unsubscribe(ws) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															-    await release_control(ws, room) 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+    await release_control(ws, True, room) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															     print("Currently {} user{} {} using room {}".format( 
														 | 
														
														 | 
														
															     print("Currently {} user{} {} using room {}".format( 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         len(room.channel.subscribers), 
														 | 
														
														 | 
														
															         len(room.channel.subscribers), 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         "s" if len(room.channel.subscribers) != 1 else "", 
														 | 
														
														 | 
														
															         "s" if len(room.channel.subscribers) != 1 else "", 
														 |