From fb7622549c40226a47d2374d26b4e5495ac51c16 Mon Sep 17 00:00:00 2001 From: Carsten Kvist Date: Sun, 19 Apr 2026 17:19:59 +0200 Subject: [PATCH] rettelser --- linedance-api/app/routers/sync.py | 6 +-- linedance-app/local/local_db.py | 28 ++++++++++++-- linedance-app/local/sync_manager.py | 55 +++++++++++++++++++--------- linedance-app/ui/main_window.py | 1 + linedance-app/ui/playlist_browser.py | 8 ++-- linedance-app/ui/playlist_manager.py | 9 +---- linedance-app/ui/playlist_panel.py | 7 ++++ 7 files changed, 81 insertions(+), 33 deletions(-) diff --git a/linedance-api/app/routers/sync.py b/linedance-api/app/routers/sync.py index c91c389e..618c911c 100644 --- a/linedance-api/app/routers/sync.py +++ b/linedance-api/app/routers/sync.py @@ -252,9 +252,9 @@ def push( return { "status": "ok", "songs_synced": len(song_id_map), - "playlists_synced": len(playlist_id_map), - "song_id_map": song_id_map, - "playlist_id_map": playlist_id_map, + "playlists_synced": len(playlist_id_map) + #"song_id_map": song_id_map, + #"playlist_id_map": playlist_id_map, } diff --git a/linedance-app/local/local_db.py b/linedance-app/local/local_db.py index 20f1e05d..1a201690 100644 --- a/linedance-app/local/local_db.py +++ b/linedance-app/local/local_db.py @@ -304,11 +304,15 @@ MIGRATIONS: dict[int, list[str]] = { 12: [ # Tabel til at huske slettede playlister — til sync med serveren """CREATE TABLE IF NOT EXISTS deleted_playlists ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name TEXT NOT NULL, - deleted_at TEXT NOT NULL DEFAULT (datetime('now')) + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + deleted_at TEXT NOT NULL DEFAULT (datetime('now')) )""", ], + 13: [ + # Tilføj api_project_id så serveren præcist ved hvilken playlist der skal slettes + """ALTER TABLE deleted_playlists ADD COLUMN api_project_id TEXT""", + ], } @@ -546,6 +550,24 @@ def create_playlist(name: str, description: str = "", tags: str = "") -> int: return cur.lastrowid +def delete_playlist(playlist_id: int): + """ + Slet en playliste lokalt og registrér sletningen til næste sync. + Gemmer api_project_id så serveren præcist ved hvad der skal slettes. + """ + with get_db() as conn: + row = conn.execute( + "SELECT name, api_project_id FROM playlists WHERE id=?", + (playlist_id,) + ).fetchone() + if row: + conn.execute( + "INSERT INTO deleted_playlists (name, api_project_id) VALUES (?,?)", + (row["name"], row["api_project_id"] or None) + ) + conn.execute("DELETE FROM playlists WHERE id=?", (playlist_id,)) + + def create_linked_playlist(name: str, api_project_id: str, permission: str = "view", description: str = "", tags: str = "") -> int: diff --git a/linedance-app/local/sync_manager.py b/linedance-app/local/sync_manager.py index a45044e1..22f2ef50 100644 --- a/linedance-app/local/sync_manager.py +++ b/linedance-app/local/sync_manager.py @@ -110,19 +110,29 @@ class SyncManager: try: # 1. Push lokal data op — inkl. sletninger payload = self._build_push_payload() + deleted = payload.get("deleted_playlists", []) + logger.info(f"Sync push — {len(payload['songs'])} sange, " + f"{len(payload['playlists'])} playlister, " + f"sletter {len(deleted)}: {deleted}") push_result = self._post("/sync/push", payload) self._save_playlist_ids(push_result.get("playlist_id_map", {})) + logger.info(f"Push svar: {push_result}") - # Ryd deleted_playlists nu de er sendt - if payload.get("deleted_playlists"): + # 2. Pull — sletninger er nu gennemført på serveren. + # VIGTIGT: ryd deleted_playlists EFTER pull, så _apply_pull + # stadig kan filtrere de slettede lister fra. + pull_result = self._get("/sync/pull") + pl_names = [p.get("name") for p in pull_result.get("my_playlists", [])] + logger.info(f"Pull modtog {len(pl_names)} playlister: {pl_names}") + self._apply_pull(pull_result) + + # Ryd deleted_playlists nu pull er kørt og filtreringen er sket + if deleted: conn = sqlite3.connect(self._db_path) conn.execute("DELETE FROM deleted_playlists") conn.commit() conn.close() - - # 2. Pull — nu er sletninger gennemført på serveren - pull_result = self._get("/sync/pull") - self._apply_pull(pull_result) + logger.info(f"deleted_playlists ryddet efter pull") pl_count = len(pull_result.get("my_playlists", [])) logger.info( @@ -240,11 +250,15 @@ class SyncManager: "songs": pl_songs, }) - # Slettede playlister — skal fjernes fra serveren + # Slettede playlister — skal fjernes fra serveren. + # Serveren forventer en liste af strings (api_project_id). + # Playlister uden api_project_id har aldrig nået serveren — ignorer dem. deleted = [ - row["name"] for row in conn.execute( - "SELECT name FROM deleted_playlists" + row["api_project_id"] + for row in conn.execute( + "SELECT api_project_id FROM deleted_playlists" ).fetchall() + if row["api_project_id"] ] conn.close() @@ -282,14 +296,18 @@ class SyncManager: d.get("stepsheet_url",""), existing["id"])) # Importer/opdater egne playlister fra server — server er sandhed - # Hent navne på lokalt slettede playlister så vi ikke genskaber dem + # Hent både navne og server-IDs på lokalt slettede playlister try: - deleted_names = set( - row["name"] for row in conn.execute( - "SELECT name FROM deleted_playlists" - ).fetchall() - ) + deleted_rows = conn.execute( + "SELECT name, api_project_id FROM deleted_playlists" + ).fetchall() + deleted_server_ids = { + row["api_project_id"] for row in deleted_rows + if row["api_project_id"] + } + deleted_names = {row["name"] for row in deleted_rows} except Exception: + deleted_server_ids = set() deleted_names = set() for pl in data.get("my_playlists", []): @@ -299,7 +317,10 @@ class SyncManager: continue # Spring over hvis listen er markeret som slettet lokalt - if name in deleted_names: + # Tjek på server-ID (præcist) og navn (fallback) + if server_id in deleted_server_ids: + continue + if name in deleted_names and not server_id: continue existing = conn.execute( @@ -408,4 +429,4 @@ class SyncManager: position += 1 conn.commit() - conn.close() + conn.close() \ No newline at end of file diff --git a/linedance-app/ui/main_window.py b/linedance-app/ui/main_window.py index 0ba5b15d..78e8d0bf 100644 --- a/linedance-app/ui/main_window.py +++ b/linedance-app/ui/main_window.py @@ -365,6 +365,7 @@ class MainWindow(QMainWindow): self._playlist_panel.event_started.connect(self._on_event_started) self._playlist_panel.next_song_ready.connect(self._on_next_song_ready) self._playlist_panel.playlist_changed.connect(self._on_playlist_changed) + self._playlist_panel.sync_requested.connect(self._manual_sync) # Debounce-timer til auto-sync — starter sync 5 sek efter sidst ændring self._sync_debounce = QTimer(self) diff --git a/linedance-app/ui/playlist_browser.py b/linedance-app/ui/playlist_browser.py index e5c26c96..e5360a68 100644 --- a/linedance-app/ui/playlist_browser.py +++ b/linedance-app/ui/playlist_browser.py @@ -20,6 +20,7 @@ class PlaylistBrowserDialog(QDialog): """Kombineret gem/hent dialog til danselister.""" playlist_selected = pyqtSignal(int, str) # playlist_id, name + sync_requested = pyqtSignal() # bed main_window om at køre sync def __init__(self, mode: str = "load", current_songs: list = None, current_name: str = "", parent=None): @@ -344,10 +345,11 @@ class PlaylistBrowserDialog(QDialog): ) if reply == QMessageBox.StandardButton.Yes: try: - from local.local_db import get_db - with get_db() as conn: - conn.execute("DELETE FROM playlists WHERE id=?", (pl["id"],)) + from local.local_db import delete_playlist + delete_playlist(pl["id"]) self._load_data() + # Signal til main_window om at køre sync + self.sync_requested.emit() except Exception as e: QMessageBox.warning(self, "Fejl", f"Kunne ikke slette: {e}") diff --git a/linedance-app/ui/playlist_manager.py b/linedance-app/ui/playlist_manager.py index 678d665e..839492a3 100644 --- a/linedance-app/ui/playlist_manager.py +++ b/linedance-app/ui/playlist_manager.py @@ -178,13 +178,8 @@ class PlaylistManagerDialog(QDialog): ) if reply == QMessageBox.StandardButton.Yes: try: - from local.local_db import get_db - with get_db() as conn: - conn.execute( - "INSERT INTO deleted_playlists (name) " - "SELECT name FROM playlists WHERE id=?", (pl["id"],) - ) - conn.execute("DELETE FROM playlists WHERE id=?", (pl["id"],)) + from local.local_db import delete_playlist + delete_playlist(pl["id"]) self._load_saved_playlists() except Exception as e: self._load_status.setText(f"Fejl: {e}") diff --git a/linedance-app/ui/playlist_panel.py b/linedance-app/ui/playlist_panel.py index 8e750fcb..d66ee67e 100644 --- a/linedance-app/ui/playlist_panel.py +++ b/linedance-app/ui/playlist_panel.py @@ -39,6 +39,7 @@ class PlaylistPanel(QWidget): playlist_changed = pyqtSignal() event_started = pyqtSignal() next_song_ready = pyqtSignal(dict) # udsendes når næste sang ændres — main_window indlæser den # udsendes af Start event — main_window indlæser første sang # udsendes ved enhver ændring → trigger autogem + sync_requested = pyqtSignal() # bed main_window om at køre sync (efter sletning) STATUS_ICON = {"pending": " ", "playing": " ▶ ", "played": " ✓ ", "skipped": " — ", "next": " ▷ "} STATUS_COLOR = {"pending": "#5a6070", "playing": "#e8a020", "played": "#2ecc71", "skipped": "#e74c3c", "next": "#3b8fd4"} @@ -526,6 +527,7 @@ class PlaylistPanel(QWidget): self._btn_save_current.setToolTip(f"Gem ændringer til '{name}'") self._save_named_playlist_id(pl_id) dialog.playlist_selected.connect(on_saved) + dialog.sync_requested.connect(self._request_sync) dialog.exec() def _save_current(self): @@ -572,10 +574,15 @@ class PlaylistPanel(QWidget): except Exception as e: QMessageBox.warning(self, "Fejl", f"Kunne ikke gemme: {e}") + def _request_sync(self): + """Bobl sync-anmodning op til main_window.""" + self.sync_requested.emit() + def _load_dialog(self): from ui.playlist_browser import PlaylistBrowserDialog dialog = PlaylistBrowserDialog(mode="load", parent=self.window()) dialog.playlist_selected.connect(self._load_playlist_by_id) + dialog.sync_requested.connect(self._request_sync) dialog.exec() def _load_playlist_by_id(self, pl_id: int, pl_name: str):