Added configuration options for "Next Up Box" (Issue #13)
Some checks failed
Check / mypy (push) Successful in 29s
Check / ruff (push) Failing after 6s

This commit is contained in:
Christoph Stahl 2025-06-23 23:55:14 +02:00
parent 4c93964123
commit 7ae894cdfd
3 changed files with 18 additions and 12 deletions

View file

@ -81,13 +81,14 @@ def default_config() -> dict[str, Optional[int | str]]:
"server": "https://syng.rocks", "server": "https://syng.rocks",
"room": "", "room": "",
"preview_duration": 3, "preview_duration": 3,
"next_up_position": "top",
"secret": None, "secret": None,
"last_song": None, "last_song": None,
"waiting_room_policy": None, "waiting_room_policy": None,
"key": None, "key": None,
"buffer_in_advance": 2, "buffer_in_advance": 2,
"qr_box_size": 5, "qr_box_size": 7,
"qr_position": "bottom-right", "qr_position": "top-right",
"show_advanced": False, "show_advanced": False,
"log_level": "info", "log_level": "info",
} }
@ -121,6 +122,8 @@ class State:
* `preview_duration` (`Optional[int]`): The duration in seconds the * `preview_duration` (`Optional[int]`): The duration in seconds the
playback client shows a preview for the next song. This is accounted for playback client shows a preview for the next song. This is accounted for
in the calculation of the ETA for songs later in the queue. in the calculation of the ETA for songs later in the queue.
* `next_up_position` (`str`): The position of the "next up" box on the screen.
Possible values are: top or bottom.
* `last_song` (`Optional[datetime.datetime]`): A timestamp, defining the end of * `last_song` (`Optional[datetime.datetime]`): A timestamp, defining the end of
the queue. the queue.
* `waiting_room_policy` (Optional[str]): One of: * `waiting_room_policy` (Optional[str]): One of:
@ -168,9 +171,7 @@ class Client:
self.currentLock = asyncio.Semaphore(0) self.currentLock = asyncio.Semaphore(0)
self.buffer_in_advance = config["config"]["buffer_in_advance"] self.buffer_in_advance = config["config"]["buffer_in_advance"]
self.player = Player( self.player = Player(
f"{config['config']['server']}/{config['config']['room']}", config["config"],
1 if config["config"]["qr_box_size"] < 1 else config["config"]["qr_box_size"],
QRPosition.from_string(config["config"]["qr_position"]),
self.quit_callback, self.quit_callback,
self.state.queue, self.state.queue,
) )

View file

@ -483,6 +483,11 @@ class GeneralConfig(OptionFrame):
self.add_int_option( self.add_int_option(
"preview_duration", "Preview duration in seconds", int(config["preview_duration"]) "preview_duration", "Preview duration in seconds", int(config["preview_duration"])
) )
self.add_int_option(
"next_up_time",
"Time remaining before Next Up Box is shown",
int(config["next_up_time"]),
)
self.add_string_option( self.add_string_option(
"key", "Key for server (if necessary)", config["key"], is_password=True "key", "Key for server (if necessary)", config["key"], is_password=True
) )

View file

@ -2,7 +2,7 @@ import asyncio
from enum import Enum from enum import Enum
import locale import locale
import sys import sys
from typing import Callable, Iterable, Optional, cast from typing import Any, Callable, Iterable, Optional, cast
from qrcode.main import QRCode from qrcode.main import QRCode
import mpv import mpv
import os import os
@ -34,13 +34,12 @@ class QRPosition(Enum):
class Player: class Player:
def __init__( def __init__(
self, self,
qr_string: str, config: dict[str, Any],
qr_box_size: int,
qr_position: QRPosition,
quit_callback: Callable[[], None], quit_callback: Callable[[], None],
queue: Optional[list[Entry]] = None, queue: Optional[list[Entry]] = None,
) -> None: ) -> None:
locale.setlocale(locale.LC_ALL, "C") locale.setlocale(locale.LC_ALL, "C")
qr_string = f"{config['server']}/{config['room']}"
self.queue = queue if queue is not None else [] self.queue = queue if queue is not None else []
self.base_dir = f"{os.path.dirname(__file__)}/static" self.base_dir = f"{os.path.dirname(__file__)}/static"
@ -49,8 +48,9 @@ class Player:
self.closing = False self.closing = False
self.mpv: Optional[mpv.MPV] = None self.mpv: Optional[mpv.MPV] = None
self.qr_overlay: Optional[mpv.ImageOverlay] = None self.qr_overlay: Optional[mpv.ImageOverlay] = None
self.qr_box_size = qr_box_size self.qr_box_size = 1 if config["qr_box_size"] < 1 else config["qr_box_size"]
self.qr_position = qr_position self.qr_position = QRPosition.from_string(config["qr_position"])
self.next_up_time = config.get("next_up_time", 20)
self.update_qr( self.update_qr(
qr_string, qr_string,
) )
@ -91,7 +91,7 @@ class Player:
if self.mpv is None: if self.mpv is None:
print("MPV is not initialized", file=sys.stderr) print("MPV is not initialized", file=sys.stderr)
return return
hidden = value is None or value > 30 hidden = value is None or value > self.next_up_time
if len(self.queue) < 2: if len(self.queue) < 2:
return return