217 lines
6.9 KiB
Python
217 lines
6.9 KiB
Python
"""Bereits geschaute Filme und ihre Bewertungen.
|
|
|
|
Der Host trägt ein, was am Abend lief. Bewerten darf jeder, eine Stimme
|
|
je Sitzung — dieselbe Cookie-Sitzung wie bei den Vorschlägen. Der Name ist
|
|
freiwillig, ohne ihn zählt die Stimme trotzdem.
|
|
|
|
Titel und Poster werden mitgespeichert, damit ein Eintrag lesbar bleibt,
|
|
auch wenn der Film später aus dem Katalog fällt.
|
|
"""
|
|
|
|
from datetime import datetime, timezone
|
|
|
|
from . import users
|
|
from .db import connect
|
|
from .users import WEM, besitzer, gehoert_mir
|
|
|
|
SCHEMA = """
|
|
CREATE TABLE IF NOT EXISTS watched (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
movie_id INTEGER NOT NULL UNIQUE,
|
|
title TEXT NOT NULL,
|
|
year INTEGER,
|
|
poster_path TEXT,
|
|
watched_at TEXT NOT NULL,
|
|
hidden INTEGER NOT NULL DEFAULT 0
|
|
);
|
|
"""
|
|
|
|
RATINGS = """
|
|
CREATE TABLE IF NOT EXISTS ratings (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
watched_id INTEGER NOT NULL,
|
|
session_id TEXT NOT NULL,
|
|
user_id INTEGER,
|
|
stars INTEGER NOT NULL,
|
|
name TEXT,
|
|
text TEXT,
|
|
created_at TEXT NOT NULL
|
|
);
|
|
"""
|
|
|
|
MAX_STERNE = 5
|
|
# Manche schreiben eine ganze Rezension — rund 600 Wörter passen hinein
|
|
MAX_TEXT = 4000
|
|
|
|
|
|
def init():
|
|
with connect() as conn:
|
|
conn.executescript(SCHEMA + RATINGS)
|
|
# Eine Stimme je Person und Film
|
|
users.je_person(conn, "ratings", RATINGS, "watched_id")
|
|
# Die Tabelle stand vor der Spalte schon in bestehenden Datenbanken
|
|
spalten = {r["name"] for r in conn.execute("PRAGMA table_info(watched)")}
|
|
if "hidden" not in spalten:
|
|
conn.execute(
|
|
"ALTER TABLE watched ADD COLUMN hidden INTEGER NOT NULL DEFAULT 0"
|
|
)
|
|
# Ein Satz zur Wertung kam später dazu
|
|
spalten = {r["name"] for r in conn.execute("PRAGMA table_info(ratings)")}
|
|
if "text" not in spalten:
|
|
conn.execute("ALTER TABLE ratings ADD COLUMN text TEXT")
|
|
|
|
|
|
def _jetzt():
|
|
return datetime.now(timezone.utc).isoformat(timespec="seconds")
|
|
|
|
|
|
def alle(session_id):
|
|
"""Zuletzt geschaut zuerst, mit Schnitt und der eigenen Stimme."""
|
|
with connect() as conn:
|
|
filme = conn.execute(
|
|
"SELECT * FROM watched ORDER BY watched_at DESC, id DESC"
|
|
).fetchall()
|
|
stimmen = conn.execute(
|
|
"SELECT id, watched_id, session_id, user_id, stars, name, text "
|
|
"FROM ratings ORDER BY created_at ASC"
|
|
).fetchall()
|
|
|
|
ich = besitzer(session_id)
|
|
je_film = {}
|
|
for s in stimmen:
|
|
je_film.setdefault(s["watched_id"], []).append(s)
|
|
|
|
out = []
|
|
for film in filme:
|
|
eigene = je_film.get(film["id"], [])
|
|
werte = [s["stars"] for s in eigene]
|
|
meine = next((s for s in eigene if gehoert_mir(s, session_id, ich)), None)
|
|
out.append(
|
|
{
|
|
**dict(film),
|
|
"ratings": [
|
|
{
|
|
"id": s["id"],
|
|
"stars": s["stars"],
|
|
"name": s["name"],
|
|
"text": s["text"],
|
|
"mine": gehoert_mir(s, session_id, ich),
|
|
}
|
|
for s in eigene
|
|
],
|
|
"average": round(sum(werte) / len(werte), 1) if werte else None,
|
|
"count": len(werte),
|
|
"mine": meine["stars"] if meine else None,
|
|
"mine_text": meine["text"] if meine else None,
|
|
}
|
|
)
|
|
return out
|
|
|
|
|
|
def markieren(movie):
|
|
"""Film als geschaut eintragen. Ein zweiter Klick ändert nichts."""
|
|
with connect() as conn:
|
|
conn.execute(
|
|
"INSERT OR IGNORE INTO watched "
|
|
"(movie_id, title, year, poster_path, watched_at) "
|
|
"VALUES (?, ?, ?, ?, ?)",
|
|
(
|
|
movie["id"],
|
|
movie["title"],
|
|
movie.get("year"),
|
|
movie.get("poster_path"),
|
|
_jetzt(),
|
|
),
|
|
)
|
|
row = conn.execute(
|
|
"SELECT * FROM watched WHERE movie_id = ?", (movie["id"],)
|
|
).fetchone()
|
|
return dict(row)
|
|
|
|
|
|
def entfernen(watched_id):
|
|
with connect() as conn:
|
|
conn.execute("DELETE FROM ratings WHERE watched_id = ?", (watched_id,))
|
|
return conn.execute(
|
|
"DELETE FROM watched WHERE id = ?", (watched_id,)
|
|
).rowcount
|
|
|
|
|
|
def datum_setzen(watched_id, tag):
|
|
"""tag im Format JJJJ-MM-TT. Mittags in UTC, damit die Anzeige in
|
|
keiner Zeitzone auf den Nachbartag rutscht."""
|
|
with connect() as conn:
|
|
return conn.execute(
|
|
"UPDATE watched SET watched_at = ? WHERE id = ?",
|
|
(f"{tag}T12:00:00+00:00", watched_id),
|
|
).rowcount
|
|
|
|
|
|
def sichtbarkeit(watched_id, versteckt):
|
|
"""Versteckte Filme sieht nur der Host."""
|
|
with connect() as conn:
|
|
return conn.execute(
|
|
"UPDATE watched SET hidden = ? WHERE id = ?",
|
|
(1 if versteckt else 0, watched_id),
|
|
).rowcount
|
|
|
|
|
|
def bewerten(watched_id, session_id, stars, name=None, text=None):
|
|
"""Sterne und ein optionaler Satz dazu.
|
|
|
|
Kommt kein Text mit (None), bleibt der bisherige stehen — wer nur die
|
|
Sterne nachjustiert, verliert seinen Satz nicht. Ein leerer String
|
|
löscht ihn ausdrücklich.
|
|
|
|
Gibt None zurück, wenn der Film gar nicht in der Liste steht.
|
|
"""
|
|
with connect() as conn:
|
|
da = conn.execute(
|
|
"SELECT 1 FROM watched WHERE id = ?", (watched_id,)
|
|
).fetchone()
|
|
if not da:
|
|
return None
|
|
ich = besitzer(session_id)
|
|
if text is None:
|
|
alt = conn.execute(
|
|
f"SELECT text FROM ratings WHERE watched_id = ? AND {WEM}",
|
|
(watched_id, ich, ich, session_id),
|
|
).fetchone()
|
|
text = alt["text"] if alt else None
|
|
else:
|
|
text = text.strip()[:MAX_TEXT] or None
|
|
# Eine Stimme je Person — die eigene alte fliegt vorher raus
|
|
conn.execute(
|
|
f"DELETE FROM ratings WHERE watched_id = ? AND {WEM}",
|
|
(watched_id, ich, ich, session_id),
|
|
)
|
|
conn.execute(
|
|
"INSERT INTO ratings "
|
|
"(watched_id, session_id, user_id, stars, name, text, created_at) "
|
|
"VALUES (?, ?, ?, ?, ?, ?, ?)",
|
|
(
|
|
watched_id,
|
|
session_id,
|
|
ich,
|
|
stars,
|
|
(name or "").strip()[:40] or None,
|
|
text,
|
|
_jetzt(),
|
|
),
|
|
)
|
|
return {"watched_id": watched_id, "stars": stars, "text": text}
|
|
|
|
|
|
def stimme_loeschen(rating_id):
|
|
"""Der Host räumt eine einzelne Wertung weg."""
|
|
with connect() as conn:
|
|
return conn.execute(
|
|
"DELETE FROM ratings WHERE id = ?", (rating_id,)
|
|
).rowcount
|
|
|
|
|
|
def ids():
|
|
"""movie_ids der geschauten Filme, für die Detailansicht."""
|
|
with connect() as conn:
|
|
return [r["movie_id"] for r in conn.execute("SELECT movie_id FROM watched")]
|