diff --git a/back/src/Kyoo.Abstractions/Controllers/IWatchStatusRepository.cs b/back/src/Kyoo.Abstractions/Controllers/IWatchStatusRepository.cs index a4372d23..17ebe40c 100644 --- a/back/src/Kyoo.Abstractions/Controllers/IWatchStatusRepository.cs +++ b/back/src/Kyoo.Abstractions/Controllers/IWatchStatusRepository.cs @@ -47,8 +47,8 @@ public interface IWatchStatusRepository int? percent ); - static event ResourceEventHandler OnMovieStatusChangedHandler; - protected static Task OnMovieStatusChanged(MovieWatchStatus obj) => + static event ResourceEventHandler> OnMovieStatusChangedHandler; + protected static Task OnMovieStatusChanged(WatchStatus obj) => OnMovieStatusChangedHandler?.Invoke(obj) ?? Task.CompletedTask; Task DeleteMovieStatus(Guid movieId, Guid userId); @@ -57,8 +57,8 @@ public interface IWatchStatusRepository Task SetShowStatus(Guid showId, Guid userId, WatchStatus status); - static event ResourceEventHandler OnShowStatusChangedHandler; - protected static Task OnShowStatusChanged(ShowWatchStatus obj) => + static event ResourceEventHandler> OnShowStatusChangedHandler; + protected static Task OnShowStatusChanged(WatchStatus obj) => OnShowStatusChangedHandler?.Invoke(obj) ?? Task.CompletedTask; Task DeleteShowStatus(Guid showId, Guid userId); @@ -75,8 +75,8 @@ public interface IWatchStatusRepository int? percent ); - static event ResourceEventHandler OnEpisodeStatusChangedHandler; - protected static Task OnEpisodeStatusChanged(EpisodeWatchStatus obj) => + static event ResourceEventHandler> OnEpisodeStatusChangedHandler; + protected static Task OnEpisodeStatusChanged(WatchStatus obj) => OnEpisodeStatusChangedHandler?.Invoke(obj) ?? Task.CompletedTask; Task DeleteEpisodeStatus(Guid episodeId, Guid userId); diff --git a/back/src/Kyoo.Abstractions/Models/Resources/WatchStatus.cs b/back/src/Kyoo.Abstractions/Models/Resources/WatchStatus.cs index 1caf380c..d6576f5e 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/WatchStatus.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/WatchStatus.cs @@ -53,20 +53,11 @@ public enum WatchStatus Deleted, } -public interface IWatchStatus -{ - /// - /// Has the user started watching, is it planned? - /// - public WatchStatus Status { get; set; } -} - - /// /// Metadata of what an user as started/planned to watch. /// [SqlFirstColumn(nameof(UserId))] -public class MovieWatchStatus : IAddedDate, IWatchStatus +public class MovieWatchStatus : IAddedDate { /// /// The ID of the user that started watching this episode. @@ -121,7 +112,7 @@ public class MovieWatchStatus : IAddedDate, IWatchStatus } [SqlFirstColumn(nameof(UserId))] -public class EpisodeWatchStatus : IAddedDate, IWatchStatus +public class EpisodeWatchStatus : IAddedDate { /// /// The ID of the user that started watching this episode. @@ -176,7 +167,7 @@ public class EpisodeWatchStatus : IAddedDate, IWatchStatus } [SqlFirstColumn(nameof(UserId))] -public class ShowWatchStatus : IAddedDate, IWatchStatus +public class ShowWatchStatus : IAddedDate { /// /// The ID of the user that started watching this episode. @@ -244,3 +235,45 @@ public class ShowWatchStatus : IAddedDate, IWatchStatus /// public int? WatchedPercent { get; set; } } + +public class WatchStatus : IAddedDate +{ + /// + /// Has the user started watching, is it planned? + /// + public required WatchStatus Status { get; set; } + + /// + public DateTime AddedDate { get; set; } + + /// + /// The date at which this item was played. + /// + public DateTime? PlayedDate { 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. + /// + public int? WatchedTime { get; set; } + + /// + /// Where the player has stopped watching the episode (in percentage between 0 and 100). + /// + /// + /// Null if the status is not Watching or if the next episode is not started. + /// + public int? WatchedPercent { get; set; } + + /// + /// The user that started watching this episode. + /// + public required User User { get; set; } + + /// + /// The episode/show/movie whose status changed + /// + public required T Resource { get; set; } +} diff --git a/back/src/Kyoo.Core/Controllers/Repositories/WatchStatusRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/WatchStatusRepository.cs index d8a72070..17a3db8e 100644 --- a/back/src/Kyoo.Core/Controllers/Repositories/WatchStatusRepository.cs +++ b/back/src/Kyoo.Core/Controllers/Repositories/WatchStatusRepository.cs @@ -36,6 +36,9 @@ namespace Kyoo.Core.Controllers; public class WatchStatusRepository( DatabaseContext database, IRepository movies, + IRepository shows, + IRepository episodes, + IRepository users, DbConnection db, SqlVariableContext context ) : IWatchStatusRepository @@ -265,7 +268,18 @@ public class WatchStatusRepository( .MovieWatchStatus.Upsert(ret) .UpdateIf(x => status != Watching || x.Status != Completed) .RunAsync(); - await IWatchStatusRepository.OnMovieStatusChanged(ret); + await IWatchStatusRepository.OnMovieStatusChanged( + new() + { + User = await users.Get(ret.UserId), + Resource = await movies.Get(ret.MovieId), + Status = ret.Status, + WatchedTime = ret.WatchedTime, + WatchedPercent = ret.WatchedPercent, + AddedDate = ret.AddedDate, + PlayedDate = ret.PlayedDate, + } + ); return ret; } @@ -278,8 +292,8 @@ public class WatchStatusRepository( await IWatchStatusRepository.OnMovieStatusChanged( new() { - UserId = userId, - MovieId = movieId, + User = await users.Get(userId), + Resource = await movies.Get(movieId), AddedDate = DateTime.UtcNow, Status = WatchStatus.Deleted, } @@ -413,7 +427,18 @@ public class WatchStatusRepository( .ShowWatchStatus.Upsert(ret) .UpdateIf(x => status != Watching || x.Status != Completed || newEpisode) .RunAsync(); - await IWatchStatusRepository.OnShowStatusChanged(ret); + await IWatchStatusRepository.OnShowStatusChanged( + new() + { + User = await users.Get(ret.UserId), + Resource = await shows.Get(ret.ShowId), + Status = ret.Status, + WatchedTime = ret.WatchedTime, + WatchedPercent = ret.WatchedPercent, + AddedDate = ret.AddedDate, + PlayedDate = ret.PlayedDate, + } + ); return ret; } @@ -430,8 +455,8 @@ public class WatchStatusRepository( await IWatchStatusRepository.OnShowStatusChanged( new() { - UserId = userId, - ShowId = showId, + User = await users.Get(userId), + Resource = await shows.Get(showId), AddedDate = DateTime.UtcNow, Status = WatchStatus.Deleted, } @@ -495,7 +520,18 @@ public class WatchStatusRepository( .EpisodeWatchStatus.Upsert(ret) .UpdateIf(x => status != Watching || x.Status != Completed) .RunAsync(); - await IWatchStatusRepository.OnEpisodeStatusChanged(ret); + await IWatchStatusRepository.OnEpisodeStatusChanged( + new() + { + User = await users.Get(ret.UserId), + Resource = await episodes.Get(ret.EpisodeId), + Status = ret.Status, + WatchedTime = ret.WatchedTime, + WatchedPercent = ret.WatchedPercent, + AddedDate = ret.AddedDate, + PlayedDate = ret.PlayedDate, + } + ); await SetShowStatus(episode.ShowId, userId, WatchStatus.Watching); return ret; } @@ -509,8 +545,8 @@ public class WatchStatusRepository( await IWatchStatusRepository.OnEpisodeStatusChanged( new() { - UserId = userId, - EpisodeId = episodeId, + User = await users.Get(userId), + Resource = await episodes.Get(episodeId), AddedDate = DateTime.UtcNow, Status = WatchStatus.Deleted, } diff --git a/back/src/Kyoo.RabbitMq/Message.cs b/back/src/Kyoo.RabbitMq/Message.cs index a1bbba9b..67e12760 100644 --- a/back/src/Kyoo.RabbitMq/Message.cs +++ b/back/src/Kyoo.RabbitMq/Message.cs @@ -21,11 +21,11 @@ using System.Text.Json; namespace Kyoo.RabbitMq; -public class Message +public class Message { public string Action { get; set; } public string Type { get; set; } - public object Value { get; set; } + public T Value { get; set; } public string AsRoutingKey() { diff --git a/back/src/Kyoo.RabbitMq/RabbitProducer.cs b/back/src/Kyoo.RabbitMq/RabbitProducer.cs index d04ffff7..f3809dfd 100644 --- a/back/src/Kyoo.RabbitMq/RabbitProducer.cs +++ b/back/src/Kyoo.RabbitMq/RabbitProducer.cs @@ -40,14 +40,11 @@ public class RabbitProducer _ListenResourceEvents("events.resource"); _channel.ExchangeDeclare("events.watched", ExchangeType.Topic); - IWatchStatusRepository.OnMovieStatusChangedHandler += _PublishWatchStatus( - "movie" + IWatchStatusRepository.OnMovieStatusChangedHandler += _PublishWatchStatus("movie"); + IWatchStatusRepository.OnShowStatusChangedHandler += _PublishWatchStatus("show"); + IWatchStatusRepository.OnEpisodeStatusChangedHandler += _PublishWatchStatus( + "episode" ); - IWatchStatusRepository.OnShowStatusChangedHandler += _PublishWatchStatus( - "show" - ); - IWatchStatusRepository.OnEpisodeStatusChangedHandler += - _PublishWatchStatus("episode"); } private void _ListenResourceEvents(string exchange) @@ -69,7 +66,7 @@ public class RabbitProducer { return (T resource) => { - Message message = + Message message = new() { Action = action, @@ -85,12 +82,13 @@ public class RabbitProducer }; } - private IWatchStatusRepository.ResourceEventHandler _PublishWatchStatus(string resource) - where T : IWatchStatus + private IWatchStatusRepository.ResourceEventHandler> _PublishWatchStatus( + string resource + ) { return (status) => { - Message message = + Message> message = new() { Type = resource,