From e3ae961b687a2ce4ff3243aaa9fe601445e422cb Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Sat, 19 Jul 2025 23:32:53 +0200 Subject: [PATCH] Add `progress` to `/videos/:id` --- api/src/controllers/entries.ts | 2 +- api/src/controllers/videos.ts | 36 ++++++++++++++++++++++++++++++++-- api/src/db/utils.ts | 2 +- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/api/src/controllers/entries.ts b/api/src/controllers/entries.ts index 74f54ce2..7952d503 100644 --- a/api/src/controllers/entries.ts +++ b/api/src/controllers/entries.ts @@ -54,7 +54,7 @@ export const entryProgressQ = db }) .from(history) .leftJoin(videos, eq(history.videoPk, videos.pk)) - .leftJoin(profiles, eq(history.profilePk, profiles.pk)) + .innerJoin(profiles, eq(history.profilePk, profiles.pk)) .where(eq(profiles.id, sql.placeholder("userId"))) .orderBy(history.entryPk, desc(history.playedDate)) .as("progress"); diff --git a/api/src/controllers/videos.ts b/api/src/controllers/videos.ts index c763f0e8..390f53e2 100644 --- a/api/src/controllers/videos.ts +++ b/api/src/controllers/videos.ts @@ -18,6 +18,7 @@ import { db, type Transaction } from "~/db"; import { entries, entryVideoJoin, + history, profiles, shows, showTranslations, @@ -38,8 +39,9 @@ import { import { Entry } from "~/models/entry"; import { KError } from "~/models/error"; import { bubbleVideo } from "~/models/examples"; +import { Progress } from "~/models/history"; import { Movie, type MovieStatus } from "~/models/movie"; -import { Serie, type Serie } from "~/models/serie"; +import { Serie } from "~/models/serie"; import { AcceptLanguage, buildRelations, @@ -228,6 +230,35 @@ const videoRelations = { .where(eq(entryVideoJoin.videoPk, videos.pk)) .as("slugs"); }, + progress: () => { + const query = db + .select({ + json: jsonbBuildObject({ + percent: history.percent, + time: history.time, + playedDate: sql`to_char(${history.playedDate}, 'YYYY-MM-DD"T"HH24:MI:SS"Z"')`, + videoId: videos.id, + }), + }) + .from(history) + .innerJoin(profiles, eq(history.profilePk, profiles.pk)) + .where( + and( + eq(profiles.id, sql.placeholder("userId")), + eq(history.videoPk, videos.pk), + ), + ) + .orderBy(desc(history.playedDate)) + .limit(1); + return sql` + ( + select coalesce( + ${query}, + '{"percent": 0, "time": 0, "playedDate": null, "videoId": null}'::jsonb + ) + as "progress" + )`; + }, entries: ({ languages }: { languages: string[] }) => { const transQ = getEntryTransQ(languages); @@ -431,7 +462,7 @@ export const videosH = new Elysia({ prefix: "/videos", tags: ["videos"] }) .select({ ...getColumns(videos), ...buildRelations( - ["slugs", "entries", ...relations], + ["slugs", "progress", "entries", ...relations], videoRelations, { languages, @@ -486,6 +517,7 @@ export const videosH = new Elysia({ prefix: "/videos", tags: ["videos"] }) slugs: t.Array( t.String({ format: "slug", examples: ["made-in-abyss-s1e13"] }), ), + progress: Progress, entries: t.Array(Entry), previous: t.Optional( t.Nullable( diff --git a/api/src/db/utils.ts b/api/src/db/utils.ts index ecb737d8..97cf3b67 100644 --- a/api/src/db/utils.ts +++ b/api/src/db/utils.ts @@ -107,7 +107,7 @@ export function values( }; } -export const coalesce = (val: SQL | Column, def: SQL | Column) => { +export const coalesce = (val: SQL | SQLWrapper, def: SQL | Column) => { return sql`coalesce(${val}, ${def})`; };