Compare commits
5 commits
59bf086885
...
81c6d2468c
Author | SHA1 | Date | |
---|---|---|---|
81c6d2468c | |||
72c70c03ec | |||
4760076963 | |||
ef4424ab51 | |||
8cc6674723 |
3 changed files with 67 additions and 31 deletions
|
@ -346,8 +346,14 @@ class Client:
|
||||||
if entry.ident in source.downloaded_files:
|
if entry.ident in source.downloaded_files:
|
||||||
continue
|
continue
|
||||||
logger.info("Buffering: %s (%d s)", entry.title, entry.duration)
|
logger.info("Buffering: %s (%d s)", entry.title, entry.duration)
|
||||||
|
started = datetime.datetime.now()
|
||||||
try:
|
try:
|
||||||
await self.sources[entry.source].buffer(entry, pos)
|
await self.sources[entry.source].buffer(entry, pos)
|
||||||
|
logger.info(
|
||||||
|
"Buffered %s in %d seconds",
|
||||||
|
entry.title,
|
||||||
|
(datetime.datetime.now() - started).seconds,
|
||||||
|
)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
logger.error("Error buffering: %s", e)
|
logger.error("Error buffering: %s", e)
|
||||||
await self.sio.emit("skip", {"uuid": entry.uuid})
|
await self.sio.emit("skip", {"uuid": entry.uuid})
|
||||||
|
@ -450,6 +456,14 @@ class Client:
|
||||||
f"Playing: {entry.artist} - {entry.title} [{entry.album}] "
|
f"Playing: {entry.artist} - {entry.title} [{entry.album}] "
|
||||||
f"({entry.source}) for {entry.performer}"
|
f"({entry.source}) for {entry.performer}"
|
||||||
)
|
)
|
||||||
|
logger.info(
|
||||||
|
"Playing: %s - %s [%s] (%s) for %s",
|
||||||
|
entry.artist,
|
||||||
|
entry.title,
|
||||||
|
entry.album,
|
||||||
|
entry.source,
|
||||||
|
entry.performer,
|
||||||
|
)
|
||||||
if entry.uuid not in self.skipped:
|
if entry.uuid not in self.skipped:
|
||||||
try:
|
try:
|
||||||
if self.state.config["preview_duration"] > 0:
|
if self.state.config["preview_duration"] > 0:
|
||||||
|
@ -460,6 +474,7 @@ class Client:
|
||||||
await self.player.play(video, audio, source.extra_mpv_options)
|
await self.player.play(video, audio, source.extra_mpv_options)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
logger.error("Error playing: %s", e)
|
logger.error("Error playing: %s", e)
|
||||||
|
self.skipped.append(entry.uuid)
|
||||||
except Exception: # pylint: disable=broad-except
|
except Exception: # pylint: disable=broad-except
|
||||||
print_exc()
|
print_exc()
|
||||||
if self.skipped:
|
if self.skipped:
|
||||||
|
@ -485,6 +500,7 @@ class Client:
|
||||||
:type data: dict[str, Any]
|
:type data: dict[str, Any]
|
||||||
:rtype: None
|
:rtype: None
|
||||||
"""
|
"""
|
||||||
|
logger.debug("Handling search: %s (%s)", data["query"], data["search_id"])
|
||||||
query = data["query"]
|
query = data["query"]
|
||||||
sid = data["sid"]
|
sid = data["sid"]
|
||||||
search_id = data["search_id"]
|
search_id = data["search_id"]
|
||||||
|
@ -497,6 +513,7 @@ class Client:
|
||||||
for source_result in results_list
|
for source_result in results_list
|
||||||
for search_result in source_result
|
for search_result in source_result
|
||||||
]
|
]
|
||||||
|
logger.debug("Search results: %d results", len(results))
|
||||||
|
|
||||||
await self.sio.emit(
|
await self.sio.emit(
|
||||||
"search-results", {"results": results, "sid": sid, "search_id": search_id}
|
"search-results", {"results": results, "sid": sid, "search_id": search_id}
|
||||||
|
|
20
syng/gui.py
20
syng/gui.py
|
@ -11,7 +11,7 @@ from datetime import datetime
|
||||||
import os
|
import os
|
||||||
from functools import partial
|
from functools import partial
|
||||||
import random
|
import random
|
||||||
from typing import TYPE_CHECKING, Any, Optional, cast
|
from typing import TYPE_CHECKING, Any, Optional
|
||||||
import secrets
|
import secrets
|
||||||
import string
|
import string
|
||||||
import signal
|
import signal
|
||||||
|
@ -564,21 +564,23 @@ class SyngGui(QMainWindow):
|
||||||
self.buttons_layout.addItem(spacer_item)
|
self.buttons_layout.addItem(spacer_item)
|
||||||
|
|
||||||
if os.getenv("SYNG_DEBUG", "0") == "1":
|
if os.getenv("SYNG_DEBUG", "0") == "1":
|
||||||
self.print_queue_button = QPushButton("Print Queue")
|
self.remove_room_button = QPushButton("Remove Room")
|
||||||
self.print_queue_button.clicked.connect(self.debug_print_queue)
|
self.remove_room_button.clicked.connect(self.remove_room)
|
||||||
self.buttons_layout.addWidget(self.print_queue_button)
|
self.buttons_layout.addWidget(self.remove_room_button)
|
||||||
|
self.print_background_tasks_button = QPushButton("Print Background Tasks")
|
||||||
|
self.print_background_tasks_button.clicked.connect(
|
||||||
|
lambda: print(asyncio.all_tasks(self.loop))
|
||||||
|
)
|
||||||
|
self.buttons_layout.addWidget(self.print_background_tasks_button)
|
||||||
|
|
||||||
self.startbutton = QPushButton("Connect")
|
self.startbutton = QPushButton("Connect")
|
||||||
|
|
||||||
self.startbutton.clicked.connect(self.start_syng_client)
|
self.startbutton.clicked.connect(self.start_syng_client)
|
||||||
self.buttons_layout.addWidget(self.startbutton)
|
self.buttons_layout.addWidget(self.startbutton)
|
||||||
|
|
||||||
def debug_print_queue(self) -> None:
|
def remove_room(self) -> None:
|
||||||
if self.client is not None:
|
if self.client is not None:
|
||||||
print([entry.title for entry in self.client.state.queue])
|
asyncio.create_task(self.client.remove_room())
|
||||||
model = cast(Optional[QueueModel], self.queue_list_view.model())
|
|
||||||
if model is not None:
|
|
||||||
print(model.queue)
|
|
||||||
|
|
||||||
def toggle_advanced(self, state: bool) -> None:
|
def toggle_advanced(self, state: bool) -> None:
|
||||||
self.resetbutton.setVisible(state)
|
self.resetbutton.setVisible(state)
|
||||||
|
|
|
@ -263,7 +263,7 @@ class Server:
|
||||||
return web.FileResponse(os.path.join(self.app["root_folder"], "favicon.ico"))
|
return web.FileResponse(os.path.join(self.app["root_folder"], "favicon.ico"))
|
||||||
return web.FileResponse(os.path.join(self.app["root_folder"], "index.html"))
|
return web.FileResponse(os.path.join(self.app["root_folder"], "index.html"))
|
||||||
|
|
||||||
async def get_number_connections(self) -> int:
|
def get_number_connections(self) -> int:
|
||||||
"""
|
"""
|
||||||
Get the number of connections to the server.
|
Get the number of connections to the server.
|
||||||
|
|
||||||
|
@ -277,6 +277,22 @@ class Server:
|
||||||
num += 1
|
num += 1
|
||||||
return num
|
return num
|
||||||
|
|
||||||
|
def get_connections(self) -> dict[str, dict[str, list[tuple[str, str]]]]:
|
||||||
|
"""
|
||||||
|
Get all connections to the server.
|
||||||
|
|
||||||
|
:return: A dictionary mapping namespaces to rooms and participants.
|
||||||
|
:rtype: dict[str, dict[str, list[tuple[str, str]]]]
|
||||||
|
"""
|
||||||
|
connections: dict[str, dict[str, list[tuple[str, str]]]] = {}
|
||||||
|
for namespace in self.sio.manager.get_namespaces():
|
||||||
|
connections[namespace] = {}
|
||||||
|
for room in self.sio.manager.rooms[namespace]:
|
||||||
|
connections[namespace][room] = []
|
||||||
|
for participant in self.sio.manager.get_participants(namespace, room):
|
||||||
|
connections[namespace][room].append(participant)
|
||||||
|
return connections
|
||||||
|
|
||||||
async def get_clients(self, room: str) -> list[dict[str, Any]]:
|
async def get_clients(self, room: str) -> list[dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
Get the number of clients in a room.
|
Get the number of clients in a room.
|
||||||
|
@ -294,10 +310,7 @@ class Server:
|
||||||
client["type"] = "playback"
|
client["type"] = "playback"
|
||||||
else:
|
else:
|
||||||
client["type"] = "web"
|
client["type"] = "web"
|
||||||
client["admin"] = False
|
client["admin"] = await self.is_admin(self.clients[room], sid)
|
||||||
async with self.sio.session(sid) as session:
|
|
||||||
if "admin" in session:
|
|
||||||
client["admin"] = session["admin"]
|
|
||||||
clients.append(client)
|
clients.append(client)
|
||||||
return clients
|
return clients
|
||||||
|
|
||||||
|
@ -320,7 +333,8 @@ class Server:
|
||||||
info_dict = {
|
info_dict = {
|
||||||
"version": SYNG_VERSION,
|
"version": SYNG_VERSION,
|
||||||
"protocol_version": SYNG_PROTOCOL_VERSION,
|
"protocol_version": SYNG_PROTOCOL_VERSION,
|
||||||
"connections": await self.get_number_connections(),
|
"num_connections": self.get_number_connections(),
|
||||||
|
"connections": self.get_connections(),
|
||||||
"rooms": rooms,
|
"rooms": rooms,
|
||||||
}
|
}
|
||||||
return web.json_response(info_dict, dumps=jsonencoder.dumps)
|
return web.json_response(info_dict, dumps=jsonencoder.dumps)
|
||||||
|
@ -642,6 +656,7 @@ class Server:
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
logger.debug(f"Appending {entry} to queue in room {state.sid}")
|
||||||
entry.uid = data["uid"] if "uid" in data else None
|
entry.uid = data["uid"] if "uid" in data else None
|
||||||
|
|
||||||
await self.append_to_queue(state, entry, sid)
|
await self.append_to_queue(state, entry, sid)
|
||||||
|
@ -1026,17 +1041,17 @@ class Server:
|
||||||
:rtype: None
|
:rtype: None
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if "version" not in data:
|
# if "version" not in data:
|
||||||
await self.sio.emit(
|
# await self.sio.emit(
|
||||||
"client-registered",
|
# "client-registered",
|
||||||
{"success": False, "room": None, "reason": "NO_VERSION"},
|
# {"success": False, "room": None, "reason": "NO_VERSION"},
|
||||||
room=sid,
|
# room=sid,
|
||||||
)
|
# )
|
||||||
return
|
# return
|
||||||
|
#
|
||||||
client_version = tuple(data["version"])
|
# client_version = tuple(data["version"])
|
||||||
if not await self.check_client_version(client_version, sid):
|
# if not await self.check_client_version(client_version, sid):
|
||||||
return
|
# return
|
||||||
|
|
||||||
def gen_id(length: int = 4) -> str:
|
def gen_id(length: int = 4) -> str:
|
||||||
client_id = "".join([random.choice(string.ascii_letters) for _ in range(length)])
|
client_id = "".join([random.choice(string.ascii_letters) for _ in range(length)])
|
||||||
|
@ -1222,10 +1237,12 @@ class Server:
|
||||||
:rtype: None
|
:rtype: None
|
||||||
"""
|
"""
|
||||||
logger.debug("Client %s connected", sid)
|
logger.debug("Client %s connected", sid)
|
||||||
logger.debug("Data: %s", auth)
|
|
||||||
if auth is None or "type" not in auth:
|
if auth is None or "type" not in auth:
|
||||||
logger.warning("Client %s connected without auth data", sid)
|
logger.warning(
|
||||||
raise ConnectionRefusedError("No authentication data provided. Please register first.")
|
"Client %s connected without auth data, fall back to old registration", sid
|
||||||
|
)
|
||||||
|
return
|
||||||
|
# raise ConnectionRefusedError("No authentication data provided. Please register first.")
|
||||||
|
|
||||||
match auth["type"]:
|
match auth["type"]:
|
||||||
case "playback":
|
case "playback":
|
||||||
|
@ -1351,7 +1368,7 @@ class Server:
|
||||||
if room in self.clients:
|
if room in self.clients:
|
||||||
old_state: State = self.clients[room]
|
old_state: State = self.clients[room]
|
||||||
if data["config"]["secret"] == old_state.client.config["secret"]:
|
if data["config"]["secret"] == old_state.client.config["secret"]:
|
||||||
logger.info("Got new client connection for %s", room)
|
logger.info("Got new playback client connection for %s", room)
|
||||||
old_state.sid = sid
|
old_state.sid = sid
|
||||||
old_state.client = Client(
|
old_state.client = Client(
|
||||||
sources=old_state.client.sources,
|
sources=old_state.client.sources,
|
||||||
|
@ -1364,7 +1381,7 @@ class Server:
|
||||||
logger.warning("Got wrong secret for %s", room)
|
logger.warning("Got wrong secret for %s", room)
|
||||||
raise ConnectionRefusedError(f"Wrong secret for room {room}.")
|
raise ConnectionRefusedError(f"Wrong secret for room {room}.")
|
||||||
else:
|
else:
|
||||||
logger.info("Registerd new client %s", room)
|
logger.info("Registerd new playback client %s", room)
|
||||||
initial_entries = [Entry(**entry) for entry in data["queue"]]
|
initial_entries = [Entry(**entry) for entry in data["queue"]]
|
||||||
initial_waiting_room = [Entry(**entry) for entry in data["waiting_room"]]
|
initial_waiting_room = [Entry(**entry) for entry in data["waiting_room"]]
|
||||||
initial_recent = [Entry(**entry) for entry in data["recent"]]
|
initial_recent = [Entry(**entry) for entry in data["recent"]]
|
||||||
|
|
Loading…
Add table
Reference in a new issue