Rettelser og reset
This commit is contained in:
51
full_reset.sh
Normal file
51
full_reset.sh
Normal file
@@ -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 ""
|
||||||
@@ -646,10 +646,11 @@ def get_playlist_with_songs(playlist_id: int) -> dict:
|
|||||||
|
|
||||||
songs = conn.execute("""
|
songs = conn.execute("""
|
||||||
SELECT ps.id as ps_id, ps.position, ps.status,
|
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
|
FROM playlist_songs ps
|
||||||
JOIN songs s ON s.id = ps.song_id
|
JOIN songs s ON s.id = ps.song_id
|
||||||
LEFT JOIN song_dances sd ON sd.song_id = s.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 = ?
|
WHERE ps.playlist_id = ?
|
||||||
GROUP BY ps.id
|
GROUP BY ps.id
|
||||||
ORDER BY ps.position
|
ORDER BY ps.position
|
||||||
|
|||||||
@@ -54,10 +54,10 @@ class SyncManager:
|
|||||||
def _run():
|
def _run():
|
||||||
try:
|
try:
|
||||||
payload = self._build_push_payload()
|
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)
|
result = self._post("/sync/push", payload)
|
||||||
self._save_playlist_ids(result.get("playlist_id_map", {}))
|
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:
|
if on_done:
|
||||||
on_done(result)
|
on_done(result)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -88,9 +88,7 @@ class SyncManager:
|
|||||||
try:
|
try:
|
||||||
result = self._get("/sync/pull")
|
result = self._get("/sync/pull")
|
||||||
pl_count = len(result.get("my_playlists", []))
|
pl_count = len(result.get("my_playlists", []))
|
||||||
logger.info(f"Pull: {len(result.get('dances', []))} danse, {pl_count} playlister")
|
logger.info(f"Pull OK: {pl_count} playlister")
|
||||||
for pl in result.get("my_playlists", []):
|
|
||||||
logger.info(f" Playliste fra server: '{pl['name']}' ({len(pl.get('songs',[]))} sange)")
|
|
||||||
self._apply_pull(result)
|
self._apply_pull(result)
|
||||||
if on_done:
|
if on_done:
|
||||||
on_done(result)
|
on_done(result)
|
||||||
@@ -104,16 +102,15 @@ class SyncManager:
|
|||||||
"""Push og derefter pull i samme tråd."""
|
"""Push og derefter pull i samme tråd."""
|
||||||
def _run():
|
def _run():
|
||||||
try:
|
try:
|
||||||
logger.info("push_and_pull: bygger payload...")
|
|
||||||
payload = self._build_push_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)
|
push_result = self._post("/sync/push", payload)
|
||||||
logger.info(f"push_and_pull: push OK — {push_result}")
|
|
||||||
pull_result = self._get("/sync/pull")
|
pull_result = self._get("/sync/pull")
|
||||||
pl_count = len(pull_result.get("my_playlists", []))
|
pl_count = len(pull_result.get("my_playlists", []))
|
||||||
logger.info(f"push_and_pull: pull OK — {pl_count} playlister")
|
logger.info(
|
||||||
for pl in pull_result.get("my_playlists", []):
|
f"Sync OK — {len(payload['songs'])} sange, "
|
||||||
logger.info(f" Playliste: '{pl['name']}' ({len(pl.get('songs',[]))} sange)")
|
f"{len(payload['playlists'])} playlister, "
|
||||||
|
f"{pl_count} server-playlister"
|
||||||
|
)
|
||||||
self._apply_pull(pull_result)
|
self._apply_pull(pull_result)
|
||||||
if on_done:
|
if on_done:
|
||||||
on_done({"push": push_result, "pull": pull_result})
|
on_done({"push": push_result, "pull": pull_result})
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ Start:
|
|||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
|
||||||
APP_VERSION = "0.8.2"
|
APP_VERSION = "0.8.3"
|
||||||
|
|
||||||
sys.path.insert(0, os.path.dirname(__file__))
|
sys.path.insert(0, os.path.dirname(__file__))
|
||||||
|
|
||||||
|
|||||||
@@ -312,9 +312,14 @@ class LibraryPanel(QWidget):
|
|||||||
missing = song.get("file_missing", False)
|
missing = song.get("file_missing", False)
|
||||||
|
|
||||||
dance_parts = []
|
dance_parts = []
|
||||||
|
choreos = song.get("dance_choreographers", [])
|
||||||
for i, d in enumerate(dances):
|
for i, d in enumerate(dances):
|
||||||
lvl = dance_levels[i] if i < len(dance_levels) else ""
|
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 ""
|
dance_str = " · " + " | ".join(dance_parts) if dance_parts else ""
|
||||||
|
|
||||||
prefix = "⚠ " if missing else ""
|
prefix = "⚠ " if missing else ""
|
||||||
|
|||||||
@@ -144,7 +144,9 @@ class PlaylistManagerDialog(QDialog):
|
|||||||
for row in data.get("songs", []):
|
for row in data.get("songs", []):
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
dances = conn.execute(
|
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"],)
|
(row["id"],)
|
||||||
).fetchall()
|
).fetchall()
|
||||||
songs.append({
|
songs.append({
|
||||||
@@ -157,7 +159,7 @@ class PlaylistManagerDialog(QDialog):
|
|||||||
"local_path": row.get("local_path", ""),
|
"local_path": row.get("local_path", ""),
|
||||||
"file_format": row.get("file_format", ""),
|
"file_format": row.get("file_format", ""),
|
||||||
"file_missing": bool(row.get("file_missing", False)),
|
"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.playlist_loaded.emit(pl["name"], songs)
|
||||||
self._load_status.setText(f"✓ Indlæst: {pl['name']} ({len(songs)} sange)")
|
self._load_status.setText(f"✓ Indlæst: {pl['name']} ({len(songs)} sange)")
|
||||||
@@ -277,7 +279,9 @@ class PlaylistManagerDialog(QDialog):
|
|||||||
# Hent danse
|
# Hent danse
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
dances = conn.execute(
|
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"],)
|
(row["id"],)
|
||||||
).fetchall()
|
).fetchall()
|
||||||
found.append({
|
found.append({
|
||||||
@@ -290,7 +294,7 @@ class PlaylistManagerDialog(QDialog):
|
|||||||
"local_path": row["local_path"],
|
"local_path": row["local_path"],
|
||||||
"file_format": row["file_format"],
|
"file_format": row["file_format"],
|
||||||
"file_missing": bool(row["file_missing"]),
|
"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):
|
elif os.path.exists(p) and is_supported(p):
|
||||||
# Filen er ikke scannet endnu — høst tags og tilføj
|
# Filen er ikke scannet endnu — høst tags og tilføj
|
||||||
|
|||||||
@@ -120,6 +120,27 @@ class TagEditorDialog(QDialog):
|
|||||||
grp = QGroupBox(_("tags.dances"))
|
grp = QGroupBox(_("tags.dances"))
|
||||||
layout = QVBoxLayout(grp)
|
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
|
# Eksisterende danse
|
||||||
scroll = QScrollArea()
|
scroll = QScrollArea()
|
||||||
scroll.setWidgetResizable(True)
|
scroll.setWidgetResizable(True)
|
||||||
@@ -175,6 +196,8 @@ class TagEditorDialog(QDialog):
|
|||||||
|
|
||||||
edit = DanceLineEdit("Dans...", self)
|
edit = DanceLineEdit("Dans...", self)
|
||||||
edit.setText(name)
|
edit.setText(name)
|
||||||
|
edit.setToolTip(name)
|
||||||
|
edit.textChanged.connect(lambda txt, e=edit: e.setToolTip(txt))
|
||||||
row_layout.addWidget(edit, stretch=2)
|
row_layout.addWidget(edit, stretch=2)
|
||||||
|
|
||||||
# Niveau-dropdown
|
# Niveau-dropdown
|
||||||
@@ -195,8 +218,12 @@ class TagEditorDialog(QDialog):
|
|||||||
choreo_edit.setText(choreographer)
|
choreo_edit.setText(choreographer)
|
||||||
choreo_edit.setPlaceholderText("Koreograf...")
|
choreo_edit.setPlaceholderText("Koreograf...")
|
||||||
choreo_edit.setFixedWidth(140)
|
choreo_edit.setFixedWidth(140)
|
||||||
|
choreo_edit.setToolTip(choreographer)
|
||||||
choreo_edit.textChanged.connect(
|
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)
|
row_layout.addWidget(choreo_edit)
|
||||||
|
|
||||||
|
|||||||
44
reset_local.sh
Normal file
44
reset_local.sh
Normal file
@@ -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 ""
|
||||||
Reference in New Issue
Block a user