mirror of
				https://github.com/zoriya/Kyoo.git
				synced 2025-10-31 02:27:11 -04:00 
			
		
		
		
	Fix & test GET /videos
				
					
				
			This commit is contained in:
		
							parent
							
								
									45e769828b
								
							
						
					
					
						commit
						e26bc931f5
					
				| @ -14,6 +14,7 @@ import { KError } from "~/models/error"; | ||||
| import { bubbleVideo } from "~/models/examples"; | ||||
| import { | ||||
| 	Page, | ||||
| 	type Resource, | ||||
| 	Sort, | ||||
| 	createPage, | ||||
| 	isUuid, | ||||
| @ -54,8 +55,9 @@ export const videosH = new Elysia({ prefix: "/videos", tags: ["videos"] }) | ||||
| 						slug: shows.slug, | ||||
| 					}) | ||||
| 					.from(videos) | ||||
| 					.crossJoin( | ||||
| 					.leftJoin( | ||||
| 						sql`jsonb_array_elements_text(${videos.guess}->'year') as year`, | ||||
| 						sql`true`, | ||||
| 					) | ||||
| 					.innerJoin(entryVideoJoin, eq(entryVideoJoin.videoPk, videos.pk)) | ||||
| 					.innerJoin(entries, eq(entries.pk, entryVideoJoin.entryPk)) | ||||
| @ -78,7 +80,10 @@ export const videosH = new Elysia({ prefix: "/videos", tags: ["videos"] }) | ||||
| 			const [{ guesses }] = await db | ||||
| 				.with(years, guess) | ||||
| 				.select({ | ||||
| 					guesses: jsonbObjectAgg<Guesses["guesses"]>(guess.guess, guess.years), | ||||
| 					guesses: jsonbObjectAgg<Record<string, Resource>>( | ||||
| 						guess.guess, | ||||
| 						guess.years, | ||||
| 					), | ||||
| 				}) | ||||
| 				.from(guess); | ||||
| 
 | ||||
| @ -98,7 +103,7 @@ export const videosH = new Elysia({ prefix: "/videos", tags: ["videos"] }) | ||||
| 
 | ||||
| 			return { | ||||
| 				paths: paths.map((x) => x.path), | ||||
| 				guesses, | ||||
| 				guesses: guesses ?? {}, | ||||
| 				unmatched: unmatched.map((x) => x.path), | ||||
| 			}; | ||||
| 		}, | ||||
| @ -177,8 +182,7 @@ export const videosH = new Elysia({ prefix: "/videos", tags: ["videos"] }) | ||||
| 							path: videos.path, | ||||
| 						}); | ||||
| 				} catch (e) { | ||||
| 					if (!isUniqueConstraint(e)) | ||||
| 						throw e; | ||||
| 					if (!isUniqueConstraint(e)) throw e; | ||||
| 					return error(409, { | ||||
| 						status: 409, | ||||
| 						message: comment` | ||||
|  | ||||
| @ -144,5 +144,7 @@ export const jsonbBuildObject = <T>(select: JsonFields) => { | ||||
| }; | ||||
| 
 | ||||
| export const isUniqueConstraint = (e: unknown): boolean => { | ||||
| 	return typeof e === "object" && e != null && "code" in e && e.code === "23505"; | ||||
| 	return ( | ||||
| 		typeof e === "object" && e != null && "code" in e && e.code === "23505" | ||||
| 	); | ||||
| }; | ||||
|  | ||||
| @ -13,6 +13,7 @@ export const Resource = () => | ||||
| 		id: t.String({ format: "uuid" }), | ||||
| 		slug: t.String({ format: "slug" }), | ||||
| 	}); | ||||
| export type Resource = ReturnType<typeof Resource>["static"]; | ||||
| 
 | ||||
| const checker = TypeCompiler.Compile(t.String({ format: "uuid" })); | ||||
| export const isUuid = (id: string) => checker.Check(id); | ||||
|  | ||||
| @ -167,10 +167,7 @@ export const Guesses = t.Object({ | ||||
| 	paths: t.Array(t.String()), | ||||
| 	guesses: t.Record( | ||||
| 		t.String(), | ||||
| 		t.Record( | ||||
| 			t.Union([t.Literal("unknown"), t.String({ pattern: "[1-9][0-9]*" })]), | ||||
| 			Resource(), | ||||
| 		), | ||||
| 		t.Record(t.String({ pattern: "^([1-9][0-9]{3})|unknown$" }), Resource()), | ||||
| 	), | ||||
| 	unmatched: t.Array(t.String()), | ||||
| }); | ||||
| @ -188,7 +185,7 @@ registerExamples(Guesses, { | ||||
| 				id: "43b742f5-9ce6-467d-ad29-74460624020a", | ||||
| 				slug: "evangelion", | ||||
| 			}, | ||||
| 			1995: { | ||||
| 			"1995": { | ||||
| 				id: "43b742f5-9ce6-467d-ad29-74460624020a", | ||||
| 				slug: "evangelion", | ||||
| 			}, | ||||
|  | ||||
| @ -17,3 +17,29 @@ export const createVideo = async (video: SeedVideo | SeedVideo[]) => { | ||||
| 	const body = await resp.json(); | ||||
| 	return [resp, body] as const; | ||||
| }; | ||||
| 
 | ||||
| export const getVideos = async () => { | ||||
| 	const resp = await app.handle( | ||||
| 		new Request(buildUrl("videos"), { | ||||
| 			method: "GET", | ||||
| 			headers: await getJwtHeaders(), | ||||
| 		}), | ||||
| 	); | ||||
| 	const body = await resp.json(); | ||||
| 	return [resp, body] as const; | ||||
| }; | ||||
| 
 | ||||
| export const deleteVideo = async (paths: string[]) => { | ||||
| 	const resp = await app.handle( | ||||
| 		new Request(buildUrl("videos"), { | ||||
| 			method: "DELETE", | ||||
| 			body: JSON.stringify(paths), | ||||
| 			headers: { | ||||
| 				"Content-Type": "application/json", | ||||
| 				...(await getJwtHeaders()), | ||||
| 			}, | ||||
| 		}), | ||||
| 	); | ||||
| 	const body = await resp.json(); | ||||
| 	return [resp, body] as const; | ||||
| }; | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| import { db, migrate } from "~/db"; | ||||
| import { profiles, shows } from "~/db/schema"; | ||||
| import { madeInAbyss } from "~/models/examples"; | ||||
| import { createSerie, createVideo } from "./helpers"; | ||||
| import { bubble, madeInAbyss } from "~/models/examples"; | ||||
| import { createMovie, createSerie, createVideo, getVideos } from "./helpers"; | ||||
| 
 | ||||
| // test file used to run manually using `bun tests/manual.ts`
 | ||||
| // run those before running this script
 | ||||
| @ -12,22 +12,42 @@ await migrate(); | ||||
| await db.delete(shows); | ||||
| await db.delete(profiles); | ||||
| 
 | ||||
| const [__, ser] = await createSerie(madeInAbyss); | ||||
| console.log(ser); | ||||
| const [_, body] = await createVideo({ | ||||
| const [_, ser] = await createSerie(madeInAbyss); | ||||
| const [__, mov] = await createMovie(bubble); | ||||
| const [resp, body] = await createVideo([ | ||||
| 	{ | ||||
| 		guess: { title: "mia", season: [1], episode: [13], from: "test" }, | ||||
| 		part: null, | ||||
| 		path: "/video/mia s1e13.mkv", | ||||
| 	rendering: "renderingsha", | ||||
| 		rendering: "sha2", | ||||
| 		version: 1, | ||||
| 	for: [ | ||||
| 		{ | ||||
| 			serie: madeInAbyss.slug, | ||||
| 			season: madeInAbyss.entries[0].seasonNumber!, | ||||
| 			episode: madeInAbyss.entries[0].episodeNumber!, | ||||
| 		for: [{ slug: `${madeInAbyss.slug}-s1e13` }], | ||||
| 	}, | ||||
| 	], | ||||
| }); | ||||
| 	{ | ||||
| 		guess: { | ||||
| 			title: "mia", | ||||
| 			season: [2], | ||||
| 			episode: [1], | ||||
| 			year: [2017], | ||||
| 			from: "test", | ||||
| 		}, | ||||
| 		part: null, | ||||
| 		path: "/video/mia 2017 s2e1.mkv", | ||||
| 		rendering: "sha8", | ||||
| 		version: 1, | ||||
| 		for: [{ slug: `${madeInAbyss.slug}-s2e1` }], | ||||
| 	}, | ||||
| 	{ | ||||
| 		guess: { title: "bubble", from: "test" }, | ||||
| 		part: null, | ||||
| 		path: "/video/bubble.mkv", | ||||
| 		rendering: "sha5", | ||||
| 		version: 1, | ||||
| 		for: [{ movie: bubble.slug }], | ||||
| 	}, | ||||
| ]); | ||||
| console.log(body); | ||||
| const [___, ret] = await getVideos(); | ||||
| console.log(JSON.stringify(ret, undefined, 4)); | ||||
| 
 | ||||
| process.exit(0); | ||||
|  | ||||
							
								
								
									
										154
									
								
								api/tests/videos/getdel.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								api/tests/videos/getdel.test.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,154 @@ | ||||
| import { beforeAll, describe, expect, it } from "bun:test"; | ||||
| import { | ||||
| 	createMovie, | ||||
| 	createSerie, | ||||
| 	createVideo, | ||||
| 	getVideos, | ||||
| } from "tests/helpers"; | ||||
| import { expectStatus } from "tests/utils"; | ||||
| import { db } from "~/db"; | ||||
| import { shows, videos } from "~/db/schema"; | ||||
| import { bubble, madeInAbyss } from "~/models/examples"; | ||||
| 
 | ||||
| beforeAll(async () => { | ||||
| 	await db.delete(shows); | ||||
| 	await db.delete(videos); | ||||
| 
 | ||||
| 	let [ret, body] = await createSerie(madeInAbyss); | ||||
| 	expectStatus(ret, body).toBe(201); | ||||
| 	[ret, body] = await createMovie(bubble); | ||||
| 	expectStatus(ret, body).toBe(201); | ||||
| 
 | ||||
| 	[ret, body] = await createVideo([ | ||||
| 		{ | ||||
| 			guess: { title: "mia", season: [1], episode: [13], from: "test" }, | ||||
| 			part: null, | ||||
| 			path: "/video/mia s1e13.mkv", | ||||
| 			rendering: "sha2", | ||||
| 			version: 1, | ||||
| 			for: [{ slug: `${madeInAbyss.slug}-s1e13` }], | ||||
| 		}, | ||||
| 		{ | ||||
| 			guess: { | ||||
| 				title: "mia", | ||||
| 				season: [2], | ||||
| 				episode: [1], | ||||
| 				year: [2017], | ||||
| 				from: "test", | ||||
| 			}, | ||||
| 			part: null, | ||||
| 			path: "/video/mia 2017 s2e1.mkv", | ||||
| 			rendering: "sha8", | ||||
| 			version: 1, | ||||
| 			for: [{ slug: `${madeInAbyss.slug}-s2e1` }], | ||||
| 		}, | ||||
| 		{ | ||||
| 			guess: { title: "bubble", from: "test" }, | ||||
| 			part: null, | ||||
| 			path: "/video/bubble.mkv", | ||||
| 			rendering: "sha5", | ||||
| 			version: 1, | ||||
| 			for: [{ movie: bubble.slug }], | ||||
| 		}, | ||||
| 	]); | ||||
| 	expectStatus(ret, body).toBe(201); | ||||
| 	expect(body).toBeArrayOfSize(3); | ||||
| 	expect(body[0].entries).toBeArrayOfSize(1); | ||||
| 	expect(body[1].entries).toBeArrayOfSize(1); | ||||
| 	expect(body[2].entries).toBeArrayOfSize(1); | ||||
| }); | ||||
| 
 | ||||
| describe("Video get/deletion", () => { | ||||
| 	it("Get current state", async () => { | ||||
| 		const [resp, body] = await getVideos(); | ||||
| 		expectStatus(resp, body).toBe(200); | ||||
| 		expect(body.guesses).toMatchObject({ | ||||
| 			mia: { | ||||
| 				unknown: { | ||||
| 					id: expect.any(String), | ||||
| 					slug: "made-in-abyss", | ||||
| 				}, | ||||
| 				"2017": { | ||||
| 					id: expect.any(String), | ||||
| 					slug: "made-in-abyss", | ||||
| 				}, | ||||
| 			}, | ||||
| 			bubble: { | ||||
| 				unknown: { | ||||
| 					id: expect.any(String), | ||||
| 					slug: "bubble", | ||||
| 				}, | ||||
| 			}, | ||||
| 		}); | ||||
| 	}); | ||||
| 
 | ||||
| 	it("With unknown", async () => { | ||||
| 		let [resp, body] = await createVideo({ | ||||
| 			guess: { title: "mia", season: [1], episode: [13], from: "test" }, | ||||
| 			part: null, | ||||
| 			path: "/video/mia s1e13 unknown test.mkv", | ||||
| 			rendering: "shanthnth", | ||||
| 			version: 1, | ||||
| 		}); | ||||
| 		expectStatus(resp, body).toBe(201); | ||||
| 
 | ||||
| 		[resp, body] = await getVideos(); | ||||
| 		expectStatus(resp, body).toBe(200); | ||||
| 		expect(body.guesses).toMatchObject({ | ||||
| 			mia: { | ||||
| 				unknown: { | ||||
| 					id: expect.any(String), | ||||
| 					slug: "made-in-abyss", | ||||
| 				}, | ||||
| 				"2017": { | ||||
| 					id: expect.any(String), | ||||
| 					slug: "made-in-abyss", | ||||
| 				}, | ||||
| 			}, | ||||
| 			bubble: { | ||||
| 				unknown: { | ||||
| 					id: expect.any(String), | ||||
| 					slug: "bubble", | ||||
| 				}, | ||||
| 			}, | ||||
| 		}); | ||||
| 		expect(body.unmatched).toBeArrayOfSize(1); | ||||
| 		expect(body.unmatched[0]).toBe("/video/mia s1e13 unknown test.mkv"); | ||||
| 	}); | ||||
| 
 | ||||
| 	it("Mismatch title guess", async () => { | ||||
| 		let [resp, body] = await createVideo({ | ||||
| 			guess: { title: "mia", season: [1], episode: [13], from: "test" }, | ||||
| 			part: null, | ||||
| 			path: "/video/mia s1e13 mismatch.mkv", | ||||
| 			rendering: "mismatch", | ||||
| 			version: 1, | ||||
| 			for: [{ movie: "bubble" }], | ||||
| 		}); | ||||
| 		expectStatus(resp, body).toBe(201); | ||||
| 
 | ||||
| 		[resp, body] = await getVideos(); | ||||
| 		expectStatus(resp, body).toBe(200); | ||||
| 		expect(body.guesses).toMatchObject({ | ||||
| 			mia: { | ||||
| 				unknown: { | ||||
| 					id: expect.any(String), | ||||
| 					// take the latest slug
 | ||||
| 					slug: "bubble", | ||||
| 				}, | ||||
| 				"2017": { | ||||
| 					id: expect.any(String), | ||||
| 					slug: "made-in-abyss", | ||||
| 				}, | ||||
| 			}, | ||||
| 			bubble: { | ||||
| 				unknown: { | ||||
| 					id: expect.any(String), | ||||
| 					slug: "bubble", | ||||
| 				}, | ||||
| 			}, | ||||
| 		}); | ||||
| 	}); | ||||
| 
 | ||||
| 	it.todo("Delete video", async () => {}); | ||||
| }); | ||||
| @ -8,7 +8,6 @@ import { bubble, madeInAbyss } from "~/models/examples"; | ||||
| 
 | ||||
| beforeAll(async () => { | ||||
| 	await db.delete(shows); | ||||
| 	await db.delete(entries); | ||||
| 	await db.delete(videos); | ||||
| 	let [ret, body] = await createSerie(madeInAbyss); | ||||
| 	expectStatus(ret, body).toBe(201); | ||||
| @ -358,7 +357,6 @@ describe("Video seeding", () => { | ||||
| 		expect(body.message).toBeString(); | ||||
| 	}); | ||||
| 
 | ||||
| 
 | ||||
| 	it("Two for the same entry", async () => { | ||||
| 		const [resp, body] = await createVideo({ | ||||
| 			guess: { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user