import pygame import time import threading import base64 import os from flask import Flask, Response, render_template_string from io import BytesIO from PIL import Image os.environ['SDL_VIDEODRIVER'] = 'dummy' pygame.init() WIDTH, HEIGHT = 800, 600 shared = { "current_file": "frame_a.jpg", "frame_count": 0, "streaming": True, "last_switch": time.time() } def pingpong_loop(): """Alternate between two files""" screen = pygame.Surface((WIDTH, HEIGHT)) # Two different colored circles circles = [ {"x": 200, "y": 300, "color": (255, 80, 80), "size": 50}, # Red {"x": 600, "y": 300, "color": (80, 180, 255), "size": 50} # Blue ] while shared["streaming"]: # Switch files every 0.5 seconds current_time = time.time() if current_time - shared["last_switch"] > 0.5: if shared["current_file"] == "frame_a.jpg": shared["current_file"] = "frame_b.jpg" # Draw blue circle screen.fill((25, 25, 45)) pygame.draw.circle(screen, circles[1]["color"], (circles[1]["x"], circles[1]["y"]), circles[1]["size"]) else: shared["current_file"] = "frame_a.jpg" # Draw red circle screen.fill((25, 25, 45)) pygame.draw.circle(screen, circles[0]["color"], (circles[0]["x"], circles[0]["y"]), circles[0]["size"]) # Save to file frame_str = pygame.image.tostring(screen, 'RGB') img = Image.frombytes('RGB', (WIDTH, HEIGHT), frame_str) img.save(shared["current_file"], quality=85) shared["last_switch"] = current_time shared["frame_count"] += 1 # Log to console print(f"Switched to: {shared['current_file']} | Frame: {shared['frame_count']}") time.sleep(0.1) # Check 10 times per second app = Flask(__name__) HTML = '''
Frame: 0 | File: none
''' @app.route('/') def index(): return render_template_string(HTML) @app.route('/stats') def stats(): return { 'frame_count': shared['frame_count'], 'current_file': shared['current_file'] } @app.route('/stream') def stream(): try: if os.path.exists(shared["current_file"]): with open(shared["current_file"], 'rb') as f: frame_bytes = f.read() return Response( frame_bytes, mimetype='image/jpeg', headers={ 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0', 'Pragma': 'no-cache', 'Expires': '0', 'Last-Modified': time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime()) } ) except Exception as e: print(f"Stream error: {e}") # Return a small black image as fallback fallback = base64.b64decode('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCAABAAEDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAv/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAX/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABmX/9k=') return Response(fallback, mimetype='image/jpeg') if __name__ == "__main__": # Create initial files screen = pygame.Surface((WIDTH, HEIGHT)) screen.fill((25, 25, 45)) pygame.draw.circle(screen, (255, 80, 80), (200, 300), 50) img = Image.frombytes('RGB', (WIDTH, HEIGHT), pygame.image.tostring(screen, 'RGB')) img.save("frame_a.jpg", quality=85) screen.fill((25, 25, 45)) pygame.draw.circle(screen, (80, 180, 255), (600, 300), 50) img = Image.frombytes('RGB', (WIDTH, HEIGHT), pygame.image.tostring(screen, 'RGB')) img.save("frame_b.jpg", quality=85) print("Created initial files: frame_a.jpg (red) and frame_b.jpg (blue)") # Start ping-pong thread thread = threading.Thread(target=pingpong_loop, daemon=True) thread.start() # Start server app.run( host='0.0.0.0', port=int(os.environ.get('PORT', 7860)), debug=False, threaded=True )