feat: add /image endpoint for chapter pages with Content-Length header

New GET endpoint at /api/v1/manga/{mangaId}/chapter/{chapterIndex}/page/{index}/image
that buffers the image into a byte array and sets Content-Length, enabling
progress tracking in Tachiyomi-based Android extensions.
This commit is contained in:
achmad
2026-05-10 01:29:05 +07:00
parent a11e5e623d
commit 8780597091
2 changed files with 41 additions and 0 deletions
@@ -79,6 +79,7 @@ object MangaAPI {
patch("{mangaId}/chapter/{chapterIndex}/meta", MangaController.chapterMeta) patch("{mangaId}/chapter/{chapterIndex}/meta", MangaController.chapterMeta)
get("{mangaId}/chapter/{chapterIndex}/page/{index}", MangaController.pageRetrieve) get("{mangaId}/chapter/{chapterIndex}/page/{index}", MangaController.pageRetrieve)
get("{mangaId}/chapter/{chapterIndex}/page/{index}/image", MangaController.pageImage)
} }
path("chapter") { path("chapter") {
@@ -503,6 +503,46 @@ object MangaController {
}, },
) )
/** Get page image binary with Content-Length for progress tracking */
val pageImage =
handler(
pathParam<Int>("mangaId"),
pathParam<Int>("chapterIndex"),
pathParam<Int>("index"),
queryParam<String?>("format"),
documentWith = {
withOperation {
summary("Get a chapter page image")
description("Returns the raw image binary with Content-Length header for progress tracking.")
}
},
behaviorOf = { ctx, mangaId, chapterIndex, index, format ->
ctx.getAttribute(Attribute.TachideskUser).requireUser()
ctx.future {
future {
Page.getPageImageServe(
mangaId = mangaId,
chapterIndex = chapterIndex,
index = index,
format = format,
)
}.thenApply { (stream, mimeType) ->
val bytes = stream.readBytes()
ctx.header("content-type", mimeType)
ctx.header("content-length", bytes.size.toString())
val httpCacheSeconds = 1.days.inWholeSeconds
ctx.header("cache-control", "max-age=$httpCacheSeconds")
ctx.result(bytes)
}
}
},
withResults = {
image(HttpStatus.OK)
httpCode(HttpStatus.NOT_FOUND)
},
)
val downloadChapter = val downloadChapter =
handler( handler(
pathParam<Int>("chapterId"), pathParam<Int>("chapterId"),