From b635a79b63bb5966912df3abe9f41034854f43c5 Mon Sep 17 00:00:00 2001 From: kodi Date: Tue, 10 Mar 2026 11:01:56 +0100 Subject: [PATCH] fix (ui): select the same episode multiple times --- .gitignore | 1 + app/services/session_service.py | 20 ++++++++++++++++++++ data/session_state.sqlite3 | Bin 303104 -> 303104 bytes feature_tests_selected_episodes.sh | 18 ++++++++++++++++++ 4 files changed, 39 insertions(+) diff --git a/.gitignore b/.gitignore index bc353e8..06b3256 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ __pycache__/ .venv/ venv/ .DS_Store +.sqlite3 diff --git a/app/services/session_service.py b/app/services/session_service.py index 5b6d450..733eb23 100644 --- a/app/services/session_service.py +++ b/app/services/session_service.py @@ -341,6 +341,21 @@ class SessionService: return self.list_selected_episodes(session_id) with self._connect() as conn: + existing_rows = conn.execute( + """ + SELECT payload_json + FROM selected_episodes + WHERE session_id = ? + """, + (session_id,), + ).fetchall() + existing_episode_ids: set[str] = set() + for row in existing_rows: + payload = json.loads(row["payload_json"]) + episode_id = str(payload.get("id") or "").strip() + if episode_id: + existing_episode_ids.add(episode_id) + current_max = conn.execute( """ SELECT COALESCE(MAX(position), -1) AS max_position @@ -352,6 +367,9 @@ class SessionService: next_position = int(current_max["max_position"]) + 1 for item in items: + episode_id = str(item.get("id") or "").strip() + if episode_id and episode_id in existing_episode_ids: + continue conn.execute( """ INSERT INTO selected_episodes (session_id, position, payload_json) @@ -359,6 +377,8 @@ class SessionService: """, (session_id, next_position, json.dumps(item, ensure_ascii=True)), ) + if episode_id: + existing_episode_ids.add(episode_id) next_position += 1 return self.list_selected_episodes(session_id) diff --git a/data/session_state.sqlite3 b/data/session_state.sqlite3 index 3e6d2aa976f7bfcab1cae3dd4316ef2fb326ec6f..f083fe3202ca26ff8f03634bfcfe08580e602f76 100644 GIT binary patch delta 1755 zcmbVLOKclO7@pbLS?{LaU6Z7tc~suI5k#dM&+M+fUUNw#NFt;bM==7?LyEAWfuK^H zAP|b2jiIL^a5v3XYE213aH&)xgEnd_`jC3y!0Q4+R8Vm%6#;>Slp+ul2qB3a;&7P5 z%=i6|@0x$*UOxfuZP06T;oSnjf6^W4F=RgqV3u?JvO!;$Y)k-CUoTE?rt zM&DIo#d{UWoLH_y&Ft7x8{?fMmi#1RJ=8U&LV?uI`HLa)tb8{_(MVPR~C(QaGH;7xb}wVeFq= z)FL{i3F=USz{%x+Vx18j@Zn$OC&6dS_$1W4F^nnZzkKS zeaR0cl)(qQP*1NYI6?#d8lUwBdYHF|a2Y?358!b;&b&Rx7u%4%fmfA{q0<{fr@GPb zrfU8bQ#`pfzP~m4%x3gGW^&bkgA;3nt+TeLzpYg13o3muCkbd4sPLvA%D}E_XXHE# zZVtkE$g>f@Q7(TIl(O)Zr#qGR)$8gr%2#S2ACu?gFXZ2p*OaFeO}SqkQ2tPNtH;&j z>>Ccs!Lg5F3bs1wgpsDCJDEt5lyeUuX+pS8v=9217C6oS{S$brk&-NN(x#K9X18sS zq?rnCe+n0(HGv=D&v9jK*5G!OlRqnGcx)^!X8#?(l3%K zHiaHmw=0jxqrxOU!(U-xvwYNj)ZHln86$@|<=5DR`-0oN)J~~?rJdE2;}vF(Htp47kBvN+UrHbQJJ#|a%)(ah`b>wq zl8>ddViUm}hdzRS4x=BI=ILU&Jnz5Aqwntn?jd&v(*&m`>ehsoMNwi}Hg#;Ks>{<# xGAq3EKf4-S*OlwIcm7qoem}W-49(Us^hvjcm6Em~^Z%+`@BL8?y`%Aye*)qb*?j;2 delta 446 zcmZoTAk=U`Xo55^I|BoQ7Z4i&G1Ej1b4K=!2}}4nnE5{f1sDuB^9VfRpBTW#Bv!Hc zoBVQq#>tcC>8G)Hu<0;N=16dy9BAM#!pegQH!BJ>uulGI!Z&%H8P8@nvwfV*9&F8% z*$bQ|2RZ;a4#oQ+WxYz*d% z&76}Tx{GeV%FH~Mar>)4#_f#L3t5>TY;O!3 emtuamJ&=ugJtsu(#04Vl%nHognH5<6)&l@M)_v6g diff --git a/feature_tests_selected_episodes.sh b/feature_tests_selected_episodes.sh index 5444e83..3085513 100755 --- a/feature_tests_selected_episodes.sh +++ b/feature_tests_selected_episodes.sh @@ -66,6 +66,24 @@ assert data["items"][1]["episode"]["title"] == "A Classic New York Character", " print("add/list validation passed") PY +curl --fail --silent --show-error \ + -X POST "${BASE_URL}/api/session/selected-episodes?session_id=${SESSION_ID}" \ + -H "Content-Type: application/json" \ + --data @"${TMP_DIR}/add_payload.json" \ + -o "${TMP_DIR}/add_duplicate_response.json" + +python3 - "${TMP_DIR}/add_duplicate_response.json" <<'PY' +import json +import sys +from pathlib import Path + +data = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8")) +items = data.get("items") +assert isinstance(items, list), "items must be a list" +assert len(items) == 2, "duplicate add should be skipped; still expected 2 selected episodes" +print("duplicate skip validation passed") +PY + echo echo "== Feature test 2: reorder selected episodes ==" cat > "${TMP_DIR}/reorder_payload.json" <<'JSON'