Compare commits

...

5 commits

Author SHA1 Message Date
81c6d2468c More infos in debug/admin mode in server
All checks were successful
Check / mypy (push) Successful in 1m6s
Check / ruff (push) Successful in 7s
2025-06-16 23:13:55 +02:00
72c70c03ec Backwards compatibilty with 2.1.0 2025-06-16 23:13:23 +02:00
4760076963 Remove room and show background task button in debug mode 2025-06-16 23:12:12 +02:00
ef4424ab51 More logging 2025-06-16 23:11:44 +02:00
8cc6674723 Correct handling of failed playback (do not skip two songs) 2025-06-16 23:10:13 +02:00
3 changed files with 67 additions and 31 deletions

View file

@ -346,8 +346,14 @@ class Client:
if entry.ident in source.downloaded_files:
continue
logger.info("Buffering: %s (%d s)", entry.title, entry.duration)
started = datetime.datetime.now()
try:
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:
logger.error("Error buffering: %s", e)
await self.sio.emit("skip", {"uuid": entry.uuid})
@ -450,6 +456,14 @@ class Client:
f"Playing: {entry.artist} - {entry.title} [{entry.album}] "
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:
try:
if self.state.config["preview_duration"] > 0:
@ -460,6 +474,7 @@ class Client:
await self.player.play(video, audio, source.extra_mpv_options)
except ValueError as e:
logger.error("Error playing: %s", e)
self.skipped.append(entry.uuid)
except Exception: # pylint: disable=broad-except
print_exc()
if self.skipped:
@ -485,6 +500,7 @@ class Client:
:type data: dict[str, Any]
:rtype: None
"""
logger.debug("Handling search: %s (%s)", data["query"], data["search_id"])
query = data["query"]
sid = data["sid"]
search_id = data["search_id"]
@ -497,6 +513,7 @@ class Client:
for source_result in results_list
for search_result in source_result
]
logger.debug("Search results: %d results", len(results))
await self.sio.emit(
"search-results", {"results": results, "sid": sid, "search_id": search_id}

View file

@ -11,7 +11,7 @@ from datetime import datetime
import os
from functools import partial
import random
from typing import TYPE_CHECKING, Any, Optional, cast
from typing import TYPE_CHECKING, Any, Optional
import secrets
import string
import signal
@ -564,21 +564,23 @@ class SyngGui(QMainWindow):
self.buttons_layout.addItem(spacer_item)
if os.getenv("SYNG_DEBUG", "0") == "1":
self.print_queue_button = QPushButton("Print Queue")
self.print_queue_button.clicked.connect(self.debug_print_queue)
self.buttons_layout.addWidget(self.print_queue_button)
self.remove_room_button = QPushButton("Remove Room")
self.remove_room_button.clicked.connect(self.remove_room)
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.clicked.connect(self.start_syng_client)
self.buttons_layout.addWidget(self.startbutton)
def debug_print_queue(self) -> None:
def remove_room(self) -> None:
if self.client is not None:
print([entry.title for entry in self.client.state.queue])
model = cast(Optional[QueueModel], self.queue_list_view.model())
if model is not None:
print(model.queue)
asyncio.create_task(self.client.remove_room())
def toggle_advanced(self, state: bool) -> None:
self.resetbutton.setVisible(state)

View file

@ -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"], "index.html"))
async def get_number_connections(self) -> int:
def get_number_connections(self) -> int:
"""
Get the number of connections to the server.
@ -277,6 +277,22 @@ class Server:
num += 1
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]]:
"""
Get the number of clients in a room.
@ -294,10 +310,7 @@ class Server:
client["type"] = "playback"
else:
client["type"] = "web"
client["admin"] = False
async with self.sio.session(sid) as session:
if "admin" in session:
client["admin"] = session["admin"]
client["admin"] = await self.is_admin(self.clients[room], sid)
clients.append(client)
return clients
@ -320,7 +333,8 @@ class Server:
info_dict = {
"version": SYNG_VERSION,
"protocol_version": SYNG_PROTOCOL_VERSION,
"connections": await self.get_number_connections(),
"num_connections": self.get_number_connections(),
"connections": self.get_connections(),
"rooms": rooms,
}
return web.json_response(info_dict, dumps=jsonencoder.dumps)
@ -642,6 +656,7 @@ class Server:
)
return None
logger.debug(f"Appending {entry} to queue in room {state.sid}")
entry.uid = data["uid"] if "uid" in data else None
await self.append_to_queue(state, entry, sid)
@ -1026,17 +1041,17 @@ class Server:
:rtype: None
"""
if "version" not in data:
await self.sio.emit(
"client-registered",
{"success": False, "room": None, "reason": "NO_VERSION"},
room=sid,
)
return
client_version = tuple(data["version"])
if not await self.check_client_version(client_version, sid):
return
# if "version" not in data:
# await self.sio.emit(
# "client-registered",
# {"success": False, "room": None, "reason": "NO_VERSION"},
# room=sid,
# )
# return
#
# client_version = tuple(data["version"])
# if not await self.check_client_version(client_version, sid):
# return
def gen_id(length: int = 4) -> str:
client_id = "".join([random.choice(string.ascii_letters) for _ in range(length)])
@ -1222,10 +1237,12 @@ class Server:
:rtype: None
"""
logger.debug("Client %s connected", sid)
logger.debug("Data: %s", auth)
if auth is None or "type" not in auth:
logger.warning("Client %s connected without auth data", sid)
raise ConnectionRefusedError("No authentication data provided. Please register first.")
logger.warning(
"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"]:
case "playback":
@ -1351,7 +1368,7 @@ class Server:
if room in self.clients:
old_state: State = self.clients[room]
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.client = Client(
sources=old_state.client.sources,
@ -1364,7 +1381,7 @@ class Server:
logger.warning("Got wrong secret for %s", room)
raise ConnectionRefusedError(f"Wrong secret for room {room}.")
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_waiting_room = [Entry(**entry) for entry in data["waiting_room"]]
initial_recent = [Entry(**entry) for entry in data["recent"]]