diff --git a/Kyoo.Common/Controllers/ILibraryManager.cs b/Kyoo.Common/Controllers/ILibraryManager.cs index 3da6fd8f..e79bb825 100644 --- a/Kyoo.Common/Controllers/ILibraryManager.cs +++ b/Kyoo.Common/Controllers/ILibraryManager.cs @@ -292,6 +292,26 @@ namespace Kyoo.Controllers Expression> sort, Pagination limit = default ) => GetLibrariesFromCollection(slug, where, new Sort(sort), limit); + + Task> GetRolesFromPeople(int showID, + Expression> where = null, + Sort sort = default, + Pagination limit = default); + Task> GetRolesFromPeople(int showID, + [Optional] Expression> where, + Expression> sort, + Pagination limit = default + ) => GetRolesFromPeople(showID, where, new Sort(sort), limit); + + Task> GetRolesFromPeople(string showSlug, + Expression> where = null, + Sort sort = default, + Pagination limit = default); + Task> GetRolesFromPeople(string showSlug, + [Optional] Expression> where, + Expression> sort, + Pagination limit = default + ) => GetRolesFromPeople(showSlug, where, new Sort(sort), limit); // Helpers diff --git a/Kyoo.Common/Controllers/IRepository.cs b/Kyoo.Common/Controllers/IRepository.cs index 1553951e..2c4f5c23 100644 --- a/Kyoo.Common/Controllers/IRepository.cs +++ b/Kyoo.Common/Controllers/IRepository.cs @@ -395,6 +395,26 @@ namespace Kyoo.Controllers Expression> sort, Pagination limit = default ) => GetFromShow(showSlug, where, new Sort(sort), limit); + + Task> GetFromPeople(int showID, + Expression> where = null, + Sort sort = default, + Pagination limit = default); + Task> GetFromPeople(int showID, + [Optional] Expression> where, + Expression> sort, + Pagination limit = default + ) => GetFromPeople(showID, where, new Sort(sort), limit); + + Task> GetFromPeople(string showSlug, + Expression> where = null, + Sort sort = default, + Pagination limit = default); + Task> GetFromPeople(string showSlug, + [Optional] Expression> where, + Expression> sort, + Pagination limit = default + ) => GetFromPeople(showSlug, where, new Sort(sort), limit); } public interface IProviderRepository : IRepository {} } \ No newline at end of file diff --git a/Kyoo.Common/Controllers/Implementations/LibraryManager.cs b/Kyoo.Common/Controllers/Implementations/LibraryManager.cs index 82f0a8b3..db85d358 100644 --- a/Kyoo.Common/Controllers/Implementations/LibraryManager.cs +++ b/Kyoo.Common/Controllers/Implementations/LibraryManager.cs @@ -411,6 +411,22 @@ namespace Kyoo.Controllers { return LibraryRepository.GetFromCollection(slug, where, sort, limit); } + + public Task> GetRolesFromPeople(int id, + Expression> where = null, + Sort sort = default, + Pagination limit = default) + { + return PeopleRepository.GetFromPeople(id, where, sort, limit); + } + + public Task> GetRolesFromPeople(string slug, + Expression> where = null, + Sort sort = default, + Pagination limit = default) + { + return PeopleRepository.GetFromPeople(slug, where, sort, limit); + } public Task AddShowLink(int showID, int? libraryID, int? collectionID) { diff --git a/Kyoo.Common/Models/PeopleLink.cs b/Kyoo.Common/Models/PeopleLink.cs index f095d802..04555298 100644 --- a/Kyoo.Common/Models/PeopleLink.cs +++ b/Kyoo.Common/Models/PeopleLink.cs @@ -1,4 +1,6 @@ +using System; using System.Collections.Generic; +using System.Linq.Expressions; using Newtonsoft.Json; namespace Kyoo.Models @@ -21,6 +23,12 @@ namespace Kyoo.Models set => People.Name = value; } + public string Poster + { + get => People.Poster; + set => People.Poster = value; + } + public IEnumerable ExternalIDs { get => People.ExternalIDs; @@ -42,11 +50,79 @@ namespace Kyoo.Models Type = type; } - public PeopleLink(string slug, string name, string role, string type, string imgPrimary, IEnumerable externalIDs) + public PeopleLink(string slug, + string name, + string role, + string type, + string poster, + IEnumerable externalIDs) { - People = new People(slug, name, imgPrimary, externalIDs); + People = new People(slug, name, poster, externalIDs); Role = role; 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 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> 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 + }; + } } \ No newline at end of file diff --git a/Kyoo.Common/Models/Resources/Collection.cs b/Kyoo.Common/Models/Resources/Collection.cs index eb932de2..07bae5bc 100644 --- a/Kyoo.Common/Models/Resources/Collection.cs +++ b/Kyoo.Common/Models/Resources/Collection.cs @@ -13,7 +13,7 @@ namespace Kyoo.Models public string Poster { get; set; } public string Overview { get; set; } [NotMergable] [JsonIgnore] public virtual IEnumerable Links { get; set; } - public virtual IEnumerable Shows + [JsonIgnore] public virtual IEnumerable Shows { get => Links.Select(x => x.Show); set => Links = value.Select(x => new CollectionLink(this, x)); diff --git a/Kyoo.Common/Models/Resources/People.cs b/Kyoo.Common/Models/Resources/People.cs index b2bc658e..78a9c87d 100644 --- a/Kyoo.Common/Models/Resources/People.cs +++ b/Kyoo.Common/Models/Resources/People.cs @@ -9,18 +9,18 @@ namespace Kyoo.Models public int ID { get; set; } public string Slug { get; set; } public string Name { get; set; } - [JsonIgnore] public string ImgPrimary { get; set; } + public string Poster { get; set; } public virtual IEnumerable ExternalIDs { get; set; } [JsonIgnore] public virtual IEnumerable Roles { get; set; } public People() {} - public People(string slug, string name, string imgPrimary, IEnumerable externalIDs) + public People(string slug, string name, string poster, IEnumerable externalIDs) { Slug = slug; Name = name; - ImgPrimary = imgPrimary; + Poster = poster; ExternalIDs = externalIDs; } } diff --git a/Kyoo.CommonAPI/JsonSerializer.cs b/Kyoo.CommonAPI/JsonSerializer.cs index 42c035f6..11c696fe 100644 --- a/Kyoo.CommonAPI/JsonSerializer.cs +++ b/Kyoo.CommonAPI/JsonSerializer.cs @@ -77,8 +77,9 @@ namespace Kyoo.Controllers { ContractResolver = new JsonPropertySelector(null, new Dictionary>() { - {typeof(Show), new HashSet {"genres", "studio", "people", "seasons"}}, - {typeof(Episode), new HashSet {"tracks"}} + {typeof(Show), new HashSet {"genres", "studio"}}, + {typeof(Episode), new HashSet {"tracks"}}, + {typeof(PeopleLink), new HashSet {"show"}} }) }, context.HttpContext.RequestServices.GetRequiredService>(), diff --git a/Kyoo/Controllers/Repositories/PeopleRepository.cs b/Kyoo/Controllers/Repositories/PeopleRepository.cs index 67fdf775..a9f2e920 100644 --- a/Kyoo/Controllers/Repositories/PeopleRepository.cs +++ b/Kyoo/Controllers/Repositories/PeopleRepository.cs @@ -102,8 +102,8 @@ namespace Kyoo.Controllers }; } - ICollection people = await ApplyFilters(_database.PeopleLinks.Where(x => x.ShowID == showID), - id => _database.PeopleLinks.FirstOrDefaultAsync(x => x.ID == id), + ICollection people = await ApplyFilters(_database.PeopleRoles.Where(x => x.ShowID == showID), + id => _database.PeopleRoles.FirstOrDefaultAsync(x => x.ID == id), x => x.People.Name, where, sort, @@ -128,8 +128,8 @@ namespace Kyoo.Controllers }; } - ICollection people = await ApplyFilters(_database.PeopleLinks.Where(x => x.Show.Slug == showSlug), - id => _database.PeopleLinks.FirstOrDefaultAsync(x => x.ID == id), + ICollection people = await ApplyFilters(_database.PeopleRoles.Where(x => x.Show.Slug == showSlug), + id => _database.PeopleRoles.FirstOrDefaultAsync(x => x.ID == id), x => x.People.Name, where, sort, @@ -138,5 +138,39 @@ namespace Kyoo.Controllers throw new ItemNotFound(); return people; } + + public async Task> GetFromPeople(int peopleID, + Expression> where = null, + Sort sort = default, + Pagination limit = default) + { + ICollection 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> GetFromPeople(string slug, + Expression> where = null, + Sort sort = default, + Pagination limit = default) + { + ICollection 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; + } } } \ No newline at end of file diff --git a/Kyoo/Controllers/Repositories/ShowRepository.cs b/Kyoo/Controllers/Repositories/ShowRepository.cs index 36e285a6..9ea7906c 100644 --- a/Kyoo/Controllers/Repositories/ShowRepository.cs +++ b/Kyoo/Controllers/Repositories/ShowRepository.cs @@ -78,9 +78,10 @@ namespace Kyoo.Controllers public override async Task> Search(string query) { + query = $"%{query}%"; return await _database.Shows - .Where(x => EF.Functions.ILike(x.Title, $"%{query}%") - /*|| EF.Functions.ILike(x.Aliases, $"%{query}%")*/) + .Where(x => EF.Functions.ILike(x.Title, query) + /*|| x.Aliases.Any(y => EF.Functions.ILike(y, query))*/) // NOT TRANSLATABLE. .Take(20) .ToListAsync(); } diff --git a/Kyoo/Controllers/ThumbnailsManager.cs b/Kyoo/Controllers/ThumbnailsManager.cs index 75f8ee5c..ba40992a 100644 --- a/Kyoo/Controllers/ThumbnailsManager.cs +++ b/Kyoo/Controllers/ThumbnailsManager.cs @@ -68,10 +68,10 @@ namespace Kyoo.Controllers foreach (PeopleLink peop in people) { string localPath = Path.Combine(root, peop.People.Slug + ".jpg"); - if (peop.People.ImgPrimary == null) + if (peop.People.Poster == null) continue; 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; diff --git a/Kyoo/Models/DatabaseContext.cs b/Kyoo/Models/DatabaseContext.cs index f6157af7..e730ca69 100644 --- a/Kyoo/Models/DatabaseContext.cs +++ b/Kyoo/Models/DatabaseContext.cs @@ -9,6 +9,7 @@ using IdentityServer4.EntityFramework.Interfaces; using IdentityServer4.EntityFramework.Options; using Kyoo.Models; using Kyoo.Models.Exceptions; +using Kyoo.Models.Watch; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; @@ -68,37 +69,46 @@ namespace Kyoo public DbSet Providers { get; set; } public DbSet MetadataIds { get; set; } - public DbSet LibraryLinks { get; set; } - public DbSet CollectionLinks { get; set; } - public DbSet PeopleLinks { get; set; } + public DbSet PeopleRoles { 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. + public DbSet LibraryLinks { get; set; } + public DbSet CollectionLinks { get; set; } public DbSet GenreLinks { get; set; } public DbSet ProviderLinks { get; set; } - - - private readonly ValueConverter, string> _stringArrayConverter = - new ValueConverter, string>( - arr => string.Join("|", arr), - str => str.Split("|", StringSplitOptions.None)); + public DatabaseContext() + { + NpgsqlConnection.GlobalTypeMapper.MapEnum(); + NpgsqlConnection.GlobalTypeMapper.MapEnum(); + NpgsqlConnection.GlobalTypeMapper.MapEnum(); + } + private readonly ValueComparer> _stringArrayComparer = new ValueComparer>( - (l1, l2) => l1.SequenceEqual(l2), - arr => arr.Aggregate(0, (i, s) => s.GetHashCode())); - + (l1, l2) => l1.SequenceEqual(l2), + arr => arr.Aggregate(0, (i, s) => s.GetHashCode())); protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); - modelBuilder.Entity().Property(e => e.Paths) - .HasConversion(_stringArrayConverter).Metadata - .SetValueComparer(_stringArrayComparer); - modelBuilder.Entity().Property(e => e.Aliases) - .HasConversion(_stringArrayConverter).Metadata - .SetValueComparer(_stringArrayComparer); + modelBuilder.HasPostgresEnum(); + modelBuilder.HasPostgresEnum(); + modelBuilder.HasPostgresEnum(); + modelBuilder.Entity() + .Property(x => x.Paths) + .HasColumnType("text[]") + .Metadata.SetValueComparer(_stringArrayComparer); + + modelBuilder.Entity() + .Property(x => x.Aliases) + .HasColumnType("text[]") + .Metadata.SetValueComparer(_stringArrayComparer); + + modelBuilder.Entity() .Property(t => t.IsDefault) .ValueGeneratedNever(); @@ -127,6 +137,7 @@ namespace Kyoo modelBuilder.Entity() .Ignore(x => x.Slug) .Ignore(x => x.Name) + .Ignore(x => x.Poster) .Ignore(x => x.ExternalIDs); modelBuilder.Entity() diff --git a/Kyoo/Models/DatabaseMigrations/Internal/20200803040029_Initial.Designer.cs b/Kyoo/Models/DatabaseMigrations/Internal/20200804172021_Initial.Designer.cs similarity index 97% rename from Kyoo/Models/DatabaseMigrations/Internal/20200803040029_Initial.Designer.cs rename to Kyoo/Models/DatabaseMigrations/Internal/20200804172021_Initial.Designer.cs index 825758b2..0e398aef 100644 --- a/Kyoo/Models/DatabaseMigrations/Internal/20200803040029_Initial.Designer.cs +++ b/Kyoo/Models/DatabaseMigrations/Internal/20200804172021_Initial.Designer.cs @@ -1,5 +1,6 @@ // using System; +using System.Collections.Generic; using Kyoo; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -10,13 +11,16 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; namespace Kyoo.Models.DatabaseMigrations.Internal { [DbContext(typeof(DatabaseContext))] - [Migration("20200803040029_Initial")] + [Migration("20200804172021_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 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("ProductVersion", "3.1.3") .HasAnnotation("Relational:MaxIdentifierLength", 63); @@ -167,8 +171,8 @@ namespace Kyoo.Models.DatabaseMigrations.Internal b.Property("Name") .HasColumnType("text"); - b.Property("Paths") - .HasColumnType("text"); + b.Property>("Paths") + .HasColumnType("text[]"); b.Property("Slug") .HasColumnType("text"); @@ -262,10 +266,10 @@ namespace Kyoo.Models.DatabaseMigrations.Internal .HasColumnType("integer") .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - b.Property("ImgPrimary") + b.Property("Name") .HasColumnType("text"); - b.Property("Name") + b.Property("Poster") .HasColumnType("text"); b.Property("Slug") @@ -304,7 +308,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal b.HasIndex("ShowID"); - b.ToTable("PeopleLinks"); + b.ToTable("PeopleRoles"); }); modelBuilder.Entity("Kyoo.Models.ProviderID", b => @@ -393,8 +397,8 @@ namespace Kyoo.Models.DatabaseMigrations.Internal .HasColumnType("integer") .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - b.Property("Aliases") - .HasColumnType("text"); + b.Property>("Aliases") + .HasColumnType("text[]"); b.Property("Backdrop") .HasColumnType("text"); diff --git a/Kyoo/Models/DatabaseMigrations/Internal/20200803040029_Initial.cs b/Kyoo/Models/DatabaseMigrations/Internal/20200804172021_Initial.cs similarity index 96% rename from Kyoo/Models/DatabaseMigrations/Internal/20200803040029_Initial.cs rename to Kyoo/Models/DatabaseMigrations/Internal/20200804172021_Initial.cs index c42433a5..d94bb616 100644 --- a/Kyoo/Models/DatabaseMigrations/Internal/20200803040029_Initial.cs +++ b/Kyoo/Models/DatabaseMigrations/Internal/20200804172021_Initial.cs @@ -8,6 +8,11 @@ namespace Kyoo.Models.DatabaseMigrations.Internal { 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( name: "Collections", columns: table => new @@ -46,7 +51,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), Slug = table.Column(nullable: true), Name = table.Column(nullable: true), - Paths = table.Column(nullable: true) + Paths = table.Column(type: "text[]", nullable: true) }, constraints: table => { @@ -61,7 +66,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), Slug = table.Column(nullable: true), Name = table.Column(nullable: true), - ImgPrimary = table.Column(nullable: true) + Poster = table.Column(nullable: true) }, constraints: table => { @@ -131,7 +136,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), Slug = table.Column(nullable: true), Title = table.Column(nullable: true), - Aliases = table.Column(nullable: true), + Aliases = table.Column(type: "text[]", nullable: true), Path = table.Column(nullable: true), Overview = table.Column(nullable: true), Status = table.Column(nullable: true), @@ -239,7 +244,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal }); migrationBuilder.CreateTable( - name: "PeopleLinks", + name: "PeopleRoles", columns: table => new { ID = table.Column(nullable: false) @@ -251,15 +256,15 @@ namespace Kyoo.Models.DatabaseMigrations.Internal }, constraints: table => { - table.PrimaryKey("PK_PeopleLinks", x => x.ID); + table.PrimaryKey("PK_PeopleRoles", x => x.ID); table.ForeignKey( - name: "FK_PeopleLinks_People_PeopleID", + name: "FK_PeopleRoles_People_PeopleID", column: x => x.PeopleID, principalTable: "People", principalColumn: "ID", onDelete: ReferentialAction.Cascade); table.ForeignKey( - name: "FK_PeopleLinks_Shows_ShowID", + name: "FK_PeopleRoles_Shows_ShowID", column: x => x.ShowID, principalTable: "Shows", principalColumn: "ID", @@ -500,13 +505,13 @@ namespace Kyoo.Models.DatabaseMigrations.Internal unique: true); migrationBuilder.CreateIndex( - name: "IX_PeopleLinks_PeopleID", - table: "PeopleLinks", + name: "IX_PeopleRoles_PeopleID", + table: "PeopleRoles", column: "PeopleID"); migrationBuilder.CreateIndex( - name: "IX_PeopleLinks_ShowID", - table: "PeopleLinks", + name: "IX_PeopleRoles_ShowID", + table: "PeopleRoles", column: "ShowID"); migrationBuilder.CreateIndex( @@ -569,7 +574,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal name: "MetadataIds"); migrationBuilder.DropTable( - name: "PeopleLinks"); + name: "PeopleRoles"); migrationBuilder.DropTable( name: "ProviderLinks"); diff --git a/Kyoo/Models/DatabaseMigrations/Internal/DatabaseContextModelSnapshot.cs b/Kyoo/Models/DatabaseMigrations/Internal/DatabaseContextModelSnapshot.cs index 762ea73d..b7c0e3cf 100644 --- a/Kyoo/Models/DatabaseMigrations/Internal/DatabaseContextModelSnapshot.cs +++ b/Kyoo/Models/DatabaseMigrations/Internal/DatabaseContextModelSnapshot.cs @@ -1,5 +1,6 @@ // using System; +using System.Collections.Generic; using Kyoo; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -15,6 +16,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal { #pragma warning disable 612, 618 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("ProductVersion", "3.1.3") .HasAnnotation("Relational:MaxIdentifierLength", 63); @@ -165,8 +169,8 @@ namespace Kyoo.Models.DatabaseMigrations.Internal b.Property("Name") .HasColumnType("text"); - b.Property("Paths") - .HasColumnType("text"); + b.Property>("Paths") + .HasColumnType("text[]"); b.Property("Slug") .HasColumnType("text"); @@ -260,10 +264,10 @@ namespace Kyoo.Models.DatabaseMigrations.Internal .HasColumnType("integer") .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - b.Property("ImgPrimary") + b.Property("Name") .HasColumnType("text"); - b.Property("Name") + b.Property("Poster") .HasColumnType("text"); b.Property("Slug") @@ -302,7 +306,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal b.HasIndex("ShowID"); - b.ToTable("PeopleLinks"); + b.ToTable("PeopleRoles"); }); modelBuilder.Entity("Kyoo.Models.ProviderID", b => @@ -391,8 +395,8 @@ namespace Kyoo.Models.DatabaseMigrations.Internal .HasColumnType("integer") .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - b.Property("Aliases") - .HasColumnType("text"); + b.Property>("Aliases") + .HasColumnType("text[]"); b.Property("Backdrop") .HasColumnType("text"); diff --git a/Kyoo/Views/API/PeopleAPI.cs b/Kyoo/Views/API/PeopleAPI.cs deleted file mode 100644 index ad27d8b9..00000000 --- a/Kyoo/Views/API/PeopleAPI.cs +++ /dev/null @@ -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> 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 - }; - } - } -} \ No newline at end of file diff --git a/Kyoo/Views/API/PeopleApi.cs b/Kyoo/Views/API/PeopleApi.cs new file mode 100644 index 00000000..2803ead9 --- /dev/null +++ b/Kyoo/Views/API/PeopleApi.cs @@ -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 + { + 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>> GetRoles(int id, + [FromQuery] string sortBy, + [FromQuery] int afterID, + [FromQuery] Dictionary where, + [FromQuery] int limit = 20) + { + where.Remove("sortBy"); + where.Remove("limit"); + where.Remove("afterID"); + + try + { + ICollection resources = await _libraryManager.GetRolesFromPeople(id, + ApiHelper.ParseWhere(where), + new Sort(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>> GetRoles(string slug, + [FromQuery] string sortBy, + [FromQuery] int afterID, + [FromQuery] Dictionary where, + [FromQuery] int limit = 20) + { + where.Remove("sortBy"); + where.Remove("limit"); + where.Remove("afterID"); + + try + { + ICollection ressources = await _libraryManager.GetRolesFromPeople(slug, + ApiHelper.ParseWhere(where), + new Sort(sortBy), + new Pagination(limit, afterID)); + + return Page(ressources, limit); + } + catch (ItemNotFound) + { + return NotFound(); + } + catch (ArgumentException ex) + { + return BadRequest(new {Error = ex.Message}); + } + } + } +} \ No newline at end of file diff --git a/Kyoo/Views/API/SearchAPI.cs b/Kyoo/Views/API/SearchApi.cs similarity index 80% rename from Kyoo/Views/API/SearchAPI.cs rename to Kyoo/Views/API/SearchApi.cs index 4efcf93a..20c4297d 100644 --- a/Kyoo/Views/API/SearchAPI.cs +++ b/Kyoo/Views/API/SearchApi.cs @@ -6,13 +6,13 @@ using Microsoft.AspNetCore.Mvc; namespace Kyoo.Api { - [Route("api/[controller]")] + [Route("api/search")] [ApiController] - public class SearchController : ControllerBase + public class SearchApi : ControllerBase { private readonly ILibraryManager _libraryManager; - public SearchController(ILibraryManager libraryManager) + public SearchApi(ILibraryManager libraryManager) { _libraryManager = libraryManager; } @@ -21,7 +21,7 @@ namespace Kyoo.Api [Authorize(Policy="Read")] public async Task> Search(string query) { - SearchResult result = new SearchResult + return new SearchResult { Query = query, Collections = await _libraryManager.SearchCollections(query), @@ -31,7 +31,6 @@ namespace Kyoo.Api Genres = await _libraryManager.SearchGenres(query), Studios = await _libraryManager.SearchStudios(query) }; - return result; } } } \ No newline at end of file diff --git a/Kyoo/Views/WebClient b/Kyoo/Views/WebClient index de1b3b06..3dad4b29 160000 --- a/Kyoo/Views/WebClient +++ b/Kyoo/Views/WebClient @@ -1 +1 @@ -Subproject commit de1b3b069aa4f920bd5248223eda151b1eedf541 +Subproject commit 3dad4b29d6565d08ef0bce1e450b5de65f6fac16