mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Add show info on news episode, Add news on the front
This commit is contained in:
parent
5a6bb57fd5
commit
56a96540b4
@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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");
|
||||
});
|
||||
|
||||
|
@ -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
|
||||
");
|
||||
}
|
||||
|
@ -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");
|
||||
});
|
||||
|
||||
|
@ -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({
|
||||
|
@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
export * from "./library-item";
|
||||
export * from "./news";
|
||||
export * from "./show";
|
||||
export * from "./movie";
|
||||
export * from "./collection";
|
||||
|
55
front/packages/models/src/resources/news.ts
Normal file
55
front/packages/models/src/resources/news.ts
Normal 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>;
|
@ -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)
|
||||
|
@ -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(),
|
||||
|
84
front/packages/ui/src/home/news.tsx
Normal file
84
front/packages/ui/src/home/news.tsx
Normal 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,
|
||||
},
|
||||
});
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"home": {
|
||||
"recommanded": "Recommanded",
|
||||
"news": "News",
|
||||
"info": "See more",
|
||||
"none": "No episodes"
|
||||
},
|
||||
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"home": {
|
||||
"recommanded": "Recommandé",
|
||||
"news": "Nouveautés",
|
||||
"info": "Voir plus",
|
||||
"none": "Aucun episode"
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user