Add show info on news episode, Add news on the front

This commit is contained in:
Zoe Roux 2023-10-30 01:21:52 +01:00
parent 5a6bb57fd5
commit 56a96540b4
14 changed files with 244 additions and 9 deletions

View File

@ -135,6 +135,12 @@ namespace Kyoo.Abstractions.Models
/// </summary>
public int? AbsoluteNumber { get; set; }
/// <summary>
/// A simple summary of informations about the show of this episode
/// (this is specially useful since news can't have includes).
/// </summary>
public ShowInfo? Show { get; set; }
/// <summary>
/// Is the item a a movie or an episode?
/// </summary>
@ -148,5 +154,23 @@ namespace Kyoo.Abstractions.Models
Direct = $"/video/{Kind.ToString().ToLower()}/{Slug}/direct",
Hls = $"/video/{Kind.ToString().ToLower()}/{Slug}/master.m3u8",
};
/// <summary>
/// A simple summary of informations about the show of this episode
/// (this is specially useful since news can't have includes).
/// </summary>
public class ShowInfo : IResource
{
/// <inheritdoc/>
public int Id { get; set; }
/// <inheritdoc/>
public string Slug { get; set; }
/// <summary>
/// The title of this show.
/// </summary>
public string Name { get; set; }
}
}
}

View File

@ -19,7 +19,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models.Attributes;
using Kyoo.Utils;
using Newtonsoft.Json;

View File

@ -360,6 +360,9 @@ namespace Kyoo.Postgresql
.Ignore(x => x.Links);
modelBuilder.Entity<News>()
.Ignore(x => x.Links);
modelBuilder.Entity<News>()
.OwnsOne(x => x.Show);
}
/// <summary>

View File

@ -1275,10 +1275,41 @@ namespace Kyoo.Postgresql.Migrations
.HasConstraintName("fk_news_news_id");
});
b.OwnsOne("Kyoo.Abstractions.Models.ShowInfo", "Show", b1 =>
{
b1.Property<int>("NewsId")
.HasColumnType("integer")
.HasColumnName("id");
b1.Property<int>("Id")
.HasColumnType("integer")
.HasColumnName("show_info_id");
b1.Property<string>("Name")
.IsRequired()
.HasColumnType("text")
.HasColumnName("show_info_name");
b1.Property<string>("Slug")
.IsRequired()
.HasColumnType("text")
.HasColumnName("show_info_slug");
b1.HasKey("NewsId");
b1.ToTable("news");
b1.WithOwner()
.HasForeignKey("NewsId")
.HasConstraintName("fk_news_news_id");
});
b.Navigation("Logo");
b.Navigation("Poster");
b.Navigation("Show");
b.Navigation("Thumbnail");
});

View File

@ -38,14 +38,15 @@ namespace Kyoo.Postgresql.Migrations
e.id, e.slug, e.name, NULL AS tagline, '{}' AS aliases, e.path, e.overview, '{}' AS tags, '{}' AS genres,
NULL AS status, e.release_date AS air_date, e.poster_source, e.poster_blurhash, e.thumbnail_source, e.thumbnail_blurhash,
e.logo_source,e.logo_blurhash, NULL AS trailer, e.external_id, e.season_number, e.episode_number, e.absolute_number,
'episode'::news_kind AS kind, e.added_date
'episode'::news_kind AS kind, e.added_date, s.id AS show_id, s.slug AS show_slug, s.name AS show_name
FROM episodes AS e
LEFT JOIN shows AS s ON e.show_id = s.id
UNION ALL
SELECT
-m.id, m.slug, m.name, m.tagline, m.aliases, m.path, m.overview, m.tags, m.genres,
m.status, m.air_date, m.poster_source, m.poster_blurhash, m.thumbnail_source, m.thumbnail_blurhash,
m.logo_source, m.logo_blurhash, m.trailer, m.external_id, NULL AS season_number, NULL AS episode_number, NULL as absolute_number,
'movie'::news_kind AS kind, m.added_date
'movie'::news_kind AS kind, m.added_date, NULL AS show_id, NULL AS show_slug, NULL AS show_name
FROM movies AS m
");
}

View File

@ -1,4 +1,4 @@
// <auto-generated />
// <auto-generated />
using System;
using System.Collections.Generic;
using Kyoo.Abstractions.Models;
@ -1272,10 +1272,41 @@ namespace Kyoo.Postgresql.Migrations
.HasConstraintName("fk_news_news_id");
});
b.OwnsOne("Kyoo.Abstractions.Models.ShowInfo", "Show", b1 =>
{
b1.Property<int>("NewsId")
.HasColumnType("integer")
.HasColumnName("id");
b1.Property<int>("Id")
.HasColumnType("integer")
.HasColumnName("show_info_id");
b1.Property<string>("Name")
.IsRequired()
.HasColumnType("text")
.HasColumnName("show_info_name");
b1.Property<string>("Slug")
.IsRequired()
.HasColumnType("text")
.HasColumnName("show_info_slug");
b1.HasKey("NewsId");
b1.ToTable("news");
b1.WithOwner()
.HasForeignKey("NewsId")
.HasConstraintName("fk_news_news_id");
});
b.Navigation("Logo");
b.Navigation("Poster");
b.Navigation("Show");
b.Navigation("Thumbnail");
});

View File

@ -24,7 +24,7 @@ import { withImages, imageFn } from "../traits";
import { ResourceP } from "../traits/resource";
import { ShowP } from "./show";
const BaseEpisodeP = withImages(
export const BaseEpisodeP = withImages(
ResourceP.extend({
/**
* The season in witch this episode is in.
@ -73,7 +73,10 @@ const BaseEpisodeP = withImages(
}),
}),
"episodes",
);
).transform((x) => ({
...x,
href: `/watch/${x.slug}`,
}));
export const EpisodeP = BaseEpisodeP.and(
z.object({

View File

@ -19,6 +19,7 @@
*/
export * from "./library-item";
export * from "./news";
export * from "./show";
export * from "./movie";
export * from "./collection";

View File

@ -0,0 +1,55 @@
/*
* Kyoo - A portable and vast media library solution.
* Copyright (c) Kyoo.
*
* See AUTHORS.md and LICENSE file in the project root for full license information.
*
* Kyoo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* Kyoo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
*/
import { z } from "zod";
import { MovieP } from "./movie";
import { BaseEpisodeP } from "./episode";
import { ResourceP } from "../traits/resource";
/**
* 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
*/
BaseEpisodeP.and(
z.object({
kind: z.literal(NewsKind.Episode),
show: ResourceP.extend({
name: z.string(),
}),
}),
),
/*
* Or a Movie
*/
MovieP.and(z.object({ kind: z.literal(NewsKind.Movie) })),
]);
/**
* A new item added to kyoo.
*/
export type News = z.infer<typeof NewsP>;

View File

@ -77,7 +77,6 @@ export const GenreGrid = ({ genre }: { genre: Genre }) => {
query={query}
layout={{ ...ItemGrid.layout, layout: "horizontal" }}
empty={displayEmpty.current ? t("home.none") : undefined}
headerProps={{ title: genre, displayEmpty: displayEmpty.current }}
>
{(x, i) => {
// only display empty list if a loading as been displayed (not durring ssr)

View File

@ -22,10 +22,11 @@ import { Genre, ItemKind, QueryPage } from "@kyoo/models";
import { Fetch } from "../fetch";
import { Header } from "./header";
import { DefaultLayout } from "../layout";
import { ScrollView, View } from "react-native";
import { ScrollView } from "react-native";
import { GenreGrid } from "./genre";
import { Recommanded } from "./recommanded";
import { VerticalRecommanded } from "./vertical";
import { NewsList } from "./news";
export const HomePage: QueryPage<{}, Genre> = ({ randomItems }) => {
return (
@ -43,7 +44,7 @@ export const HomePage: QueryPage<{}, Genre> = ({ randomItems }) => {
/>
)}
</Fetch>
{/* <News /> */}
<NewsList />
{randomItems
.filter((_, i) => i < 2)
.map((x) => (
@ -71,6 +72,7 @@ HomePage.getLayout = { Layout: DefaultLayout, props: { transparent: true } };
HomePage.getFetchUrls = () => [
Header.query(),
NewsList.query(),
...Object.values(Genre).map((x) => GenreGrid.query(x)),
Recommanded.query(),
VerticalRecommanded.query(),

View File

@ -0,0 +1,84 @@
/*
* Kyoo - A portable and vast media library solution.
* Copyright (c) Kyoo.
*
* See AUTHORS.md and LICENSE file in the project root for full license information.
*
* Kyoo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* Kyoo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
*/
import {
Genre,
ItemKind,
News,
NewsKind,
NewsP,
QueryIdentifier,
getDisplayDate,
} from "@kyoo/models";
import { H3, IconButton, ts } from "@kyoo/primitives";
import { ReactElement, forwardRef, useRef } from "react";
import { View } from "react-native";
import { px, useYoshiki } from "yoshiki/native";
import { ItemGrid } from "../browse/grid";
import ChevronLeft from "@material-symbols/svg-400/rounded/chevron_left-fill.svg";
import ChevronRight from "@material-symbols/svg-400/rounded/chevron_right-fill.svg";
import { InfiniteFetch, InfiniteFetchList } from "../fetch-infinite";
import { useTranslation } from "react-i18next";
import { Header } from "./genre";
import { EpisodeBox } from "../details/episode";
export const NewsList = () => {
const { t } = useTranslation();
return (
<>
<Header title={t("home.news")} />
<InfiniteFetch
query={NewsList.query()}
layout={{ ...ItemGrid.layout, layout: "horizontal" }}
empty={t("home.none")}
>
{(x, i) =>
x.kind === NewsKind.Movie || (x.isLoading && i % 2) ? (
<ItemGrid
isLoading={x.isLoading as any}
href={x.href}
name={x.name!}
subtitle={!x.isLoading ? getDisplayDate(x) : undefined}
poster={x.poster}
/>
) : (
<EpisodeBox
isLoading={x.isLoading as any}
name={x.name}
overview={x.overview!}
thumbnail={x.thumbnail}
/>
)
}
</InfiniteFetch>
</>
);
};
NewsList.query = (): QueryIdentifier<News> => ({
parser: NewsP,
infinite: true,
path: ["news"],
params: {
// Limit the inital numbers of items
limit: 10,
},
});

View File

@ -1,6 +1,7 @@
{
"home": {
"recommanded": "Recommanded",
"news": "News",
"info": "See more",
"none": "No episodes"
},

View File

@ -1,6 +1,7 @@
{
"home": {
"recommanded": "Recommandé",
"news": "Nouveautés",
"info": "Voir plus",
"none": "Aucun episode"
},