From b6bb190e69d97997e971177f539163b6d46c6169 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Sun, 12 Nov 2023 19:30:07 +0100 Subject: [PATCH] Add every tables for watchlists --- back/Kyoo.ruleset | 3 + .../Models/Resources/Episode.cs | 11 ++ .../Models/Resources/Movie.cs | 6 +- .../Models/Resources/Show.cs | 11 ++ .../Models/Resources/User.cs | 10 +- .../Models/Resources/WatchInfo.cs | 109 +++++++++++++++--- back/src/Kyoo.Postgresql/DatabaseContext.cs | 26 ++++- 7 files changed, 151 insertions(+), 25 deletions(-) diff --git a/back/Kyoo.ruleset b/back/Kyoo.ruleset index 60883533..82ed916b 100644 --- a/back/Kyoo.ruleset +++ b/back/Kyoo.ruleset @@ -28,7 +28,10 @@ + + + diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Episode.cs b/back/src/Kyoo.Abstractions/Models/Resources/Episode.cs index 6d7ab289..8adc3ca4 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Episode.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Episode.cs @@ -238,6 +238,17 @@ namespace Kyoo.Abstractions.Models || (x.SeasonNumber == SeasonNumber && x.EpisodeNumber > EpisodeNumber) ); + [SerializeIgnore] public ICollection Watched { get; set; } + + /// + /// Metadata of what an user as started/planned to watch. + /// + [Projectable(UseMemberBody = nameof(_WatchInfo), OnlyOnInclude = true)] + [LoadableRelation] public EpisodeWatchInfo? WatchInfo { get; set; } + + // There is a global query filter to filter by user so we just need to do single. + private EpisodeWatchInfo? _WatchInfo => Watched.FirstOrDefault(); + /// /// Links to watch this episode. /// diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Movie.cs b/back/src/Kyoo.Abstractions/Models/Resources/Movie.cs index 8723d73f..71377ca8 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Movie.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Movie.cs @@ -146,16 +146,16 @@ namespace Kyoo.Abstractions.Models Hls = $"/video/movie/{Slug}/master.m3u8", }; - [SerializeIgnore] public ICollection Watched { get; set; } + [SerializeIgnore] public ICollection Watched { get; set; } /// /// Metadata of what an user as started/planned to watch. /// [Projectable(UseMemberBody = nameof(_WatchInfo), OnlyOnInclude = true)] - [LoadableRelation] public WatchInfo? WatchInfo { get; set; } + [LoadableRelation] public MovieWatchInfo? WatchInfo { get; set; } // There is a global query filter to filter by user so we just need to do single. - private WatchInfo? _WatchInfo => Watched.FirstOrDefault(); + private MovieWatchInfo? _WatchInfo => Watched.FirstOrDefault(); /// public void OnMerge(object merged) diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Show.cs b/back/src/Kyoo.Abstractions/Models/Resources/Show.cs index a6a5fed9..8363b7d1 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Show.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Show.cs @@ -178,6 +178,17 @@ namespace Kyoo.Abstractions.Models .ThenBy(x => x.EpisodeNumber) .FirstOrDefault(); + [SerializeIgnore] public ICollection Watched { get; set; } + + /// + /// Metadata of what an user as started/planned to watch. + /// + [Projectable(UseMemberBody = nameof(_WatchInfo), OnlyOnInclude = true)] + [LoadableRelation] public ShowWatchInfo? WatchInfo { get; set; } + + // There is a global query filter to filter by user so we just need to do single. + private ShowWatchInfo? _WatchInfo => Watched.FirstOrDefault(); + /// public void OnMerge(object merged) { diff --git a/back/src/Kyoo.Abstractions/Models/Resources/User.cs b/back/src/Kyoo.Abstractions/Models/Resources/User.cs index 5328f381..b4f9913a 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/User.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/User.cs @@ -69,11 +69,11 @@ namespace Kyoo.Abstractions.Models /// public Image? Logo { get; set; } - /// - /// The user's watch list. - /// - [SerializeIgnore] - public ICollection? Watchlist { get; set; } + // /// + // /// The user's watch list. + // /// + // // [SerializeIgnore] + // // public ICollection? Watchlist { get; set; } public User() { } diff --git a/back/src/Kyoo.Abstractions/Models/Resources/WatchInfo.cs b/back/src/Kyoo.Abstractions/Models/Resources/WatchInfo.cs index 5a1a2834..c6ae4dc2 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/WatchInfo.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/WatchInfo.cs @@ -17,6 +17,8 @@ // along with Kyoo. If not, see . using System; +using System.Linq; +using EntityFrameworkCore.Projectables; using Kyoo.Abstractions.Models.Attributes; namespace Kyoo.Abstractions.Models @@ -50,7 +52,46 @@ namespace Kyoo.Abstractions.Models /// /// Metadata of what an user as started/planned to watch. /// - public class WatchInfo : IAddedDate + public class MovieWatchInfo : IAddedDate + { + /// + /// The ID of the user that started watching this episode. + /// + [SerializeIgnore] public Guid UserId { get; set; } + + /// + /// The user that started watching this episode. + /// + [SerializeIgnore] public User User { get; set; } + + /// + /// The ID of the movie started. + /// + [SerializeIgnore] public Guid MovieId { get; set; } + + /// + /// The started. + /// + [SerializeIgnore] public Movie Movie { get; set; } + + /// + public DateTime AddedDate { get; set; } + + /// + /// Has the user started watching, is it planned? + /// + public WatchStatus Status { get; set; } + + /// + /// Where the player has stopped watching the movie (in seconds). + /// + /// + /// Null if the status is not Watching. + /// + public int? WatchedTime { get; set; } + } + + public class EpisodeWatchInfo : IAddedDate { /// /// The ID of the user that started watching this episode. @@ -70,20 +111,10 @@ namespace Kyoo.Abstractions.Models /// /// The started. /// - [SerializeIgnore] public Episode? Episode { get; set; } - - /// - /// The ID of the movie started. - /// - [SerializeIgnore] public Guid? MovieId { get; set; } - - /// - /// The started. - /// - [SerializeIgnore] public Movie? Movie { get; set; } + [SerializeIgnore] public Episode Episode { get; set; } /// - [SerializeIgnore] public DateTime AddedDate { get; set; } + public DateTime AddedDate { get; set; } /// /// Has the user started watching, is it planned? @@ -98,4 +129,56 @@ namespace Kyoo.Abstractions.Models /// public int? WatchedTime { get; set; } } + + public class ShowWatchInfo : IAddedDate + { + /// + /// The ID of the user that started watching this episode. + /// + [SerializeIgnore] public Guid UserId { get; set; } + + /// + /// The user that started watching this episode. + /// + [SerializeIgnore] public User User { get; set; } + + /// + /// The ID of the show started. + /// + [SerializeIgnore] public Guid ShowId { get; set; } + + /// + /// The started. + /// + [SerializeIgnore] public Show Show { get; set; } + + /// + public DateTime AddedDate { get; set; } + + /// + /// Has the user started watching, is it planned? + /// + public WatchStatus Status { get; set; } + + /// + /// The ID of the episode started. + /// + [SerializeIgnore] public Guid NextEpisodeId { get; set; } + + /// + /// The started. + /// + public Episode? NextEpisode { get; set; } + + /// + /// Where the player has stopped watching the episode (in seconds). + /// + /// + /// Null if the status is not Watching or if the next episode is not started. + /// + [Projectable(UseMemberBody = nameof(_WatchedTime), NullConditionalRewriteSupport = NullConditionalRewriteSupport.Ignore)] + public int? WatchedTime { get; set; } + + private int? _WatchedTime => NextEpisode?.Watched.FirstOrDefault()?.WatchedTime; + } } diff --git a/back/src/Kyoo.Postgresql/DatabaseContext.cs b/back/src/Kyoo.Postgresql/DatabaseContext.cs index f9d097b4..26bffbab 100644 --- a/back/src/Kyoo.Postgresql/DatabaseContext.cs +++ b/back/src/Kyoo.Postgresql/DatabaseContext.cs @@ -100,7 +100,11 @@ namespace Kyoo.Postgresql // /// // public DbSet PeopleRoles { get; set; } - public DbSet WatchInfo { get; set; } + public DbSet MovieWatchInfo { get; set; } + + public DbSet ShowWatchInfo { get; set; } + + public DbSet EpisodeWatchInfo { get; set; } /// /// Add a many to many link between two resources. @@ -302,10 +306,24 @@ namespace Kyoo.Postgresql modelBuilder.Entity().OwnsOne(x => x.Logo); - modelBuilder.Entity() - .HasKey(x => new { User = x.UserId, Episode = x.EpisodeId, Movie = x.MovieId }); - modelBuilder.Entity().HasQueryFilter(x => x.UserId == CurrentUserId); + modelBuilder.Entity() + .HasKey(x => new { User = x.UserId, Movie = x.MovieId }); + modelBuilder.Entity() + .HasKey(x => new { User = x.UserId, Show = x.ShowId }); + modelBuilder.Entity() + .HasKey(x => new { User = x.UserId, Episode = x.EpisodeId }); + + modelBuilder.Entity().HasQueryFilter(x => x.UserId == CurrentUserId); + modelBuilder.Entity().HasQueryFilter(x => x.UserId == CurrentUserId); + modelBuilder.Entity().HasQueryFilter(x => x.UserId == CurrentUserId); + + _HasAddedDate(modelBuilder); + _HasAddedDate(modelBuilder); + _HasAddedDate(modelBuilder); + modelBuilder.Entity().Ignore(x => x.WatchInfo); + modelBuilder.Entity().Ignore(x => x.WatchInfo); + modelBuilder.Entity().Ignore(x => x.WatchInfo); modelBuilder.Entity() .HasIndex(x => x.Slug)