Version 2.0.0

This commit is contained in:
Erik Thiele
2026-04-22 20:26:00 +02:00
parent 6faf207246
commit 5ac9dee8fc
10 changed files with 398 additions and 119 deletions

186
app.py Normal file → Executable file
View File

@@ -23,11 +23,11 @@ BASE_DIR = os.path.dirname(os.path.abspath(__file__))
MEDIA_DIR = os.path.join(BASE_DIR, "media")
CONFIG_FILE = os.path.join(BASE_DIR, "config.json")
APP_VERSION = "2.0.0"
APP_VERSION = "2.1.0"
UPLOAD_EXTENSIONS = {".jpg", ".jpeg", ".png", ".mp4"}
app = Flask(__name__)
app.secret_key = "CHANGE_THIS_SECRET"
app.secret_key = "CHANGE_THIS_SECRET!!!"
login_manager = LoginManager(app)
login_manager.login_view = "login"
@@ -91,6 +91,7 @@ def media(screen, filename):
# -------------------------------------------------
# Player
# -------------------------------------------------
@app.route("/player/<screen>")
def player(screen):
config = load_config()
@@ -116,81 +117,109 @@ def player(screen):
return show_videos
return False
ordered = []
# ------------------------------
# Normale Screen-Playlist
# ------------------------------
normal_files = []
# 1. Playlist-Reihenfolge
for name in playlist:
if os.path.exists(os.path.join(folder, name)) and allowed_file(name):
ordered.append(name)
normal_files.append(name)
# 2. Neue Dateien hintendran
for f in sorted(os.listdir(folder)):
if f not in ordered and allowed_file(f):
ordered.append(f)
if f not in normal_files and allowed_file(f):
normal_files.append(f)
# ------------------------------
# Priority-Playlist (global)
# WICHTIG: IMMER definieren!
# ------------------------------
priority_cfg = config.get("priority", {})
if priority_cfg.get("enabled", False):
prio_files = priority_cfg.get("playlist", [])
else:
prio_files = []
return render_template(
"player.html",
screen=screen,
files=ordered,
normal_files=normal_files, # ✅ explizit
prio_files=prio_files, # ✅ IMMER Liste
interval=screen_cfg.get("interval", 10)
)
# -------------------------------------------------
# Hash für automatisches Player-Reload
# -------------------------------------------------
@app.route("/playlist/<screen>/hash")
def playlist_hash(screen):
screen_dir = os.path.join(MEDIA_DIR, screen)
if not os.path.isdir(screen_dir):
return ""
config = load_config()
entries = []
for f in os.listdir(screen_dir):
if f.startswith("._"):
continue
p = os.path.join(screen_dir, f)
try:
entries.append(f"{f}:{int(os.path.getmtime(p))}")
except OSError:
pass
# ✅ Globaler Hash über ALLE relevanten Daten
relevant = {
"screens": {
screen: config["screens"].get(screen, {})
},
"priority": config.get("priority", {})
}
blob = json.dumps(relevant, sort_keys=True).encode()
return hashlib.md5(blob).hexdigest()
h = hashlib.md5("|".join(sorted(entries)).encode()).hexdigest()
return h
# -------------------------------------------------
# Admin Dashboard
# -------------------------------------------------
@app.route("/admin")
@login_required
def admin():
config = load_config()
screens_cfg = config.setdefault("screens", {})
cfg = load_config()
screens = {}
media_files = {}
screen_status = {}
for screen in sorted(os.listdir(MEDIA_DIR)):
screen_dir = os.path.join(MEDIA_DIR, screen)
if not os.path.isdir(screen_dir):
for screen in os.listdir(MEDIA_DIR):
if screen == "priority":
continue # ✅ kein echter Screen
path = os.path.join(MEDIA_DIR, screen)
if not os.path.isdir(path):
continue
screens_cfg.setdefault(screen, {
"interval": 10,
"show_images": True,
"show_videos": True,
"playlist": []
})
screens[screen] = screens_cfg[screen]
files = []
for f in sorted(os.listdir(screen_dir)):
if f.startswith("._"):
playlist = cfg["screens"][screen].get("playlist", [])
# 1⃣ Playlist-Reihenfolge
for name in playlist:
file_path = os.path.join(path, name)
if not os.path.exists(file_path):
continue
ext = os.path.splitext(name)[1].lower()
ftype = "video" if ext == ".mp4" else "image"
size = os.path.getsize(file_path) // 1024
files.append({
"name": name,
"type": ftype,
"size": size
})
# 2⃣ Neue Dateien anhängen (nicht in Playlist)
for f in sorted(os.listdir(path)):
if f in playlist or f.startswith("._"):
continue
file_path = os.path.join(path, f)
ext = os.path.splitext(f)[1].lower()
ftype = "video" if ext == ".mp4" else "image"
size = os.path.getsize(os.path.join(screen_dir, f)) // 1024
size = os.path.getsize(file_path) // 1024
files.append({
"name": f,
@@ -198,21 +227,63 @@ def admin():
"size": size
})
screens[screen] = cfg["screens"][screen]
media_files[screen] = files
screen_status[screen] = "active" if files else "empty"
save_config(config)
# --- PRIORITY EXTENSION: Admin ---
prio_dir = os.path.join(MEDIA_DIR, "priority")
os.makedirs(prio_dir, exist_ok=True)
priority_files = []
prio_playlist = cfg["priority"].get("playlist", [])
# 1⃣ Playlist-Reihenfolge
for name in prio_playlist:
file_path = os.path.join(MEDIA_DIR, "priority")
if not os.path.exists(file_path):
continue
ext = os.path.splitext(name)[1].lower()
ftype = "video" if ext == ".mp4" else "image"
size = os.path.getsize(file_path) // 1024
priority_files.append({
"name": name,
"type": ftype,
"size": size
})
# 2⃣ Neue Dateien anhängen (nicht in Playlist)
for f in sorted(os.listdir(prio_dir)):
if f in prio_playlist or f.startswith("._"):
continue
file_path = os.path.join(prio_dir, f)
ext = os.path.splitext(f)[1].lower()
ftype = "video" if ext == ".mp4" else "image"
size = os.path.getsize(file_path) // 1024
priority_files.append({
"name": f,
"type": ftype,
"size": size
})
return render_template(
"admin.html",
screens=screens,
media_files=media_files,
screen_status=screen_status,
hostname=socket.gethostname(),
version=APP_VERSION,
year=datetime.now().year
year=datetime.now().year,
hostname=os.uname().nodename,
priority_files=priority_files
)
# -------------------------------------------------
# Admin: Screen-Einstellungen speichern
# -------------------------------------------------
@@ -251,29 +322,50 @@ def upload(screen):
# -------------------------------------------------
# Admin: Datei löschen
# -------------------------------------------------
@app.route("/admin/delete/<screen>/<filename>", methods=["POST"])
@login_required
def delete_file(screen, filename):
cfg = load_config()
# Datei löschen
path = os.path.join(MEDIA_DIR, screen, filename)
if os.path.exists(path):
os.remove(path)
# --- Playlist bereinigen ---
if screen == "priority":
playlist = cfg.get("priority", {}).get("playlist", [])
if filename in playlist:
playlist.remove(filename)
else:
playlist = cfg["screens"].get(screen, {}).get("playlist", [])
if filename in playlist:
playlist.remove(filename)
save_config(cfg)
return redirect("/admin")
# -------------------------------------------------
# Admin: Playlist speichern
# -------------------------------------------------
@app.route("/admin/playlist/<screen>", methods=["POST"])
@login_required
def update_playlist(screen):
config = load_config()
cfg = config["screens"][screen]
def save_playlist(screen):
cfg = load_config()
data = request.get_json()
cfg["playlist"] = data.get("playlist", [])
save_config(config)
if screen == "priority":
cfg["priority"]["playlist"] = data["playlist"]
else:
cfg["screens"][screen]["playlist"] = data["playlist"]
save_config(cfg)
return "", 204
# -------------------------------------------------
# Main
# -------------------------------------------------