OPDS: Offer CBZ in older mimetype (#1731)
* OPDS: Offer CBZ in older mimetype * OPDS: Include length when offering CBZ download * Disable compression on CBZ endpoint Zipping a zip * CBZ download match content type of OPDS * Move compression disable * Introduce setting for configuring CBZ mimetype * Document new option [no-ci] * Update server/src/main/kotlin/suwayomi/tachidesk/opds/impl/OpdsEntryBuilder.kt Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com> --------- Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>
This commit is contained in:
@@ -29,6 +29,7 @@ import suwayomi.tachidesk.manga.model.table.ChapterTable
|
||||
import suwayomi.tachidesk.server.JavalinSetup.Attribute
|
||||
import suwayomi.tachidesk.server.JavalinSetup.future
|
||||
import suwayomi.tachidesk.server.JavalinSetup.getAttribute
|
||||
import suwayomi.tachidesk.server.serverConfig
|
||||
import suwayomi.tachidesk.server.user.requireUser
|
||||
import suwayomi.tachidesk.server.util.formParam
|
||||
import suwayomi.tachidesk.server.util.handler
|
||||
@@ -507,10 +508,12 @@ object MangaController {
|
||||
},
|
||||
behaviorOf = { ctx, chapterId, markAsRead ->
|
||||
ctx.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
ctx.disableCompression()
|
||||
val contentType = serverConfig.opdsCbzMimetype.value.mediaType
|
||||
if (ctx.method() == HandlerType.HEAD) {
|
||||
ctx.future {
|
||||
future { ChapterDownloadHelper.getCbzMetadataForDownload(chapterId) }
|
||||
.thenApply { (fileName, fileSize, contentType) ->
|
||||
.thenApply { (fileName, fileSize) ->
|
||||
ctx.header("Content-Type", contentType)
|
||||
ctx.header("Content-Disposition", "attachment; filename=\"$fileName\"")
|
||||
ctx.header("Content-Length", fileSize.toString())
|
||||
@@ -522,7 +525,7 @@ object MangaController {
|
||||
ctx.future {
|
||||
future { ChapterDownloadHelper.getCbzForDownload(chapterId, shouldMarkAsRead) }
|
||||
.thenApply { (inputStream, fileName, fileSize) ->
|
||||
ctx.header("Content-Type", "application/vnd.comicbook+zip")
|
||||
ctx.header("Content-Type", contentType)
|
||||
ctx.header("Content-Disposition", "attachment; filename=\"$fileName\"")
|
||||
ctx.header("Content-Length", fileSize.toString())
|
||||
ctx.result(inputStream)
|
||||
|
||||
@@ -100,12 +100,11 @@ object ChapterDownloadHelper {
|
||||
return Triple(cbzFile.first, fileName, cbzFile.second)
|
||||
}
|
||||
|
||||
fun getCbzMetadataForDownload(chapterId: Int): Triple<String, Long, String> { // fileName, fileSize, contentType
|
||||
fun getCbzMetadataForDownload(chapterId: Int): Pair<String, Long> { // fileName, fileSize
|
||||
val (chapterData, fileName) = getChapterWithCbzFileName(chapterId)
|
||||
|
||||
val fileSize = provider(chapterData.mangaId, chapterData.id).getArchiveSize()
|
||||
val contentType = "application/vnd.comicbook+zip"
|
||||
|
||||
return Triple(fileName, fileSize, contentType)
|
||||
return Pair(fileName, fileSize)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,5 +40,4 @@ object OpdsConstants {
|
||||
const val TYPE_ATOM_XML_ENTRY_PROFILE_OPDS = "application/atom+xml;type=entry;profile=opds-catalog"
|
||||
const val TYPE_OPENSEARCH_DESCRIPTION = "application/opensearchdescription+xml"
|
||||
const val TYPE_IMAGE_JPEG = "image/jpeg"
|
||||
const val TYPE_CBZ = "application/vnd.comicbook+zip"
|
||||
}
|
||||
|
||||
@@ -336,6 +336,14 @@ object OpdsEntryBuilder {
|
||||
}
|
||||
|
||||
val entryTitle = "$titlePrefix ${chapter.name}"
|
||||
val cbzFileSize =
|
||||
if (chapter.downloaded) {
|
||||
withContext(Dispatchers.IO) {
|
||||
runCatching { ChapterDownloadHelper.getArchiveStreamWithSize(manga.id, chapter.id).second }.getOrNull()
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
val links = mutableListOf<OpdsLinkXml>()
|
||||
chapter.url?.let {
|
||||
@@ -348,8 +356,9 @@ object OpdsEntryBuilder {
|
||||
OpdsLinkXml(
|
||||
OpdsConstants.LINK_REL_ACQUISITION_OPEN_ACCESS,
|
||||
"/api/v1/chapter/${chapter.id}/download?markAsRead=${serverConfig.opdsMarkAsReadOnDownload.value}",
|
||||
OpdsConstants.TYPE_CBZ,
|
||||
serverConfig.opdsCbzMimetype.value.mediaType,
|
||||
MR.strings.opds_linktitle_download_cbz.localized(locale),
|
||||
length = cbzFileSize,
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -411,15 +420,6 @@ object OpdsEntryBuilder {
|
||||
)
|
||||
}
|
||||
|
||||
val cbzFileSize =
|
||||
if (chapter.downloaded) {
|
||||
withContext(Dispatchers.IO) {
|
||||
runCatching { ChapterDownloadHelper.getArchiveStreamWithSize(manga.id, chapter.id).second }.getOrNull()
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
return OpdsEntryXml(
|
||||
id = "urn:suwayomi:chapter:${chapter.id}:metadata$idSuffix",
|
||||
title = entryTitle,
|
||||
|
||||
@@ -19,6 +19,8 @@ data class OpdsLinkXml(
|
||||
// Thread count
|
||||
@XmlSerialName("count", OpdsConstants.NS_THREAD, "thr")
|
||||
val thrCount: Int? = null,
|
||||
// link download size in bytes
|
||||
val length: Long? = null,
|
||||
// OPDS-PSE attributes
|
||||
@XmlSerialName("count", OpdsConstants.NS_PSE, "pse")
|
||||
val pseCount: Int? = null,
|
||||
|
||||
Reference in New Issue
Block a user