Added configuration for the QR code

This commit is contained in:
Christoph Stahl 2024-11-21 14:15:45 +01:00
parent 9b5b1ee9d0
commit 948bb4da5c
3 changed files with 85 additions and 20 deletions

View file

@ -36,7 +36,7 @@ from socketio.exceptions import ConnectionError
import engineio import engineio
from yaml import load, Loader from yaml import load, Loader
from syng.player_libmpv import Player from syng.player_libmpv import Player, QRPosition
from . import jsonencoder from . import jsonencoder
from .entry import Entry from .entry import Entry
@ -60,6 +60,8 @@ def default_config() -> dict[str, Optional[int | str]]:
"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_position": "bottom-left",
"show_advanced": False, "show_advanced": False,
} }
@ -102,6 +104,15 @@ class State:
- `None`, performers are always added to the queue. - `None`, performers are always added to the queue.
* `buffer_in_advance` (`int`): The number of songs, that are buffered in * `buffer_in_advance` (`int`): The number of songs, that are buffered in
advance. advance.
* `qr_box_size` (`int`): The size of one box in the QR code.
* `qr_position` (`str`): The position of the QR code on the screen. One of:
- `top-left`
- `top-right`
- `bottom-left`
- `bottom-right`
* `show_advanced` (`bool`): If the advanced options should be shown in the
gui.
:type config: dict[str, Any]: :type config: dict[str, Any]:
""" """
@ -128,7 +139,10 @@ 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']}", self.quit_callback f"{config['config']['server']}/{config['config']['room']}",
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.register_handlers() self.register_handlers()

View file

@ -330,6 +330,17 @@ class OptionFrame(QWidget):
self.date_time_options: dict[str, tuple[QDateTimeEdit, QCheckBox]] = {} self.date_time_options: dict[str, tuple[QDateTimeEdit, QCheckBox]] = {}
self.rows: dict[str, tuple[QLabel, QWidget | QLayout]] = {} self.rows: dict[str, tuple[QLabel, QWidget | QLayout]] = {}
@property
def option_names(self) -> set[str]:
return set(
self.string_options.keys()
| self.int_options.keys()
| self.choose_options.keys()
| self.bool_options.keys()
| self.list_options.keys()
| self.date_time_options.keys()
)
def get_config(self) -> dict[str, Any]: def get_config(self) -> dict[str, Any]:
config: dict[str, Any] = {} config: dict[str, Any] = {}
for name, textbox in self.string_options.items(): for name, textbox in self.string_options.items():
@ -446,15 +457,18 @@ class GeneralConfig(OptionFrame):
"Buffer the next songs in advance", "Buffer the next songs in advance",
int(config["buffer_in_advance"]), int(config["buffer_in_advance"]),
) )
self.add_int_option("qr_box_size", "QR Code Box Size", int(config["qr_box_size"]))
self.add_choose_option(
"qr_position",
"QR Code Position",
["top-left", "top-right", "bottom-left", "bottom-right"],
config["qr_position"],
)
self.simple_options = ["server", "room", "secret"]
if not config["show_advanced"]: if not config["show_advanced"]:
for option in [ for option in self.option_names.difference(self.simple_options):
"waiting_room_policy",
"last_song",
"preview_duration",
"key",
"buffer_in_advance",
]:
self.rows[option][0].setVisible(False) self.rows[option][0].setVisible(False)
widget_or_layout = self.rows[option][1] widget_or_layout = self.rows[option][1]
if isinstance(widget_or_layout, QWidget): if isinstance(widget_or_layout, QWidget):
@ -518,13 +532,9 @@ class SyngGui(QMainWindow):
self.exportbutton.setVisible(state) self.exportbutton.setVisible(state)
self.importbutton.setVisible(state) self.importbutton.setVisible(state)
for option in [ for option in self.general_config.option_names.difference(
"waiting_room_policy", self.general_config.simple_options
"last_song", ):
"preview_duration",
"key",
"buffer_in_advance",
]:
self.general_config.rows[option][0].setVisible(state) self.general_config.rows[option][0].setVisible(state)
widget_or_layout = self.general_config.rows[option][1] widget_or_layout = self.general_config.rows[option][1]
if isinstance(widget_or_layout, QWidget): if isinstance(widget_or_layout, QWidget):

View file

@ -1,4 +1,5 @@
import asyncio import asyncio
from enum import Enum
import locale import locale
import sys import sys
from typing import Callable, Iterable, Optional, cast from typing import Callable, Iterable, Optional, cast
@ -9,8 +10,35 @@ import os
from .entry import Entry from .entry import Entry
class QRPosition(Enum):
TOP_LEFT = 1
TOP_RIGHT = 2
BOTTOM_LEFT = 3
BOTTOM_RIGHT = 4
@staticmethod
def from_string(value: str) -> "QRPosition":
match value:
case "top-left":
return QRPosition.TOP_LEFT
case "top-right":
return QRPosition.TOP_RIGHT
case "bottom-left":
return QRPosition.BOTTOM_LEFT
case "bottom-right":
return QRPosition.BOTTOM_RIGHT
case _:
return QRPosition.BOTTOM_LEFT
class Player: class Player:
def __init__(self, qr_string: str, quit_callback: Callable[[], None]) -> None: def __init__(
self,
qr_string: str,
qr_box_size: int,
qr_position: QRPosition,
quit_callback: Callable[[], None],
) -> None:
locale.setlocale(locale.LC_ALL, "C") locale.setlocale(locale.LC_ALL, "C")
self.base_dir = f"{os.path.dirname(__file__)}/static" self.base_dir = f"{os.path.dirname(__file__)}/static"
@ -19,6 +47,8 @@ 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_position = qr_position
self.update_qr( self.update_qr(
qr_string, qr_string,
) )
@ -47,7 +77,7 @@ class Player:
self.quit_callback() self.quit_callback()
def update_qr(self, qr_string: str) -> None: def update_qr(self, qr_string: str) -> None:
qr = QRCode(box_size=5, border=1) qr = QRCode(box_size=self.qr_box_size, border=1)
qr.add_data(qr_string) qr.add_data(qr_string)
qr.make() qr.make()
self.qr = qr.make_image().convert("RGBA") self.qr = qr.make_image().convert("RGBA")
@ -62,8 +92,19 @@ class Player:
osd_width: int = cast(int, self.mpv.osd_width) osd_width: int = cast(int, self.mpv.osd_width)
osd_height: int = cast(int, self.mpv.osd_height) osd_height: int = cast(int, self.mpv.osd_height)
x_pos = osd_width - self.qr.width - 10 match self.qr_position:
y_pos = osd_height - self.qr.height - 10 case QRPosition.BOTTOM_LEFT:
x_pos = osd_width - self.qr.width - 10
y_pos = osd_height - self.qr.height - 10
case QRPosition.BOTTOM_RIGHT:
x_pos = 10
y_pos = osd_height - self.qr.height - 10
case QRPosition.TOP_LEFT:
x_pos = osd_width - self.qr.width - 10
y_pos = 10
case QRPosition.TOP_RIGHT:
x_pos = 10
y_pos = 10
self.qr_overlay = self.mpv.create_image_overlay(self.qr, pos=(x_pos, y_pos)) self.qr_overlay = self.mpv.create_image_overlay(self.qr, pos=(x_pos, y_pos))