diff --git a/back/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs b/back/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs index ad4e6afe..ef5bd683 100644 --- a/back/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs +++ b/back/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs @@ -41,7 +41,7 @@ namespace Kyoo.Abstractions.Controllers /// /// The repository that handle watched items. /// - IWatchItemsRepository WatchItems { get; } + IWatchStatusRepository WatchStatus { get; } /// /// The repository that handle collections. diff --git a/back/src/Kyoo.Abstractions/Controllers/IRepository.cs b/back/src/Kyoo.Abstractions/Controllers/IRepository.cs index b53d8c38..9665e091 100644 --- a/back/src/Kyoo.Abstractions/Controllers/IRepository.cs +++ b/back/src/Kyoo.Abstractions/Controllers/IRepository.cs @@ -88,10 +88,12 @@ namespace Kyoo.Abstractions.Controllers /// A predicate to filter the resource. /// The related fields to include. /// A custom sort method to handle cases where multiples items match the filters. + /// Reverse the sort. /// The resource found Task GetOrDefault(Filter? filter, Include? include = default, - Sort? sortBy = default); + Sort? sortBy = default, + bool reverse = false); /// /// Search for resources with the database. diff --git a/back/src/Kyoo.Abstractions/Controllers/IWatchItemsRepository.cs b/back/src/Kyoo.Abstractions/Controllers/IWatchStatusRepository.cs similarity index 58% rename from back/src/Kyoo.Abstractions/Controllers/IWatchItemsRepository.cs rename to back/src/Kyoo.Abstractions/Controllers/IWatchStatusRepository.cs index 465bc838..0a60f458 100644 --- a/back/src/Kyoo.Abstractions/Controllers/IWatchItemsRepository.cs +++ b/back/src/Kyoo.Abstractions/Controllers/IWatchStatusRepository.cs @@ -26,7 +26,7 @@ namespace Kyoo.Abstractions.Controllers; /// /// A local repository to handle watched items /// -public interface IWatchItemsRepository : IBaseRepository +public interface IWatchStatusRepository { // /// // /// The event handler type for all events of this repository. @@ -53,4 +53,40 @@ public interface IWatchItemsRepository : IBaseRepository /// is /// The movie's status Task SetMovieStatus(int movieId, int userId, WatchStatus status, int? watchedTime); + + /// + /// Get the watch status of a show. + /// + /// The show selector. + /// The id of the user. + /// The show's status + Task GetShowStatus(Expression> where, int userId); + + /// + /// Set the watch status of a show. + /// + /// The id of the movie. + /// The id of the user. + /// The new status. + /// The shows's status + Task SetShowStatus(int showId, int userId, WatchStatus status); + + /// + /// Get the watch status of an episode. + /// + /// The episode selector. + /// The id of the user. + /// The episode's status + Task GetEpisodeStatus(Expression> where, int userId); + + /// + /// Set the watch status of an episode. + /// + /// The id of the episode. + /// The id of the user. + /// The new status. + /// Where the user has stopped watching. Only usable if Status + /// is + /// The episode's status + Task SetEpisodeStatus(int episodeId, int userId, WatchStatus status, int? watchedTime); } diff --git a/back/src/Kyoo.Core/Controllers/LibraryManager.cs b/back/src/Kyoo.Core/Controllers/LibraryManager.cs index ad94977f..db52bd66 100644 --- a/back/src/Kyoo.Core/Controllers/LibraryManager.cs +++ b/back/src/Kyoo.Core/Controllers/LibraryManager.cs @@ -32,7 +32,7 @@ namespace Kyoo.Core.Controllers public LibraryManager( IRepository libraryItemRepository, IRepository newsRepository, - IWatchItemsRepository watchItemsRepository, + IWatchStatusRepository watchStatusRepository, IRepository collectionRepository, IRepository movieRepository, IRepository showRepository, @@ -44,7 +44,7 @@ namespace Kyoo.Core.Controllers { LibraryItems = libraryItemRepository; News = newsRepository; - WatchItems = watchItemsRepository; + WatchStatus = watchStatusRepository; Collections = collectionRepository; Movies = movieRepository; Shows = showRepository; @@ -58,7 +58,6 @@ namespace Kyoo.Core.Controllers { LibraryItems, News, - WatchItems, Collections, Movies, Shows, @@ -77,7 +76,7 @@ namespace Kyoo.Core.Controllers public IRepository News { get; } /// - public IWatchItemsRepository WatchItems { get; } + public IWatchStatusRepository WatchStatus { get; } /// public IRepository Collections { get; } diff --git a/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs index 46aff561..4f69ca5f 100644 --- a/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs +++ b/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs @@ -257,13 +257,16 @@ namespace Kyoo.Core.Controllers /// public virtual Task GetOrDefault(Filter? filter, Include? include = default, - Sort? sortBy = default) + Sort? sortBy = default, + bool reverse = false) { - return Sort( - AddIncludes(Database.Set(), include), - sortBy - ) - .FirstOrDefaultAsync(ParseFilter(filter)); + IQueryable query = Sort( + AddIncludes(Database.Set(), include), + sortBy + ); + if (reverse) + query = query.Reverse(); + return query.FirstOrDefaultAsync(ParseFilter(filter)); } /// diff --git a/back/src/Kyoo.Core/Controllers/Repositories/WatchItemsRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/WatchItemsRepository.cs deleted file mode 100644 index c2974767..00000000 --- a/back/src/Kyoo.Core/Controllers/Repositories/WatchItemsRepository.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Kyoo - A portable and vast media library solution. -// Copyright (c) Kyoo. -// -// See AUTHORS.md and LICENSE file in the project root for full license information. -// -// Kyoo is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// any later version. -// -// Kyoo is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Kyoo. If not, see . - -using System; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Linq.Expressions; -using System.Threading.Tasks; -using Kyoo.Abstractions.Controllers; -using Kyoo.Abstractions.Models; -using Kyoo.Postgresql; -using Microsoft.EntityFrameworkCore; - -namespace Kyoo.Core.Controllers; - -public class WatchItemsRepository : IWatchItemsRepository -{ - private readonly DatabaseContext _database; - - public WatchItemsRepository(DatabaseContext database) - { - _database = database; - } - - /// - public Task GetMovieStatus(Expression> where, int userId) - { - return _database.MovieWatchInfo.FirstOrDefaultAsync(x => - x.Movie == _database.Movies.FirstOrDefault(where) - && x.UserId == userId - ); - } - - /// - public async Task SetMovieStatus( - int movieId, - int userId, - WatchStatus status, - int? watchedTime) - { - if (watchedTime.HasValue && status != WatchStatus.Watching) - throw new ValidationException("Can't have a watched time if the status is not watching."); - MovieWatchStatus ret = new() - { - UserId = userId, - MovieId = movieId, - Status = status, - WatchedTime = watchedTime, - }; - await _database.MovieWatchInfo.Upsert(ret).RunAsync(); - return ret; - } -} diff --git a/back/src/Kyoo.Core/Controllers/Repositories/WatchStatusRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/WatchStatusRepository.cs new file mode 100644 index 00000000..743e5e64 --- /dev/null +++ b/back/src/Kyoo.Core/Controllers/Repositories/WatchStatusRepository.cs @@ -0,0 +1,138 @@ +// Kyoo - A portable and vast media library solution. +// Copyright (c) Kyoo. +// +// See AUTHORS.md and LICENSE file in the project root for full license information. +// +// Kyoo is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// Kyoo is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Kyoo. If not, see . + +using System; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Linq.Expressions; +using System.Threading.Tasks; +using Kyoo.Abstractions.Controllers; +using Kyoo.Abstractions.Models; +using Kyoo.Postgresql; +using Microsoft.EntityFrameworkCore; + +namespace Kyoo.Core.Controllers; + +public class WatchStatusRepository : IWatchStatusRepository +{ + private readonly DatabaseContext _database; + private readonly IRepository _episodes; + + public WatchStatusRepository(DatabaseContext database, IRepository episodes) + { + _database = database; + _episodes = episodes; + } + + /// + public Task GetMovieStatus(Expression> where, int userId) + { + return _database.MovieWatchInfo.FirstOrDefaultAsync(x => + x.Movie == _database.Movies.FirstOrDefault(where) + && x.UserId == userId + ); + } + + /// + public async Task SetMovieStatus( + int movieId, + int userId, + WatchStatus status, + int? watchedTime) + { + if (watchedTime.HasValue && status != WatchStatus.Watching) + throw new ValidationException("Can't have a watched time if the status is not watching."); + MovieWatchStatus ret = new() + { + UserId = userId, + MovieId = movieId, + Status = status, + WatchedTime = watchedTime, + }; + await _database.MovieWatchInfo.Upsert(ret) + .UpdateIf(x => !(status == WatchStatus.Watching && x.Status == WatchStatus.Completed)) + .RunAsync(); + return ret; + } + + /// + public Task GetShowStatus(Expression> where, int userId) + { + return _database.ShowWatchInfo.FirstOrDefaultAsync(x => + x.Show == _database.Shows.FirstOrDefault(where) + && x.UserId == userId + ); + } + + /// + public async Task SetShowStatus( + int showId, + int userId, + WatchStatus status) + { + ShowWatchStatus ret = new() + { + UserId = userId, + ShowId = showId, + Status = status, + NextEpisode = status == WatchStatus.Watching + ? await _episodes.GetOrDefault( + where: x => x.ShowId == showId + && (x.WatchStatus!.Status == WatchStatus.Watching + || x.WatchStatus.Status == WatchStatus.Completed), + reverse: true + ) + : null, + }; + await _database.ShowWatchInfo.Upsert(ret) + .UpdateIf(x => !(status == WatchStatus.Watching && x.Status == WatchStatus.Completed)) + .RunAsync(); + return ret; + } + + /// + public Task GetEpisodeStatus(Expression> where, int userId) + { + return _database.EpisodeWatchInfo.FirstOrDefaultAsync(x => + x.Episode == _database.Episodes.FirstOrDefault(where) + && x.UserId == userId + ); + } + + /// + public async Task SetEpisodeStatus( + int episodeId, + int userId, + WatchStatus status, + int? watchedTime) + { + Episode episode = await _episodes.Get(episodeId); + if (watchedTime.HasValue && status != WatchStatus.Watching) + throw new ValidationException("Can't have a watched time if the status is not watching."); + EpisodeWatchStatus ret = new() + { + UserId = userId, + EpisodeId = episodeId, + Status = status, + WatchedTime = watchedTime, + }; + await _database.EpisodeWatchInfo.Upsert(ret).RunAsync(); + await SetShowStatus(episode.ShowId, userId, WatchStatus.Watching); + return ret; + } +} diff --git a/back/src/Kyoo.Core/Views/Resources/MovieApi.cs b/back/src/Kyoo.Core/Views/Resources/MovieApi.cs index 5aec36b3..eca3006d 100644 --- a/back/src/Kyoo.Core/Views/Resources/MovieApi.cs +++ b/back/src/Kyoo.Core/Views/Resources/MovieApi.cs @@ -170,7 +170,7 @@ namespace Kyoo.Core.Api [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetWatchStatus(Identifier identifier) { - return await _libraryManager.WatchItems.GetMovieStatus( + return await _libraryManager.WatchStatus.GetMovieStatus( identifier.IsSame(), User.GetId()!.Value ); @@ -202,7 +202,7 @@ namespace Kyoo.Core.Api id => Task.FromResult(id), async slug => (await _libraryManager.Movies.Get(slug)).Id ); - return await _libraryManager.WatchItems.SetMovieStatus( + return await _libraryManager.WatchStatus.SetMovieStatus( id, User.GetId()!.Value, status,