import streamlit as st import threading import time import schedule import random import datetime from playwright.sync_api import sync_playwright # ── Streamlit UI Page Config ── # Must be the first Streamlit command called on the page st.set_page_config(page_title="Keep-Alive Console", page_icon="πŸš€", layout="wide") TARGET_URL = "https://streamer1-hsd7neqlzku825vdo6rtkz.streamlit.app/" # ── Shared log list (thread-safe for appends in CPython) ── logs = ["πŸš€ System initialized – service starting…"] def add_log(msg): ts = datetime.datetime.now().strftime("%H:%M:%S") entry = f"[{ts}] {msg}" print(entry) logs.append(entry) if len(logs) > 50: logs.pop(0) # ── Keep-alive routine ── def visit_and_scroll(): add_log(f"Opening {TARGET_URL}") try: with sync_playwright() as p: browser = p.chromium.launch( headless=True, args=["--no-sandbox", "--disable-dev-shm-usage", "--disable-gpu"], ) try: page = browser.new_page( user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) " "AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/120.0.0.0 Safari/537.36" ) page.goto(TARGET_URL, wait_until="networkidle", timeout=60_000) add_log("Page loaded – waiting 10 s for hydration…") time.sleep(10) for i in range(1, 6): y = i * 800 page.evaluate(f"window.scrollTo(0, {y});") add_log(f"Scrolled to {y}px") time.sleep(random.uniform(1.5, 3.0)) page.evaluate("window.scrollTo(0, 0);") add_log("Visit completed successfully βœ…") finally: browser.close() except Exception as e: add_log(f"ERROR: {e}") # ── Background scheduler (one thread, runs forever) ── def _loop(): visit_and_scroll() schedule.every(10).minutes.do(visit_and_scroll) while True: schedule.run_pending() time.sleep(10) # check for scheduled tasks more frequently # Guard: start the thread only once per Streamlit process using cache_resource @st.cache_resource def start_scheduler(): thread = threading.Thread(target=_loop, daemon=True) thread.start() return thread start_scheduler() # ── Streamlit UI layout ── st.title("πŸ€– Keep-Alive Cloud Console") st.caption(f"Target: **{TARGET_URL}** β€’ Frequency: every 10 minutes") st.divider() # Fragment for non-blocking UI logs refresh if supported (Streamlit >= 1.33) if hasattr(st, "fragment"): @st.fragment(run_every="30s") def display_logs_fragment(): st.text_area("Logs (newest first)", "\n".join(reversed(logs)), height=400, disabled=True) else: def display_logs_fragment(): st.text_area("Logs (newest first)", "\n".join(reversed(logs)), height=400, disabled=True) c1, c2 = st.columns([3, 1]) with c1: st.subheader("Activity Log") display_logs_fragment() with c2: st.subheader("Controls") if st.button("πŸš€ Push Now"): with st.spinner("Visiting…"): visit_and_scroll() st.success("Done!") st.rerun() # Force rerun to refresh logs immediately on manual push st.info("Background scheduler is active.") # Page level auto-refresh fallback for older Streamlit versions (< 1.33) if not hasattr(st, "fragment"): time.sleep(30) st.rerun()