Spaces:
Sleeping
Sleeping
| import pygame, time, threading, base64, os | |
| from flask import Flask, render_template_string | |
| from flask_socketio import SocketIO, emit | |
| from io import BytesIO | |
| from PIL import Image | |
| os.environ['SDL_VIDEODRIVER'] = 'dummy' | |
| pygame.init() | |
| WIDTH, HEIGHT = 400, 300 # Smaller for faster transfer | |
| app = Flask(__name__) | |
| app.config['SECRET_KEY'] = 'secret!' | |
| socketio = SocketIO(app, async_mode='threading') | |
| # Shared state | |
| shared = {"frame_count": 0, "streaming": True} | |
| def game_loop(): | |
| """Game loop that emits frames via WebSocket""" | |
| screen = pygame.Surface((WIDTH, HEIGHT)) | |
| circle_x, circle_y = WIDTH//2, HEIGHT//2 | |
| speed_x, speed_y = 3, 2 | |
| while shared["streaming"]: | |
| start = time.time() | |
| # Update position | |
| circle_x += speed_x | |
| circle_y += speed_y | |
| if circle_x < 30 or circle_x > WIDTH-30: speed_x *= -1 | |
| if circle_y < 30 or circle_y > HEIGHT-30: speed_y *= -1 | |
| # Draw | |
| screen.fill((25, 25, 45)) | |
| pygame.draw.circle(screen, (255, 80, 80), (int(circle_x), int(circle_y)), 20) | |
| # Convert to JPEG (small, efficient) | |
| frame_str = pygame.image.tostring(screen, 'RGB') | |
| img = Image.frombytes('RGB', (WIDTH, HEIGHT), frame_str) | |
| buf = BytesIO() | |
| img.save(buf, format='JPEG', quality=85) # Smaller file | |
| frame_b64 = base64.b64encode(buf.getvalue()).decode('utf-8') | |
| # Emit to ALL connected clients | |
| socketio.emit('new_frame', { | |
| 'frame': frame_b64, | |
| 'count': shared["frame_count"] | |
| }) | |
| shared["frame_count"] += 1 | |
| # Control FPS | |
| elapsed = time.time() - start | |
| if elapsed < 1.0/30: | |
| time.sleep(1.0/30 - elapsed) | |
| HTML = '''<!DOCTYPE html> | |
| <html> | |
| <head> | |
| <style> | |
| body { background:#0f172a; color:white; text-align:center; padding:20px; } | |
| #streamImg { border:3px solid #60a5fa; width:400px; height:300px; } | |
| </style> | |
| <script src="https://cdn.socket.io/4.5.0/socket.io.min.js"></script> | |
| </head> | |
| <body> | |
| <h1>🎮 Real-time PyGame Stream</h1> | |
| <img id="streamImg" src=""> | |
| <p>Frames: <span id="count">0</span></p> | |
| <script> | |
| const socket = io(); | |
| const img = document.getElementById('streamImg'); | |
| socket.on('connect', () => { | |
| console.log('Connected to stream'); | |
| }); | |
| socket.on('new_frame', (data) => { | |
| img.src = 'data:image/jpeg;base64,' + data.frame; | |
| document.getElementById('count').textContent = data.count; | |
| }); | |
| socket.on('disconnect', () => { | |
| console.log('Disconnected'); | |
| }); | |
| </script> | |
| </body> | |
| </html>''' | |
| def index(): | |
| return render_template_string(HTML) | |
| if __name__ == '__main__': | |
| # Start game loop in background | |
| threading.Thread(target=game_loop, daemon=True).start() | |
| # Start server | |
| socketio.run(app, | |
| host='0.0.0.0', | |
| port=int(os.environ.get('PORT', 7860)), | |
| debug=False, | |
| allow_unsafe_werkzeug=True) |