diff --git a/back/src/Kyoo.Core/Controllers/Repositories/WatchStatusRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/WatchStatusRepository.cs
index d4be5192..18ea31ea 100644
--- a/back/src/Kyoo.Core/Controllers/Repositories/WatchStatusRepository.cs
+++ b/back/src/Kyoo.Core/Controllers/Repositories/WatchStatusRepository.cs
@@ -95,6 +95,7 @@ public class WatchStatusRepository : IWatchStatusRepository
MovieId = movieId,
Status = status,
WatchedTime = watchedTime,
+ AddedDate = DateTime.UtcNow
};
await _database.MovieWatchStatus.Upsert(ret)
.UpdateIf(x => !(status == WatchStatus.Watching && x.Status == WatchStatus.Completed))
@@ -149,6 +150,7 @@ public class WatchStatusRepository : IWatchStatusRepository
)
: null,
UnseenEpisodesCount = unseenEpisodeCount,
+ AddedDate = DateTime.UtcNow
};
await _database.ShowWatchStatus.Upsert(ret)
.UpdateIf(x => !(status == WatchStatus.Watching && x.Status == WatchStatus.Completed))
@@ -211,6 +213,7 @@ public class WatchStatusRepository : IWatchStatusRepository
Status = status,
WatchedTime = watchedTime,
WatchedPercent = percent,
+ AddedDate = DateTime.UtcNow
};
await _database.EpisodeWatchStatus.Upsert(ret)
.UpdateIf(x => !(status == WatchStatus.Watching && x.Status == WatchStatus.Completed))
diff --git a/back/src/Kyoo.Core/Views/Resources/EpisodeApi.cs b/back/src/Kyoo.Core/Views/Resources/EpisodeApi.cs
index 47c84b70..a91db99e 100644
--- a/back/src/Kyoo.Core/Views/Resources/EpisodeApi.cs
+++ b/back/src/Kyoo.Core/Views/Resources/EpisodeApi.cs
@@ -22,6 +22,7 @@ using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Attributes;
using Kyoo.Abstractions.Models.Permissions;
using Kyoo.Abstractions.Models.Utils;
+using Kyoo.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using static Kyoo.Abstractions.Models.Utils.Constants;
@@ -108,5 +109,86 @@ namespace Kyoo.Core.Api
? NotFound()
: NoContent();
}
+
+ ///
+ /// Get watch status
+ ///
+ ///
+ /// Get when an item has been wathed and if it was watched.
+ ///
+ /// The ID or slug of the .
+ /// The status.
+ /// This episode does not have a specific status.
+ /// No episode with the given ID or slug could be found.
+ [HttpGet("{identifier:id}/watchStatus")]
+ [HttpGet("{identifier:id}/watchStatus", Order = AlternativeRoute)]
+ [UserOnly]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ public async Task GetWatchStatus(Identifier identifier)
+ {
+ return await _libraryManager.WatchStatus.GetEpisodeStatus(
+ identifier.IsSame(),
+ User.GetId()!.Value
+ );
+ }
+
+ ///
+ /// Set watch status
+ ///
+ ///
+ /// Set when an item has been wathed and if it was watched.
+ ///
+ /// The ID or slug of the .
+ /// The new watch status.
+ /// Where the user stopped watching.
+ /// The newly set status.
+ /// The status has been set
+ /// The status was not considered impactfull enough to be saved (less then 5% of watched for example).
+ /// No episode with the given ID or slug could be found.
+ [HttpPost("{identifier:id}/watchStatus")]
+ [HttpPost("{identifier:id}/watchStatus", Order = AlternativeRoute)]
+ [UserOnly]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ public async Task SetWatchStatus(Identifier identifier, WatchStatus status, int? watchedTime)
+ {
+ int id = await identifier.Match(
+ id => Task.FromResult(id),
+ async slug => (await _libraryManager.Episodes.Get(slug)).Id
+ );
+ return await _libraryManager.WatchStatus.SetEpisodeStatus(
+ id,
+ User.GetId()!.Value,
+ status,
+ watchedTime
+ );
+ }
+
+ ///
+ /// Delete watch status
+ ///
+ ///
+ /// Delete watch status (to rewatch for example).
+ ///
+ /// The ID or slug of the .
+ /// The newly set status.
+ /// The status has been deleted.
+ /// No episode with the given ID or slug could be found.
+ [HttpDelete("{identifier:id}/watchStatus")]
+ [HttpDelete("{identifier:id}/watchStatus", Order = AlternativeRoute)]
+ [UserOnly]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ public async Task DeleteWatchStatus(Identifier identifier)
+ {
+ await _libraryManager.WatchStatus.DeleteEpisodeStatus(
+ identifier.IsSame(),
+ User.GetId()!.Value
+ );
+ }
}
}
diff --git a/back/src/Kyoo.Core/Views/Resources/ShowApi.cs b/back/src/Kyoo.Core/Views/Resources/ShowApi.cs
index 077b99dd..98f11a78 100644
--- a/back/src/Kyoo.Core/Views/Resources/ShowApi.cs
+++ b/back/src/Kyoo.Core/Views/Resources/ShowApi.cs
@@ -24,6 +24,7 @@ using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Attributes;
using Kyoo.Abstractions.Models.Permissions;
using Kyoo.Abstractions.Models.Utils;
+using Kyoo.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using static Kyoo.Abstractions.Models.Utils.Constants;
@@ -226,5 +227,84 @@ namespace Kyoo.Core.Api
return NotFound();
return Page(resources, pagination.Limit);
}
+
+ ///
+ /// Get watch status
+ ///
+ ///
+ /// Get when an item has been wathed and if it was watched.
+ ///
+ /// The ID or slug of the .
+ /// The status.
+ /// This show does not have a specific status.
+ /// No show with the given ID or slug could be found.
+ [HttpGet("{identifier:id}/watchStatus")]
+ [HttpGet("{identifier:id}/watchStatus", Order = AlternativeRoute)]
+ [UserOnly]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ public async Task GetWatchStatus(Identifier identifier)
+ {
+ return await _libraryManager.WatchStatus.GetShowStatus(
+ identifier.IsSame(),
+ User.GetId()!.Value
+ );
+ }
+
+ ///
+ /// Set watch status
+ ///
+ ///
+ /// Set when an item has been wathed and if it was watched.
+ ///
+ /// The ID or slug of the .
+ /// The new watch status.
+ /// The newly set status.
+ /// The status has been set
+ /// The status was not considered impactfull enough to be saved (less then 5% of watched for example).
+ /// No movie with the given ID or slug could be found.
+ [HttpPost("{identifier:id}/watchStatus")]
+ [HttpPost("{identifier:id}/watchStatus", Order = AlternativeRoute)]
+ [UserOnly]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ public async Task SetWatchStatus(Identifier identifier, WatchStatus status)
+ {
+ int id = await identifier.Match(
+ id => Task.FromResult(id),
+ async slug => (await _libraryManager.Shows.Get(slug)).Id
+ );
+ return await _libraryManager.WatchStatus.SetShowStatus(
+ id,
+ User.GetId()!.Value,
+ status
+ );
+ }
+
+ ///
+ /// Delete watch status
+ ///
+ ///
+ /// Delete watch status (to rewatch for example).
+ ///
+ /// The ID or slug of the .
+ /// The newly set status.
+ /// The status has been deleted.
+ /// No show with the given ID or slug could be found.
+ [HttpDelete("{identifier:id}/watchStatus")]
+ [HttpDelete("{identifier:id}/watchStatus", Order = AlternativeRoute)]
+ [UserOnly]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ public async Task DeleteWatchStatus(Identifier identifier)
+ {
+ await _libraryManager.WatchStatus.DeleteShowStatus(
+ identifier.IsSame(),
+ User.GetId()!.Value
+ );
+ }
}
}
diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml
index 333ca536..9ee2c7d0 100644
--- a/docker-compose.prod.yml
+++ b/docker-compose.prod.yml
@@ -4,7 +4,7 @@ services:
back:
image: zoriya/kyoo_back:edge
restart: unless-stopped
- cpus: 0.8
+ cpus: 1.5
env_file:
- ./.env
depends_on:
@@ -36,7 +36,6 @@ services:
transcoder:
image: zoriya/kyoo_transcoder:edge
restart: unless-stopped
- cpus: 0.8
env_file:
- ./.env
volumes: