Spaces:
Running
Running
Fix audio looping and update version to 0.2.12
Browse filesUpdated the version number in `__init__.py` to 0.2.12.
Added a `loop` argument to `_mount_background_audio` in `audio.py`
to control audio looping, defaulting to `True`. Adjusted the
function to dynamically set or remove the `loop` attribute.
Modified `_game_over_content` in `ui.py` to play congratulations
music once by setting `loop=False`. Refactored `_render_game_over`
to separate handling of congratulations and background music,
ensuring correct looping behavior. Removed unnecessary
`remount_background_audio` logic. Updated README.md with a
changelog entry for version 0.2.12, highlighting the fix for
music looping on the congratulations screen.
- README.md +3 -0
- battlewords/__init__.py +1 -1
- battlewords/audio.py +23 -4
- battlewords/ui.py +14 -10
README.md
CHANGED
|
@@ -106,6 +106,9 @@ docker run -p 8501:8501 battlewords
|
|
| 106 |
|
| 107 |
## Changelog
|
| 108 |
|
|
|
|
|
|
|
|
|
|
| 109 |
-0.2.11
|
| 110 |
- update timer to be live during gameplay, but reset with each action
|
| 111 |
- compact design
|
|
|
|
| 106 |
|
| 107 |
## Changelog
|
| 108 |
|
| 109 |
+
-0.2.12
|
| 110 |
+
- fix music looping on congratulations screen
|
| 111 |
+
|
| 112 |
-0.2.11
|
| 113 |
- update timer to be live during gameplay, but reset with each action
|
| 114 |
- compact design
|
battlewords/__init__.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
| 1 |
-
__version__ = "0.2.
|
| 2 |
__all__ = ["models", "generator", "logic", "ui"]
|
|
|
|
| 1 |
+
__version__ = "0.2.12"
|
| 2 |
__all__ = ["models", "generator", "logic", "ui"]
|
battlewords/audio.py
CHANGED
|
@@ -34,8 +34,15 @@ def _load_audio_data_url(path: str) -> str:
|
|
| 34 |
encoded = base64.b64encode(fp.read()).decode("ascii")
|
| 35 |
return f"data:{mime};base64,{encoded}"
|
| 36 |
|
| 37 |
-
def _mount_background_audio(enabled: bool, src_data_url: Optional[str], volume: float) -> None:
|
| 38 |
-
"""Create/update a single hidden <audio> element in the top page and play/pause it.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
from streamlit.components.v1 import html as _html
|
| 40 |
|
| 41 |
if not enabled or not src_data_url:
|
|
@@ -55,6 +62,8 @@ def _mount_background_audio(enabled: bool, src_data_url: Optional[str], volume:
|
|
| 55 |
|
| 56 |
# Clamp volume
|
| 57 |
vol = max(0.0, min(1.0, float(volume)))
|
|
|
|
|
|
|
| 58 |
# Inject or update a single persistent audio element and make sure it starts after interaction if autoplay is blocked
|
| 59 |
_html(
|
| 60 |
f"""
|
|
@@ -66,10 +75,20 @@ def _mount_background_audio(enabled: bool, src_data_url: Optional[str], volume:
|
|
| 66 |
audio = doc.createElement('audio');
|
| 67 |
audio.id = 'bw-bg-audio';
|
| 68 |
audio.style.display = 'none';
|
| 69 |
-
audio.setAttribute('loop', '');
|
| 70 |
-
audio.setAttribute('autoplay', '');
|
| 71 |
doc.body.appendChild(audio);
|
| 72 |
}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
const newSrc = "{src_data_url}";
|
| 74 |
if (audio.src !== newSrc) {{
|
| 75 |
audio.src = newSrc;
|
|
|
|
| 34 |
encoded = base64.b64encode(fp.read()).decode("ascii")
|
| 35 |
return f"data:{mime};base64,{encoded}"
|
| 36 |
|
| 37 |
+
def _mount_background_audio(enabled: bool, src_data_url: Optional[str], volume: float, loop: bool = True) -> None:
|
| 38 |
+
"""Create/update a single hidden <audio> element in the top page and play/pause it.
|
| 39 |
+
|
| 40 |
+
Args:
|
| 41 |
+
enabled: Whether the background audio should be active.
|
| 42 |
+
src_data_url: data: URL for the audio source.
|
| 43 |
+
volume: 0.0–1.0 volume level.
|
| 44 |
+
loop: Whether the audio should loop (default True).
|
| 45 |
+
"""
|
| 46 |
from streamlit.components.v1 import html as _html
|
| 47 |
|
| 48 |
if not enabled or not src_data_url:
|
|
|
|
| 62 |
|
| 63 |
# Clamp volume
|
| 64 |
vol = max(0.0, min(1.0, float(volume)))
|
| 65 |
+
should_loop = "true" if loop else "false"
|
| 66 |
+
|
| 67 |
# Inject or update a single persistent audio element and make sure it starts after interaction if autoplay is blocked
|
| 68 |
_html(
|
| 69 |
f"""
|
|
|
|
| 75 |
audio = doc.createElement('audio');
|
| 76 |
audio.id = 'bw-bg-audio';
|
| 77 |
audio.style.display = 'none';
|
|
|
|
|
|
|
| 78 |
doc.body.appendChild(audio);
|
| 79 |
}}
|
| 80 |
+
|
| 81 |
+
// Ensure loop is explicitly set every time, even if element already exists
|
| 82 |
+
const shouldLoop = {should_loop};
|
| 83 |
+
audio.loop = shouldLoop;
|
| 84 |
+
if (shouldLoop) {{
|
| 85 |
+
audio.setAttribute('loop', '');
|
| 86 |
+
}} else {{
|
| 87 |
+
audio.removeAttribute('loop');
|
| 88 |
+
}}
|
| 89 |
+
audio.autoplay = true;
|
| 90 |
+
audio.setAttribute('autoplay', '');
|
| 91 |
+
|
| 92 |
const newSrc = "{src_data_url}";
|
| 93 |
if (audio.src !== newSrc) {{
|
| 94 |
audio.src = newSrc;
|
battlewords/ui.py
CHANGED
|
@@ -1094,10 +1094,9 @@ def _game_over_content(state: GameState) -> None:
|
|
| 1094 |
congrats_music_path = os.path.join(music_dir, "congratulations.mp3")
|
| 1095 |
if os.path.exists(congrats_music_path):
|
| 1096 |
src_url = _load_audio_data_url(congrats_music_path)
|
| 1097 |
-
# Play
|
| 1098 |
-
_mount_background_audio(True, src_url, (st.session_state.get("music_volume", 100)) / 100)
|
| 1099 |
else:
|
| 1100 |
-
# Fallback: keep previous music or silence
|
| 1101 |
_mount_background_audio(False, None, 0.0)
|
| 1102 |
|
| 1103 |
# Set end_time if not already set
|
|
@@ -1208,20 +1207,25 @@ else:
|
|
| 1208 |
_game_over_content(state)
|
| 1209 |
|
| 1210 |
def _render_game_over(state: GameState):
|
| 1211 |
-
# Determine visibility
|
| 1212 |
visible = bool(st.session_state.get("show_gameover_overlay", True)) and is_game_over(state)
|
| 1213 |
-
|
| 1214 |
-
|
| 1215 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1216 |
background_path = os.path.join(music_dir, "background.mp3")
|
| 1217 |
if os.path.exists(background_path):
|
| 1218 |
src_url = _load_audio_data_url(background_path)
|
| 1219 |
_mount_background_audio(True, src_url, (st.session_state.get("music_volume", 100)) / 100)
|
| 1220 |
else:
|
| 1221 |
_mount_background_audio(False, None, 0.0)
|
| 1222 |
-
st.session_state["remount_background_audio"] = False # reset flag
|
| 1223 |
-
if visible:
|
| 1224 |
-
_game_over_dialog(state)
|
| 1225 |
|
| 1226 |
def _sort_wordlist(filename):
|
| 1227 |
import time # Add this import
|
|
|
|
| 1094 |
congrats_music_path = os.path.join(music_dir, "congratulations.mp3")
|
| 1095 |
if os.path.exists(congrats_music_path):
|
| 1096 |
src_url = _load_audio_data_url(congrats_music_path)
|
| 1097 |
+
# Play once (no loop) at configured volume
|
| 1098 |
+
_mount_background_audio(True, src_url, (st.session_state.get("music_volume", 100)) / 100, loop=False)
|
| 1099 |
else:
|
|
|
|
| 1100 |
_mount_background_audio(False, None, 0.0)
|
| 1101 |
|
| 1102 |
# Set end_time if not already set
|
|
|
|
| 1207 |
_game_over_content(state)
|
| 1208 |
|
| 1209 |
def _render_game_over(state: GameState):
|
|
|
|
| 1210 |
visible = bool(st.session_state.get("show_gameover_overlay", True)) and is_game_over(state)
|
| 1211 |
+
music_dir = _get_music_dir()
|
| 1212 |
+
if visible:
|
| 1213 |
+
# Mount congratulations music (play once, do not loop)
|
| 1214 |
+
congrats_music_path = os.path.join(music_dir, "congratulations.mp3")
|
| 1215 |
+
if os.path.exists(congrats_music_path):
|
| 1216 |
+
src_url = _load_audio_data_url(congrats_music_path)
|
| 1217 |
+
_mount_background_audio(True, src_url, (st.session_state.get("music_volume", 100)) / 100, loop=False)
|
| 1218 |
+
else:
|
| 1219 |
+
_mount_background_audio(False, None, 0.0)
|
| 1220 |
+
_game_over_dialog(state)
|
| 1221 |
+
else:
|
| 1222 |
+
# Mount background music (loop by default)
|
| 1223 |
background_path = os.path.join(music_dir, "background.mp3")
|
| 1224 |
if os.path.exists(background_path):
|
| 1225 |
src_url = _load_audio_data_url(background_path)
|
| 1226 |
_mount_background_audio(True, src_url, (st.session_state.get("music_volume", 100)) / 100)
|
| 1227 |
else:
|
| 1228 |
_mount_background_audio(False, None, 0.0)
|
|
|
|
|
|
|
|
|
|
| 1229 |
|
| 1230 |
def _sort_wordlist(filename):
|
| 1231 |
import time # Add this import
|