Add watch status changed events

This commit is contained in:
Zoe Roux 2024-03-17 12:23:11 +01:00
parent 0d91001376
commit c15dcb02ec
No known key found for this signature in database
2 changed files with 43 additions and 46 deletions

View File

@ -29,12 +29,7 @@ namespace Kyoo.Abstractions.Controllers;
/// </summary> /// </summary>
public interface IWatchStatusRepository public interface IWatchStatusRepository
{ {
// /// <summary> public delegate Task ResourceEventHandler<T>(T resource);
// /// The event handler type for all events of this repository.
// /// </summary>
// /// <param name="resource">The resource created/modified/deleted</param>
// /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
// public delegate Task ResourceEventHandler(T resource);
Task<ICollection<IWatchlist>> GetAll( Task<ICollection<IWatchlist>> GetAll(
Filter<IWatchlist>? filter = default, Filter<IWatchlist>? filter = default,
@ -52,12 +47,22 @@ public interface IWatchStatusRepository
int? percent int? percent
); );
static event ResourceEventHandler<Movie> OnMovieStatusChangedHandler;
protected static Task OnMovieStatusChanged(Movie obj) =>
OnMovieStatusChangedHandler?.Invoke(obj) ?? Task.CompletedTask;
Task DeleteMovieStatus(Guid movieId, Guid userId); Task DeleteMovieStatus(Guid movieId, Guid userId);
Task<ShowWatchStatus?> GetShowStatus(Guid showId, Guid userId); Task<ShowWatchStatus?> GetShowStatus(Guid showId, Guid userId);
Task<ShowWatchStatus?> SetShowStatus(Guid showId, Guid userId, WatchStatus status); Task<ShowWatchStatus?> SetShowStatus(Guid showId, Guid userId, WatchStatus status);
static event ResourceEventHandler<Show> OnShowStatusChangedHandler;
protected static Task OnShowStatusChanged(Show obj) =>
OnShowStatusChangedHandler?.Invoke(obj) ?? Task.CompletedTask;
Task DeleteShowStatus(Guid showId, Guid userId); Task DeleteShowStatus(Guid showId, Guid userId);
Task<EpisodeWatchStatus?> GetEpisodeStatus(Guid episodeId, Guid userId); Task<EpisodeWatchStatus?> GetEpisodeStatus(Guid episodeId, Guid userId);
@ -72,5 +77,10 @@ public interface IWatchStatusRepository
int? percent int? percent
); );
static event ResourceEventHandler<Episode> OnEpisodeStatusChangedHandler;
protected static Task OnEpisodeStatusChanged(Episode obj) =>
OnEpisodeStatusChangedHandler?.Invoke(obj) ?? Task.CompletedTask;
Task DeleteEpisodeStatus(Guid episodeId, Guid userId); Task DeleteEpisodeStatus(Guid episodeId, Guid userId);
} }

View File

@ -33,7 +33,12 @@ using Microsoft.Extensions.DependencyInjection;
namespace Kyoo.Core.Controllers; namespace Kyoo.Core.Controllers;
public class WatchStatusRepository : IWatchStatusRepository public class WatchStatusRepository(
DatabaseContext database,
IRepository<Movie> movies,
DbConnection db,
SqlVariableContext context
) : IWatchStatusRepository
{ {
/// <summary> /// <summary>
/// If the watch percent is below this value, don't consider the item started. /// If the watch percent is below this value, don't consider the item started.
@ -55,11 +60,6 @@ public class WatchStatusRepository : IWatchStatusRepository
private WatchStatus Completed = WatchStatus.Completed; private WatchStatus Completed = WatchStatus.Completed;
private WatchStatus Planned = WatchStatus.Planned; private WatchStatus Planned = WatchStatus.Planned;
private readonly DatabaseContext _database;
private readonly IRepository<Movie> _movies;
private readonly DbConnection _db;
private readonly SqlVariableContext _context;
static WatchStatusRepository() static WatchStatusRepository()
{ {
IRepository<Episode>.OnCreated += async (ep) => IRepository<Episode>.OnCreated += async (ep) =>
@ -78,19 +78,6 @@ public class WatchStatusRepository : IWatchStatusRepository
}; };
} }
public WatchStatusRepository(
DatabaseContext database,
IRepository<Movie> movies,
DbConnection db,
SqlVariableContext context
)
{
_database = database;
_movies = movies;
_db = db;
_context = context;
}
// language=PostgreSQL // language=PostgreSQL
protected FormattableString Sql => protected FormattableString Sql =>
$""" $"""
@ -169,11 +156,11 @@ public class WatchStatusRepository : IWatchStatusRepository
/// <inheritdoc /> /// <inheritdoc />
public Task<IWatchlist?> GetOrDefault(Guid id, Include<IWatchlist>? include = null) public Task<IWatchlist?> GetOrDefault(Guid id, Include<IWatchlist>? include = null)
{ {
return _db.QuerySingle<IWatchlist>( return db.QuerySingle<IWatchlist>(
Sql, Sql,
Config, Config,
Mapper, Mapper,
_context, context,
include, include,
new Filter<IWatchlist>.Eq(nameof(IResource.Id), id) new Filter<IWatchlist>.Eq(nameof(IResource.Id), id)
); );
@ -208,12 +195,12 @@ public class WatchStatusRepository : IWatchStatusRepository
limit.AfterID = null; limit.AfterID = null;
} }
return await _db.Query( return await db.Query(
Sql, Sql,
Config, Config,
Mapper, Mapper,
(id) => Get(id), (id) => Get(id),
_context, context,
include, include,
filter, filter,
null, null,
@ -224,7 +211,7 @@ public class WatchStatusRepository : IWatchStatusRepository
/// <inheritdoc /> /// <inheritdoc />
public Task<MovieWatchStatus?> GetMovieStatus(Guid movieId, Guid userId) public Task<MovieWatchStatus?> GetMovieStatus(Guid movieId, Guid userId)
{ {
return _database.MovieWatchStatus.FirstOrDefaultAsync(x => return database.MovieWatchStatus.FirstOrDefaultAsync(x =>
x.MovieId == movieId && x.UserId == userId x.MovieId == movieId && x.UserId == userId
); );
} }
@ -238,7 +225,7 @@ public class WatchStatusRepository : IWatchStatusRepository
int? percent int? percent
) )
{ {
Movie movie = await _movies.Get(movieId); Movie movie = await movies.Get(movieId);
if (percent == null && watchedTime != null && movie.Runtime > 0) if (percent == null && watchedTime != null && movie.Runtime > 0)
percent = (int)Math.Round(watchedTime.Value / (movie.Runtime.Value * 60f) * 100f); percent = (int)Math.Round(watchedTime.Value / (movie.Runtime.Value * 60f) * 100f);
@ -274,7 +261,7 @@ public class WatchStatusRepository : IWatchStatusRepository
AddedDate = DateTime.UtcNow, AddedDate = DateTime.UtcNow,
PlayedDate = status == WatchStatus.Completed ? DateTime.UtcNow : null, PlayedDate = status == WatchStatus.Completed ? DateTime.UtcNow : null,
}; };
await _database await database
.MovieWatchStatus.Upsert(ret) .MovieWatchStatus.Upsert(ret)
.UpdateIf(x => status != Watching || x.Status != Completed) .UpdateIf(x => status != Watching || x.Status != Completed)
.RunAsync(); .RunAsync();
@ -284,7 +271,7 @@ public class WatchStatusRepository : IWatchStatusRepository
/// <inheritdoc /> /// <inheritdoc />
public async Task DeleteMovieStatus(Guid movieId, Guid userId) public async Task DeleteMovieStatus(Guid movieId, Guid userId)
{ {
await _database await database
.MovieWatchStatus.Where(x => x.MovieId == movieId && x.UserId == userId) .MovieWatchStatus.Where(x => x.MovieId == movieId && x.UserId == userId)
.ExecuteDeleteAsync(); .ExecuteDeleteAsync();
} }
@ -292,7 +279,7 @@ public class WatchStatusRepository : IWatchStatusRepository
/// <inheritdoc /> /// <inheritdoc />
public Task<ShowWatchStatus?> GetShowStatus(Guid showId, Guid userId) public Task<ShowWatchStatus?> GetShowStatus(Guid showId, Guid userId)
{ {
return _database.ShowWatchStatus.FirstOrDefaultAsync(x => return database.ShowWatchStatus.FirstOrDefaultAsync(x =>
x.ShowId == showId && x.UserId == userId x.ShowId == showId && x.UserId == userId
); );
} }
@ -310,7 +297,7 @@ public class WatchStatusRepository : IWatchStatusRepository
{ {
int unseenEpisodeCount = int unseenEpisodeCount =
status != WatchStatus.Completed status != WatchStatus.Completed
? await _database ? await database
.Episodes.Where(x => x.ShowId == showId) .Episodes.Where(x => x.ShowId == showId)
.Where(x => .Where(x =>
x.Watched!.First(x => x.UserId == userId)!.Status != WatchStatus.Completed x.Watched!.First(x => x.UserId == userId)!.Status != WatchStatus.Completed
@ -324,7 +311,7 @@ public class WatchStatusRepository : IWatchStatusRepository
Guid? nextEpisodeId = null; Guid? nextEpisodeId = null;
if (status == WatchStatus.Watching) if (status == WatchStatus.Watching)
{ {
var cursor = await _database var cursor = await database
.Episodes.IgnoreQueryFilters() .Episodes.IgnoreQueryFilters()
.Where(x => x.ShowId == showId) .Where(x => x.ShowId == showId)
.OrderByDescending(x => x.AbsoluteNumber) .OrderByDescending(x => x.AbsoluteNumber)
@ -346,7 +333,7 @@ public class WatchStatusRepository : IWatchStatusRepository
nextEpisodeId = nextEpisodeId =
cursor?.Status.Status == WatchStatus.Watching cursor?.Status.Status == WatchStatus.Watching
? cursor.Id ? cursor.Id
: await _database : await database
.Episodes.IgnoreQueryFilters() .Episodes.IgnoreQueryFilters()
.Where(x => x.ShowId == showId) .Where(x => x.ShowId == showId)
.OrderBy(x => x.AbsoluteNumber) .OrderBy(x => x.AbsoluteNumber)
@ -374,11 +361,11 @@ public class WatchStatusRepository : IWatchStatusRepository
} }
else if (status == WatchStatus.Completed) else if (status == WatchStatus.Completed)
{ {
List<Guid> episodes = await _database List<Guid> episodes = await database
.Episodes.Where(x => x.ShowId == showId) .Episodes.Where(x => x.ShowId == showId)
.Select(x => x.Id) .Select(x => x.Id)
.ToListAsync(); .ToListAsync();
await _database await database
.EpisodeWatchStatus.UpsertRange( .EpisodeWatchStatus.UpsertRange(
episodes.Select(episodeId => new EpisodeWatchStatus episodes.Select(episodeId => new EpisodeWatchStatus
{ {
@ -412,7 +399,7 @@ public class WatchStatusRepository : IWatchStatusRepository
UnseenEpisodesCount = unseenEpisodeCount, UnseenEpisodesCount = unseenEpisodeCount,
PlayedDate = status == WatchStatus.Completed ? DateTime.UtcNow : null, PlayedDate = status == WatchStatus.Completed ? DateTime.UtcNow : null,
}; };
await _database await database
.ShowWatchStatus.Upsert(ret) .ShowWatchStatus.Upsert(ret)
.UpdateIf(x => status != Watching || x.Status != Completed || newEpisode) .UpdateIf(x => status != Watching || x.Status != Completed || newEpisode)
.RunAsync(); .RunAsync();
@ -422,11 +409,11 @@ public class WatchStatusRepository : IWatchStatusRepository
/// <inheritdoc /> /// <inheritdoc />
public async Task DeleteShowStatus(Guid showId, Guid userId) public async Task DeleteShowStatus(Guid showId, Guid userId)
{ {
await _database await database
.ShowWatchStatus.IgnoreAutoIncludes() .ShowWatchStatus.IgnoreAutoIncludes()
.Where(x => x.ShowId == showId && x.UserId == userId) .Where(x => x.ShowId == showId && x.UserId == userId)
.ExecuteDeleteAsync(); .ExecuteDeleteAsync();
await _database await database
.EpisodeWatchStatus.Where(x => x.Episode.ShowId == showId && x.UserId == userId) .EpisodeWatchStatus.Where(x => x.Episode.ShowId == showId && x.UserId == userId)
.ExecuteDeleteAsync(); .ExecuteDeleteAsync();
} }
@ -434,7 +421,7 @@ public class WatchStatusRepository : IWatchStatusRepository
/// <inheritdoc /> /// <inheritdoc />
public Task<EpisodeWatchStatus?> GetEpisodeStatus(Guid episodeId, Guid userId) public Task<EpisodeWatchStatus?> GetEpisodeStatus(Guid episodeId, Guid userId)
{ {
return _database.EpisodeWatchStatus.FirstOrDefaultAsync(x => return database.EpisodeWatchStatus.FirstOrDefaultAsync(x =>
x.EpisodeId == episodeId && x.UserId == userId x.EpisodeId == episodeId && x.UserId == userId
); );
} }
@ -448,7 +435,7 @@ public class WatchStatusRepository : IWatchStatusRepository
int? percent int? percent
) )
{ {
Episode episode = await _database.Episodes.FirstAsync(x => x.Id == episodeId); Episode episode = await database.Episodes.FirstAsync(x => x.Id == episodeId);
if (percent == null && watchedTime != null && episode.Runtime > 0) if (percent == null && watchedTime != null && episode.Runtime > 0)
percent = (int)Math.Round(watchedTime.Value / (episode.Runtime.Value * 60f) * 100f); percent = (int)Math.Round(watchedTime.Value / (episode.Runtime.Value * 60f) * 100f);
@ -484,7 +471,7 @@ public class WatchStatusRepository : IWatchStatusRepository
AddedDate = DateTime.UtcNow, AddedDate = DateTime.UtcNow,
PlayedDate = status == WatchStatus.Completed ? DateTime.UtcNow : null, PlayedDate = status == WatchStatus.Completed ? DateTime.UtcNow : null,
}; };
await _database await database
.EpisodeWatchStatus.Upsert(ret) .EpisodeWatchStatus.Upsert(ret)
.UpdateIf(x => status != Watching || x.Status != Completed) .UpdateIf(x => status != Watching || x.Status != Completed)
.RunAsync(); .RunAsync();
@ -495,7 +482,7 @@ public class WatchStatusRepository : IWatchStatusRepository
/// <inheritdoc /> /// <inheritdoc />
public async Task DeleteEpisodeStatus(Guid episodeId, Guid userId) public async Task DeleteEpisodeStatus(Guid episodeId, Guid userId)
{ {
await _database await database
.EpisodeWatchStatus.Where(x => x.EpisodeId == episodeId && x.UserId == userId) .EpisodeWatchStatus.Where(x => x.EpisodeId == episodeId && x.UserId == userId)
.ExecuteDeleteAsync(); .ExecuteDeleteAsync();
} }