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:
@@ -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"),
|
||||||
|
|||||||
Reference in New Issue
Block a user