Spaces:
Sleeping
Sleeping
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)
|