From 80407e98fb12260bead5128f94347c2d2ec22eac Mon Sep 17 00:00:00 2001 From: Carsten Kvist Date: Sun, 19 Apr 2026 11:28:28 +0200 Subject: [PATCH] Rettelser og reset --- full_reset.sh | 51 ++++++++++++++++++++++++++++ linedance-app/local/local_db.py | 3 +- linedance-app/local/sync_manager.py | 19 +++++------ linedance-app/main.py | 2 +- linedance-app/ui/library_panel.py | 7 +++- linedance-app/ui/playlist_manager.py | 12 ++++--- linedance-app/ui/tag_editor.py | 29 +++++++++++++++- reset_local.sh | 44 ++++++++++++++++++++++++ 8 files changed, 148 insertions(+), 19 deletions(-) create mode 100644 full_reset.sh create mode 100644 reset_local.sh diff --git a/full_reset.sh b/full_reset.sh new file mode 100644 index 00000000..74064deb --- /dev/null +++ b/full_reset.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# ================================================================ +# full_reset.sh — KOMPLET nulstilling af LineDance-systemet +# +# Kør dette script på APP-SERVEREN: +# bash full_reset.sh +# +# Herefter skal du selv: +# docker compose down && docker compose up -d --build +# ================================================================ +set -e + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +echo "" +echo -e "${RED}╔══════════════════════════════════════════════════════╗${NC}" +echo -e "${RED}║ KOMPLET NULSTILLING — LINEDANCE AFSPILLER ║${NC}" +echo -e "${RED}║ Sletter ALT: sange, danse, playlister, synk-data ║${NC}" +echo -e "${RED}╚══════════════════════════════════════════════════════╝${NC}" +echo "" +echo -e "${YELLOW}Dette kan IKKE fortrydes. Al data går tabt.${NC}" +echo "" +read -p "Skriv 'SLET ALT' for at fortsætte: " confirm +[ "$confirm" = "SLET ALT" ] || { echo "Afbrudt."; exit 1; } + +COMPOSE_DIR="/opt/docker/linedanceafspiller/linedance-api" + +# ── MySQL: drop og genskab tom database ─────────────────────── +echo "" +echo -e "${YELLOW}▶ Dropper og genskaber MySQL-database...${NC}" +docker compose -f "$COMPOSE_DIR/docker-compose.yml" exec -T db \ + mysql -u root -proot << 'MYSQL' +DROP DATABASE IF EXISTS linedance; +CREATE DATABASE linedance CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; +MYSQL +echo -e "${GREEN} ✓ MySQL klar — tom database oprettet${NC}" + +# ── Færdig ──────────────────────────────────────────────────── +echo "" +echo -e "${GREEN}╔══════════════════════════════════════════════════════╗${NC}" +echo -e "${GREEN}║ ✓ Server-database nulstillet ║${NC}" +echo -e "${GREEN}╚══════════════════════════════════════════════════════╝${NC}" +echo "" +echo "Gør nu dette:" +echo " 1. Rebuild og genstart Docker:" +echo " cd $COMPOSE_DIR" +echo " docker compose down && docker compose up -d --build" +echo "" diff --git a/linedance-app/local/local_db.py b/linedance-app/local/local_db.py index f99d7657..84edaf64 100644 --- a/linedance-app/local/local_db.py +++ b/linedance-app/local/local_db.py @@ -646,10 +646,11 @@ def get_playlist_with_songs(playlist_id: int) -> dict: songs = conn.execute(""" SELECT ps.id as ps_id, ps.position, ps.status, - s.*, GROUP_CONCAT(sd.dance_name ORDER BY sd.dance_order) as dances + s.*, GROUP_CONCAT(d.name ORDER BY sd.dance_order) as dances FROM playlist_songs ps JOIN songs s ON s.id = ps.song_id LEFT JOIN song_dances sd ON sd.song_id = s.id + LEFT JOIN dances d ON d.id = sd.dance_id WHERE ps.playlist_id = ? GROUP BY ps.id ORDER BY ps.position diff --git a/linedance-app/local/sync_manager.py b/linedance-app/local/sync_manager.py index a1fb7122..70da8ff6 100644 --- a/linedance-app/local/sync_manager.py +++ b/linedance-app/local/sync_manager.py @@ -54,10 +54,10 @@ class SyncManager: def _run(): try: payload = self._build_push_payload() - logger.info(f"Push: {len(payload['songs'])} sange, {len(payload['playlists'])} playlister") + logger.info(f"Push OK: {len(payload['songs'])} sange") result = self._post("/sync/push", payload) self._save_playlist_ids(result.get("playlist_id_map", {})) - logger.info(f"Push OK: {result}") + logger.info(f"Push OK: {result.get('songs_synced', '?')} sange synkroniseret") if on_done: on_done(result) except Exception as e: @@ -88,9 +88,7 @@ class SyncManager: try: result = self._get("/sync/pull") pl_count = len(result.get("my_playlists", [])) - logger.info(f"Pull: {len(result.get('dances', []))} danse, {pl_count} playlister") - for pl in result.get("my_playlists", []): - logger.info(f" Playliste fra server: '{pl['name']}' ({len(pl.get('songs',[]))} sange)") + logger.info(f"Pull OK: {pl_count} playlister") self._apply_pull(result) if on_done: on_done(result) @@ -104,16 +102,15 @@ class SyncManager: """Push og derefter pull i samme tråd.""" def _run(): try: - logger.info("push_and_pull: bygger payload...") payload = self._build_push_payload() - logger.info(f"push_and_pull: sender {len(payload['songs'])} sange, {len(payload['playlists'])} playlister") push_result = self._post("/sync/push", payload) - logger.info(f"push_and_pull: push OK — {push_result}") pull_result = self._get("/sync/pull") pl_count = len(pull_result.get("my_playlists", [])) - logger.info(f"push_and_pull: pull OK — {pl_count} playlister") - for pl in pull_result.get("my_playlists", []): - logger.info(f" Playliste: '{pl['name']}' ({len(pl.get('songs',[]))} sange)") + logger.info( + f"Sync OK — {len(payload['songs'])} sange, " + f"{len(payload['playlists'])} playlister, " + f"{pl_count} server-playlister" + ) self._apply_pull(pull_result) if on_done: on_done({"push": push_result, "pull": pull_result}) diff --git a/linedance-app/main.py b/linedance-app/main.py index 9b023f0b..8534ced1 100644 --- a/linedance-app/main.py +++ b/linedance-app/main.py @@ -8,7 +8,7 @@ Start: import sys import os -APP_VERSION = "0.8.2" +APP_VERSION = "0.8.3" sys.path.insert(0, os.path.dirname(__file__)) diff --git a/linedance-app/ui/library_panel.py b/linedance-app/ui/library_panel.py index 87d76877..548957c3 100644 --- a/linedance-app/ui/library_panel.py +++ b/linedance-app/ui/library_panel.py @@ -312,9 +312,14 @@ class LibraryPanel(QWidget): missing = song.get("file_missing", False) dance_parts = [] + choreos = song.get("dance_choreographers", []) for i, d in enumerate(dances): lvl = dance_levels[i] if i < len(dance_levels) else "" - dance_parts.append(f"{d} / {lvl}" if lvl else d) + choreo = choreos[i] if i < len(choreos) else "" + part = f"{d} / {lvl}" if lvl else d + if choreo: + part += f" · {choreo}" + dance_parts.append(part) dance_str = " · " + " | ".join(dance_parts) if dance_parts else "" prefix = "⚠ " if missing else "" diff --git a/linedance-app/ui/playlist_manager.py b/linedance-app/ui/playlist_manager.py index bfab4021..0f67f2a4 100644 --- a/linedance-app/ui/playlist_manager.py +++ b/linedance-app/ui/playlist_manager.py @@ -144,7 +144,9 @@ class PlaylistManagerDialog(QDialog): for row in data.get("songs", []): with get_db() as conn: dances = conn.execute( - "SELECT dance_name FROM song_dances WHERE song_id=? ORDER BY dance_order", + """SELECT d.name FROM song_dances sd + JOIN dances d ON d.id = sd.dance_id + WHERE sd.song_id=? ORDER BY sd.dance_order""", (row["id"],) ).fetchall() songs.append({ @@ -157,7 +159,7 @@ class PlaylistManagerDialog(QDialog): "local_path": row.get("local_path", ""), "file_format": row.get("file_format", ""), "file_missing": bool(row.get("file_missing", False)), - "dances": [d["dance_name"] for d in dances], + "dances": [d["name"] for d in dances], }) self.playlist_loaded.emit(pl["name"], songs) self._load_status.setText(f"✓ Indlæst: {pl['name']} ({len(songs)} sange)") @@ -277,7 +279,9 @@ class PlaylistManagerDialog(QDialog): # Hent danse with get_db() as conn: dances = conn.execute( - "SELECT dance_name FROM song_dances WHERE song_id=? ORDER BY dance_order", + """SELECT d.name FROM song_dances sd + JOIN dances d ON d.id = sd.dance_id + WHERE sd.song_id=? ORDER BY sd.dance_order""", (row["id"],) ).fetchall() found.append({ @@ -290,7 +294,7 @@ class PlaylistManagerDialog(QDialog): "local_path": row["local_path"], "file_format": row["file_format"], "file_missing": bool(row["file_missing"]), - "dances": [d["dance_name"] for d in dances], + "dances": [d["name"] for d in dances], }) elif os.path.exists(p) and is_supported(p): # Filen er ikke scannet endnu — høst tags og tilføj diff --git a/linedance-app/ui/tag_editor.py b/linedance-app/ui/tag_editor.py index a6604d70..cc78388a 100644 --- a/linedance-app/ui/tag_editor.py +++ b/linedance-app/ui/tag_editor.py @@ -120,6 +120,27 @@ class TagEditorDialog(QDialog): grp = QGroupBox(_("tags.dances")) layout = QVBoxLayout(grp) + # Kolonneoverskrifter + hdr = QWidget() + hdr_layout = QHBoxLayout(hdr) + hdr_layout.setContentsMargins(0, 0, 0, 0) + hdr_layout.setSpacing(4) + lbl_dans = QLabel("Dans") + lbl_dans.setObjectName("result_count") + lbl_niveau = QLabel("Niveau") + lbl_niveau.setObjectName("result_count") + lbl_niveau.setFixedWidth(130) + lbl_choreo = QLabel("Koreograf") + lbl_choreo.setObjectName("result_count") + lbl_choreo.setFixedWidth(140) + lbl_btn = QLabel("") # plads til knapper + lbl_btn.setFixedWidth(72) + hdr_layout.addWidget(lbl_dans, stretch=2) + hdr_layout.addWidget(lbl_niveau) + hdr_layout.addWidget(lbl_choreo) + hdr_layout.addWidget(lbl_btn) + layout.addWidget(hdr) + # Eksisterende danse scroll = QScrollArea() scroll.setWidgetResizable(True) @@ -175,6 +196,8 @@ class TagEditorDialog(QDialog): edit = DanceLineEdit("Dans...", self) edit.setText(name) + edit.setToolTip(name) + edit.textChanged.connect(lambda txt, e=edit: e.setToolTip(txt)) row_layout.addWidget(edit, stretch=2) # Niveau-dropdown @@ -195,8 +218,12 @@ class TagEditorDialog(QDialog): choreo_edit.setText(choreographer) choreo_edit.setPlaceholderText("Koreograf...") choreo_edit.setFixedWidth(140) + choreo_edit.setToolTip(choreographer) choreo_edit.textChanged.connect( - lambda txt, ce=choreo_edit: self._show_choreo_suggestions(txt, ce) + lambda txt, ce=choreo_edit: ( + ce.setToolTip(txt), + self._show_choreo_suggestions(txt, ce) + ) ) row_layout.addWidget(choreo_edit) diff --git a/reset_local.sh b/reset_local.sh new file mode 100644 index 00000000..226706a9 --- /dev/null +++ b/reset_local.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# ================================================================ +# reset_local.sh — Nulstil SQLite på desktop-maskinen +# Kør på den PC hvor LineDance-appen kører +# ================================================================ +set -e + +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +echo "" +echo -e "${YELLOW}▶ Finder SQLite-database...${NC}" + +SQLITE_DB="" +for candidate in \ + "$HOME/.local/share/LineDanceAfspiller/library.db" \ + "$HOME/.linedance/library.db" \ + "$HOME/AppData/Local/LineDanceAfspiller/library.db"; do + if [ -f "$candidate" ]; then + SQLITE_DB="$candidate" + break + fi +done + +if [ -z "$SQLITE_DB" ]; then + FOUND=$(find "$HOME" -name "library.db" 2>/dev/null | head -1) + [ -n "$FOUND" ] && SQLITE_DB="$FOUND" +fi + +if [ -n "$SQLITE_DB" ]; then + BACKUP="${SQLITE_DB}.backup_$(date +%Y%m%d_%H%M%S)" + cp "$SQLITE_DB" "$BACKUP" + rm "$SQLITE_DB" + echo -e "${GREEN} ✓ Slettet: $SQLITE_DB${NC}" + echo " Backup gemt: $BACKUP" +else + echo -e "${GREEN} ✓ Ingen SQLite-fil fundet — appen starter allerede frisk${NC}" +fi + +echo "" +echo -e "${GREEN}✓ Lokal database nulstillet${NC}" +echo "Start nu LineDance-appen — den genskaber databasen automatisk." +echo ""