aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--solo-tool-project/src/solo_tool/solo_tool.py2
-rw-r--r--web-project/src/solo_tool_web.py58
2 files changed, 40 insertions, 20 deletions
diff --git a/solo-tool-project/src/solo_tool/solo_tool.py b/solo-tool-project/src/solo_tool/solo_tool.py
index ad1bb23..92b5595 100644
--- a/solo-tool-project/src/solo_tool/solo_tool.py
+++ b/solo-tool-project/src/solo_tool/solo_tool.py
@@ -79,7 +79,7 @@ class SoloTool:
@property
def keyPoint(self) -> float:
- return self._keyPoint
+ return float(self._keyPoint) if self._keyPoint is not None else None
@keyPoint.setter
def keyPoint(self, new: float) -> None:
diff --git a/web-project/src/solo_tool_web.py b/web-project/src/solo_tool_web.py
index a3143c5..8ae36b5 100644
--- a/web-project/src/solo_tool_web.py
+++ b/web-project/src/solo_tool_web.py
@@ -1,11 +1,11 @@
from glob import glob
from os.path import basename, splitext
from nicegui import ui
+from starlette.formparsers import MultiPartParser
from solo_tool import SoloTool
from solo_tool.session_manager import loadSession, saveSession
from solo_tool import handlers
-from solo_tool.midi_controller_launchpad_mini import MidiController
SESSION_DIR = "/home/eddy/music/sessions"
SONG_POOL = "/home/eddy/music"
@@ -14,17 +14,25 @@ def fileName(path: str) -> str:
return basename(splitext(path)[0])
@ui.refreshable
-def keyPointTables(st: SoloTool) -> None:
- for i, song in enumerate(st.songs):
- with ui.list().props('separator').bind_visibility_from(st, 'song', value=i):
- for kp in st._keyPoints[i]:
- ui.item(f"{kp:0.2}", on_click=handlers.setKeyPoint(st, kp)).props('clickable v-ripple').classes('text-lg')
+def keyPointList(st: SoloTool) -> None:
+ with ui.list().props('separator'):
+ for kp in st.keyPoints:
+ ui.item(f"{kp:0.2}", on_click=handlers.setKeyPoint(st, kp)).props('clickable v-ripple').classes('text-lg')
+
+@ui.refreshable
+def songList(st: SoloTool, songDrawer) -> None:
+ with ui.list().props('separator'):
+ for i, path in enumerate(st.songs):
+ ui.item(fileName(path), on_click=handlers.setSong(st, i, lambda: songDrawer.hide())).props('clickable v-ripple')
sessions = {}
for f in glob(f"{SESSION_DIR}/*.json"):
sessionName = fileName(f)
- sessions[sessionName] = loadSession(f, SONG_POOL)
- sessions[sessionName].registerKeyPointListCallback(lambda new: keyPointTables.refresh())
+ 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
@ui.page('/{sessionName}')
def sessionPage(sessionName: str):
@@ -36,32 +44,44 @@ def sessionPage(sessionName: str):
ui.colors(secondary='#ffc107')
ui.page_title(sessionName)
+ # Improved performance with large file uploads
+ MultiPartParser.max_file_size = 1024 * 1024 * 100 # 100 MB
+
st = sessions[sessionName]
+ # 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)
+
+ with ui.dialog() as uploadSongDialog:
+ ui.upload(label="Upload songs", auto_upload=True, on_upload=handleFileUpload).classes('max-w-full')
+
# Header
with ui.header().classes('items-center justify-between'):
with ui.row().classes('items-center justify-start'):
- ui.button(icon='menu', on_click=lambda: song_drawer.toggle()).props('flat round dense color=white')
+ ui.button(icon='menu', on_click=lambda: songDrawer.toggle()).props('flat round color=white')
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")
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')
+ ui.button(icon='fullscreen', on_click=fullscreen.toggle).props('flat round color=white')
# Key points list
with ui.right_drawer(top_corner=True, bottom_corner=True).props('width=120 behavior=desktop'):
ui.label("Key Points").classes('text-lg')
- keyPointTables(st)
-
+ keyPointList(st)
def addKeyPoint() -> None: st.keyPoints += [st.keyPoint]
ui.button(icon='add', on_click=addKeyPoint).props('flat round dense color=white')
# Song list
- with ui.left_drawer(bottom_corner=True).props('overlay breakpoint=8000') as song_drawer:
- with ui.list().props('separator'):
- for i, path in enumerate(st.songs):
- ui.item(fileName(path), on_click=handlers.setSong(st, i, lambda: song_drawer.hide())).props('clickable v-ripple')
- ui.button(icon='add', on_click=lambda e: print(e)).props('flat round dense color=white')
+ with ui.left_drawer(bottom_corner=True).props('overlay breakpoint=8000') as songDrawer:
+ songList(st, songDrawer)
+ ui.button(icon='add', on_click=uploadSongDialog.open).props('flat round dense color=white')
# Playback position
def setPosition(e) -> None: st.position = e.args
@@ -78,7 +98,7 @@ def sessionPage(sessionName: str):
buttonSize = "20px"
ui.button(icon='skip_previous', on_click=handlers.restartOrPreviousSong(st, 0.01)).props(f"size={buttonSize}").style('flex: 1')
ui.button(color='positive', on_click=handlers.playPause(st)).bind_icon_from(st, "playing", lambda playing: "pause" if playing else "play_arrow").props(f"size={buttonSize}").style('flex: 1')
- ui.button(icon='vertical_align_bottom', on_click=handlers.positionToKeyPoint(st), color='amber-5').props(f"size={buttonSize}").style('flex: 2')
+ ui.button(icon='vertical_align_bottom', on_click=handlers.positionToKeyPoint(st), color='negative').props(f"size={buttonSize}").style('flex: 2')
ui.button(icon='undo', on_click=st.jump, color='secondary').props(f"size={buttonSize}").style('flex: 2')
ui.button(icon='skip_next', on_click=handlers.changeSong(st, 1)).props(f"size={buttonSize}").style('flex: 1')
@@ -102,6 +122,6 @@ def landingPage():
ui.label("Choose a session").classes('text-lg')
for name, soloTool in sessions.items():
- ui.link(name, f"/{name}")
+ ui.button(name, on_click=lambda: ui.navigate.to(f"/{name}"))
ui.run(binding_refresh_interval=0.2)