black -> line-length=100
This commit is contained in:
parent
f4e15908cc
commit
411ccdd2c9
13 changed files with 56 additions and 137 deletions
|
@ -79,3 +79,6 @@ ignore_missing_imports = true
|
|||
|
||||
[tool.ruff]
|
||||
line-length = 100
|
||||
|
||||
[tool.black]
|
||||
line-length = 100
|
||||
|
|
|
@ -356,9 +356,7 @@ async def handle_request_config(data: dict[str, Any]) -> None:
|
|||
:rtype: None
|
||||
"""
|
||||
if data["source"] in sources:
|
||||
config: dict[str, Any] | list[dict[str, Any]] = await sources[
|
||||
data["source"]
|
||||
].get_config()
|
||||
config: dict[str, Any] | list[dict[str, Any]] = await sources[data["source"]].get_config()
|
||||
if isinstance(config, list):
|
||||
num_chunks: int = len(config)
|
||||
for current, chunk in enumerate(config):
|
||||
|
|
|
@ -76,8 +76,7 @@ class Entry:
|
|||
def normalize(performers: str) -> set[str]:
|
||||
return set(
|
||||
filter(
|
||||
lambda x: len(x) > 0
|
||||
and x not in ["der", "die", "das", "alle", "und"],
|
||||
lambda x: len(x) > 0 and x not in ["der", "die", "das", "alle", "und"],
|
||||
re.sub(
|
||||
r"[^a-zA-Z0-9\s]",
|
||||
"",
|
||||
|
|
44
syng/gui.py
44
syng/gui.py
|
@ -68,9 +68,7 @@ class DateAndTimePickerWindow(customtkinter.CTkToplevel): # type: ignore
|
|||
|
||||
self.timepicker.pack(expand=True, fill="both")
|
||||
|
||||
button = customtkinter.CTkButton(
|
||||
self, text="Ok", command=partial(self.insert, input_field)
|
||||
)
|
||||
button = customtkinter.CTkButton(self, text="Ok", command=partial(self.insert, input_field))
|
||||
button.pack(expand=True, fill="x")
|
||||
|
||||
def insert(self, input_field: customtkinter.CTkTextbox) -> None:
|
||||
|
@ -121,12 +119,8 @@ class OptionFrame(customtkinter.CTkScrollableFrame): # type:ignore
|
|||
if value is None:
|
||||
value = ""
|
||||
|
||||
self.string_options[name] = customtkinter.CTkTextbox(
|
||||
self, wrap="none", height=1
|
||||
)
|
||||
self.string_options[name].grid(
|
||||
column=1, row=self.number_of_options, sticky="EW"
|
||||
)
|
||||
self.string_options[name] = customtkinter.CTkTextbox(self, wrap="none", height=1)
|
||||
self.string_options[name].grid(column=1, row=self.number_of_options, sticky="EW")
|
||||
self.string_options[name].insert("0.0", value)
|
||||
if callback is not None:
|
||||
self.string_options[name].bind("<KeyRelease>", callback)
|
||||
|
@ -196,22 +190,16 @@ class OptionFrame(customtkinter.CTkScrollableFrame): # type:ignore
|
|||
) -> None:
|
||||
self.add_option_label(description)
|
||||
self.choose_options[name] = customtkinter.CTkOptionMenu(self, values=values)
|
||||
self.choose_options[name].grid(
|
||||
column=1, row=self.number_of_options, sticky="EW"
|
||||
)
|
||||
self.choose_options[name].grid(column=1, row=self.number_of_options, sticky="EW")
|
||||
self.choose_options[name].set(value)
|
||||
self.number_of_options += 1
|
||||
|
||||
def open_date_and_time_picker(
|
||||
self, name: str, input_field: customtkinter.CTkTextbox
|
||||
) -> None:
|
||||
def open_date_and_time_picker(self, name: str, input_field: customtkinter.CTkTextbox) -> None:
|
||||
if (
|
||||
name not in self.date_and_time_pickers
|
||||
or not self.date_and_time_pickers[name].winfo_exists()
|
||||
):
|
||||
self.date_and_time_pickers[name] = DateAndTimePickerWindow(
|
||||
self, input_field
|
||||
)
|
||||
self.date_and_time_pickers[name] = DateAndTimePickerWindow(self, input_field)
|
||||
else:
|
||||
self.date_and_time_pickers[name].focus()
|
||||
|
||||
|
@ -307,9 +295,7 @@ class GeneralConfig(OptionFrame):
|
|||
str(config["waiting_room_policy"]).lower(),
|
||||
)
|
||||
self.add_date_time_option("last_song", "Time of last song", config["last_song"])
|
||||
self.add_string_option(
|
||||
"preview_duration", "Preview Duration", config["preview_duration"]
|
||||
)
|
||||
self.add_string_option("preview_duration", "Preview Duration", config["preview_duration"])
|
||||
|
||||
def get_config(self) -> dict[str, Any]:
|
||||
config = super().get_config()
|
||||
|
@ -346,9 +332,7 @@ class SyngGui(customtkinter.CTk): # type:ignore
|
|||
self.syng_server: Optional[Process] = None
|
||||
self.syng_client: Optional[Process] = None
|
||||
|
||||
self.configfile = os.path.join(
|
||||
platformdirs.user_config_dir("syng"), "config.yaml"
|
||||
)
|
||||
self.configfile = os.path.join(platformdirs.user_config_dir("syng"), "config.yaml")
|
||||
|
||||
try:
|
||||
with open(self.configfile, encoding="utf8") as cfile:
|
||||
|
@ -380,13 +364,9 @@ class SyngGui(customtkinter.CTk): # type:ignore
|
|||
self.startsyng_serverbutton = customtkinter.CTkButton(
|
||||
button_line, text="Start Local Server", command=self.start_syng_server
|
||||
)
|
||||
self.startsyng_serverbutton.pack(
|
||||
side="left", expand=True, anchor="w", padx=10, pady=5
|
||||
)
|
||||
self.startsyng_serverbutton.pack(side="left", expand=True, anchor="w", padx=10, pady=5)
|
||||
|
||||
savebutton = customtkinter.CTkButton(
|
||||
button_line, text="Save", command=self.save_config
|
||||
)
|
||||
savebutton = customtkinter.CTkButton(button_line, text="Save", command=self.save_config)
|
||||
savebutton.pack(side="left", padx=10, pady=5)
|
||||
|
||||
# open_web_button = customtkinter.CTkButton(
|
||||
|
@ -430,9 +410,7 @@ class SyngGui(customtkinter.CTk): # type:ignore
|
|||
except (KeyError, TypeError):
|
||||
source_config = {}
|
||||
|
||||
self.tabs[source_name] = SourceTab(
|
||||
tabview.tab(source_name), source_name, source_config
|
||||
)
|
||||
self.tabs[source_name] = SourceTab(tabview.tab(source_name), source_name, source_config)
|
||||
self.tabs[source_name].pack(ipadx=10, expand=True, fill="both")
|
||||
|
||||
self.update_qr()
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
"""Wraps the ``json`` module, so that own classes get encoded."""
|
||||
|
||||
import json
|
||||
from dataclasses import asdict
|
||||
from typing import Any
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
"""A async queue with synchronization."""
|
||||
|
||||
import asyncio
|
||||
from collections import deque
|
||||
from collections.abc import Callable, Iterable
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
"""Module for search results."""
|
||||
|
||||
from __future__ import annotations
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional
|
||||
|
|
|
@ -138,9 +138,7 @@ class State:
|
|||
recent: list[Entry]
|
||||
sid: str
|
||||
client: Client
|
||||
last_seen: datetime.datetime = field(
|
||||
init=False, default_factory=datetime.datetime.now
|
||||
)
|
||||
last_seen: datetime.datetime = field(init=False, default_factory=datetime.datetime.now)
|
||||
|
||||
|
||||
clients: dict[str, State] = {}
|
||||
|
@ -163,9 +161,7 @@ async def send_state(state: State, sid: str) -> None:
|
|||
:rtype: None
|
||||
"""
|
||||
|
||||
safe_config = {
|
||||
k: v for k, v in state.client.config.items() if k not in ["secret", "key"]
|
||||
}
|
||||
safe_config = {k: v for k, v in state.client.config.items() if k not in ["secret", "key"]}
|
||||
|
||||
await sio.emit(
|
||||
"state",
|
||||
|
@ -216,18 +212,13 @@ async def handle_waiting_room_append(sid: str, data: dict[str, Any]) -> None:
|
|||
if entry is None:
|
||||
await sio.emit(
|
||||
"msg",
|
||||
{
|
||||
"msg": f"Unable to add to the waiting room: {data['ident']}. Maybe try again?"
|
||||
},
|
||||
{"msg": f"Unable to add to the waiting room: {data['ident']}. Maybe try again?"},
|
||||
room=sid,
|
||||
)
|
||||
return
|
||||
|
||||
if "uid" not in data or (
|
||||
(
|
||||
data["uid"] is not None
|
||||
and len(list(state.queue.find_by_uid(data["uid"]))) == 0
|
||||
)
|
||||
(data["uid"] is not None and len(list(state.queue.find_by_uid(data["uid"]))) == 0)
|
||||
or (data["uid"] is None and state.queue.find_by_name(data["performer"]) is None)
|
||||
):
|
||||
await append_to_queue(room, entry, sid)
|
||||
|
@ -244,9 +235,7 @@ async def handle_waiting_room_append(sid: str, data: dict[str, Any]) -> None:
|
|||
)
|
||||
|
||||
|
||||
async def append_to_queue(
|
||||
room: str, entry: Entry, report_to: Optional[str] = None
|
||||
) -> None:
|
||||
async def append_to_queue(room: str, entry: Entry, report_to: Optional[str] = None) -> None:
|
||||
"""
|
||||
Append a song to the queue for a given session.
|
||||
|
||||
|
@ -270,10 +259,7 @@ async def append_to_queue(
|
|||
start_time = first_song.started_at
|
||||
|
||||
start_time = state.queue.fold(
|
||||
lambda item, time: time
|
||||
+ item.duration
|
||||
+ state.client.config["preview_duration"]
|
||||
+ 1,
|
||||
lambda item, time: time + item.duration + state.client.config["preview_duration"] + 1,
|
||||
start_time,
|
||||
)
|
||||
|
||||
|
@ -395,15 +381,11 @@ async def handle_append(sid: str, data: dict[str, Any]) -> None:
|
|||
state = clients[room]
|
||||
|
||||
if len(data["performer"]) > 50:
|
||||
await sio.emit(
|
||||
"err", {"type": "NAME_LENGTH", "name": data["performer"]}, room=sid
|
||||
)
|
||||
await sio.emit("err", {"type": "NAME_LENGTH", "name": data["performer"]}, room=sid)
|
||||
return
|
||||
|
||||
if predict([data["performer"]]) == [1]:
|
||||
await sio.emit(
|
||||
"err", {"type": "PROFANITY", "name": data["performer"]}, room=sid
|
||||
)
|
||||
await sio.emit("err", {"type": "PROFANITY", "name": data["performer"]}, room=sid)
|
||||
return
|
||||
|
||||
if state.client.config["waiting_room_policy"] and (
|
||||
|
@ -462,15 +444,11 @@ async def handle_append_anyway(sid: str, data: dict[str, Any]) -> None:
|
|||
state = clients[room]
|
||||
|
||||
if len(data["performer"]) > 50:
|
||||
await sio.emit(
|
||||
"err", {"type": "NAME_LENGTH", "name": data["performer"]}, room=sid
|
||||
)
|
||||
await sio.emit("err", {"type": "NAME_LENGTH", "name": data["performer"]}, room=sid)
|
||||
return
|
||||
|
||||
if predict([data["performer"]]) == [1]:
|
||||
await sio.emit(
|
||||
"err", {"type": "PROFANITY", "name": data["performer"]}, room=sid
|
||||
)
|
||||
await sio.emit("err", {"type": "PROFANITY", "name": data["performer"]}, room=sid)
|
||||
return
|
||||
|
||||
if state.client.config["waiting_room_policy"].lower() == "forced":
|
||||
|
@ -582,11 +560,7 @@ async def handle_waiting_room_to_queue(sid: str, data: dict[str, Any]) -> None:
|
|||
|
||||
if is_admin:
|
||||
entry = next(
|
||||
(
|
||||
wr_entry
|
||||
for wr_entry in state.waiting_room
|
||||
if str(wr_entry.uuid) == data["uuid"]
|
||||
),
|
||||
(wr_entry for wr_entry in state.waiting_room if str(wr_entry.uuid) == data["uuid"]),
|
||||
None,
|
||||
)
|
||||
if entry is not None:
|
||||
|
@ -718,9 +692,7 @@ async def handle_register_client(sid: str, data: dict[str, Any]) -> None:
|
|||
"""
|
||||
|
||||
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)])
|
||||
if client_id in clients:
|
||||
client_id = gen_id(length + 1)
|
||||
return client_id
|
||||
|
@ -732,8 +704,7 @@ async def handle_register_client(sid: str, data: dict[str, Any]) -> None:
|
|||
|
||||
if (
|
||||
"key" not in data["config"]
|
||||
or hashlib.sha256(data["config"]["key"].encode()).hexdigest()
|
||||
not in keys
|
||||
or hashlib.sha256(data["config"]["key"].encode()).hexdigest() not in keys
|
||||
):
|
||||
await sio.emit(
|
||||
"client-registered",
|
||||
|
@ -743,9 +714,7 @@ async def handle_register_client(sid: str, data: dict[str, Any]) -> None:
|
|||
return
|
||||
|
||||
room: str = (
|
||||
data["config"]["room"]
|
||||
if "room" in data["config"] and data["config"]["room"]
|
||||
else gen_id()
|
||||
data["config"]["room"] if "room" in data["config"] and data["config"]["room"] else gen_id()
|
||||
)
|
||||
async with sio.session(sid) as session:
|
||||
session["room"] = room
|
||||
|
@ -761,15 +730,11 @@ async def handle_register_client(sid: str, data: dict[str, Any]) -> None:
|
|||
config=DEFAULT_CONFIG | data["config"],
|
||||
)
|
||||
await sio.enter_room(sid, room)
|
||||
await sio.emit(
|
||||
"client-registered", {"success": True, "room": room}, room=sid
|
||||
)
|
||||
await sio.emit("client-registered", {"success": True, "room": room}, room=sid)
|
||||
await send_state(clients[room], sid)
|
||||
else:
|
||||
logger.warning("Got wrong secret for %s", room)
|
||||
await sio.emit(
|
||||
"client-registered", {"success": False, "room": room}, room=sid
|
||||
)
|
||||
await sio.emit("client-registered", {"success": False, "room": room}, room=sid)
|
||||
else:
|
||||
logger.info("Registerd new client %s", room)
|
||||
initial_entries = [Entry(**entry) for entry in data["queue"]]
|
||||
|
@ -860,9 +825,7 @@ async def handle_config_chunk(sid: str, data: dict[str, Any]) -> None:
|
|||
return
|
||||
|
||||
if data["source"] not in state.client.sources:
|
||||
state.client.sources[data["source"]] = available_sources[data["source"]](
|
||||
data["config"]
|
||||
)
|
||||
state.client.sources[data["source"]] = available_sources[data["source"]](data["config"])
|
||||
else:
|
||||
state.client.sources[data["source"]].add_to_config(data["config"])
|
||||
|
||||
|
@ -891,9 +854,7 @@ async def handle_config(sid: str, data: dict[str, Any]) -> None:
|
|||
if sid != state.sid:
|
||||
return
|
||||
|
||||
state.client.sources[data["source"]] = available_sources[data["source"]](
|
||||
data["config"]
|
||||
)
|
||||
state.client.sources[data["source"]] = available_sources[data["source"]](data["config"])
|
||||
|
||||
|
||||
@sio.on("register-web")
|
||||
|
@ -1078,17 +1039,10 @@ async def handle_search(sid: str, data: dict[str, Any]) -> None:
|
|||
|
||||
query = data["query"]
|
||||
results_list = await asyncio.gather(
|
||||
*[
|
||||
state.client.sources[source].search(query)
|
||||
for source in state.client.sources_prio
|
||||
]
|
||||
*[state.client.sources[source].search(query) for source in state.client.sources_prio]
|
||||
)
|
||||
|
||||
results = [
|
||||
search_result
|
||||
for source_result in results_list
|
||||
for search_result in source_result
|
||||
]
|
||||
results = [search_result for source_result in results_list for search_result in source_result]
|
||||
await sio.emit(
|
||||
"search-results",
|
||||
{"results": results},
|
||||
|
@ -1152,9 +1106,7 @@ def run_server(args: Namespace) -> None:
|
|||
|
||||
app["root_folder"] = args.root_folder
|
||||
|
||||
app.add_routes(
|
||||
[web.static("/assets/", os.path.join(app["root_folder"], "assets/"))]
|
||||
)
|
||||
app.add_routes([web.static("/assets/", os.path.join(app["root_folder"], "assets/"))])
|
||||
|
||||
app.router.add_route("*", "/", root_handler)
|
||||
app.router.add_route("*", "/{room}", root_handler)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
Imports all sources, so that they add themselves to the
|
||||
``available_sources`` dictionary.
|
||||
"""
|
||||
|
||||
# pylint: disable=useless-import-alias
|
||||
|
||||
from typing import Any
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
"""Module for the files Source."""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from typing import Any, Optional
|
||||
|
|
|
@ -64,13 +64,9 @@ class S3Source(FileBasedSource):
|
|||
secure=(config["secure"] if "secure" in config else True),
|
||||
)
|
||||
self.bucket: str = config["bucket"]
|
||||
self.tmp_dir: str = (
|
||||
config["tmp_dir"] if "tmp_dir" in config else "/tmp/syng"
|
||||
)
|
||||
self.tmp_dir: str = config["tmp_dir"] if "tmp_dir" in config else "/tmp/syng"
|
||||
|
||||
self.index_file: Optional[str] = (
|
||||
config["index_file"] if "index_file" in config else None
|
||||
)
|
||||
self.index_file: Optional[str] = config["index_file"] if "index_file" in config else None
|
||||
self.extra_mpv_arguments = ["--scale=oversample"]
|
||||
|
||||
async def get_file_list(self) -> list[str]:
|
||||
|
@ -93,8 +89,7 @@ class S3Source(FileBasedSource):
|
|||
file_list = [
|
||||
obj.object_name
|
||||
for obj in self.minio.list_objects(self.bucket, recursive=True)
|
||||
if obj.object_name is not None
|
||||
and self.has_correct_extension(obj.object_name)
|
||||
if obj.object_name is not None and self.has_correct_extension(obj.object_name)
|
||||
]
|
||||
if self.index_file is not None and not os.path.isfile(self.index_file):
|
||||
with open(self.index_file, "w", encoding="utf8") as index_file_handle:
|
||||
|
@ -140,9 +135,7 @@ class S3Source(FileBasedSource):
|
|||
video_dl_path: str = os.path.join(self.tmp_dir, video_path)
|
||||
os.makedirs(os.path.dirname(video_dl_path), exist_ok=True)
|
||||
video_dl_task: asyncio.Task[Any] = asyncio.create_task(
|
||||
asyncio.to_thread(
|
||||
self.minio.fget_object, self.bucket, entry.ident, video_dl_path
|
||||
)
|
||||
asyncio.to_thread(self.minio.fget_object, self.bucket, entry.ident, video_dl_path)
|
||||
)
|
||||
|
||||
audio_dl_path: Optional[str]
|
||||
|
@ -150,9 +143,7 @@ class S3Source(FileBasedSource):
|
|||
audio_dl_path = os.path.join(self.tmp_dir, audio_path)
|
||||
|
||||
audio_dl_task: asyncio.Task[Any] = asyncio.create_task(
|
||||
asyncio.to_thread(
|
||||
self.minio.fget_object, self.bucket, audio_path, audio_dl_path
|
||||
)
|
||||
asyncio.to_thread(self.minio.fget_object, self.bucket, audio_path, audio_dl_path)
|
||||
)
|
||||
else:
|
||||
audio_dl_path = None
|
||||
|
|
|
@ -4,6 +4,7 @@ Abstract class for sources.
|
|||
Also defines the dictionary of available sources. Each source should add itself
|
||||
to this dictionary in its module.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
|
|
|
@ -41,9 +41,7 @@ class YouTube:
|
|||
self._infos = YouTube.__cache__[url]
|
||||
else:
|
||||
try:
|
||||
self._infos = YoutubeDL({"quiet": True}).extract_info(
|
||||
url, download=False
|
||||
)
|
||||
self._infos = YoutubeDL({"quiet": True}).extract_info(url, download=False)
|
||||
except DownloadError:
|
||||
self.length = 300
|
||||
self._title = None
|
||||
|
@ -104,7 +102,9 @@ class Search:
|
|||
else:
|
||||
if channel[0] == "/":
|
||||
channel = channel[1:]
|
||||
query_url = f"https://www.youtube.com/{channel}/search?{urlencode({'query': query, 'sp':sp})}"
|
||||
query_url = (
|
||||
f"https://www.youtube.com/{channel}/search?{urlencode({'query': query, 'sp':sp})}"
|
||||
)
|
||||
|
||||
results = YoutubeDL(
|
||||
{
|
||||
|
@ -118,9 +118,7 @@ class Search:
|
|||
)
|
||||
self.results = []
|
||||
if results is not None:
|
||||
filtered_entries = filter(
|
||||
lambda entry: "short" not in entry["url"], results["entries"]
|
||||
)
|
||||
filtered_entries = filter(lambda entry: "short" not in entry["url"], results["entries"])
|
||||
|
||||
for r in filtered_entries:
|
||||
try:
|
||||
|
@ -169,8 +167,7 @@ class YoutubeSource(Source):
|
|||
config["start_streaming"] if "start_streaming" in config else False
|
||||
)
|
||||
self.formatstring = (
|
||||
f"bestvideo[height<={self.max_res}]+"
|
||||
f"bestaudio/best[height<={self.max_res}]"
|
||||
f"bestvideo[height<={self.max_res}]+" f"bestaudio/best[height<={self.max_res}]"
|
||||
)
|
||||
self._yt_dlp = YoutubeDL(
|
||||
params={
|
||||
|
@ -278,15 +275,10 @@ class YoutubeSource(Source):
|
|||
|
||||
results: list[YouTube] = []
|
||||
results_lists: list[list[YouTube]] = await asyncio.gather(
|
||||
*[
|
||||
asyncio.to_thread(self._channel_search, query, channel)
|
||||
for channel in self.channels
|
||||
],
|
||||
*[asyncio.to_thread(self._channel_search, query, channel) for channel in self.channels],
|
||||
asyncio.to_thread(self._yt_search, query),
|
||||
)
|
||||
results = [
|
||||
search_result for yt_result in results_lists for search_result in yt_result
|
||||
]
|
||||
results = [search_result for yt_result in results_lists for search_result in yt_result]
|
||||
|
||||
results.sort(key=partial(_contains_index, query))
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue