Updating the search api

This commit is contained in:
Zoe Roux 2020-08-04 20:18:33 +02:00
parent 6a0fb2dd38
commit 2df3562045
18 changed files with 351 additions and 103 deletions

View File

@ -292,6 +292,26 @@ namespace Kyoo.Controllers
Expression<Func<Library, object>> sort, Expression<Func<Library, object>> sort,
Pagination limit = default Pagination limit = default
) => GetLibrariesFromCollection(slug, where, new Sort<Library>(sort), limit); ) => GetLibrariesFromCollection(slug, where, new Sort<Library>(sort), limit);
Task<ICollection<ShowRole>> GetRolesFromPeople(int showID,
Expression<Func<ShowRole, bool>> where = null,
Sort<ShowRole> sort = default,
Pagination limit = default);
Task<ICollection<ShowRole>> GetRolesFromPeople(int showID,
[Optional] Expression<Func<ShowRole, bool>> where,
Expression<Func<ShowRole, object>> sort,
Pagination limit = default
) => GetRolesFromPeople(showID, where, new Sort<ShowRole>(sort), limit);
Task<ICollection<ShowRole>> GetRolesFromPeople(string showSlug,
Expression<Func<ShowRole, bool>> where = null,
Sort<ShowRole> sort = default,
Pagination limit = default);
Task<ICollection<ShowRole>> GetRolesFromPeople(string showSlug,
[Optional] Expression<Func<ShowRole, bool>> where,
Expression<Func<ShowRole, object>> sort,
Pagination limit = default
) => GetRolesFromPeople(showSlug, where, new Sort<ShowRole>(sort), limit);
// Helpers // Helpers

View File

@ -395,6 +395,26 @@ namespace Kyoo.Controllers
Expression<Func<PeopleLink, object>> sort, Expression<Func<PeopleLink, object>> sort,
Pagination limit = default Pagination limit = default
) => GetFromShow(showSlug, where, new Sort<PeopleLink>(sort), limit); ) => GetFromShow(showSlug, where, new Sort<PeopleLink>(sort), limit);
Task<ICollection<ShowRole>> GetFromPeople(int showID,
Expression<Func<ShowRole, bool>> where = null,
Sort<ShowRole> sort = default,
Pagination limit = default);
Task<ICollection<ShowRole>> GetFromPeople(int showID,
[Optional] Expression<Func<ShowRole, bool>> where,
Expression<Func<ShowRole, object>> sort,
Pagination limit = default
) => GetFromPeople(showID, where, new Sort<ShowRole>(sort), limit);
Task<ICollection<ShowRole>> GetFromPeople(string showSlug,
Expression<Func<ShowRole, bool>> where = null,
Sort<ShowRole> sort = default,
Pagination limit = default);
Task<ICollection<ShowRole>> GetFromPeople(string showSlug,
[Optional] Expression<Func<ShowRole, bool>> where,
Expression<Func<ShowRole, object>> sort,
Pagination limit = default
) => GetFromPeople(showSlug, where, new Sort<ShowRole>(sort), limit);
} }
public interface IProviderRepository : IRepository<ProviderID> {} public interface IProviderRepository : IRepository<ProviderID> {}
} }

View File

@ -411,6 +411,22 @@ namespace Kyoo.Controllers
{ {
return LibraryRepository.GetFromCollection(slug, where, sort, limit); return LibraryRepository.GetFromCollection(slug, where, sort, limit);
} }
public Task<ICollection<ShowRole>> GetRolesFromPeople(int id,
Expression<Func<ShowRole, bool>> where = null,
Sort<ShowRole> sort = default,
Pagination limit = default)
{
return PeopleRepository.GetFromPeople(id, where, sort, limit);
}
public Task<ICollection<ShowRole>> GetRolesFromPeople(string slug,
Expression<Func<ShowRole, bool>> where = null,
Sort<ShowRole> sort = default,
Pagination limit = default)
{
return PeopleRepository.GetFromPeople(slug, where, sort, limit);
}
public Task AddShowLink(int showID, int? libraryID, int? collectionID) public Task AddShowLink(int showID, int? libraryID, int? collectionID)
{ {

View File

@ -1,4 +1,6 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq.Expressions;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace Kyoo.Models namespace Kyoo.Models
@ -21,6 +23,12 @@ namespace Kyoo.Models
set => People.Name = value; set => People.Name = value;
} }
public string Poster
{
get => People.Poster;
set => People.Poster = value;
}
public IEnumerable<MetadataID> ExternalIDs public IEnumerable<MetadataID> ExternalIDs
{ {
get => People.ExternalIDs; get => People.ExternalIDs;
@ -42,11 +50,79 @@ namespace Kyoo.Models
Type = type; Type = type;
} }
public PeopleLink(string slug, string name, string role, string type, string imgPrimary, IEnumerable<MetadataID> externalIDs) public PeopleLink(string slug,
string name,
string role,
string type,
string poster,
IEnumerable<MetadataID> externalIDs)
{ {
People = new People(slug, name, imgPrimary, externalIDs); People = new People(slug, name, poster, externalIDs);
Role = role; Role = role;
Type = type; Type = type;
} }
} }
public class ShowRole : IResource
{
public int ID { get; set; }
public string Role { get; set; }
public string Type { get; set; }
public string Slug { get; set; }
public string Title { get; set; }
public IEnumerable<string> Aliases { get; set; }
[JsonIgnore] public string Path { get; set; }
public string Overview { get; set; }
public Status? Status { get; set; }
public string TrailerUrl { get; set; }
public int? StartYear { get; set; }
public int? EndYear { get; set; }
public string Poster { get; set; }
public string Logo { get; set; }
public string Backdrop { get; set; }
public bool IsMovie { get; set; }
public ShowRole() {}
public ShowRole(PeopleLink x)
{
ID = x.ID;
Role = x.Role;
Type = x.Type;
Slug = x.Show.Slug;
Title = x.Show.Title;
Aliases = x.Show.Aliases;
Path = x.Show.Path;
Overview = x.Show.Overview;
Status = x.Show.Status;
TrailerUrl = x.Show.TrailerUrl;
StartYear = x.Show.StartYear;
EndYear = x.Show.EndYear;
Poster = x.Show.Poster;
Logo = x.Show.Logo;
Backdrop = x.Show.Backdrop;
IsMovie = x.Show.IsMovie;
}
public static Expression<Func<PeopleLink, ShowRole>> FromPeopleRole => x => new ShowRole
{
ID = x.ID,
Role = x.Role,
Type = x.Type,
Slug = x.Show.Slug,
Title = x.Show.Title,
Aliases = x.Show.Aliases,
Path = x.Show.Path,
Overview = x.Show.Overview,
Status = x.Show.Status,
TrailerUrl = x.Show.TrailerUrl,
StartYear = x.Show.StartYear,
EndYear = x.Show.EndYear,
Poster = x.Show.Poster,
Logo = x.Show.Logo,
Backdrop = x.Show.Backdrop,
IsMovie = x.Show.IsMovie
};
}
} }

View File

@ -13,7 +13,7 @@ namespace Kyoo.Models
public string Poster { get; set; } public string Poster { get; set; }
public string Overview { get; set; } public string Overview { get; set; }
[NotMergable] [JsonIgnore] public virtual IEnumerable<CollectionLink> Links { get; set; } [NotMergable] [JsonIgnore] public virtual IEnumerable<CollectionLink> Links { get; set; }
public virtual IEnumerable<Show> Shows [JsonIgnore] public virtual IEnumerable<Show> Shows
{ {
get => Links.Select(x => x.Show); get => Links.Select(x => x.Show);
set => Links = value.Select(x => new CollectionLink(this, x)); set => Links = value.Select(x => new CollectionLink(this, x));

View File

@ -9,18 +9,18 @@ namespace Kyoo.Models
public int ID { get; set; } public int ID { get; set; }
public string Slug { get; set; } public string Slug { get; set; }
public string Name { get; set; } public string Name { get; set; }
[JsonIgnore] public string ImgPrimary { get; set; } public string Poster { get; set; }
public virtual IEnumerable<MetadataID> ExternalIDs { get; set; } public virtual IEnumerable<MetadataID> ExternalIDs { get; set; }
[JsonIgnore] public virtual IEnumerable<PeopleLink> Roles { get; set; } [JsonIgnore] public virtual IEnumerable<PeopleLink> Roles { get; set; }
public People() {} public People() {}
public People(string slug, string name, string imgPrimary, IEnumerable<MetadataID> externalIDs) public People(string slug, string name, string poster, IEnumerable<MetadataID> externalIDs)
{ {
Slug = slug; Slug = slug;
Name = name; Name = name;
ImgPrimary = imgPrimary; Poster = poster;
ExternalIDs = externalIDs; ExternalIDs = externalIDs;
} }
} }

View File

@ -77,8 +77,9 @@ namespace Kyoo.Controllers
{ {
ContractResolver = new JsonPropertySelector(null, new Dictionary<Type, HashSet<string>>() ContractResolver = new JsonPropertySelector(null, new Dictionary<Type, HashSet<string>>()
{ {
{typeof(Show), new HashSet<string> {"genres", "studio", "people", "seasons"}}, {typeof(Show), new HashSet<string> {"genres", "studio"}},
{typeof(Episode), new HashSet<string> {"tracks"}} {typeof(Episode), new HashSet<string> {"tracks"}},
{typeof(PeopleLink), new HashSet<string> {"show"}}
}) })
}, },
context.HttpContext.RequestServices.GetRequiredService<ArrayPool<char>>(), context.HttpContext.RequestServices.GetRequiredService<ArrayPool<char>>(),

View File

@ -102,8 +102,8 @@ namespace Kyoo.Controllers
}; };
} }
ICollection<PeopleLink> people = await ApplyFilters(_database.PeopleLinks.Where(x => x.ShowID == showID), ICollection<PeopleLink> people = await ApplyFilters(_database.PeopleRoles.Where(x => x.ShowID == showID),
id => _database.PeopleLinks.FirstOrDefaultAsync(x => x.ID == id), id => _database.PeopleRoles.FirstOrDefaultAsync(x => x.ID == id),
x => x.People.Name, x => x.People.Name,
where, where,
sort, sort,
@ -128,8 +128,8 @@ namespace Kyoo.Controllers
}; };
} }
ICollection<PeopleLink> people = await ApplyFilters(_database.PeopleLinks.Where(x => x.Show.Slug == showSlug), ICollection<PeopleLink> people = await ApplyFilters(_database.PeopleRoles.Where(x => x.Show.Slug == showSlug),
id => _database.PeopleLinks.FirstOrDefaultAsync(x => x.ID == id), id => _database.PeopleRoles.FirstOrDefaultAsync(x => x.ID == id),
x => x.People.Name, x => x.People.Name,
where, where,
sort, sort,
@ -138,5 +138,39 @@ namespace Kyoo.Controllers
throw new ItemNotFound(); throw new ItemNotFound();
return people; return people;
} }
public async Task<ICollection<ShowRole>> GetFromPeople(int peopleID,
Expression<Func<ShowRole, bool>> where = null,
Sort<ShowRole> sort = default,
Pagination limit = default)
{
ICollection<ShowRole> roles = await ApplyFilters(_database.PeopleRoles.Where(x => x.PeopleID == peopleID)
.Select(ShowRole.FromPeopleRole),
async id => new ShowRole(await _database.PeopleRoles.FirstOrDefaultAsync(x => x.ID == id)),
x => x.Title,
where,
sort,
limit);
if (!roles.Any() && await Get(peopleID) == null)
throw new ItemNotFound();
return roles;
}
public async Task<ICollection<ShowRole>> GetFromPeople(string slug,
Expression<Func<ShowRole, bool>> where = null,
Sort<ShowRole> sort = default,
Pagination limit = default)
{
ICollection<ShowRole> roles = await ApplyFilters(_database.PeopleRoles.Where(x => x.People.Slug == slug)
.Select(ShowRole.FromPeopleRole),
async id => new ShowRole(await _database.PeopleRoles.FirstOrDefaultAsync(x => x.ID == id)),
x => x.Title,
where,
sort,
limit);
if (!roles.Any() && await Get(slug) == null)
throw new ItemNotFound();
return roles;
}
} }
} }

View File

@ -78,9 +78,10 @@ namespace Kyoo.Controllers
public override async Task<ICollection<Show>> Search(string query) public override async Task<ICollection<Show>> Search(string query)
{ {
query = $"%{query}%";
return await _database.Shows return await _database.Shows
.Where(x => EF.Functions.ILike(x.Title, $"%{query}%") .Where(x => EF.Functions.ILike(x.Title, query)
/*|| EF.Functions.ILike(x.Aliases, $"%{query}%")*/) /*|| x.Aliases.Any(y => EF.Functions.ILike(y, query))*/) // NOT TRANSLATABLE.
.Take(20) .Take(20)
.ToListAsync(); .ToListAsync();
} }

View File

@ -68,10 +68,10 @@ namespace Kyoo.Controllers
foreach (PeopleLink peop in people) foreach (PeopleLink peop in people)
{ {
string localPath = Path.Combine(root, peop.People.Slug + ".jpg"); string localPath = Path.Combine(root, peop.People.Slug + ".jpg");
if (peop.People.ImgPrimary == null) if (peop.People.Poster == null)
continue; continue;
if (alwaysDownload || !File.Exists(localPath)) if (alwaysDownload || !File.Exists(localPath))
await DownloadImage(peop.People.ImgPrimary, localPath, $"The profile picture of {peop.People.Name}"); await DownloadImage(peop.People.Poster, localPath, $"The profile picture of {peop.People.Name}");
} }
return people; return people;

View File

@ -9,6 +9,7 @@ using IdentityServer4.EntityFramework.Interfaces;
using IdentityServer4.EntityFramework.Options; using IdentityServer4.EntityFramework.Options;
using Kyoo.Models; using Kyoo.Models;
using Kyoo.Models.Exceptions; using Kyoo.Models.Exceptions;
using Kyoo.Models.Watch;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -68,37 +69,46 @@ namespace Kyoo
public DbSet<ProviderID> Providers { get; set; } public DbSet<ProviderID> Providers { get; set; }
public DbSet<MetadataID> MetadataIds { get; set; } public DbSet<MetadataID> MetadataIds { get; set; }
public DbSet<LibraryLink> LibraryLinks { get; set; } public DbSet<PeopleLink> PeopleRoles { get; set; }
public DbSet<CollectionLink> CollectionLinks { get; set; }
public DbSet<PeopleLink> PeopleLinks { get; set; }
// This is used because EF doesn't support Many-To-Many relationships so for now we need to override the getter/setters to store this. // This is used because EF doesn't support Many-To-Many relationships so for now we need to override the getter/setters to store this.
public DbSet<LibraryLink> LibraryLinks { get; set; }
public DbSet<CollectionLink> CollectionLinks { get; set; }
public DbSet<GenreLink> GenreLinks { get; set; } public DbSet<GenreLink> GenreLinks { get; set; }
public DbSet<ProviderLink> ProviderLinks { get; set; } public DbSet<ProviderLink> ProviderLinks { get; set; }
private readonly ValueConverter<IEnumerable<string>, string> _stringArrayConverter =
new ValueConverter<IEnumerable<string>, string>(
arr => string.Join("|", arr),
str => str.Split("|", StringSplitOptions.None));
public DatabaseContext()
{
NpgsqlConnection.GlobalTypeMapper.MapEnum<Status>();
NpgsqlConnection.GlobalTypeMapper.MapEnum<ItemType>();
NpgsqlConnection.GlobalTypeMapper.MapEnum<StreamType>();
}
private readonly ValueComparer<IEnumerable<string>> _stringArrayComparer = private readonly ValueComparer<IEnumerable<string>> _stringArrayComparer =
new ValueComparer<IEnumerable<string>>( new ValueComparer<IEnumerable<string>>(
(l1, l2) => l1.SequenceEqual(l2), (l1, l2) => l1.SequenceEqual(l2),
arr => arr.Aggregate(0, (i, s) => s.GetHashCode())); arr => arr.Aggregate(0, (i, s) => s.GetHashCode()));
protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnModelCreating(ModelBuilder modelBuilder)
{ {
base.OnModelCreating(modelBuilder); base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Library>().Property(e => e.Paths) modelBuilder.HasPostgresEnum<Status>();
.HasConversion(_stringArrayConverter).Metadata modelBuilder.HasPostgresEnum<ItemType>();
.SetValueComparer(_stringArrayComparer); modelBuilder.HasPostgresEnum<StreamType>();
modelBuilder.Entity<Show>().Property(e => e.Aliases)
.HasConversion(_stringArrayConverter).Metadata
.SetValueComparer(_stringArrayComparer);
modelBuilder.Entity<Library>()
.Property(x => x.Paths)
.HasColumnType("text[]")
.Metadata.SetValueComparer(_stringArrayComparer);
modelBuilder.Entity<Show>()
.Property(x => x.Aliases)
.HasColumnType("text[]")
.Metadata.SetValueComparer(_stringArrayComparer);
modelBuilder.Entity<Track>() modelBuilder.Entity<Track>()
.Property(t => t.IsDefault) .Property(t => t.IsDefault)
.ValueGeneratedNever(); .ValueGeneratedNever();
@ -127,6 +137,7 @@ namespace Kyoo
modelBuilder.Entity<PeopleLink>() modelBuilder.Entity<PeopleLink>()
.Ignore(x => x.Slug) .Ignore(x => x.Slug)
.Ignore(x => x.Name) .Ignore(x => x.Name)
.Ignore(x => x.Poster)
.Ignore(x => x.ExternalIDs); .Ignore(x => x.ExternalIDs);
modelBuilder.Entity<Genre>() modelBuilder.Entity<Genre>()

View File

@ -1,5 +1,6 @@
// <auto-generated /> // <auto-generated />
using System; using System;
using System.Collections.Generic;
using Kyoo; using Kyoo;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;
@ -10,13 +11,16 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace Kyoo.Models.DatabaseMigrations.Internal namespace Kyoo.Models.DatabaseMigrations.Internal
{ {
[DbContext(typeof(DatabaseContext))] [DbContext(typeof(DatabaseContext))]
[Migration("20200803040029_Initial")] [Migration("20200804172021_Initial")]
partial class Initial partial class Initial
{ {
protected override void BuildTargetModel(ModelBuilder modelBuilder) protected override void BuildTargetModel(ModelBuilder modelBuilder)
{ {
#pragma warning disable 612, 618 #pragma warning disable 612, 618
modelBuilder modelBuilder
.HasAnnotation("Npgsql:Enum:item_type", "show,movie,collection")
.HasAnnotation("Npgsql:Enum:status", "finished,airing,planned,unknown")
.HasAnnotation("Npgsql:Enum:stream_type", "unknow,video,audio,subtitle")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn)
.HasAnnotation("ProductVersion", "3.1.3") .HasAnnotation("ProductVersion", "3.1.3")
.HasAnnotation("Relational:MaxIdentifierLength", 63); .HasAnnotation("Relational:MaxIdentifierLength", 63);
@ -167,8 +171,8 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
b.Property<string>("Name") b.Property<string>("Name")
.HasColumnType("text"); .HasColumnType("text");
b.Property<string>("Paths") b.Property<IEnumerable<string>>("Paths")
.HasColumnType("text"); .HasColumnType("text[]");
b.Property<string>("Slug") b.Property<string>("Slug")
.HasColumnType("text"); .HasColumnType("text");
@ -262,10 +266,10 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
.HasColumnType("integer") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("ImgPrimary") b.Property<string>("Name")
.HasColumnType("text"); .HasColumnType("text");
b.Property<string>("Name") b.Property<string>("Poster")
.HasColumnType("text"); .HasColumnType("text");
b.Property<string>("Slug") b.Property<string>("Slug")
@ -304,7 +308,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
b.HasIndex("ShowID"); b.HasIndex("ShowID");
b.ToTable("PeopleLinks"); b.ToTable("PeopleRoles");
}); });
modelBuilder.Entity("Kyoo.Models.ProviderID", b => modelBuilder.Entity("Kyoo.Models.ProviderID", b =>
@ -393,8 +397,8 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
.HasColumnType("integer") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Aliases") b.Property<IEnumerable<string>>("Aliases")
.HasColumnType("text"); .HasColumnType("text[]");
b.Property<string>("Backdrop") b.Property<string>("Backdrop")
.HasColumnType("text"); .HasColumnType("text");

View File

@ -8,6 +8,11 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
{ {
protected override void Up(MigrationBuilder migrationBuilder) protected override void Up(MigrationBuilder migrationBuilder)
{ {
migrationBuilder.AlterDatabase()
.Annotation("Npgsql:Enum:item_type", "show,movie,collection")
.Annotation("Npgsql:Enum:status", "finished,airing,planned,unknown")
.Annotation("Npgsql:Enum:stream_type", "unknow,video,audio,subtitle");
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
name: "Collections", name: "Collections",
columns: table => new columns: table => new
@ -46,7 +51,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Slug = table.Column<string>(nullable: true), Slug = table.Column<string>(nullable: true),
Name = table.Column<string>(nullable: true), Name = table.Column<string>(nullable: true),
Paths = table.Column<string>(nullable: true) Paths = table.Column<string[]>(type: "text[]", nullable: true)
}, },
constraints: table => constraints: table =>
{ {
@ -61,7 +66,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Slug = table.Column<string>(nullable: true), Slug = table.Column<string>(nullable: true),
Name = table.Column<string>(nullable: true), Name = table.Column<string>(nullable: true),
ImgPrimary = table.Column<string>(nullable: true) Poster = table.Column<string>(nullable: true)
}, },
constraints: table => constraints: table =>
{ {
@ -131,7 +136,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Slug = table.Column<string>(nullable: true), Slug = table.Column<string>(nullable: true),
Title = table.Column<string>(nullable: true), Title = table.Column<string>(nullable: true),
Aliases = table.Column<string>(nullable: true), Aliases = table.Column<string[]>(type: "text[]", nullable: true),
Path = table.Column<string>(nullable: true), Path = table.Column<string>(nullable: true),
Overview = table.Column<string>(nullable: true), Overview = table.Column<string>(nullable: true),
Status = table.Column<int>(nullable: true), Status = table.Column<int>(nullable: true),
@ -239,7 +244,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
}); });
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
name: "PeopleLinks", name: "PeopleRoles",
columns: table => new columns: table => new
{ {
ID = table.Column<int>(nullable: false) ID = table.Column<int>(nullable: false)
@ -251,15 +256,15 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
}, },
constraints: table => constraints: table =>
{ {
table.PrimaryKey("PK_PeopleLinks", x => x.ID); table.PrimaryKey("PK_PeopleRoles", x => x.ID);
table.ForeignKey( table.ForeignKey(
name: "FK_PeopleLinks_People_PeopleID", name: "FK_PeopleRoles_People_PeopleID",
column: x => x.PeopleID, column: x => x.PeopleID,
principalTable: "People", principalTable: "People",
principalColumn: "ID", principalColumn: "ID",
onDelete: ReferentialAction.Cascade); onDelete: ReferentialAction.Cascade);
table.ForeignKey( table.ForeignKey(
name: "FK_PeopleLinks_Shows_ShowID", name: "FK_PeopleRoles_Shows_ShowID",
column: x => x.ShowID, column: x => x.ShowID,
principalTable: "Shows", principalTable: "Shows",
principalColumn: "ID", principalColumn: "ID",
@ -500,13 +505,13 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
unique: true); unique: true);
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_PeopleLinks_PeopleID", name: "IX_PeopleRoles_PeopleID",
table: "PeopleLinks", table: "PeopleRoles",
column: "PeopleID"); column: "PeopleID");
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_PeopleLinks_ShowID", name: "IX_PeopleRoles_ShowID",
table: "PeopleLinks", table: "PeopleRoles",
column: "ShowID"); column: "ShowID");
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
@ -569,7 +574,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
name: "MetadataIds"); name: "MetadataIds");
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "PeopleLinks"); name: "PeopleRoles");
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "ProviderLinks"); name: "ProviderLinks");

View File

@ -1,5 +1,6 @@
// <auto-generated /> // <auto-generated />
using System; using System;
using System.Collections.Generic;
using Kyoo; using Kyoo;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;
@ -15,6 +16,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
{ {
#pragma warning disable 612, 618 #pragma warning disable 612, 618
modelBuilder modelBuilder
.HasAnnotation("Npgsql:Enum:item_type", "show,movie,collection")
.HasAnnotation("Npgsql:Enum:status", "finished,airing,planned,unknown")
.HasAnnotation("Npgsql:Enum:stream_type", "unknow,video,audio,subtitle")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn)
.HasAnnotation("ProductVersion", "3.1.3") .HasAnnotation("ProductVersion", "3.1.3")
.HasAnnotation("Relational:MaxIdentifierLength", 63); .HasAnnotation("Relational:MaxIdentifierLength", 63);
@ -165,8 +169,8 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
b.Property<string>("Name") b.Property<string>("Name")
.HasColumnType("text"); .HasColumnType("text");
b.Property<string>("Paths") b.Property<IEnumerable<string>>("Paths")
.HasColumnType("text"); .HasColumnType("text[]");
b.Property<string>("Slug") b.Property<string>("Slug")
.HasColumnType("text"); .HasColumnType("text");
@ -260,10 +264,10 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
.HasColumnType("integer") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("ImgPrimary") b.Property<string>("Name")
.HasColumnType("text"); .HasColumnType("text");
b.Property<string>("Name") b.Property<string>("Poster")
.HasColumnType("text"); .HasColumnType("text");
b.Property<string>("Slug") b.Property<string>("Slug")
@ -302,7 +306,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
b.HasIndex("ShowID"); b.HasIndex("ShowID");
b.ToTable("PeopleLinks"); b.ToTable("PeopleRoles");
}); });
modelBuilder.Entity("Kyoo.Models.ProviderID", b => modelBuilder.Entity("Kyoo.Models.ProviderID", b =>
@ -391,8 +395,8 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
.HasColumnType("integer") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Aliases") b.Property<IEnumerable<string>>("Aliases")
.HasColumnType("text"); .HasColumnType("text[]");
b.Property<string>("Backdrop") b.Property<string>("Backdrop")
.HasColumnType("text"); .HasColumnType("text");

View File

@ -1,36 +0,0 @@
using System.Linq;
using System.Threading.Tasks;
using Kyoo.Controllers;
using Kyoo.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Kyoo.Api
{
[Route("api/[controller]")]
[ApiController]
public class PeopleController : ControllerBase
{
private readonly ILibraryManager _libraryManager;
public PeopleController(ILibraryManager libraryManager)
{
_libraryManager = libraryManager;
}
[HttpGet("{peopleSlug}")]
[Authorize(Policy="Read")]
public async Task<ActionResult<Collection>> GetPeople(string peopleSlug)
{
People people = await _libraryManager.GetPeople(peopleSlug);
if (people == null)
return NotFound();
return new Collection(people.Slug, people.Name, null, null)
{
Shows = people.Roles.Select(x => x.Show),
Poster = "peopleimg/" + people.Slug
};
}
}
}

View File

@ -0,0 +1,93 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Kyoo.CommonApi;
using Kyoo.Controllers;
using Kyoo.Models;
using Kyoo.Models.Exceptions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
namespace Kyoo.Api
{
[Route("api/people")]
[ApiController]
public class PeopleApi : CrudApi<People>
{
private readonly ILibraryManager _libraryManager;
public PeopleApi(ILibraryManager libraryManager, IConfiguration configuration)
: base(libraryManager.PeopleRepository, configuration)
{
_libraryManager = libraryManager;
}
[HttpGet("{id:int}/role")]
[HttpGet("{id:int}/roles")]
[Authorize(Policy = "Read")]
[JsonDetailed]
public async Task<ActionResult<Page<ShowRole>>> GetRoles(int id,
[FromQuery] string sortBy,
[FromQuery] int afterID,
[FromQuery] Dictionary<string, string> where,
[FromQuery] int limit = 20)
{
where.Remove("sortBy");
where.Remove("limit");
where.Remove("afterID");
try
{
ICollection<ShowRole> resources = await _libraryManager.GetRolesFromPeople(id,
ApiHelper.ParseWhere<ShowRole>(where),
new Sort<ShowRole>(sortBy),
new Pagination(limit, afterID));
return Page(resources, limit);
}
catch (ItemNotFound)
{
return NotFound();
}
catch (ArgumentException ex)
{
return BadRequest(new {Error = ex.Message});
}
}
[HttpGet("{slug}/role")]
[HttpGet("{slug}/roles")]
[Authorize(Policy = "Read")]
[JsonDetailed]
public async Task<ActionResult<Page<ShowRole>>> GetRoles(string slug,
[FromQuery] string sortBy,
[FromQuery] int afterID,
[FromQuery] Dictionary<string, string> where,
[FromQuery] int limit = 20)
{
where.Remove("sortBy");
where.Remove("limit");
where.Remove("afterID");
try
{
ICollection<ShowRole> ressources = await _libraryManager.GetRolesFromPeople(slug,
ApiHelper.ParseWhere<ShowRole>(where),
new Sort<ShowRole>(sortBy),
new Pagination(limit, afterID));
return Page(ressources, limit);
}
catch (ItemNotFound)
{
return NotFound();
}
catch (ArgumentException ex)
{
return BadRequest(new {Error = ex.Message});
}
}
}
}

View File

@ -6,13 +6,13 @@ using Microsoft.AspNetCore.Mvc;
namespace Kyoo.Api namespace Kyoo.Api
{ {
[Route("api/[controller]")] [Route("api/search")]
[ApiController] [ApiController]
public class SearchController : ControllerBase public class SearchApi : ControllerBase
{ {
private readonly ILibraryManager _libraryManager; private readonly ILibraryManager _libraryManager;
public SearchController(ILibraryManager libraryManager) public SearchApi(ILibraryManager libraryManager)
{ {
_libraryManager = libraryManager; _libraryManager = libraryManager;
} }
@ -21,7 +21,7 @@ namespace Kyoo.Api
[Authorize(Policy="Read")] [Authorize(Policy="Read")]
public async Task<ActionResult<SearchResult>> Search(string query) public async Task<ActionResult<SearchResult>> Search(string query)
{ {
SearchResult result = new SearchResult return new SearchResult
{ {
Query = query, Query = query,
Collections = await _libraryManager.SearchCollections(query), Collections = await _libraryManager.SearchCollections(query),
@ -31,7 +31,6 @@ namespace Kyoo.Api
Genres = await _libraryManager.SearchGenres(query), Genres = await _libraryManager.SearchGenres(query),
Studios = await _libraryManager.SearchStudios(query) Studios = await _libraryManager.SearchStudios(query)
}; };
return result;
} }
} }
} }

@ -1 +1 @@
Subproject commit de1b3b069aa4f920bd5248223eda151b1eedf541 Subproject commit 3dad4b29d6565d08ef0bce1e450b5de65f6fac16