mirror of
				https://github.com/zoriya/Kyoo.git
				synced 2025-10-31 02:27:11 -04:00 
			
		
		
		
	Delete unknown entries, rework them as part of unmatched videos
This commit is contained in:
		
							parent
							
								
									1fca8957a2
								
							
						
					
					
						commit
						6194d806cc
					
				| @ -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"], | ||||
| 		}, | ||||
| 	); | ||||
|  | ||||
| @ -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 }) => { | ||||
|  | ||||
| @ -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", | ||||
|  | ||||
| @ -17,4 +17,3 @@ export * from "./episode"; | ||||
| export * from "./movie-entry"; | ||||
| export * from "./special"; | ||||
| export * from "./extra"; | ||||
| export * from "./unknown-entry"; | ||||
|  | ||||
| @ -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<typeof UnknownEntry.static>; | ||||
| 
 | ||||
| registerExamples(UnknownEntry, { ...youtubeExample, ...bubbleImages }); | ||||
| @ -35,4 +35,3 @@ export * from "./made-in-abyss"; | ||||
| export * from "./dune-1984"; | ||||
| export * from "./dune-2021"; | ||||
| export * from "./dune-collection"; | ||||
| export * from "./others"; | ||||
|  | ||||
| @ -1,10 +0,0 @@ | ||||
| import type { UnknownEntry } from "~/models/entry"; | ||||
| 
 | ||||
| export const youtubeExample: Partial<UnknownEntry> = { | ||||
| 	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, | ||||
| }; | ||||
| @ -114,7 +114,9 @@ export const SeedVideo = t.Object({ | ||||
| export type SeedVideo = Prettify<typeof SeedVideo.static>; | ||||
| 
 | ||||
| export const Video = t.Intersect([ | ||||
| 	Resource(), | ||||
| 	t.Object({ | ||||
| 		id: t.String({ format: "uuid" }), | ||||
| 	}), | ||||
| 	t.Omit(SeedVideo, ["for"]), | ||||
| 	DbMetadata, | ||||
| ]); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user