diff options
author | Eddy Pedroni <epedroni@pm.me> | 2025-07-16 07:10:50 +0200 |
---|---|---|
committer | Eddy Pedroni <epedroni@pm.me> | 2025-07-16 07:10:50 +0200 |
commit | 1dcde6cc9cb322b743e0b0355c697af869c2934a (patch) | |
tree | e4cae31881e3eb129bcdc998dee706f8cda2a590 | |
parent | 1d42bfe5f7b3c671fc5b50e716c5e8aa68728fb3 (diff) |
Session manager add song, interface, web UI tested
-rw-r--r-- | solo-tool-project/src/solo_tool/session_manager.py | 31 | ||||
-rw-r--r-- | solo-tool-project/test/session_manager_unittest.py | 10 | ||||
-rw-r--r-- | web-project/src/solo_tool_web.py | 15 |
3 files changed, 44 insertions, 12 deletions
diff --git a/solo-tool-project/src/solo_tool/session_manager.py b/solo-tool-project/src/solo_tool/session_manager.py index 4fae19f..ece67d8 100644 --- a/solo-tool-project/src/solo_tool/session_manager.py +++ b/solo-tool-project/src/solo_tool/session_manager.py @@ -1,9 +1,28 @@ +from typing import BinaryIO, Protocol +from abc import abstractmethod from glob import glob import json from pathlib import Path from . import SoloTool -class FileSystemSessionManager: +class SessionManager(Protocol): + @abstractmethod + def getSessions(self) -> list[str]: + raise NotImplementedError + + @abstractmethod + def loadSession(self, key: str, player=None) -> SoloTool: + raise NotImplementedError + + @abstractmethod + def saveSession(self, soloTool: SoloTool, key: str) -> None: + raise NotImplementedError + + @abstractmethod + def addSong(self, name: str, content: BinaryIO) -> None: + raise NotImplementedError + +class _FileSystemSessionManager(SessionManager): def __init__(self, songPool: str, sessionPath: str): self._songPool = Path(songPool) self._sessionPath = Path(sessionPath) @@ -39,5 +58,11 @@ class FileSystemSessionManager: with open(self._sessionPath / f"{key}.json", "w") as f: json.dump(session, f) -def getSessionManager(songPool: str, sessionPath: str) -> FileSystemSessionManager: - return FileSystemSessionManager(songPool, sessionPath) + def addSong(self, name: str, content: BinaryIO): + from shutil import copyfileobj + newSong = self._songPool / name + with open(newSong, "wb") as f: + copyfileobj(content, f) + +def getSessionManager(songPool: str, sessionPath: str) -> SessionManager: + return _FileSystemSessionManager(songPool, sessionPath) diff --git a/solo-tool-project/test/session_manager_unittest.py b/solo-tool-project/test/session_manager_unittest.py index bd6fbb6..bef4e5d 100644 --- a/solo-tool-project/test/session_manager_unittest.py +++ b/solo-tool-project/test/session_manager_unittest.py @@ -64,3 +64,13 @@ def test_loadAndSaveEmptySession(sessionManager, sessionPath, soloTool, tmp_path assert reloadedTool.songs == [] +def test_uploadSong(sessionManager, songPool, tmp_path): + song = tmp_path / "song-to-be-uploaded.mp3" + song.touch() + + expected = songPool / "song-to-be-uploaded.mp3" + assert not expected.exists() + + with open(song, "rb") as f: + sessionManager.addSong("song-to-be-uploaded.mp3", f) + assert expected.exists() diff --git a/web-project/src/solo_tool_web.py b/web-project/src/solo_tool_web.py index 5512408..7b36b75 100644 --- a/web-project/src/solo_tool_web.py +++ b/web-project/src/solo_tool_web.py @@ -2,7 +2,7 @@ import sys from os import getenv from os.path import basename, splitext from functools import partial -from nicegui import ui +from nicegui import ui, events from starlette.formparsers import MultiPartParser import click @@ -45,13 +45,9 @@ def sessionPage(sessionName: str): st = sessions[sessionName] # Upload song dialog - def handleFileUpload(e): - if False: - from shutil import copyfileobj - newSong = f"{SONG_POOL}/{e.name}" - with open(newSong, "wb") as f: - copyfileobj(e.content, f) - st.addSong(newSong) + def handleFileUpload(e: events.UploadEventArguments): + sessionManager.addSong(e.name, e.content) + st.addSong(e.name) with ui.dialog() as uploadSongDialog: ui.upload(label="Upload songs", auto_upload=True, on_upload=handleFileUpload).classes('max-w-full') @@ -63,7 +59,7 @@ def sessionPage(sessionName: str): ui.label().bind_text_from(st, 'song', lambda index: fileName(st.songs[index]) if index is not None else "Select a song").classes('text-lg') with ui.row().classes('items-center justify-start'): ui.button(icon='home', on_click=lambda: ui.navigate.to("/")).props('flat dense round color=white') - def save(): sessionManager.saveSession(st, f"{sessionName}.json") + def save(): sessionManager.saveSession(st, sessionName) ui.button(icon='save', on_click=save).props('flat dense round color=white') ui.button(icon='fullscreen', on_click=fullscreen.toggle).props('flat dense round color=white') @@ -121,6 +117,7 @@ def landingPage(): ui.button(name, on_click=partial(ui.navigate.to, f"/{name}")) def start(port, refresh, reload, session_path, song_path): + global sessionManager sessionManager = getSessionManager(song_path, session_path) for key in sessionManager.getSessions(): |