diff --git a/html/demo.js b/html/demo.js index 34a77c7..33324ef 100644 --- a/html/demo.js +++ b/html/demo.js @@ -285,6 +285,7 @@ function takeLeadClick() { singer_client.x_send_metadata("markStartSinging", true); leadButtonState = "stop-singing"; window.backingTrack.style.display = "none"; + window.provideLyrics.style.display = "none"; } else if (leadButtonState == "stop-singing") { singer_client.x_send_metadata("markStopSinging", true); window.takeLead.textContent = "Lead a Song"; @@ -296,6 +297,25 @@ function takeLeadClick() { window.takeLead.addEventListener("click", takeLeadClick); +window.provideLyrics.addEventListener("click", () => { + window.lyricsEntry.style.display = "block"; +}); + +window.lyricsEntryCancel.addEventListener("click", () => { + window.lyricsEntry.style.display = "none"; + window.lyricsTooLong.style.display = "none"; +}); + +window.lyricsEntryOk.addEventListener("click", () => { + if (window.lyricsEntryBox.value.length > 2500) { + window.lyricsTooLong.style.display = "block"; + } else { + window.lyricsEntry.style.display = "none"; + window.lyricsTooLong.style.display = "none"; + singer_client.send_kv("lyrics", window.lyricsEntryBox.value); + } +}); + window.bpm.addEventListener("change", () => { const newBpm = parseInt(window.bpm.value); if (isNaN(newBpm) || newBpm < 0 || newBpm > 500) { @@ -522,6 +542,7 @@ function set_controls() { window.estLatency.innerText = "..."; window.backingTrack.display = "none"; + window.provideLyrics.style.display = "none"; } function in_select_change() { @@ -868,8 +889,10 @@ function update_active_users( leadButtonState = "start-singing"; window.backingTrack.style.display = "inline-block"; window.backingTrack.selectedIndex = 0; + window.provideLyrics.style.display = "inline-block"; } else if (!imLeading) { window.backingTrack.style.display = "none"; + window.provideLyrics.style.display = "none"; if (hasLeader && song_active()) { window.takeLead.textContent = "Halt Song"; leadButtonState = "stop-singing" @@ -1463,7 +1486,6 @@ async function start_singing() { window.backingVolumeControl.value = metadata["backingVolume"]; } - first_bucket_s = metadata["first_bucket"] || first_bucket_s; if (metadata["twilio_token"]) { @@ -1471,6 +1493,11 @@ async function start_singing() { connect_twilio(); } + if (metadata["lyrics"]) { + window.lyricsDisplay.value = metadata["lyrics"]; + window.lyricsDisplay.style.display = "block"; + } + let startSingingCountdown = null; let stopSingingCountdown = null; @@ -1571,6 +1598,10 @@ async function start_singing() { window.buckets.style.display = showBuckets ? "flex" : "none"; window.unbucketedUsers.style.display = showBuckets ? "none" : "block"; + if (!showBuckets) { + window.lyricsDisplay.style.display = "none"; + } + const showBucketingGuide = hasLeader && !song_active(); window.bucketingGuide.style.display = showBucketingGuide ? "block" : "none"; diff --git a/html/index.html b/html/index.html index e10318d..65207a7 100644 --- a/html/index.html +++ b/html/index.html @@ -93,6 +93,7 @@ } #backingTrack { display: none; } +#provideLyrics { display: none; } #crash { display: none; @@ -411,8 +412,43 @@ #aboveBuckets > * { margin-bottom: 1em; } + +#lyricsEntry { + position: absolute; + top: 1em; + left: 1em; + border-radius: 0.5em; + border: 1px solid #aaa; + width: calc(100vw - 2em); + height: calc(100vh - 2em); + background: rgb(224, 242, 242); + z-index: 2; + display: none; +} +#lyricsEntryBox { + width: calc(100% - 2em); + height: calc(100% - 4em); + margin: 1em; +} +#lyricsEntryBottom { + display: flex; + flex-direction: row; + justify-content: flex-end; + margin-right: 1em; +} +#lyricsTooLong { + color: red; + display: none; + margin-right: 1em; +} +#lyricsDisplay { + width: 100%; + height: 40vh; + display: none; +} + @@ -421,6 +457,15 @@ +
+ +
+
Sorry, too many lyrics
+ + +
+
+
@@ -879,6 +924,7 @@

Settings that affect everyone

+
@@ -904,6 +950,9 @@

Settings that affect everyone

+
diff --git a/server.py b/server.py index e0e7aff..f6e73e8 100755 --- a/server.py +++ b/server.py @@ -107,6 +107,8 @@ def reset(self): self.disable_auto_gain = False self.disable_song_video = False + self.lyrics = "" + if recorder: recorder.reset() @@ -359,6 +361,8 @@ def __init__(self, userid, name, last_heard_server_clock, delay_samples) -> None scalar_to_friendly_volume(state.backing_volume)) if state.disable_song_video: self.send("disableSongVideo", state.disable_song_video) + if state.lyrics: + self.send("lyrics", state.lyrics) def allocate_twilio_token(self): token = AccessToken(secrets["twilio"]["account_sid"], @@ -755,11 +759,7 @@ def handle_json_post(in_json_raw, in_data): else: return json.dumps({"error": "unknown request " + in_json["request"]}), np.zeros(0) - query_string = in_json["query_string"] - client_address = in_json.get("client_address", None) - - out_data, x_audio_metadata = handle_post( - in_data, query_string, print_status=True, client_address=client_address) + out_data, x_audio_metadata = handle_post(in_json, in_data) return json.dumps({ "x-audio-metadata": x_audio_metadata, @@ -909,11 +909,12 @@ def extract_params(params, keys): def get_events_to_send() -> Any: return [{"evid": i[0], "clock": i[1]} for i in events.items()] -def handle_post(in_data, query_string, print_status, client_address=None) -> Tuple[Any, str]: +def handle_post(in_json, in_data) -> Tuple[Any, str]: in_data = in_data.view(dtype=np.float32) raw_params = {} # For some reason urllib can't handle the query_string being empty + query_string = in_json["query_string"] if query_string: raw_params = urllib.parse.parse_qs(query_string, strict_parsing=True) query_params = clean_query_params(raw_params) @@ -1046,8 +1047,8 @@ def handle_post(in_data, query_string, print_status, client_address=None) -> Tup update_users(userid, username, server_clock, client_read_clock) user = users[userid] - if client_address is not None: - user.client_address = client_address + if "client_address" in in_json: + user.client_address = in_json["client_address"] user.in_spectator_mode = query_params.get("spectator", None) @@ -1064,6 +1065,10 @@ def handle_post(in_data, query_string, print_status, client_address=None) -> Tup user.backing_volume = friendly_volume_to_scalar( float(user_backing_volume)) + if "lyrics" in in_json: + state.lyrics = in_json["lyrics"] + sendall("lyrics", state.lyrics) + # If we are running under Ritual Engine, disable functionality that is not # required in that setting, and would be disruptive if triggered by # accident. @@ -1194,7 +1199,7 @@ def handle_post(in_data, query_string, print_status, client_address=None) -> Tup x_audio_metadata.update(user.to_send) user.mark_sent() - if print_status: + if in_json.get("print_status", False): maybe_print_status() bin_summary = binary_user_summary(user_summary(requested_user_summary))