diff --git a/back/src/Kyoo.Abstractions/Models/Resources/User.cs b/back/src/Kyoo.Abstractions/Models/Resources/User.cs
index b4f9913a..f0461775 100644
--- a/back/src/Kyoo.Abstractions/Models/Resources/User.cs
+++ b/back/src/Kyoo.Abstractions/Models/Resources/User.cs
@@ -17,7 +17,6 @@
// along with Kyoo. If not, see .
using System;
-using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models.Attributes;
diff --git a/back/src/Kyoo.Authentication/Views/AuthApi.cs b/back/src/Kyoo.Authentication/Views/AuthApi.cs
index 3de4f0e0..e14b5889 100644
--- a/back/src/Kyoo.Authentication/Views/AuthApi.cs
+++ b/back/src/Kyoo.Authentication/Views/AuthApi.cs
@@ -18,7 +18,6 @@
using System;
using System.Linq;
-using System.Security.Claims;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
diff --git a/back/src/Kyoo.Core/Views/Helper/Serializers/JsonSerializerContract.cs b/back/src/Kyoo.Core/Views/Helper/Serializers/JsonSerializerContract.cs
index 0aad78b4..10248071 100644
--- a/back/src/Kyoo.Core/Views/Helper/Serializers/JsonSerializerContract.cs
+++ b/back/src/Kyoo.Core/Views/Helper/Serializers/JsonSerializerContract.cs
@@ -25,6 +25,7 @@ using Kyoo.Abstractions.Models.Attributes;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
+using static System.Text.Json.JsonNamingPolicy;
namespace Kyoo.Core.Api
{
@@ -99,7 +100,7 @@ namespace Kyoo.Core.Api
PropertyName = "kind",
UnderlyingName = "kind",
PropertyType = typeof(string),
- ValueProvider = new FixedValueProvider(type.Name),
+ ValueProvider = new FixedValueProvider(CamelCase.ConvertName(type.Name)),
Readable = true,
Writable = false,
TypeNameHandling = TypeNameHandling.None,
diff --git a/front/packages/models/src/accounts.tsx b/front/packages/models/src/accounts.tsx
index c603d614..6fd1961d 100644
--- a/front/packages/models/src/accounts.tsx
+++ b/front/packages/models/src/accounts.tsx
@@ -19,7 +19,7 @@
*/
import { ReactNode, createContext, useContext, useEffect, useMemo, useRef } from "react";
-import { UserP } from "./resources";
+import { User, UserP } from "./resources";
import { z } from "zod";
import { zdate } from "./utils";
import { removeAccounts, setAccountCookie, updateAccount } from "./account-internal";
@@ -38,13 +38,13 @@ export const TokenP = z.object({
});
export type Token = z.infer;
-export const AccountP = UserP.and(
- z.object({
- token: TokenP,
- apiUrl: z.string(),
- selected: z.boolean(),
- }),
-);
+export const AccountP = UserP.merge(z.object({
+ // set it optional for accounts logged in before the kind was present
+ kind: z.literal("user").optional(),
+ token: TokenP,
+ apiUrl: z.string(),
+ selected: z.boolean(),
+}));
export type Account = z.infer;
const AccountContext = createContext<(Account & { select: () => void; remove: () => void })[]>([]);
@@ -100,7 +100,7 @@ export const AccountProvider = ({
const user = useFetch({
path: ["auth", "me"],
parser: UserP,
- placeholderData: selected,
+ placeholderData: selected as User,
enabled: !!selected,
timeout: 5_000,
});
diff --git a/front/packages/models/src/resources/collection.ts b/front/packages/models/src/resources/collection.ts
index 2e7c1cc1..41954fc7 100644
--- a/front/packages/models/src/resources/collection.ts
+++ b/front/packages/models/src/resources/collection.ts
@@ -22,7 +22,7 @@ import { z } from "zod";
import { withImages, ResourceP } from "../traits";
export const CollectionP = withImages(
- ResourceP.extend({
+ ResourceP("collection").extend({
/**
* The title of this collection.
*/
@@ -31,8 +31,7 @@ export const CollectionP = withImages(
* The summary of this show.
*/
overview: z.string().nullable(),
- }),
- "collections",
+ })
).transform((x) => ({
...x,
href: `/collection/${x.slug}`,
diff --git a/front/packages/models/src/resources/episode.base.ts b/front/packages/models/src/resources/episode.base.ts
index 6da1d810..ab6907d3 100644
--- a/front/packages/models/src/resources/episode.base.ts
+++ b/front/packages/models/src/resources/episode.base.ts
@@ -24,7 +24,7 @@ import { withImages, imageFn } from "../traits";
import { ResourceP } from "../traits/resource";
export const BaseEpisodeP = withImages(
- ResourceP.extend({
+ ResourceP("episode").extend({
/**
* The season in witch this episode is in.
*/
@@ -72,7 +72,6 @@ export const BaseEpisodeP = withImages(
*/
showId: z.string(),
}),
- "episodes",
)
.transform((x) => ({
...x,
diff --git a/front/packages/models/src/resources/library-item.ts b/front/packages/models/src/resources/library-item.ts
index d3f648b7..aab0ab11 100644
--- a/front/packages/models/src/resources/library-item.ts
+++ b/front/packages/models/src/resources/library-item.ts
@@ -23,28 +23,19 @@ import { CollectionP } from "./collection";
import { MovieP } from "./movie";
import { ShowP } from "./show";
-/**
- * The type of item, ether a show, a movie or a collection.
- */
-export enum ItemKind {
- Show = "Show",
- Movie = "Movie",
- Collection = "Collection",
-}
-
export const LibraryItemP = z.union([
/*
* Either a Show
*/
- ShowP.and(z.object({ kind: z.literal(ItemKind.Show) })),
+ ShowP,
/*
* Or a Movie
*/
- MovieP.and(z.object({ kind: z.literal(ItemKind.Movie) })),
+ MovieP,
/*
* Or a Collection
*/
- CollectionP.and(z.object({ kind: z.literal(ItemKind.Collection) })),
+ CollectionP,
]);
/**
diff --git a/front/packages/models/src/resources/movie.ts b/front/packages/models/src/resources/movie.ts
index c0d1ae35..d2343876 100644
--- a/front/packages/models/src/resources/movie.ts
+++ b/front/packages/models/src/resources/movie.ts
@@ -29,7 +29,7 @@ import { MetadataP } from "./metadata";
import { WatchStatusP } from "./watch-status";
export const MovieP = withImages(
- ResourceP.extend({
+ ResourceP("movie").extend({
/**
* The title of this movie.
*/
@@ -105,7 +105,6 @@ export const MovieP = withImages(
*/
watchStatus: WatchStatusP.optional().nullable(),
}),
- "movies",
)
.transform((x) => ({
...x,
diff --git a/front/packages/models/src/resources/news.ts b/front/packages/models/src/resources/news.ts
index f27d21a4..30f724a7 100644
--- a/front/packages/models/src/resources/news.ts
+++ b/front/packages/models/src/resources/news.ts
@@ -22,23 +22,15 @@ import { z } from "zod";
import { MovieP } from "./movie";
import { EpisodeP } from "./episode";
-/**
- * The type of item, ether a a movie or an episode.
- */
-export enum NewsKind {
- Episode = "Episode",
- Movie = "Movie",
-}
-
export const NewsP = z.union([
/*
* Either an episode
*/
- EpisodeP.and(z.object({ kind: z.literal(NewsKind.Episode) })),
+ EpisodeP,
/*
* Or a Movie
*/
- MovieP.and(z.object({ kind: z.literal(NewsKind.Movie) })),
+ MovieP,
]);
/**
diff --git a/front/packages/models/src/resources/person.ts b/front/packages/models/src/resources/person.ts
index 5f3f3872..00994383 100644
--- a/front/packages/models/src/resources/person.ts
+++ b/front/packages/models/src/resources/person.ts
@@ -23,7 +23,7 @@ import { withImages } from "../traits";
import { ResourceP } from "../traits/resource";
export const PersonP = withImages(
- ResourceP.extend({
+ ResourceP("people").extend({
/**
* The name of this person.
*/
@@ -40,7 +40,6 @@ export const PersonP = withImages(
*/
role: z.string().optional(),
}),
- "people",
);
/**
diff --git a/front/packages/models/src/resources/season.ts b/front/packages/models/src/resources/season.ts
index 99edb3b1..839e1519 100644
--- a/front/packages/models/src/resources/season.ts
+++ b/front/packages/models/src/resources/season.ts
@@ -24,7 +24,7 @@ import { withImages } from "../traits";
import { ResourceP } from "../traits/resource";
export const SeasonP = withImages(
- ResourceP.extend({
+ ResourceP("season").extend({
/**
* The name of this season.
*/
@@ -50,7 +50,6 @@ export const SeasonP = withImages(
*/
episodesCount: z.number(),
}),
- "seasons",
);
/**
diff --git a/front/packages/models/src/resources/show.ts b/front/packages/models/src/resources/show.ts
index 7c5fce74..9275751a 100644
--- a/front/packages/models/src/resources/show.ts
+++ b/front/packages/models/src/resources/show.ts
@@ -22,10 +22,8 @@ import { z } from "zod";
import { zdate } from "../utils";
import { withImages, ResourceP } from "../traits";
import { Genre } from "./genre";
-import { SeasonP } from "./season";
import { StudioP } from "./studio";
import { BaseEpisodeP } from "./episode.base";
-import { CollectionP } from "./collection";
import { MetadataP } from "./metadata";
import { ShowWatchStatusP } from "./watch-status";
@@ -40,7 +38,7 @@ export enum Status {
}
export const ShowP = withImages(
- ResourceP.extend({
+ ResourceP("show").extend({
/**
* The title of this show.
*/
@@ -106,7 +104,6 @@ export const ShowP = withImages(
*/
episodesCount: z.number().int().gte(0).optional(),
}),
- "shows",
)
.transform((x) => {
if (!x.thumbnail && x.poster) {
diff --git a/front/packages/models/src/resources/studio.ts b/front/packages/models/src/resources/studio.ts
index ae29f283..15330a53 100644
--- a/front/packages/models/src/resources/studio.ts
+++ b/front/packages/models/src/resources/studio.ts
@@ -21,7 +21,7 @@
import { z } from "zod";
import { ResourceP } from "../traits/resource";
-export const StudioP = ResourceP.extend({
+export const StudioP = ResourceP("studio").extend({
/**
* The name of this studio.
*/
diff --git a/front/packages/models/src/resources/user.ts b/front/packages/models/src/resources/user.ts
index ff37697a..e63b4c74 100644
--- a/front/packages/models/src/resources/user.ts
+++ b/front/packages/models/src/resources/user.ts
@@ -21,10 +21,7 @@
import { z } from "zod";
import { ResourceP } from "../traits/resource";
-/**
- * The library that will contain Shows, Collections...
- */
-export const UserP = ResourceP.extend({
+export const UserP = ResourceP("user").extend({
/**
* The name of this user.
*/
diff --git a/front/packages/models/src/resources/watchlist.ts b/front/packages/models/src/resources/watchlist.ts
index fd533afc..3f6e0e4e 100644
--- a/front/packages/models/src/resources/watchlist.ts
+++ b/front/packages/models/src/resources/watchlist.ts
@@ -22,23 +22,15 @@ import { z } from "zod";
import { MovieP } from "./movie";
import { ShowP } from "./show";
-/**
- * The type of item, ether a show, a movie or an episode.
- */
-export enum WatchlistKind {
- Show = "Show",
- Movie = "Movie",
-}
-
export const WatchlistP = z.union([
/*
* Either a show
*/
- ShowP.and(z.object({ kind: z.literal(WatchlistKind.Show) })),
+ ShowP,
/*
* Or a Movie
*/
- MovieP.and(z.object({ kind: z.literal(WatchlistKind.Movie) })),
+ MovieP,
]);
/**
diff --git a/front/packages/models/src/traits/images.ts b/front/packages/models/src/traits/images.ts
index ef77b67c..f7978d8f 100644
--- a/front/packages/models/src/traits/images.ts
+++ b/front/packages/models/src/traits/images.ts
@@ -62,13 +62,13 @@ const addQualities = (x: object | null | undefined, href: string) => {
};
};
-export const withImages = (parser: ZodObject, type: string) => {
+export const withImages = (parser: ZodObject) => {
return parser.merge(ImagesP).transform((x) => {
return {
...x,
- poster: addQualities(x.poster, `/${type}/${x.slug}/poster`),
- thumbnail: addQualities(x.thumbnail, `/${type}/${x.slug}/thumbnail`),
- logo: addQualities(x.logo, `/${type}/${x.slug}/logo`),
+ poster: addQualities(x.poster, `/${x.kind}/${x.slug}/poster`),
+ thumbnail: addQualities(x.thumbnail, `/${x.kind}/${x.slug}/thumbnail`),
+ logo: addQualities(x.logo, `/${x.kind}/${x.slug}/logo`),
};
});
};
diff --git a/front/packages/models/src/traits/resource.ts b/front/packages/models/src/traits/resource.ts
index 8377d716..87833f19 100644
--- a/front/packages/models/src/traits/resource.ts
+++ b/front/packages/models/src/traits/resource.ts
@@ -20,20 +20,26 @@
import { z } from "zod";
-export const ResourceP = z.object({
- /**
- * A unique ID for this type of resource. This can't be changed and duplicates are not allowed.
- */
- id: z.string(),
+export const ResourceP = (kind: T) =>
+ z.object({
+ /**
+ * A unique ID for this type of resource. This can't be changed and duplicates are not allowed.
+ */
+ id: z.string(),
- /**
- * A human-readable identifier that can be used instead of an ID. A slug must be unique for a type
- * of resource but it can be changed.
- */
- slug: z.string(),
-});
+ /**
+ * A human-readable identifier that can be used instead of an ID. A slug must be unique for a type
+ * of resource but it can be changed.
+ */
+ slug: z.string(),
+
+ /**
+ * The type of resource
+ */
+ kind: z.literal(kind),
+ });
/**
* The base trait used to represent identifiable resources.
*/
-export type Resource = z.infer;
+export type Resource = z.infer>;
diff --git a/front/packages/primitives/src/image/index.tsx b/front/packages/primitives/src/image/index.tsx
index 61f0ba67..a7dfdf48 100644
--- a/front/packages/primitives/src/image/index.tsx
+++ b/front/packages/primitives/src/image/index.tsx
@@ -71,7 +71,7 @@ export const ImageBackground = ({
}: {
as?: ComponentType;
gradient?: Partial | boolean;
- children: ReactNode;
+ children?: ReactNode;
containerStyle?: YoshikiEnhanced;
imageStyle?: YoshikiEnhanced;
hideLoad?: boolean;
diff --git a/front/packages/ui/src/browse/index.tsx b/front/packages/ui/src/browse/index.tsx
index ea28fd42..fab7aa09 100644
--- a/front/packages/ui/src/browse/index.tsx
+++ b/front/packages/ui/src/browse/index.tsx
@@ -23,7 +23,6 @@ import {
QueryPage,
LibraryItem,
LibraryItemP,
- ItemKind,
getDisplayDate,
} from "@kyoo/models";
import { ComponentProps, useState } from "react";
@@ -47,16 +46,16 @@ export const itemMap = (
isLoading: item.isLoading,
slug: item.slug,
name: item.name,
- subtitle: item.kind !== ItemKind.Collection ? getDisplayDate(item) : undefined,
+ subtitle: item.kind !== "collection" ? getDisplayDate(item) : undefined,
href: item.href,
poster: item.poster,
thumbnail: item.thumbnail,
- watchStatus: item.kind !== ItemKind.Collection ? item.watchStatus?.status ?? null : null,
- type: item.kind.toLowerCase() as any,
+ watchStatus: item.kind !== "collection" ? item.watchStatus?.status ?? null : null,
+ type: item.kind,
watchPercent:
- item.kind !== ItemKind.Collection ? item.watchStatus?.watchedPercent ?? null : null,
+ item.kind !== "collection" ? item.watchStatus?.watchedPercent ?? null : null,
unseenEpisodesCount:
- item.kind === ItemKind.Show
+ item.kind === "show"
? item.watchStatus?.unseenEpisodesCount ?? item.episodesCount!
: null,
};
diff --git a/front/packages/ui/src/collection/index.tsx b/front/packages/ui/src/collection/index.tsx
index 2eda6cae..1a6e0326 100644
--- a/front/packages/ui/src/collection/index.tsx
+++ b/front/packages/ui/src/collection/index.tsx
@@ -21,7 +21,6 @@
import {
Collection,
CollectionP,
- ItemKind,
LibraryItem,
LibraryItemP,
QueryIdentifier,
@@ -161,20 +160,20 @@ export const CollectionPage: QueryPage<{ slug: string }> = ({ slug }) => {
diff --git a/front/packages/ui/src/details/episode.tsx b/front/packages/ui/src/details/episode.tsx
index 5f0bc35a..88244724 100644
--- a/front/packages/ui/src/details/episode.tsx
+++ b/front/packages/ui/src/details/episode.tsx
@@ -37,7 +37,7 @@ import { percent, rem, Stylable, Theme, useYoshiki } from "yoshiki/native";
import { KyooImage, WatchStatusV } from "@kyoo/models";
import { ItemProgress } from "../browse/grid";
import { EpisodesContext } from "../components/context-menus";
-import { useRef, useState } from "react";
+import { useState } from "react";
export const episodeDisplayNumber = (
episode: {
diff --git a/front/packages/ui/src/home/index.tsx b/front/packages/ui/src/home/index.tsx
index 67fdc160..b92e0b07 100644
--- a/front/packages/ui/src/home/index.tsx
+++ b/front/packages/ui/src/home/index.tsx
@@ -18,7 +18,7 @@
* along with Kyoo. If not, see .
*/
-import { Genre, ItemKind, QueryPage } from "@kyoo/models";
+import { Genre, QueryPage } from "@kyoo/models";
import { Fetch } from "../fetch";
import { Header } from "./header";
import { DefaultLayout } from "../layout";
@@ -40,7 +40,7 @@ export const HomePage: QueryPage<{}, Genre> = ({ randomItems }) => {
tagline={"tagline" in x ? x.tagline : null}
overview={x.overview}
thumbnail={x.thumbnail}
- link={x.kind !== ItemKind.Collection && !x.isLoading ? x.playHref : undefined}
+ link={x.kind !== "collection" && !x.isLoading ? x.playHref : undefined}
infoLink={x.href}
/>
)}
diff --git a/front/packages/ui/src/home/news.tsx b/front/packages/ui/src/home/news.tsx
index a7a6bb98..45202f62 100644
--- a/front/packages/ui/src/home/news.tsx
+++ b/front/packages/ui/src/home/news.tsx
@@ -18,7 +18,7 @@
* along with Kyoo. If not, see .
*/
-import { News, NewsKind, NewsP, QueryIdentifier, getDisplayDate } from "@kyoo/models";
+import { News, NewsP, QueryIdentifier, getDisplayDate } from "@kyoo/models";
import { ItemGrid } from "../browse/grid";
import { InfiniteFetch } from "../fetch-infinite";
import { useTranslation } from "react-i18next";
@@ -37,13 +37,13 @@ export const NewsList = () => {
query={NewsList.query()}
layout={{ ...ItemGrid.layout, layout: "horizontal" }}
getItemType={(x, i) =>
- x.kind === NewsKind.Movie || (x.isLoading && i % 2) ? "movie" : "episode"
+ x.kind === "movie" || (x.isLoading && i % 2) ? "movie" : "episode"
}
getItemSize={(kind) => (kind === "episode" ? 2 : 1)}
empty={t("home.none")}
>
{(x, i) =>
- x.kind === NewsKind.Movie || (x.isLoading && i % 2) ? (
+ x.kind === "movie" || (x.isLoading && i % 2) ? (
{
{
)}
diff --git a/front/packages/ui/src/home/watchlist.tsx b/front/packages/ui/src/home/watchlist.tsx
index 8f21d2f6..544f6192 100644
--- a/front/packages/ui/src/home/watchlist.tsx
+++ b/front/packages/ui/src/home/watchlist.tsx
@@ -21,7 +21,6 @@
import {
QueryIdentifier,
Watchlist,
- WatchlistKind,
WatchlistP,
getDisplayDate,
useAccount,
@@ -48,7 +47,7 @@ export const WatchlistList = () => {
query={WatchlistList.query()}
layout={{ ...ItemGrid.layout, layout: "horizontal" }}
getItemType={(x, i) =>
- (x.kind === WatchlistKind.Show && x.watchStatus?.nextEpisode) || (x.isLoading && i % 2)
+ (x.kind === "show" && x.watchStatus?.nextEpisode) || (x.isLoading && i % 2)
? "episode"
: "item"
}
@@ -56,8 +55,8 @@ export const WatchlistList = () => {
empty={t("home.none")}
>
{(x, i) => {
- const episode = x.kind === WatchlistKind.Show ? x.watchStatus?.nextEpisode : null;
- return (x.kind === WatchlistKind.Show && x.watchStatus?.nextEpisode) ||
+ const episode = x.kind === "show" ? x.watchStatus?.nextEpisode : null;
+ return (x.kind === "show" && x.watchStatus?.nextEpisode) ||
(x.isLoading && i % 2) ? (
{
watchStatus={x.watchStatus?.status || null}
watchPercent={x.watchStatus?.watchedPercent || null}
unseenEpisodesCount={
- x.kind === WatchlistKind.Show ? x.watchStatus?.unseenEpisodesCount : null
+ x.kind === "show" ? x.watchStatus?.unseenEpisodesCount : null
}
- type={x.kind === WatchlistKind.Movie ? "movie" : "show"}
+ type={x.kind}
/>
);
}}