Fix identify

This commit is contained in:
Zoe Roux 2025-05-13 23:22:54 +02:00
parent e8deee8e33
commit a821b97286
No known key found for this signature in database
6 changed files with 33 additions and 26 deletions

View File

@ -1,37 +1,37 @@
import { PatternStringExact } from "@sinclair/typebox"; import { PatternStringExact, type TSchema } from "@sinclair/typebox";
import { t } from "elysia"; import { t } from "elysia";
import { type Prettify, comment } from "~/utils"; import { type Prettify, comment } from "~/utils";
import { ExtraType } from "./entry/extra"; import { ExtraType } from "./entry/extra";
import { bubble, bubbleVideo, registerExamples } from "./examples"; import { bubble, bubbleVideo, registerExamples } from "./examples";
import { DbMetadata, EpisodeId, ExternalId, Resource } from "./utils"; import { DbMetadata, EpisodeId, ExternalId, Resource } from "./utils";
const Opt = (schema: TSchema) => t.Optional(t.Nullable(schema));
export const Guess = t.Recursive((Self) => export const Guess = t.Recursive((Self) =>
t.Object( t.Object(
{ {
title: t.String(), title: t.String(),
kind: t.Optional(t.UnionEnum(["episode", "movie", "extra"])), kind: Opt(t.UnionEnum(["episode", "movie", "extra"])),
extraKind: t.Optional(ExtraType), extraKind: Opt(ExtraType),
years: t.Optional(t.Array(t.Integer(), { default: [] })), years: Opt(t.Array(t.Integer(), { default: [] })),
episodes: t.Optional( episodes: Opt(
t.Array( t.Array(
t.Object({ season: t.Nullable(t.Integer()), episode: t.Integer() }), t.Object({ season: t.Nullable(t.Integer()), episode: t.Integer() }),
{ default: [] }, { default: [] },
), ),
), ),
externalId: t.Optional(t.Record(t.String(), t.String())), externalId: Opt(t.Record(t.String(), t.String())),
from: t.String({ from: t.String({
description: "Name of the tool that made the guess", description: "Name of the tool that made the guess",
}), }),
history: t.Optional( history: t.Array(t.Omit(Self, ["history"]), {
t.Array(t.Omit(Self, ["history"]), { default: [],
default: [], description: comment`
description: comment` When another tool refines the guess or a user manually edit it, the history of the guesses
When another tool refines the guess or a user manually edit it, the history of the guesses are kept in this \`history\` value.
are kept in this \`history\` value. `,
`, }),
}),
),
}, },
{ {
additionalProperties: true, additionalProperties: true,

View File

@ -1,6 +1,6 @@
# Scanner # Scanner
## Workflow (for v5, not current) ## Workflow
In order of action: In order of action:

View File

@ -3,6 +3,7 @@ from logging import getLogger
from types import TracebackType from types import TracebackType
from aiohttp import ClientSession from aiohttp import ClientSession
from pydantic import TypeAdapter
from scanner.utils import Singleton from scanner.utils import Singleton
@ -44,15 +45,15 @@ class KyooClient(metaclass=Singleton):
async def create_videos(self, videos: list[Video]) -> list[VideoCreated]: async def create_videos(self, videos: list[Video]) -> list[VideoCreated]:
async with self._client.post( async with self._client.post(
"videos", "videos",
json=[x.model_dump_json() for x in videos], data=TypeAdapter(list[Video]).dump_json(videos, by_alias=True),
) as r: ) as r:
r.raise_for_status() r.raise_for_status()
return list[VideoCreated](**await r.json()) return TypeAdapter(list[VideoCreated]).validate_json(await r.text())
async def delete_videos(self, videos: list[str] | set[str]): async def delete_videos(self, videos: list[str] | set[str]):
async with self._client.delete( async with self._client.delete(
"videos", "videos",
json=videos, data=TypeAdapter(list[str] | set[str]).dump_json(videos, by_alias=True),
) as r: ) as r:
r.raise_for_status() r.raise_for_status()

View File

@ -4,6 +4,8 @@ from itertools import zip_longest
from logging import getLogger from logging import getLogger
from typing import Callable, Literal, cast from typing import Callable, Literal, cast
from rebulk.match import Match
from ..models.videos import Guess, Video from ..models.videos import Guess, Video
from .guess.guess import guessit from .guess.guess import guessit
@ -49,12 +51,15 @@ async def identify(path: str) -> Video:
for s, e in zip_longest( for s, e in zip_longest(
seasons, seasons,
episodes, episodes,
fillvalue=seasons[-1] if len(seasons) < len(episodes) else episodes[-1], fillvalue=seasons[-1] if any(seasons) else Match(0, 0, value=1),
) )
], ],
external_id={}, external_id={},
from_="guessit", from_="guessit",
raw={k: [x.value for x in v] for k, v in raw.items()}, raw={
k: [x.value if x.value is int else str(x.value) for x in v]
for k, v in raw.items()
},
) )
for step in pipeline: for step in pipeline:

View File

@ -73,6 +73,8 @@ class Video(Model):
] = [] ] = []
class VideoCreated(Resource): class VideoCreated(Model):
id: str
path: str
guess: Guess guess: Guess
entries: list[Resource] entries: list[Resource]

View File

@ -2,7 +2,7 @@ from abc import ABCMeta
from typing import Annotated, Any, Callable, override from typing import Annotated, Any, Callable, override
from langcodes import Language as BaseLanguage from langcodes import Language as BaseLanguage
from pydantic import AliasGenerator, BaseModel, ConfigDict, GetJsonSchemaHandler from pydantic import BaseModel, ConfigDict, GetJsonSchemaHandler
from pydantic.alias_generators import to_camel from pydantic.alias_generators import to_camel
from pydantic.json_schema import JsonSchemaValue from pydantic.json_schema import JsonSchemaValue
from pydantic_core import core_schema from pydantic_core import core_schema
@ -29,9 +29,8 @@ class Singleton(ABCMeta, type):
class Model(BaseModel): class Model(BaseModel):
model_config = ConfigDict( model_config = ConfigDict(
use_enum_values=True, use_enum_values=True,
alias_generator=AliasGenerator( validate_by_name=True,
serialization_alias=lambda x: to_camel(x[:-1] if x[-1] == "_" else x), alias_generator=lambda x: to_camel(x[:-1] if x[-1] == "_" else x),
),
) )