Skip to content

Commit

Permalink
feat(stats): add most seen person for all jobs
Browse files Browse the repository at this point in the history
  • Loading branch information
believer committed Sep 29, 2023
1 parent 50f5c6d commit 7282ed8
Show file tree
Hide file tree
Showing 10 changed files with 221 additions and 72 deletions.
50 changes: 50 additions & 0 deletions db/queries.sql
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,38 @@ FROM
WHERE
p.id = $1;

-- name: stats-data
SELECT
COUNT(DISTINCT movie_id) AS unique_movies,
COUNT(movie_id) seen_with_rewatches,
SUM(m.runtime) AS total_runtime,
MAX(m.imdb_rating) AS top_imdb_rating,
(
SELECT
title
FROM
movie
WHERE
imdb_rating IS NOT NULL
ORDER BY
imdb_rating DESC
LIMIT 1) AS top_imdb_title,
(
SELECT
id
FROM
movie
WHERE
imdb_rating IS NOT NULL
ORDER BY
imdb_rating DESC
LIMIT 1) AS top_imdb_id
FROM
seen AS s
INNER JOIN movie AS m ON m.id = s.movie_id
WHERE
user_id = 1;

-- name: stats-most-watched-movies
SELECT
COUNT(*) AS count,
Expand Down Expand Up @@ -147,3 +179,21 @@ GROUP BY
ORDER BY
rating;

-- name: stats-most-watched-by-job
SELECT
COUNT(*) AS count,
p.name,
p.id
FROM
seen AS s
INNER JOIN movie_person AS mp ON mp.movie_id = s.movie_id
INNER JOIN person AS p ON p.id = mp.person_id
WHERE
user_id = 1
AND mp.job = $1
GROUP BY
p.id
ORDER BY
count DESC
LIMIT 10;

43 changes: 29 additions & 14 deletions handlers/stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"believer/movies/utils"
"cmp"
"strconv"
"strings"

"slices"

Expand All @@ -13,22 +14,15 @@ import (

func HandleGetStats(c *fiber.Ctx) error {
var stats struct {
UniqueMovies int `db:"unique_movies"`
SeenWithRewatches int `db:"seen_with_rewatches"`
TotalRuntime int `db:"total_runtime"`
UniqueMovies int `db:"unique_movies"`
SeenWithRewatches int `db:"seen_with_rewatches"`
TotalRuntime int `db:"total_runtime"`
TopImdbRating float64 `db:"top_imdb_rating"`
TopImdbTitle string `db:"top_imdb_title"`
TopImdbID string `db:"top_imdb_id"`
}

err := db.Client.Get(&stats, `
SELECT
COUNT(DISTINCT movie_id) AS unique_movies,
COUNT(movie_id) seen_with_rewatches,
SUM(m.runtime) AS total_runtime
FROM
seen AS s
INNER JOIN movie as m ON m.id = s.movie_id
WHERE
user_id = 1;
`)
err := db.Dot.Get(db.Client, &stats, "stats-data")

if err != nil {
return err
Expand Down Expand Up @@ -58,6 +52,27 @@ func HandleGetMostWatchedMovies(c *fiber.Ctx) error {
})
}

func HandleGetMostWatchedByJob(c *fiber.Ctx) error {
var persons []struct {
Name string `db:"name"`
ID string `db:"id"`
Count int `db:"count"`
}

job := c.Params("job")

err := db.Dot.Select(db.Client, &persons, "stats-most-watched-by-job", job)

if err != nil {
return err
}

return c.Render("partials/stats/most-watched-person", fiber.Map{
"Data": persons,
"Job": strings.Title(job),
})
}

type Rating struct {
Rating int `db:"rating"`
Count int `db:"count"`
Expand Down
2 changes: 1 addition & 1 deletion public/styles.css

Large diffs are not rendered by default.

73 changes: 42 additions & 31 deletions public/styles.e75708.css → public/styles.f13aa4.css
Original file line number Diff line number Diff line change
Expand Up @@ -729,8 +729,8 @@ video {
fill: #f5f5f5;
}

.fill-neutral-500 {
fill: #737373;
.fill-neutral-400 {
fill: #a3a3a3;
}

.stroke-neutral-400 {
Expand Down Expand Up @@ -814,6 +814,10 @@ video {
color: rgb(64 64 64 / var(--tw-text-opacity));
}

.opacity-0 {
opacity: 0;
}

.ring-offset-2 {
--tw-ring-offset-width: 2px;
}
Expand All @@ -822,6 +826,12 @@ video {
--tw-ring-offset-color: #fff;
}

.transition-opacity {
transition-property: opacity;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}

.placeholder\:text-neutral-400::-moz-placeholder {
--tw-text-opacity: 1;
color: rgb(163 163 163 / var(--tw-text-opacity));
Expand All @@ -832,26 +842,11 @@ video {
color: rgb(163 163 163 / var(--tw-text-opacity));
}

.before\:absolute::before {
content: var(--tw-content);
position: absolute;
}

.before\:relative::before {
content: var(--tw-content);
position: relative;
}

.before\:-left-6::before {
content: var(--tw-content);
left: -1.5rem;
}

.before\:top-1\/2::before {
content: var(--tw-content);
top: 50%;
}

.before\:mb-4::before {
content: var(--tw-content);
margin-bottom: 1rem;
Expand All @@ -867,12 +862,6 @@ video {
width: 2ch;
}

.before\:-translate-y-1\/2::before {
content: var(--tw-content);
--tw-translate-y: -50%;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}

.before\:text-right::before {
content: var(--tw-content);
text-align: right;
Expand All @@ -884,18 +873,18 @@ video {
line-height: 2.5rem;
}

.before\:text-xs::before {
content: var(--tw-content);
font-size: 0.75rem;
line-height: 1rem;
}

.before\:tabular-nums::before {
content: var(--tw-content);
--tw-numeric-spacing: tabular-nums;
font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction);
}

.before\:text-neutral-400::before {
content: var(--tw-content);
--tw-text-opacity: 1;
color: rgb(163 163 163 / var(--tw-text-opacity));
}

.before\:text-transparent::before {
content: var(--tw-content);
color: transparent;
Expand Down Expand Up @@ -951,6 +940,10 @@ video {
display: none;
}

.hover\:fill-neutral-200:hover {
fill: #e5e5e5;
}

.focus\:outline-none:focus {
outline: 2px solid transparent;
outline-offset: 2px;
Expand Down Expand Up @@ -1008,8 +1001,8 @@ video {
background-color: rgb(23 23 23 / var(--tw-bg-opacity));
}

.dark\:fill-neutral-400 {
fill: #a3a3a3;
.dark\:fill-neutral-500 {
fill: #737373;
}

.dark\:fill-neutral-800 {
Expand Down Expand Up @@ -1049,6 +1042,12 @@ video {
color: rgb(82 82 82 / var(--tw-text-opacity));
}

.dark\:before\:text-neutral-600::before {
content: var(--tw-content);
--tw-text-opacity: 1;
color: rgb(82 82 82 / var(--tw-text-opacity));
}

.dark\:before\:\[-webkit-text-stroke-color\:_\#fff\]::before {
content: var(--tw-content);
-webkit-text-stroke-color: #fff;
Expand All @@ -1060,6 +1059,10 @@ video {
background-color: rgb(64 64 64 / var(--tw-bg-opacity));
}

.dark\:hover\:fill-neutral-700:hover {
fill: #404040;
}

.dark\:focus\:ring-neutral-500:focus {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(115 115 115 / var(--tw-ring-opacity));
Expand All @@ -1074,6 +1077,10 @@ video {
.sm\:grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}

.sm\:grid-cols-\[max-content_1fr\] {
grid-template-columns: max-content 1fr;
}
}

@media (min-width: 768px) {
Expand Down Expand Up @@ -1167,3 +1174,7 @@ video {
top: -2rem;
}
}

.\[\&\>text\]\:hover\:opacity-100:hover>text {
opacity: 1;
}
1 change: 1 addition & 0 deletions router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,6 @@ func SetupRoutes(app *fiber.App) {

statsGroup.Get("/", handlers.HandleGetStats)
statsGroup.Get("/most-watched-movies", handlers.HandleGetMostWatchedMovies)
statsGroup.Get("/most-watched-person/:job", handlers.HandleGetMostWatchedByJob)
statsGroup.Get("/ratings", handlers.HandleGetRatings)
}
2 changes: 1 addition & 1 deletion views/layouts/main.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<title>Movies</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link href="/public/styles.e75708.css" rel="stylesheet" />
<link href="/public/styles.f13aa4.css" rel="stylesheet" />
<script
src="https://unpkg.com/htmx.org@1.9.6"
integrity="sha384-FhXw7b6AlE/jyjlZH5iHa/tTe9EpJ1Y55RjcgPbjeWMskSxZt1v9qkxLJWNJaGni"
Expand Down
4 changes: 2 additions & 2 deletions views/partials/stats/most-watched-movies.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
<ol class="flex flex-col gap-2">
{{ range $i, $movie := .Data }}
<li
class="flex items-baseline justify-between gap-4 relative before:content-[attr(data-position)] before:absolute before:-left-6 before:text-right before:tabular-nums before:w-[2ch] before:text-xs before:top-1/2 before:-translate-y-1/2"
class="flex items-baseline justify-between gap-4 before:content-[attr(data-position)] before:text-right before:tabular-nums before:w-[2ch] before:text-neutral-400 dark:before:text-neutral-600"
data-position="{{ add $i 1 }}"
>
<a
class="border-b border-dashed border-neutral-500 dark:border-neutral-400 truncate focus:outline-none focus-visible:outline-dashed focus-visible:rounded-sm focus-visible:outline-offset-2 focus-visible:outline-neutral-400 dark:focus-visible:outline-neutral-600"
href="/movies/{{ .ID }}"
href="/movies/{{ $movie.ID }}"
hx-swap="innerHTML transition:true"
style="view-transition-name: movie-{{ .ID }}"
>
Expand Down
28 changes: 28 additions & 0 deletions views/partials/stats/most-watched-person.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<section
class="flex flex-col gap-4 md:text-sm text-neutral-500 dark:text-neutral-400"
>
{{ template "partials/data-section-title" .Job }}
<ol class="flex flex-col gap-2">
{{ range $i, $d := .Data }}
<li
class="flex items-baseline justify-between gap-4 before:content-[attr(data-position)] before:text-right before:tabular-nums before:w-[2ch] before:text-neutral-400 dark:before:text-neutral-600"
data-position="{{ add $i 1 }}"
>
<a
class="border-b border-dashed border-neutral-500 dark:border-neutral-400 truncate focus:outline-none focus-visible:outline-dashed focus-visible:rounded-sm focus-visible:outline-offset-2 focus-visible:outline-neutral-400 dark:focus-visible:outline-neutral-600"
href="/person/{{ $d.ID }}"
hx-swap="innerHTML transition:true"
style="view-transition-name: movie-{{ .ID }}"
>
{{ $d.Name }}
</a>
<hr
class="m-0 flex-1 border-dashed border-neutral-300 dark:border-neutral-700"
/>
<span class="tabular-nums text-sm text-neutral-500 dark:text-neutral-400">
{{ $d.Count }}
</span>
</li>
{{ end }}
</ol>
</section>
Loading

0 comments on commit 7282ed8

Please sign in to comment.