Update app.py
Browse files
app.py
CHANGED
@@ -35,10 +35,11 @@ FUN_USERNAMES = [
|
|
35 |
"MysticMoose π¦", "GlitchGnome π§", "VortexViper π", "ChronoChimp π"
|
36 |
]
|
37 |
|
38 |
-
# Directories for chat and
|
39 |
CHAT_DIR = "chat_logs"
|
40 |
VOTE_DIR = "vote_logs"
|
41 |
MEDIA_DIR = "media"
|
|
|
42 |
os.makedirs(CHAT_DIR, exist_ok=True)
|
43 |
os.makedirs(VOTE_DIR, exist_ok=True)
|
44 |
os.makedirs(MEDIA_DIR, exist_ok=True)
|
@@ -69,6 +70,10 @@ UNICODE_FONTS = [
|
|
69 |
("Circle", lambda x: "".join(chr(ord(c) + 0x24B6 - 0x41) if 'A' <= c <= 'Z' else chr(ord(c) + 0x24D0 - 0x61) if 'a' <= c <= 'z' else c for c in x))
|
70 |
]
|
71 |
|
|
|
|
|
|
|
|
|
72 |
# Node name - the appβs codename generator, sneaky and slick! π΅οΈββοΈπΎ
|
73 |
def get_node_name():
|
74 |
"""π² Spins the wheel of fate to name our node - a random alias or user pick! π·οΈ"""
|
@@ -194,6 +199,25 @@ def generate_user_hash():
|
|
194 |
st.session_state['user_hash'] = hash_object.hexdigest()[:8]
|
195 |
return st.session_state['user_hash']
|
196 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
197 |
# Media HTML generators - IVAβs multimedia magic! π₯πΆπΌοΈ
|
198 |
def get_video_html(video_path, width="100%"):
|
199 |
"""π¬ Rolls out the red carpet for videos - autoplay and loop like a star! π"""
|
@@ -261,12 +285,15 @@ async def broadcast_message(message, room_id):
|
|
261 |
for client_id in disconnected:
|
262 |
del active_connections[room_id][client_id]
|
263 |
|
264 |
-
# WebSocket
|
265 |
-
async def
|
266 |
-
"""π Cranks up the WebSocket jukebox,
|
267 |
-
|
268 |
-
|
269 |
-
|
|
|
|
|
|
|
270 |
|
271 |
# Chat interface maker - the stage builder for our Sector extravaganza! πποΈ
|
272 |
def create_streamlit_interface(initial_username):
|
@@ -301,10 +328,16 @@ def create_streamlit_interface(initial_username):
|
|
301 |
st.title(f"{Site_Name}")
|
302 |
st.markdown(f"Welcome to {START_ROOM} - chat, vote, and enjoy IVAβs media magic! π")
|
303 |
|
304 |
-
#
|
|
|
|
|
|
|
305 |
if 'username' not in st.session_state:
|
306 |
st.session_state.username = initial_username
|
307 |
save_chat_entry("System π", f"{initial_username} has joined {START_ROOM}!")
|
|
|
|
|
|
|
308 |
if 'refresh_rate' not in st.session_state:
|
309 |
st.session_state.refresh_rate = 5
|
310 |
if 'timer_start' not in st.session_state:
|
@@ -329,6 +362,7 @@ def create_streamlit_interface(initial_username):
|
|
329 |
user_hash = generate_user_hash()
|
330 |
save_vote(QUOTE_VOTES_FILE, line, user_hash)
|
331 |
st.session_state.timer_start = time.time()
|
|
|
332 |
st.rerun()
|
333 |
|
334 |
user_list = get_user_list(chat_content)
|
@@ -337,11 +371,13 @@ def create_streamlit_interface(initial_username):
|
|
337 |
save_chat_entry("System π", f"{st.session_state.username} switched to {new_username} in {START_ROOM}!")
|
338 |
st.session_state.username = new_username
|
339 |
st.session_state.timer_start = time.time()
|
|
|
340 |
|
341 |
message = st.text_input("Message", placeholder="Type your epic line here! βοΈ")
|
342 |
if st.button("Send π") and message.strip():
|
343 |
save_chat_entry(st.session_state.username, message)
|
344 |
st.session_state.timer_start = time.time()
|
|
|
345 |
st.rerun()
|
346 |
|
347 |
# Quote section
|
@@ -358,6 +394,7 @@ def create_streamlit_interface(initial_username):
|
|
358 |
user_hash = generate_user_hash()
|
359 |
save_vote(QUOTE_VOTES_FILE, quote, user_hash)
|
360 |
st.session_state.timer_start = time.time()
|
|
|
361 |
st.rerun()
|
362 |
if time.time() - st.session_state.timer_start > 10: # 10s quote refresh
|
363 |
st.session_state.quote_index = (st.session_state.quote_index + 1) % len(quotes)
|
@@ -365,6 +402,7 @@ def create_streamlit_interface(initial_username):
|
|
365 |
quotes = load_quotes(st.session_state.quote_source)
|
366 |
st.session_state.quote_index = st.session_state.quote_index % len(quotes) if quotes else 0
|
367 |
st.session_state.timer_start = time.time()
|
|
|
368 |
st.rerun()
|
369 |
else:
|
370 |
st.markdown("No quotes available - check back later! π")
|
@@ -391,6 +429,7 @@ def create_streamlit_interface(initial_username):
|
|
391 |
user_hash = generate_user_hash()
|
392 |
save_vote(IMAGE_VOTES_FILE, media_file, user_hash)
|
393 |
st.session_state.timer_start = time.time()
|
|
|
394 |
st.rerun()
|
395 |
else:
|
396 |
st.error("No media files (images, audio, video) found in 'media' directory!")
|
@@ -401,20 +440,24 @@ def create_streamlit_interface(initial_username):
|
|
401 |
if refresh_rate != st.session_state.refresh_rate:
|
402 |
st.session_state.refresh_rate = refresh_rate
|
403 |
st.session_state.timer_start = time.time()
|
|
|
404 |
|
405 |
col1, col2, col3 = st.columns(3)
|
406 |
with col1:
|
407 |
if st.button("π Small (1s)"):
|
408 |
st.session_state.refresh_rate = 1
|
409 |
st.session_state.timer_start = time.time()
|
|
|
410 |
with col2:
|
411 |
if st.button("π’ Medium (5s)"):
|
412 |
st.session_state.refresh_rate = 5
|
413 |
st.session_state.timer_start = time.time()
|
|
|
414 |
with col3:
|
415 |
if st.button("π Large (5m)"):
|
416 |
st.session_state.refresh_rate = 300
|
417 |
st.session_state.timer_start = time.time()
|
|
|
418 |
|
419 |
# Pulsing countdown timer with emoji digits and random Unicode font
|
420 |
timer_placeholder = st.empty()
|
@@ -427,6 +470,7 @@ def create_streamlit_interface(initial_username):
|
|
427 |
time.sleep(1) # Pulse every second
|
428 |
st.session_state.timer_start = time.time()
|
429 |
st.session_state.last_refresh = time.time()
|
|
|
430 |
st.rerun()
|
431 |
|
432 |
# Sidebar vote stats
|
@@ -441,9 +485,12 @@ def create_streamlit_interface(initial_username):
|
|
441 |
# Main event - the ringmaster kicking off the Sector circus! πͺπ€‘
|
442 |
async def main():
|
443 |
"""π€ Drops the mic and starts the Sector party - itβs showtime, folks! π"""
|
444 |
-
global NODE_NAME
|
445 |
NODE_NAME, port = get_node_name()
|
446 |
-
|
|
|
|
|
|
|
447 |
|
448 |
query_params = st.query_params if hasattr(st, 'query_params') else {}
|
449 |
initial_username = query_params.get("username", random.choice(FUN_USERNAMES)) if query_params else random.choice(FUN_USERNAMES)
|
|
|
35 |
"MysticMoose π¦", "GlitchGnome π§", "VortexViper π", "ChronoChimp π"
|
36 |
]
|
37 |
|
38 |
+
# Directories for chat, votes, and media - the secret vaults where treasures are stashed! ποΈπ
|
39 |
CHAT_DIR = "chat_logs"
|
40 |
VOTE_DIR = "vote_logs"
|
41 |
MEDIA_DIR = "media"
|
42 |
+
STATE_FILE = "user_state.txt"
|
43 |
os.makedirs(CHAT_DIR, exist_ok=True)
|
44 |
os.makedirs(VOTE_DIR, exist_ok=True)
|
45 |
os.makedirs(MEDIA_DIR, exist_ok=True)
|
|
|
70 |
("Circle", lambda x: "".join(chr(ord(c) + 0x24B6 - 0x41) if 'A' <= c <= 'Z' else chr(ord(c) + 0x24D0 - 0x61) if 'a' <= c <= 'z' else c for c in x))
|
71 |
]
|
72 |
|
73 |
+
# Global WebSocket server flag
|
74 |
+
server_running = False
|
75 |
+
server_task = None
|
76 |
+
|
77 |
# Node name - the appβs codename generator, sneaky and slick! π΅οΈββοΈπΎ
|
78 |
def get_node_name():
|
79 |
"""π² Spins the wheel of fate to name our node - a random alias or user pick! π·οΈ"""
|
|
|
199 |
st.session_state['user_hash'] = hash_object.hexdigest()[:8]
|
200 |
return st.session_state['user_hash']
|
201 |
|
202 |
+
# Username persistence - save and load across refreshes! πΎπ
|
203 |
+
def save_username(username):
|
204 |
+
"""πΎ Stashes your cosmic alias before the refresh void claims it! π"""
|
205 |
+
try:
|
206 |
+
with open(STATE_FILE, 'w') as f:
|
207 |
+
f.write(username)
|
208 |
+
except Exception as e:
|
209 |
+
print(f"Failed to save username: {e}")
|
210 |
+
|
211 |
+
def load_username():
|
212 |
+
"""π Resurrects your cosmic alias from the refresh abyss! π """
|
213 |
+
if os.path.exists(STATE_FILE):
|
214 |
+
try:
|
215 |
+
with open(STATE_FILE, 'r') as f:
|
216 |
+
return f.read().strip()
|
217 |
+
except Exception as e:
|
218 |
+
print(f"Failed to load username: {e}")
|
219 |
+
return None
|
220 |
+
|
221 |
# Media HTML generators - IVAβs multimedia magic! π₯πΆπΌοΈ
|
222 |
def get_video_html(video_path, width="100%"):
|
223 |
"""π¬ Rolls out the red carpet for videos - autoplay and loop like a star! π"""
|
|
|
285 |
for client_id in disconnected:
|
286 |
del active_connections[room_id][client_id]
|
287 |
|
288 |
+
# WebSocket server runner - the DJ spinning up the Sector tunes once! π§π₯
|
289 |
+
async def run_websocket_server():
|
290 |
+
"""π Cranks up the WebSocket jukebox once, keeping Sector rocking! πΈ"""
|
291 |
+
global server_running, server_task
|
292 |
+
if not server_running:
|
293 |
+
server = await websockets.serve(websocket_handler, '0.0.0.0', 8765)
|
294 |
+
print(f"WebSocket server jamming on ws://0.0.0.0:8765")
|
295 |
+
server_running = True
|
296 |
+
await server.wait_closed()
|
297 |
|
298 |
# Chat interface maker - the stage builder for our Sector extravaganza! πποΈ
|
299 |
def create_streamlit_interface(initial_username):
|
|
|
328 |
st.title(f"{Site_Name}")
|
329 |
st.markdown(f"Welcome to {START_ROOM} - chat, vote, and enjoy IVAβs media magic! π")
|
330 |
|
331 |
+
# Load or set username
|
332 |
+
saved_username = load_username()
|
333 |
+
if saved_username and saved_username in FUN_USERNAMES:
|
334 |
+
initial_username = saved_username
|
335 |
if 'username' not in st.session_state:
|
336 |
st.session_state.username = initial_username
|
337 |
save_chat_entry("System π", f"{initial_username} has joined {START_ROOM}!")
|
338 |
+
save_username(st.session_state.username) # Persist before any refresh
|
339 |
+
|
340 |
+
# Session state for refresh rate and quote index
|
341 |
if 'refresh_rate' not in st.session_state:
|
342 |
st.session_state.refresh_rate = 5
|
343 |
if 'timer_start' not in st.session_state:
|
|
|
362 |
user_hash = generate_user_hash()
|
363 |
save_vote(QUOTE_VOTES_FILE, line, user_hash)
|
364 |
st.session_state.timer_start = time.time()
|
365 |
+
save_username(st.session_state.username)
|
366 |
st.rerun()
|
367 |
|
368 |
user_list = get_user_list(chat_content)
|
|
|
371 |
save_chat_entry("System π", f"{st.session_state.username} switched to {new_username} in {START_ROOM}!")
|
372 |
st.session_state.username = new_username
|
373 |
st.session_state.timer_start = time.time()
|
374 |
+
save_username(st.session_state.username)
|
375 |
|
376 |
message = st.text_input("Message", placeholder="Type your epic line here! βοΈ")
|
377 |
if st.button("Send π") and message.strip():
|
378 |
save_chat_entry(st.session_state.username, message)
|
379 |
st.session_state.timer_start = time.time()
|
380 |
+
save_username(st.session_state.username)
|
381 |
st.rerun()
|
382 |
|
383 |
# Quote section
|
|
|
394 |
user_hash = generate_user_hash()
|
395 |
save_vote(QUOTE_VOTES_FILE, quote, user_hash)
|
396 |
st.session_state.timer_start = time.time()
|
397 |
+
save_username(st.session_state.username)
|
398 |
st.rerun()
|
399 |
if time.time() - st.session_state.timer_start > 10: # 10s quote refresh
|
400 |
st.session_state.quote_index = (st.session_state.quote_index + 1) % len(quotes)
|
|
|
402 |
quotes = load_quotes(st.session_state.quote_source)
|
403 |
st.session_state.quote_index = st.session_state.quote_index % len(quotes) if quotes else 0
|
404 |
st.session_state.timer_start = time.time()
|
405 |
+
save_username(st.session_state.username)
|
406 |
st.rerun()
|
407 |
else:
|
408 |
st.markdown("No quotes available - check back later! π")
|
|
|
429 |
user_hash = generate_user_hash()
|
430 |
save_vote(IMAGE_VOTES_FILE, media_file, user_hash)
|
431 |
st.session_state.timer_start = time.time()
|
432 |
+
save_username(st.session_state.username)
|
433 |
st.rerun()
|
434 |
else:
|
435 |
st.error("No media files (images, audio, video) found in 'media' directory!")
|
|
|
440 |
if refresh_rate != st.session_state.refresh_rate:
|
441 |
st.session_state.refresh_rate = refresh_rate
|
442 |
st.session_state.timer_start = time.time()
|
443 |
+
save_username(st.session_state.username)
|
444 |
|
445 |
col1, col2, col3 = st.columns(3)
|
446 |
with col1:
|
447 |
if st.button("π Small (1s)"):
|
448 |
st.session_state.refresh_rate = 1
|
449 |
st.session_state.timer_start = time.time()
|
450 |
+
save_username(st.session_state.username)
|
451 |
with col2:
|
452 |
if st.button("π’ Medium (5s)"):
|
453 |
st.session_state.refresh_rate = 5
|
454 |
st.session_state.timer_start = time.time()
|
455 |
+
save_username(st.session_state.username)
|
456 |
with col3:
|
457 |
if st.button("π Large (5m)"):
|
458 |
st.session_state.refresh_rate = 300
|
459 |
st.session_state.timer_start = time.time()
|
460 |
+
save_username(st.session_state.username)
|
461 |
|
462 |
# Pulsing countdown timer with emoji digits and random Unicode font
|
463 |
timer_placeholder = st.empty()
|
|
|
470 |
time.sleep(1) # Pulse every second
|
471 |
st.session_state.timer_start = time.time()
|
472 |
st.session_state.last_refresh = time.time()
|
473 |
+
save_username(st.session_state.username)
|
474 |
st.rerun()
|
475 |
|
476 |
# Sidebar vote stats
|
|
|
485 |
# Main event - the ringmaster kicking off the Sector circus! πͺπ€‘
|
486 |
async def main():
|
487 |
"""π€ Drops the mic and starts the Sector party - itβs showtime, folks! π"""
|
488 |
+
global NODE_NAME, server_task
|
489 |
NODE_NAME, port = get_node_name()
|
490 |
+
|
491 |
+
# Start WebSocket server only once as a background task
|
492 |
+
if server_task is None:
|
493 |
+
server_task = asyncio.create_task(run_websocket_server())
|
494 |
|
495 |
query_params = st.query_params if hasattr(st, 'query_params') else {}
|
496 |
initial_username = query_params.get("username", random.choice(FUN_USERNAMES)) if query_params else random.choice(FUN_USERNAMES)
|