mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Handle watch status on entries
This commit is contained in:
parent
11e1c59698
commit
c3abd7c61b
@ -1,11 +1,13 @@
|
|||||||
import { type SQL, and, desc, eq, isNotNull, ne, sql } from "drizzle-orm";
|
import { type SQL, and, desc, eq, isNotNull, ne, sql } from "drizzle-orm";
|
||||||
import { Elysia, t } from "elysia";
|
import { Elysia, t } from "elysia";
|
||||||
|
import { auth } from "~/auth";
|
||||||
import { db } from "~/db";
|
import { db } from "~/db";
|
||||||
import {
|
import {
|
||||||
entries,
|
entries,
|
||||||
entryTranslations,
|
entryTranslations,
|
||||||
entryVideoJoin,
|
entryVideoJoin,
|
||||||
history,
|
history,
|
||||||
|
profiles,
|
||||||
shows,
|
shows,
|
||||||
videos,
|
videos,
|
||||||
} from "~/db/schema";
|
} from "~/db/schema";
|
||||||
@ -124,7 +126,7 @@ export const entryVideosQ = db
|
|||||||
.leftJoin(videos, eq(videos.pk, entryVideoJoin.videoPk))
|
.leftJoin(videos, eq(videos.pk, entryVideoJoin.videoPk))
|
||||||
.as("videos");
|
.as("videos");
|
||||||
|
|
||||||
export const getEntryProgressQ = (userId: number) =>
|
export const getEntryProgressQ = (userId: string) =>
|
||||||
db
|
db
|
||||||
.selectDistinctOn([history.entryPk], {
|
.selectDistinctOn([history.entryPk], {
|
||||||
percent: history.percent,
|
percent: history.percent,
|
||||||
@ -133,11 +135,23 @@ export const getEntryProgressQ = (userId: number) =>
|
|||||||
videoId: videos.id,
|
videoId: videos.id,
|
||||||
})
|
})
|
||||||
.from(history)
|
.from(history)
|
||||||
.where(eq(history.profilePk, userId))
|
|
||||||
.leftJoin(videos, eq(history.videoPk, videos.pk))
|
.leftJoin(videos, eq(history.videoPk, videos.pk))
|
||||||
|
.leftJoin(profiles, eq(history.profilePk, profiles.pk))
|
||||||
|
.where(eq(profiles.id, userId))
|
||||||
.orderBy(history.entryPk, desc(history.playedDate))
|
.orderBy(history.entryPk, desc(history.playedDate))
|
||||||
.as("progress");
|
.as("progress");
|
||||||
|
|
||||||
|
export const mapProgress = (
|
||||||
|
progressQ: ReturnType<typeof getEntryProgressQ>,
|
||||||
|
) => {
|
||||||
|
const { time, percent, videoId } = getColumns(progressQ);
|
||||||
|
return {
|
||||||
|
time: coalesce(time, sql`0`),
|
||||||
|
percent: coalesce(percent, sql`0`),
|
||||||
|
videoId,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
async function getEntries({
|
async function getEntries({
|
||||||
after,
|
after,
|
||||||
limit,
|
limit,
|
||||||
@ -153,7 +167,7 @@ async function getEntries({
|
|||||||
sort: Sort;
|
sort: Sort;
|
||||||
filter: SQL | undefined;
|
filter: SQL | undefined;
|
||||||
languages: string[];
|
languages: string[];
|
||||||
userId: number;
|
userId: string;
|
||||||
}): Promise<(Entry | Extra | UnknownEntry)[]> {
|
}): Promise<(Entry | Extra | UnknownEntry)[]> {
|
||||||
const transQ = db
|
const transQ = db
|
||||||
.selectDistinctOn([entryTranslations.pk])
|
.selectDistinctOn([entryTranslations.pk])
|
||||||
@ -181,7 +195,7 @@ async function getEntries({
|
|||||||
...entryCol,
|
...entryCol,
|
||||||
...transCol,
|
...transCol,
|
||||||
videos: entryVideosQ.videos,
|
videos: entryVideosQ.videos,
|
||||||
progress: getColumns(entryProgressQ),
|
progress: mapProgress(entryProgressQ),
|
||||||
// specials don't have an `episodeNumber` but a `number` field.
|
// specials don't have an `episodeNumber` but a `number` field.
|
||||||
number: episodeNumber,
|
number: episodeNumber,
|
||||||
|
|
||||||
@ -230,6 +244,7 @@ export const entriesH = new Elysia({ tags: ["series"] })
|
|||||||
...models,
|
...models,
|
||||||
entry: t.Union([models.episode, models.movie_entry, models.special]),
|
entry: t.Union([models.episode, models.movie_entry, models.special]),
|
||||||
}))
|
}))
|
||||||
|
.use(auth)
|
||||||
.get(
|
.get(
|
||||||
"/series/:id/entries",
|
"/series/:id/entries",
|
||||||
async ({
|
async ({
|
||||||
@ -237,6 +252,7 @@ export const entriesH = new Elysia({ tags: ["series"] })
|
|||||||
query: { limit, after, query, sort, filter },
|
query: { limit, after, query, sort, filter },
|
||||||
headers: { "accept-language": languages },
|
headers: { "accept-language": languages },
|
||||||
request: { url },
|
request: { url },
|
||||||
|
jwt: { sub },
|
||||||
error,
|
error,
|
||||||
}) => {
|
}) => {
|
||||||
const [serie] = await db
|
const [serie] = await db
|
||||||
@ -270,6 +286,7 @@ export const entriesH = new Elysia({ tags: ["series"] })
|
|||||||
filter,
|
filter,
|
||||||
),
|
),
|
||||||
languages: langs,
|
languages: langs,
|
||||||
|
userId: sub,
|
||||||
})) as Entry[];
|
})) as Entry[];
|
||||||
|
|
||||||
return createPage(items, { url, sort, limit });
|
return createPage(items, { url, sort, limit });
|
||||||
@ -316,6 +333,7 @@ export const entriesH = new Elysia({ tags: ["series"] })
|
|||||||
params: { id },
|
params: { id },
|
||||||
query: { limit, after, query, sort, filter },
|
query: { limit, after, query, sort, filter },
|
||||||
request: { url },
|
request: { url },
|
||||||
|
jwt: { sub },
|
||||||
error,
|
error,
|
||||||
}) => {
|
}) => {
|
||||||
const [serie] = await db
|
const [serie] = await db
|
||||||
@ -347,6 +365,7 @@ export const entriesH = new Elysia({ tags: ["series"] })
|
|||||||
filter,
|
filter,
|
||||||
),
|
),
|
||||||
languages: ["extra"],
|
languages: ["extra"],
|
||||||
|
userId: sub,
|
||||||
})) as Extra[];
|
})) as Extra[];
|
||||||
|
|
||||||
return createPage(items, { url, sort, limit });
|
return createPage(items, { url, sort, limit });
|
||||||
@ -386,6 +405,7 @@ export const entriesH = new Elysia({ tags: ["series"] })
|
|||||||
async ({
|
async ({
|
||||||
query: { limit, after, query, sort, filter },
|
query: { limit, after, query, sort, filter },
|
||||||
request: { url },
|
request: { url },
|
||||||
|
jwt: { sub },
|
||||||
}) => {
|
}) => {
|
||||||
const items = (await getEntries({
|
const items = (await getEntries({
|
||||||
limit,
|
limit,
|
||||||
@ -394,6 +414,7 @@ export const entriesH = new Elysia({ tags: ["series"] })
|
|||||||
sort: sort,
|
sort: sort,
|
||||||
filter: and(eq(entries.kind, "unknown"), filter),
|
filter: and(eq(entries.kind, "unknown"), filter),
|
||||||
languages: ["extra"],
|
languages: ["extra"],
|
||||||
|
userId: sub,
|
||||||
})) as UnknownEntry[];
|
})) as UnknownEntry[];
|
||||||
|
|
||||||
return createPage(items, { url, sort, limit });
|
return createPage(items, { url, sort, limit });
|
||||||
@ -421,7 +442,11 @@ export const entriesH = new Elysia({ tags: ["series"] })
|
|||||||
)
|
)
|
||||||
.get(
|
.get(
|
||||||
"/news",
|
"/news",
|
||||||
async ({ query: { limit, after, query, filter }, request: { url } }) => {
|
async ({
|
||||||
|
query: { limit, after, query, filter },
|
||||||
|
request: { url },
|
||||||
|
jwt: { sub },
|
||||||
|
}) => {
|
||||||
const sort = newsSort;
|
const sort = newsSort;
|
||||||
const items = (await getEntries({
|
const items = (await getEntries({
|
||||||
limit,
|
limit,
|
||||||
@ -435,6 +460,7 @@ export const entriesH = new Elysia({ tags: ["series"] })
|
|||||||
filter,
|
filter,
|
||||||
),
|
),
|
||||||
languages: ["extra"],
|
languages: ["extra"],
|
||||||
|
userId: sub,
|
||||||
})) as Entry[];
|
})) as Entry[];
|
||||||
|
|
||||||
return createPage(items, { url, sort, limit });
|
return createPage(items, { url, sort, limit });
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
|
Column,
|
||||||
type ColumnsSelection,
|
type ColumnsSelection,
|
||||||
InferColumnsDataTypes,
|
|
||||||
type SQL,
|
type SQL,
|
||||||
type SQLWrapper,
|
type SQLWrapper,
|
||||||
type Subquery,
|
type Subquery,
|
||||||
@ -13,7 +13,7 @@ import {
|
|||||||
} from "drizzle-orm";
|
} from "drizzle-orm";
|
||||||
import type { CasingCache } from "drizzle-orm/casing";
|
import type { CasingCache } from "drizzle-orm/casing";
|
||||||
import type { AnyMySqlSelect } from "drizzle-orm/mysql-core";
|
import type { AnyMySqlSelect } from "drizzle-orm/mysql-core";
|
||||||
import type { AnyPgSelect } from "drizzle-orm/pg-core";
|
import type { AnyPgSelect, SelectedFieldsFlat } from "drizzle-orm/pg-core";
|
||||||
import type { AnySQLiteSelect } from "drizzle-orm/sqlite-core";
|
import type { AnySQLiteSelect } from "drizzle-orm/sqlite-core";
|
||||||
import type { WithSubquery } from "drizzle-orm/subquery";
|
import type { WithSubquery } from "drizzle-orm/subquery";
|
||||||
import { db } from "./index";
|
import { db } from "./index";
|
||||||
@ -95,7 +95,7 @@ export function values(items: Record<string, unknown>[]) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const coalesce = <T>(val: SQL<T>, def: SQLWrapper) => {
|
export const coalesce = <T>(val: SQL<T> | Column, def: SQL<T>) => {
|
||||||
return sql<T>`coalesce(${val}, ${def})`;
|
return sql<T>`coalesce(${val}, ${def})`;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -109,10 +109,19 @@ export const jsonbAgg = <T>(val: SQL<T>) => {
|
|||||||
return sql<T[]>`jsonb_agg(${val})`;
|
return sql<T[]>`jsonb_agg(${val})`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const jsonbBuildObject = <T>(select: Record<string, SQLWrapper>) => {
|
type JsonFields = {
|
||||||
|
[k: string]:
|
||||||
|
| SelectedFieldsFlat[string]
|
||||||
|
| Table
|
||||||
|
| SelectedFieldsFlat
|
||||||
|
| JsonFields;
|
||||||
|
};
|
||||||
|
export const jsonbBuildObject = <T>(select: JsonFields) => {
|
||||||
const query = sql.join(
|
const query = sql.join(
|
||||||
Object.entries(select).flatMap(([k, v]) => {
|
Object.entries(select).flatMap(([k, v]) => {
|
||||||
return [sql.raw(`'${k}'`), v];
|
if (v.getSQL) return [sql.raw(`'${k}'`), v];
|
||||||
|
// nested object (getSql is present in all SqlWrappers)
|
||||||
|
return [sql.raw(`'${k}'`), jsonbBuildObject<any>(v as JsonFields)];
|
||||||
}),
|
}),
|
||||||
sql.raw(", "),
|
sql.raw(", "),
|
||||||
);
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user