flaskdockernew / app.py
MySafeCode's picture
Update app.py
e98caa2 verified
Raw
History Blame
3.86 kB
import pygame
import time
import threading
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 = 400, 300
shared = {
"frame_count": 0,
"streaming": True,
"last_filename": None
}
def moving_circle_loop():
screen = pygame.Surface((WIDTH, HEIGHT))
circle_x, circle_y = WIDTH//2, HEIGHT//2
speed_x, speed_y = 5, 4
while shared["streaming"]:
start_time = time.time()
# Move circle
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)
# Create unique filename
shared["frame_count"] += 1
filename = f"frame_{shared['frame_count'] % 100:02d}.jpg"
# Save to file
frame_str = pygame.image.tostring(screen, 'RGB')
img = Image.frombytes('RGB', (WIDTH, HEIGHT), frame_str)
img.save(filename, quality=90, optimize=True)
# Clean old file
if shared["last_filename"] and os.path.exists(shared["last_filename"]):
os.remove(shared["last_filename"])
shared["last_filename"] = filename
# Console log
if shared["frame_count"] % 10 == 0:
print(f"Frame {shared['frame_count']}: {filename} | Pos: ({int(circle_x)},{int(circle_y)})")
# Control FPS
elapsed = time.time() - start_time
if elapsed < 1.0/20:
time.sleep(1.0/20 - elapsed)
app = Flask(__name__)
HTML = '''<html>
<head>
<style>
body { background:#0f172a; color:white; text-align:center; padding:20px; }
#streamImg { border:3px solid #60a5fa; width:400px; height:300px; }
</style>
</head>
<body>
<h1>🌀 Moving Circle</h1>
<img id="streamImg" src="">
<p>Frame: <span id="count">0</span></p>
<script>
function updateStream() {
const img = document.getElementById('streamImg');
fetch('/current_frame')
.then(r => r.json())
.then(data => {
if (data.filename) {
const freshUrl = `/${data.filename}?t=${Date.now()}`;
img.src = freshUrl;
document.getElementById('count').textContent = data.frame_count;
}
});
}
// Poll every 50ms (20 FPS)
setInterval(updateStream, 50);
updateStream();
</script>
</body>
</html>'''
@app.route('/')
def index():
return render_template_string(HTML)
@app.route('/current_frame')
def current_frame():
return {
'frame_count': shared['frame_count'],
'filename': shared.get('last_filename')
}
@app.route('/<filename>')
def serve_frame(filename):
if os.path.exists(filename):
with open(filename, 'rb') as f:
frame_bytes = f.read()
return Response(
frame_bytes,
mimetype='image/jpeg',
headers={
'Cache-Control': 'no-cache, no-store, must-revalidate',
'Pragma': 'no-cache',
'Expires': '0'
}
)
# No fallback - just 404
return Response(status=404)
if __name__ == "__main__":
# Start animation thread
thread = threading.Thread(target=moving_circle_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
)