using System; using System.Threading.Tasks; using Kavita.API.Services; using Kavita.Common; using Kavita.Common.Extensions; using Kavita.Models.DTOs.Koreader; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; namespace Kavita.Server.Controllers; /// /// The endpoint to interface with Koreader's Progress Sync plugin. /// /// /// Koreader uses a different form of authentication. It stores the username and password in headers. /// https://github.com/koreader/koreader/blob/master/plugins/kosync.koplugin/KOSyncClient.lua /// public class KoreaderController(IKoreaderService koreaderService, ILogger logger) : BaseApiController { [HttpGet("{apiKey}/users/auth")] public IActionResult Authenticate(string apiKey) { return Ok(new { username = Username }); } /// /// Syncs book progress with Kavita. Will attempt to save the underlying reader position if possible. /// /// /// /// [HttpPut("{apiKey}/syncs/progress")] public async Task> UpdateProgress(string apiKey, KoreaderBookDto request) { try { await koreaderService.SaveProgress(request, UserId); return Ok(new KoreaderProgressUpdateDto{ Document = request.document, Timestamp = DateTime.UtcNow }); } catch (KavitaException ex) { return BadRequest(ex.Message); } } /// /// Gets book progress from Kavita, if not found will return a 400 /// /// /// /// [HttpGet("{apiKey}/syncs/progress/{ebookHash}")] public async Task GetProgress(string apiKey, string ebookHash) { try { var response = await koreaderService.GetProgress(ebookHash, UserId); logger.LogDebug("Koreader response progress for User ({UserName}): {Progress}", Username, response.progress.Sanitize()); // We must pack this manually for Koreader due to a bug in their code: https://github.com/koreader/koreader/issues/13629 var json = System.Text.Json.JsonSerializer.Serialize(response); return new ContentResult() { Content = json, ContentType = "application/json", StatusCode = 200 }; } catch (KavitaException ex) { return BadRequest(ex.Message); } } }