summaryrefslogtreecommitdiff
path: root/routers/profile.py
blob: 8e4a0816c7f4f1cee83590676057f78574fe0a1f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
from fastapi import APIRouter, Depends, Request
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
from sqlalchemy.orm import Session

from database import get_db
from models import Film
from services.film_people import split_credit_names

router = APIRouter(tags=["profile"])
templates = Jinja2Templates(directory="templates")
templates.env.globals.update(split_credit_names=split_credit_names)


def _diary_films(db: Session) -> list[Film]:
    return (
        db.query(Film)
        .filter(Film.shelf == "diary", Film.date_watched.is_not(None))
        .order_by(Film.date_watched.desc())
        .all()
    )


def _build_profile_payload(films: list[Film]) -> dict:
    from collections import Counter
    from services.countries import split_country_names
    from services.film_people import split_credit_names

    if not films:
        return {
            "total_watched": 0,
            "average_stars": 0,
            "most_watched_directors": [],
            "star_distribution": [{"stars": stars, "count": 0} for stars in (0, 1, 2, 3)],
            "films_per_country": [],
            "recent_films": [],
        }

    countries = Counter()
    directors = Counter()
    star_counts = Counter({0: 0, 1: 0, 2: 0, 3: 0})

    total_stars = 0
    valid_ratings = 0

    for film in films:
        country_names = split_country_names(film.country)
        countries.update(country_names)

        directors.update(split_credit_names(film.director))

        stars = film.stars if film.stars in {0, 1, 2, 3} else 0
        star_counts[stars] += 1
        if film.stars in {0, 1, 2, 3}:
            total_stars += film.stars
            valid_ratings += 1

    total_watched = len(films)
    average_stars = round(total_stars / valid_ratings, 1) if valid_ratings else 0

    return {
        "total_watched": total_watched,
        "average_stars": average_stars,
        "most_watched_directors": [
            {"director": director, "count": count}
            for director, count in sorted(directors.items(), key=lambda item: (-item[1], item[0]))[:5]
        ],
        "star_distribution": [{"stars": stars, "count": star_counts[stars]} for stars in (0, 1, 2, 3)],
        "films_per_country": [
            {"country": country, "count": count}
            for country, count in sorted(countries.items(), key=lambda item: (-item[1], item[0]))[:10]
        ],
        "recent_films": [
            {
                "id": film.id,
                "title": film.title,
                "poster_url": film.poster_url,
                "year": film.year,
                "director": split_credit_names(film.director)[0] if film.director else None,
                "date_watched": film.date_watched.isoformat() if film.date_watched else None,
                "stars": film.stars,
            }
            for film in films[:4]
        ],
    }


@router.get("/tyler")
async def public_profile(request: Request, db: Session = Depends(get_db)):
    films = _diary_films(db)
    payload = _build_profile_payload(films)
    return templates.TemplateResponse(
        request=request,
        name="profile.html",
        context={"request": request, **payload},
    )


@router.get("/tyler/films/partial")
async def public_profile_films_partial(
    request: Request,
    offset: int = 0,
    limit: int = 20,
    db: Session = Depends(get_db),
):
    films = _diary_films(db)
    page = films[offset : offset + limit]
    has_more = (offset + limit) < len(films)

    html = templates.get_template("_public_feed_partial.html").render(
        request=request,
        films=page,
    )
    response = HTMLResponse(html)
    response.headers["X-Has-More"] = "true" if has_more else "false"
    return response