mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -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({
|
||||
guess: { title: "mia", season: [1], episode: [13], from: "test" },
|
||||
part: null,
|
||||
path: "/video/mia s1e13.mkv",
|
||||
rendering: "renderingsha",
|
||||
version: 1,
|
||||
for: [
|
||||
{
|
||||
serie: madeInAbyss.slug,
|
||||
season: madeInAbyss.entries[0].seasonNumber!,
|
||||
episode: madeInAbyss.entries[0].episodeNumber!,
|
||||
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: "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 }],
|
||||
},
|
||||
]);
|
||||
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