mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-13 15:54:35 -05:00
fix(api): optimize HEAD requests for chapter downloads (#1601)
Previously, handling a HEAD request on the chapter download endpoint was inefficient as it triggered the full CBZ file generation process in-memory just to retrieve metadata like Content-Length and Content-Disposition. This caused unnecessary latency especially for OPDS clients. This commit introduces a separate, lightweight path for HEAD requests. - A new `getCbzMetadataForDownload` method is added to `ChapterDownloadHelper` to calculate the filename and file size without generating an archive stream. - The `ChaptersFilesProvider` interface is updated with a `getArchiveSize()` method, implemented by both `ArchiveProvider` and `FolderProvider`, to retrieve the total size. - The `MangaController` now differentiates between GET and HEAD methods, invoking the appropriate helper to ensure HEAD requests are served instantly with only the required metadata.
This commit is contained in:
@@ -476,24 +476,31 @@ object MangaController {
|
||||
documentWith = {
|
||||
withOperation {
|
||||
summary("Download chapter as CBZ")
|
||||
description("Get the CBZ file of the specified chapter")
|
||||
description("Get the CBZ file of the specified chapter, or its metadata via a HEAD request.")
|
||||
}
|
||||
},
|
||||
behaviorOf = { ctx, chapterId, markAsRead ->
|
||||
val shouldMarkAsRead = if (ctx.method() == HandlerType.HEAD) false else markAsRead
|
||||
ctx.future {
|
||||
future { ChapterDownloadHelper.getCbzForDownload(chapterId, shouldMarkAsRead) }
|
||||
.thenApply { (inputStream, fileName, fileSize) ->
|
||||
ctx.header("Content-Type", "application/vnd.comicbook+zip")
|
||||
ctx.header("Content-Disposition", "attachment; filename=\"$fileName\"")
|
||||
ctx.header("Content-Length", fileSize.toString())
|
||||
if (ctx.method() == HandlerType.HEAD) {
|
||||
inputStream.close()
|
||||
ctx.status(200)
|
||||
} else {
|
||||
if (ctx.method() == HandlerType.HEAD) {
|
||||
ctx.future {
|
||||
future { ChapterDownloadHelper.getCbzMetadataForDownload(chapterId) }
|
||||
.thenApply { (fileName, fileSize, contentType) ->
|
||||
ctx.header("Content-Type", contentType)
|
||||
ctx.header("Content-Disposition", "attachment; filename=\"$fileName\"")
|
||||
ctx.header("Content-Length", fileSize.toString())
|
||||
ctx.status(HttpStatus.OK)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val shouldMarkAsRead = markAsRead ?: false
|
||||
ctx.future {
|
||||
future { ChapterDownloadHelper.getCbzForDownload(chapterId, shouldMarkAsRead) }
|
||||
.thenApply { (inputStream, fileName, fileSize) ->
|
||||
ctx.header("Content-Type", "application/vnd.comicbook+zip")
|
||||
ctx.header("Content-Disposition", "attachment; filename=\"$fileName\"")
|
||||
ctx.header("Content-Length", fileSize.toString())
|
||||
ctx.result(inputStream)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
withResults = {
|
||||
|
||||
Reference in New Issue
Block a user