diff options
| -rw-r--r-- | solo-tool-project/src/solo_tool/session_manager.py | 55 | ||||
| -rw-r--r-- | solo-tool-project/test/fixtures.py | 11 | ||||
| -rw-r--r-- | solo-tool-project/test/session_manager_unittest.py | 39 | ||||
| -rw-r--r-- | web-project/src/solo_tool_web.py | 46 | 
4 files changed, 87 insertions, 64 deletions
| diff --git a/solo-tool-project/src/solo_tool/session_manager.py b/solo-tool-project/src/solo_tool/session_manager.py index cd5ebf7..4fae19f 100644 --- a/solo-tool-project/src/solo_tool/session_manager.py +++ b/solo-tool-project/src/solo_tool/session_manager.py @@ -1,30 +1,43 @@ +from glob import glob  import json +from pathlib import Path  from . import SoloTool -def loadSession(file: str, songPool: str, player=None) -> SoloTool: -    with open(file, "r") as f: -        session = json.load(f) +class FileSystemSessionManager: +    def __init__(self, songPool: str, sessionPath: str): +        self._songPool = Path(songPool) +        self._sessionPath = Path(sessionPath) -    st = SoloTool(songPool, player=player) +    def getSessions(self) -> list[str]: +        return [Path(f).stem for f in glob(f"{self._sessionPath}/*.json")] -    for i, entry in enumerate(session): -        songPath = entry["path"] -        keyPoints = entry["key_points"] +    def loadSession(self, key: str, player=None) -> SoloTool: +        with open(self._sessionPath / f"{key}.json", "r") as f: +            session = json.load(f) -        st.addSong(songPath) -        st._keyPoints[i] = keyPoints +        st = SoloTool(self._songPool, player=player) -    return st -         -def saveSession(soloTool: SoloTool, file: str) -> None: -    session = [] +        for i, entry in enumerate(session): +            songPath = entry["path"] +            keyPoints = entry["key_points"] -    for i, song in enumerate(soloTool.songs): -        entry = { -            "path": song, -            "key_points" : soloTool._keyPoints[i] -        } -        session.append(entry) +            st.addSong(songPath) +            st._keyPoints[i] = keyPoints -    with open(file, "w") as f: -        json.dump(session, f) +        return st + +    def saveSession(self, soloTool: SoloTool, key: str) -> None: +        session = [] + +        for i, song in enumerate(soloTool.songs): +            entry = { +                "path": song, +                "key_points" : soloTool._keyPoints[i] +            } +            session.append(entry) + +        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) diff --git a/solo-tool-project/test/fixtures.py b/solo-tool-project/test/fixtures.py index f70901b..e63d363 100644 --- a/solo-tool-project/test/fixtures.py +++ b/solo-tool-project/test/fixtures.py @@ -11,7 +11,15 @@ def mockPlayer():  @pytest.fixture  def songPool(tmp_path): -    return tmp_path / "songs" +    path = tmp_path / "songs" +    os.mkdir(path) +    return path + +@pytest.fixture +def sessionPath(tmp_path): +    path = tmp_path / "sessions" +    os.mkdir(path) +    return path  @pytest.fixture  def soloTool(mockPlayer, songPool): @@ -25,7 +33,6 @@ def testSongs(songPool):          songPool / "test.mp4"      ] -    os.mkdir(songPool)      for song in songs:          song.touch()      return songs diff --git a/solo-tool-project/test/session_manager_unittest.py b/solo-tool-project/test/session_manager_unittest.py index cff3b35..bd6fbb6 100644 --- a/solo-tool-project/test/session_manager_unittest.py +++ b/solo-tool-project/test/session_manager_unittest.py @@ -2,11 +2,11 @@ import pytest  from json import loads  import os -from solo_tool.session_manager import loadSession, saveSession -from fixtures import songPool, soloTool, mockPlayer, testSongs +from solo_tool.session_manager import getSessionManager +from fixtures import songPool, soloTool, mockPlayer, testSongs, sessionPath  @pytest.fixture -def testSessionFile(tmp_path, testSongs): +def testSessionFile(sessionPath, testSongs):      contents = """[      {          "path" : "test.flac", @@ -17,19 +17,20 @@ def testSessionFile(tmp_path, testSongs):          "key_points" : [0.1, 0.3]      }  ]""" - -    basePath = tmp_path / "sessions" -    sessionFile = basePath / "test-session.json" - -    os.mkdir(basePath) +    sessionFile = sessionPath / "test-session.json"      with open(sessionFile, "w") as f:          f.write(contents) -      return sessionFile -def test_loadSession(songPool, testSessionFile, mockPlayer): -    soloTool = loadSession(testSessionFile, songPool, player=mockPlayer) +@pytest.fixture +def sessionManager(sessionPath, songPool): +    return getSessionManager(songPool, sessionPath) + +def test_loadSession(sessionManager, mockPlayer, testSessionFile): +    sessions = sessionManager.getSessions() +    assert sessions == [testSessionFile.stem] +    soloTool = sessionManager.loadSession(sessions[0], player=mockPlayer)      assert soloTool.songs == ["test.flac", "test.mp3"]      soloTool.song = 0 @@ -38,16 +39,16 @@ def test_loadSession(songPool, testSessionFile, mockPlayer):      soloTool.song = 1      assert soloTool.keyPoints == [0.1, 0.3] -def test_saveSession(soloTool, testSessionFile, tmp_path): +def test_saveSession(sessionManager, soloTool, testSessionFile, sessionPath):      soloTool.addSong("test.flac")      soloTool.addSong("test.mp3")      soloTool.song = 1      soloTool.keyPoints = [0.1, 0.3] -    testFile = tmp_path / "test_session_saved.json" -    saveSession(soloTool, testFile) +    sessionKey = "test_session_saved" +    sessionManager.saveSession(soloTool, sessionKey) -    with open(testFile, "r") as f: +    with open(sessionPath / f"{sessionKey}.json", "r") as f:          savedSession = loads(f.read())      with open(testSessionFile, "r") as f: @@ -55,11 +56,11 @@ def test_saveSession(soloTool, testSessionFile, tmp_path):      assert savedSession == testSession -def test_loadAndSaveEmptySession(songPool, soloTool, tmp_path): -    emptyFile = tmp_path / "empty_session.json" +def test_loadAndSaveEmptySession(sessionManager, sessionPath, soloTool, tmp_path): +    emptySession = "empty_session" -    saveSession(soloTool, emptyFile) -    reloadedTool = loadSession(emptyFile, songPool) +    sessionManager.saveSession(soloTool, emptySession) +    reloadedTool = sessionManager.loadSession(emptySession)      assert reloadedTool.songs == [] diff --git a/web-project/src/solo_tool_web.py b/web-project/src/solo_tool_web.py index 20d2d11..5512408 100644 --- a/web-project/src/solo_tool_web.py +++ b/web-project/src/solo_tool_web.py @@ -1,4 +1,3 @@ -from glob import glob  import sys  from os import getenv  from os.path import basename, splitext @@ -8,12 +7,9 @@ from starlette.formparsers import MultiPartParser  import click  from solo_tool import SoloTool -from solo_tool.session_manager import loadSession, saveSession +from solo_tool.session_manager import getSessionManager  from solo_tool import handlers -SESSION_DIR = getenv("SESSION_DIR", "/home/eddy/music/sessions") -SONG_POOL = getenv("SONG_POOL", "/home/eddy/music/songs") -  def fileName(path: str) -> str:      return basename(splitext(path)[0]) @@ -31,13 +27,7 @@ def songList(st: SoloTool, songDrawer) -> None:              ui.item(fileName(path), on_click=handlers.songAbsolute(st, i, lambda: songDrawer.hide())).props('clickable v-ripple')  sessions = {} -for f in glob(f"{SESSION_DIR}/*.json"): -    sessionName = fileName(f) -    songTool = loadSession(f, SONG_POOL) -    songTool.registerKeyPointListCallback(lambda new: keyPointList.refresh()) -    songTool.registerSongSelectionCallback(lambda new: keyPointList.refresh()) -    songTool.registerSongListCallback(lambda new: songList.refresh()) -    sessions[sessionName] = songTool +sessionManager = None  @ui.page('/{sessionName}')  def sessionPage(sessionName: str): @@ -56,11 +46,12 @@ def sessionPage(sessionName: str):      # Upload song dialog      def handleFileUpload(e): -        from shutil import copyfileobj -        newSong = f"{SONG_POOL}/{e.name}" -        with open(newSong, "wb") as f: -            copyfileobj(e.content, f) -        st.addSong(newSong) +        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)      with ui.dialog() as uploadSongDialog:          ui.upload(label="Upload songs", auto_upload=True, on_upload=handleFileUpload).classes('max-w-full') @@ -72,7 +63,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(): saveSession(st, f"{SESSION_DIR}/{sessionName}.json") +            def save(): sessionManager.saveSession(st, f"{sessionName}.json")              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') @@ -129,7 +120,16 @@ def landingPage():      for name, soloTool in sessions.items():          ui.button(name, on_click=partial(ui.navigate.to, f"/{name}")) -def start(port, refresh, reload): +def start(port, refresh, reload, session_path, song_path): +    sessionManager = getSessionManager(song_path, session_path) + +    for key in sessionManager.getSessions(): +        songTool = sessionManager.loadSession(key) +        songTool.registerKeyPointListCallback(lambda new: keyPointList.refresh()) +        songTool.registerSongSelectionCallback(lambda new: keyPointList.refresh()) +        songTool.registerSongListCallback(lambda new: songList.refresh()) +        sessions[fileName(key)] = songTool +      try:          ui.run(reload=reload, binding_refresh_interval=refresh, port=port)      except KeyboardInterrupt: @@ -139,9 +139,11 @@ def start(port, refresh, reload):  @click.option("--port", type=int, default=8080, help="Port on which to bind.")  @click.option("--refresh", type=float, default=0.5, help="Refresh interval in seconds.")  @click.option("--reload/--no-reload", default=True, help="Auto-reload when files change.") -def main(port, refresh, reload): -    start(port, refresh, reload) +@click.option("--session_path", default="/home/eddy/music/sessions", help="Look for sessions in this location.") +@click.option("--song_path", default="/home/eddy/music/songs", help="Look for songs in this location.") +def main(port, refresh, reload, session_path, song_path): +    start(port, refresh, reload, session_path, song_path)  # Hardcoded dev settings  if __name__ in {"__main__", "__mp_main__"}: -    start(8080, 0.5, True) +    start(8080, 0.5, True, "/home/eddy/music/sessions", "/home/eddy/music/songs") | 
