Files
Nexus.Reader/src/NexusReader.Application/Abstractions/Services/IEpubReader.cs
T
Antigravity bf31effd36 fix: preserve and render EPUB images via dynamic server endpoint (#65)
Fixes #64

### Summary of Changes
1. **Extended `IEpubReader` & `EpubReaderService`**: Added `GetEpubResourceAsync` to handle binary data extraction of static assets (like images) from the EPUB archive.
2. **Added Client-Side HTTP Call**: Extended `WasmEpubService` to retrieve static resources from the server using the API client.
3. **Preserved and Sanitized Images**: Updated `ExtractParagraphs` and `SanitizeParagraph` to treat `<img>` tags as first-class citizens, preserving their `src` attributes and excluding them from sanitization stripping.
4. **Dynamic URL Rewriting**: Introduced a relative-to-absolute path resolution algorithm (`ResolveRelativePath`) and rewrote image `src` attributes to use the dynamic endpoint `/api/epub/{ebookId}/resource?path=...`.
5. **Registered API Resource Serving Endpoint**: Added the `/api/epub/{ebookId:guid}/resource` minimal API endpoint in `Program.cs` that maps requests directly to `GetEpubResourceAsync` and returns files with the correct MIME type.
6. **Added Unit Tests**: Created `EpubReaderServiceTests.cs` to verify all image extraction, path resolution, and sanitization/rewriting rules. All tests pass successfully.

---------

Co-authored-by: Marek Jasiński <jasins.marek@gmail.com>
Reviewed-on: #65
Co-authored-by: Antigravity <antigravity@google.com>
Co-committed-by: Antigravity <antigravity@google.com>
2026-06-01 16:04:56 +00:00

37 lines
1.5 KiB
C#

using FluentResults;
using NexusReader.Application.Queries.Reader;
namespace NexusReader.Application.Abstractions.Services;
/// <summary>
/// Reads and parses EPUB content for a specific ebook and chapter.
/// </summary>
public interface IEpubReader
{
/// <summary>
/// Retrieves the content blocks for a given chapter of the specified ebook.
/// </summary>
/// <param name="ebookId">The unique ID of the ebook to read.</param>
/// <param name="chapterIndex">Zero-based chapter index.</param>
/// <param name="userId">The authenticated user's ID (used for tenant isolation in the DB lookup).</param>
/// <param name="cancellationToken">Cancellation token.</param>
Task<Result<ReaderPageViewModel>> GetEpubContentAsync(
Guid ebookId,
int chapterIndex,
string? userId = null,
CancellationToken cancellationToken = default);
/// <summary>
/// Retrieves a resource (like an image) from the EPUB as a byte array.
/// </summary>
/// <param name="ebookId">The unique ID of the ebook to read.</param>
/// <param name="resourcePath">The path of the resource within the EPUB archive.</param>
/// <param name="userId">The authenticated user's ID (used for tenant isolation).</param>
/// <param name="cancellationToken">Cancellation token.</param>
Task<Result<byte[]>> GetEpubResourceAsync(
Guid ebookId,
string resourcePath,
string? userId = null,
CancellationToken cancellationToken = default);
}