diff --git a/camera/main.py b/camera/main.py index 80f7090..446fc33 100644 --- a/camera/main.py +++ b/camera/main.py @@ -9,7 +9,7 @@ import os import threading import time from datetime import datetime -from flask import Flask, Response, jsonify, render_template_string +from flask import Flask, Response, jsonify, render_template, send_from_directory from picamera2 import Picamera2 from picamera2.encoders import JpegEncoder @@ -70,106 +70,6 @@ def generate_frames(): ) -# ─── Interface HTML ─────────────────────────────────────────────────────────── - -HTML_PAGE = """ - - - - - - Pi Camera Stream - - - -
-

Raspberry Pi Camera

-

HQ Camera M12 — Live Stream

-
- -
- Camera stream -
- - - - -""" - # ─── Application Flask ──────────────────────────────────────────────────────── app = Flask(__name__) @@ -177,8 +77,8 @@ app = Flask(__name__) @app.route("/") def index(): - return render_template_string( - HTML_PAGE, + return render_template( + "index.html", width=RESOLUTION[0], height=RESOLUTION[1], quality=QUALITY @@ -200,6 +100,20 @@ def capture(): return jsonify({"status": "ok", "file": filename}) +@app.route("/photos") +def photos(): + files = sorted( + [f for f in os.listdir(PHOTOS_DIR) if f.endswith(".jpg")], + reverse=True + )[:5] + return jsonify(files) + + +@app.route("/photo/") +def photo(filename): + return send_from_directory(PHOTOS_DIR, filename) + + @app.route("/video_feed") def video_feed(): """Endpoint du flux MJPEG.""" diff --git a/camera/static/script.js b/camera/static/script.js new file mode 100644 index 0000000..f67ebc8 --- /dev/null +++ b/camera/static/script.js @@ -0,0 +1,20 @@ +async function refreshGallery() { + const res = await fetch("/photos"); + const files = await res.json(); + const gallery = document.getElementById("gallery"); + + if (files.length === 0) return; + + gallery.innerHTML = files + .map((f) => `${f}`) + .join(""); +} + +document.addEventListener("keydown", async (e) => { + if (e.key !== "c" && e.key !== "C") return; + await fetch("/capture"); + refreshGallery(); +}); + +refreshGallery(); +setInterval(refreshGallery, 10000); diff --git a/camera/static/style.css b/camera/static/style.css new file mode 100644 index 0000000..48cd08b --- /dev/null +++ b/camera/static/style.css @@ -0,0 +1,103 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + background: #0a0a0a; + color: #e0e0e0; + font-family: "Courier New", monospace; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 20px; +} + +header { + text-align: center; +} + +h1 { + font-size: 1.2rem; + letter-spacing: 0.3em; + text-transform: uppercase; + color: #00ff88; +} + +.subtitle { + font-size: 0.75rem; + color: #555; + letter-spacing: 0.15em; + margin-top: 4px; +} + +.stream-container { + position: relative; + border: 1px solid #1a1a1a; + box-shadow: 0 0 40px rgba(0, 255, 136, 0.05); +} + +.stream-container::before { + content: "● REC"; + position: absolute; + top: 12px; + left: 12px; + font-size: 0.65rem; + color: #ff4444; + letter-spacing: 0.1em; + z-index: 10; + animation: blink 1.5s infinite; +} + +@keyframes blink { + 0%, + 100% { + opacity: 1; + } + 50% { + opacity: 0.2; + } +} + +img#stream { + display: block; + max-width: 75vh; + max-height: 90vw; +} + +.gallery { + display: flex; + gap: 8px; +} + +.gallery-empty { + font-size: 0.7rem; + color: #333; + letter-spacing: 0.1em; +} + +.gallery img { + width: 120px; + height: 80px; + object-fit: cover; + border: 1px solid #1a1a1a; + opacity: 0.75; + transition: opacity 0.2s; +} + +.gallery img:hover { + opacity: 1; +} + +footer { + font-size: 0.7rem; + color: #333; + letter-spacing: 0.1em; +} + +footer span { + color: #00ff88; +} diff --git a/camera/templates/index.html b/camera/templates/index.html new file mode 100644 index 0000000..c0205c1 --- /dev/null +++ b/camera/templates/index.html @@ -0,0 +1,31 @@ + + + + + + Pi Camera Stream + + + +
+

Raspberry Pi Camera

+

HQ Camera M12 — Live Stream

+
+ +
+ Camera stream +
+ + + + + + + + +