diff --git a/api/src/controllers/entries.ts b/api/src/controllers/entries.ts index 2e213a5d..269178d2 100644 --- a/api/src/controllers/entries.ts +++ b/api/src/controllers/entries.ts @@ -26,7 +26,6 @@ import { ExtraType, MovieEntry, Special, - UnknownEntry, } from "~/models/entry"; import { KError } from "~/models/error"; import { madeInAbyss } from "~/models/examples"; @@ -81,11 +80,6 @@ const extraFilters: FilterDef = { playedDate: { column: entryProgressQ.playedDate, type: "date" }, }; -const unknownFilters: FilterDef = { - runtime: { column: entries.runtime, type: "float" }, - playedDate: { column: entryProgressQ.playedDate, type: "date" }, -}; - export const entrySort = Sort( { order: entries.order, @@ -176,7 +170,7 @@ export async function getEntries({ languages: string[]; userId: string; progressQ?: typeof entryProgressQ; -}): Promise<(Entry | Extra | UnknownEntry)[]> { +}): Promise<(Entry | Extra)[]> { const transQ = db .selectDistinctOn([entryTranslations.pk]) .from(entryTranslations) @@ -244,7 +238,6 @@ export const entriesH = new Elysia({ tags: ["series"] }) movie_entry: MovieEntry, special: Special, extra: Extra, - unknown_entry: UnknownEntry, error: t.Object({}), }) .model((models) => ({ @@ -289,7 +282,6 @@ export const entriesH = new Elysia({ tags: ["series"] }) filter: and( eq(entries.showPk, serie.pk), ne(entries.kind, "extra"), - ne(entries.kind, "unknown"), filter, ), languages: langs, @@ -407,46 +399,6 @@ export const entriesH = new Elysia({ tags: ["series"] }) }, }, ) - .get( - "/unknowns", - async ({ - query: { limit, after, query, sort, filter }, - request: { url }, - jwt: { sub }, - }) => { - const items = (await getEntries({ - limit, - after, - query, - sort: sort, - filter: and(eq(entries.kind, "unknown"), filter), - languages: ["extra"], - userId: sub, - })) as UnknownEntry[]; - - return createPage(items, { url, sort, limit }); - }, - { - detail: { description: "Get unknown/unmatch videos." }, - query: t.Object({ - sort: extraSort, - filter: t.Optional(Filter({ def: unknownFilters })), - query: t.Optional(t.String({ description: description.query })), - limit: t.Integer({ - minimum: 1, - maximum: 250, - default: 50, - description: "Max page size.", - }), - after: t.Optional(t.String({ description: description.after })), - }), - response: { - 200: Page(UnknownEntry), - 422: KError, - }, - tags: ["videos"], - }, - ) .get( "/news", async ({ @@ -462,7 +414,6 @@ export const entriesH = new Elysia({ tags: ["series"] }) sort, filter: and( isNotNull(entries.availableSince), - ne(entries.kind, "unknown"), ne(entries.kind, "extra"), filter, ), @@ -489,6 +440,6 @@ export const entriesH = new Elysia({ tags: ["series"] }) 200: Page(Entry), 422: KError, }, - tags: ["videos"], + tags: ["shows"], }, ); diff --git a/api/src/controllers/videos.ts b/api/src/controllers/videos.ts index 81390336..9cd1bdc4 100644 --- a/api/src/controllers/videos.ts +++ b/api/src/controllers/videos.ts @@ -1,4 +1,4 @@ -import { and, eq, exists, inArray, not, or, sql } from "drizzle-orm"; +import { and, eq, exists, inArray, not, notExists, or, sql } from "drizzle-orm"; import { alias } from "drizzle-orm/pg-core"; import { Elysia, t } from "elysia"; import { db } from "~/db"; @@ -9,8 +9,17 @@ import { jsonbObjectAgg, values, } from "~/db/utils"; +import { KError } from "~/models/error"; import { bubbleVideo } from "~/models/examples"; -import { isUuid } from "~/models/utils"; +import { + Page, + Sort, + createPage, + isUuid, + keysetPaginate, + sortToSql, +} from "~/models/utils"; +import { desc as description } from "~/models/utils/descriptions"; import { Guesses, SeedVideo, Video } from "~/models/video"; import { comment } from "~/utils"; import { computeVideoSlug } from "./seed/insert/entries"; @@ -84,6 +93,55 @@ export const videosH = new Elysia({ prefix: "/videos", tags: ["videos"] }) }, }, ) + .get( + "unknowns", + async ({ query: { sort, query, limit, after }, request: { url } }) => { + const ret = await db + .select() + .from(videos) + .where( + and( + notExists( + db + .select() + .from(entryVideoJoin) + .where(eq(videos.pk, entryVideoJoin.videoPk)), + ), + query + ? or( + sql`${videos.path} %> ${query}::text`, + sql`${videos.guess}->'title' %> ${query}::text`, + ) + : undefined, + keysetPaginate({ after, sort }), + ), + ) + .orderBy(...(query ? [] : sortToSql(sort)), videos.pk) + .limit(limit); + return createPage(ret, { url, sort, limit }); + }, + { + detail: { description: "Get unknown/unmatch videos." }, + query: t.Object({ + sort: Sort( + { createdAt: videos.createdAt, path: videos.path }, + { default: ["-createdAt"], tablePk: videos.pk }, + ), + query: t.Optional(t.String({ description: description.query })), + limit: t.Integer({ + minimum: 1, + maximum: 250, + default: 50, + description: "Max page size.", + }), + after: t.Optional(t.String({ description: description.after })), + }), + response: { + 200: Page(Video), + 422: KError, + }, + }, + ) .post( "", async ({ body, error }) => { diff --git a/api/src/db/schema/entries.ts b/api/src/db/schema/entries.ts index 63c6298d..0c3a4a60 100644 --- a/api/src/db/schema/entries.ts +++ b/api/src/db/schema/entries.ts @@ -18,7 +18,6 @@ import { image, language, schema } from "./utils"; import { entryVideoJoin } from "./videos"; export const entryType = schema.enum("entry_type", [ - "unknown", "episode", "movie", "special", diff --git a/api/src/models/entry/index.ts b/api/src/models/entry/index.ts index 199622f6..bfdc54dc 100644 --- a/api/src/models/entry/index.ts +++ b/api/src/models/entry/index.ts @@ -17,4 +17,3 @@ export * from "./episode"; export * from "./movie-entry"; export * from "./special"; export * from "./extra"; -export * from "./unknown-entry"; diff --git a/api/src/models/entry/unknown-entry.ts b/api/src/models/entry/unknown-entry.ts deleted file mode 100644 index 5ae1c811..00000000 --- a/api/src/models/entry/unknown-entry.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { t } from "elysia"; -import { type Prettify, comment } from "~/utils"; -import { bubbleImages, registerExamples, youtubeExample } from "../examples"; -import { Progress } from "../history"; -import { DbMetadata, Resource } from "../utils"; -import { BaseEntry, EntryTranslation } from "./base-entry"; - -export const BaseUnknownEntry = t.Intersect( - [ - t.Object({ - kind: t.Literal("unknown"), - }), - t.Omit(BaseEntry(), ["airDate"]), - ], - { - description: comment` - A video not releated to any series or movie. This can be due to a matching error but it can be a youtube - video or any other video content. - `, - }, -); - -export const UnknownEntryTranslation = t.Omit(EntryTranslation(), [ - "description", -]); - -export const UnknownEntry = t.Intersect([ - Resource(), - UnknownEntryTranslation, - BaseUnknownEntry, - t.Object({ - progress: t.Omit(Progress, ["videoId"]), - }), - DbMetadata, -]); -export type UnknownEntry = Prettify; - -registerExamples(UnknownEntry, { ...youtubeExample, ...bubbleImages }); diff --git a/api/src/models/examples/index.ts b/api/src/models/examples/index.ts index 7bc7a3ba..a5601358 100644 --- a/api/src/models/examples/index.ts +++ b/api/src/models/examples/index.ts @@ -35,4 +35,3 @@ export * from "./made-in-abyss"; export * from "./dune-1984"; export * from "./dune-2021"; export * from "./dune-collection"; -export * from "./others"; diff --git a/api/src/models/examples/others.ts b/api/src/models/examples/others.ts deleted file mode 100644 index 41de7f6e..00000000 --- a/api/src/models/examples/others.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { UnknownEntry } from "~/models/entry"; - -export const youtubeExample: Partial = { - kind: "unknown", - // idk if we'll keep non-ascii characters or if we can find a way to convert them - slug: "lisa-炎-the-first-take", - name: "LiSA - 炎 / THE FIRST TAKE", - runtime: 10, - thumbnail: null, -}; diff --git a/api/src/models/video.ts b/api/src/models/video.ts index 226f064d..c36635fe 100644 --- a/api/src/models/video.ts +++ b/api/src/models/video.ts @@ -114,7 +114,9 @@ export const SeedVideo = t.Object({ export type SeedVideo = Prettify; export const Video = t.Intersect([ - Resource(), + t.Object({ + id: t.String({ format: "uuid" }), + }), t.Omit(SeedVideo, ["for"]), DbMetadata, ]);