This commit is contained in:
team3
2026-09-29 00:54:58 +02:00
parent f7c9017946
commit f80b8c5826
20 changed files with 997 additions and 77 deletions

View File

@@ -56,6 +56,28 @@ CREATE TABLE IF NOT EXISTS watched_notes (
);
"""
# Ein Herz je Person und Kommentar: "sehe ich auch so". Alle sehen die
# Zahl, wer es gegeben hat, sieht nur der Host.
HEARTS = """
CREATE TABLE IF NOT EXISTS watched_hearts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
note_id INTEGER NOT NULL,
session_id TEXT NOT NULL,
user_id INTEGER,
created_at TEXT NOT NULL
);
"""
# Wer am Abend dabei war — kommt aus der Runde am Rad, sobald der Host
# den gezogenen Film einträgt. Daraus rechnen sich die Punkte.
DABEI = """
CREATE TABLE IF NOT EXISTS watched_dabei (
watched_id INTEGER NOT NULL,
user_id INTEGER NOT NULL,
PRIMARY KEY (watched_id, user_id)
);
"""
MAX_STERNE = 5
# Manche schreiben eine ganze Rezension — rund 600 Wörter passen hinein
MAX_KOMMENTAR = 4000
@@ -66,11 +88,10 @@ AUS_KATALOG = ("backdrop_path", "images", "runtime", "genres")
def init():
with connect() as conn:
conn.executescript(SCHEMA + RATINGS + NOTES)
# Eine Stimme je Person und Film
conn.executescript(SCHEMA + RATINGS + NOTES + HEARTS + DABEI)
# Eine Stimme je Person und Film, ein Herz je Person und Kommentar
users.je_person(conn, "ratings", RATINGS, "watched_id")
# Herzen an Kommentaren gab es kurz — keiner hat sie vermisst
conn.execute("DROP TABLE IF EXISTS watched_hearts")
users.je_person(conn, "watched_hearts", HEARTS, "note_id")
# Kurz hingen Antworten an der Wertung statt aneinander. Daten gab
# es dazu nie, die Spalte bekommt nur ihren neuen Namen.
spalten = {r["name"] for r in conn.execute("PRAGMA table_info(watched_notes)")}
@@ -106,9 +127,12 @@ def _jetzt():
return datetime.now(timezone.utc).isoformat(timespec="seconds")
def alle(session_id):
"""Zuletzt geschaut zuerst, mit Schnitt, eigener Stimme und
Kommentaren. Die laufende Nummer zählt vom ersten Abend."""
def alle(session_id, host=False):
"""Zuletzt geschaut zuerst, mit Schnitt, eigener Stimme, Kommentaren
und wer dabei war. Die laufende Nummer zählt vom ersten Abend.
Wer wie gewertet und wer ein Herz gegeben hat, sieht nur der Host —
für die Runde bleibt die Wertung anonym, das nimmt Hemmung."""
felder = ", ".join(f"m.{f}" for f in AUS_KATALOG)
with connect() as conn:
filme = conn.execute(
@@ -125,10 +149,26 @@ def alle(session_id):
"LEFT JOIN users u ON u.id = n.user_id "
"ORDER BY n.created_at ASC"
).fetchall()
herzen = conn.execute(
"SELECT h.note_id, h.session_id, h.user_id, u.name FROM watched_hearts h "
"LEFT JOIN users u ON u.id = h.user_id ORDER BY h.created_at ASC"
).fetchall()
anwesend = conn.execute(
"SELECT d.watched_id, u.id, u.name FROM watched_dabei d "
"JOIN users u ON u.id = d.user_id ORDER BY u.name COLLATE NOCASE"
).fetchall()
ich = besitzer(session_id)
herz_je_notiz = {}
for h in herzen:
herz_je_notiz.setdefault(h["note_id"], []).append(h)
dabei_je_film = {}
for d in anwesend:
dabei_je_film.setdefault(d["watched_id"], []).append({"id": d["id"], "name": d["name"]})
def notiz(n):
meine_herzen = herz_je_notiz.get(n["id"], [])
return {
"id": n["id"],
"text": n["text"],
@@ -136,6 +176,9 @@ def alle(session_id):
"created_at": n["created_at"],
"mine": gehoert_mir(n, session_id, ich),
"replies": [],
"hearts": len(meine_herzen),
"hearted": any(gehoert_mir(h, session_id, ich) for h in meine_herzen),
"hearted_by": [h["name"] or "Anonym" for h in meine_herzen] if host else [],
}
# Die Kommentare eines Films als Baum: jede Antwort hängt sich an
@@ -176,7 +219,10 @@ def alle(session_id):
"mine": gehoert_mir(s, session_id, ich),
}
for s in eigene
],
]
if host
else [],
"dabei": dabei_je_film.get(film["id"], []),
"notes": kommentare.get(film["id"], []),
"average": round(sum(werte) / len(werte), 1) if werte else None,
"count": len(werte),
@@ -207,9 +253,31 @@ def markieren(movie):
return dict(row)
def entfernen(watched_id):
"""Samt Wertungen und Kommentaren."""
def dabei_setzen(watched_id, user_ids):
"""Die Anwesenheit eines Abends — ersetzt die bisherige Liste."""
with connect() as conn:
conn.execute("DELETE FROM watched_dabei WHERE watched_id = ?", (watched_id,))
conn.executemany(
"INSERT OR IGNORE INTO watched_dabei (watched_id, user_id) VALUES (?, ?)",
[(watched_id, i) for i in user_ids],
)
def _herzen_weg(conn, note_ids):
conn.executemany(
"DELETE FROM watched_hearts WHERE note_id = ?", [(i,) for i in note_ids]
)
def entfernen(watched_id):
"""Samt Wertungen, Kommentaren, Herzen und Anwesenheit."""
with connect() as conn:
notizen = [
r["id"]
for r in conn.execute("SELECT id FROM watched_notes WHERE watched_id = ?", (watched_id,))
]
_herzen_weg(conn, notizen)
conn.execute("DELETE FROM watched_dabei WHERE watched_id = ?", (watched_id,))
conn.execute("DELETE FROM watched_notes WHERE watched_id = ?", (watched_id,))
conn.execute("DELETE FROM ratings WHERE watched_id = ?", (watched_id,))
return conn.execute(
@@ -326,12 +394,35 @@ def anmerkung_loeschen(note_id, session_id, host):
if not host and not gehoert_mir(zeile, session_id, ich):
return 0
alle_ids = [note_id, *_nachkommen(conn, note_id)]
_herzen_weg(conn, alle_ids)
conn.executemany(
"DELETE FROM watched_notes WHERE id = ?", [(i,) for i in alle_ids]
)
return len(alle_ids)
def herz(session_id, note_id):
"""Herz setzen oder zurücknehmen. None, wenn es den Kommentar nicht
gibt, sonst ob das Herz jetzt steht."""
ich = besitzer(session_id)
with connect() as conn:
weg = conn.execute(
f"DELETE FROM watched_hearts WHERE note_id = ? AND {WEM}",
(note_id, ich, ich, session_id),
).rowcount
if weg:
return False
da = conn.execute("SELECT 1 FROM watched_notes WHERE id = ?", (note_id,)).fetchone()
if not da:
return None
conn.execute(
"INSERT INTO watched_hearts (note_id, session_id, user_id, created_at) "
"VALUES (?, ?, ?, ?)",
(note_id, session_id, ich, _jetzt()),
)
return True
def ids():
"""movie_ids der geschauten Filme, für die Detailansicht."""
with connect() as conn: