mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-06-30 17:34:39 -05:00
Fix/page download conversion reduce logs (#1545)
* Cleanup chapter page conversion * Reduce chapter page conversion logging
This commit is contained in:
@@ -11,7 +11,6 @@ import kotlinx.coroutines.flow.onEach
|
|||||||
import kotlinx.coroutines.flow.sample
|
import kotlinx.coroutines.flow.sample
|
||||||
import libcore.net.MimeUtils
|
import libcore.net.MimeUtils
|
||||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry
|
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
|
||||||
import org.jetbrains.exposed.sql.selectAll
|
import org.jetbrains.exposed.sql.selectAll
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
import org.jetbrains.exposed.sql.update
|
import org.jetbrains.exposed.sql.update
|
||||||
@@ -23,6 +22,7 @@ import suwayomi.tachidesk.manga.impl.util.getChapterDownloadPath
|
|||||||
import suwayomi.tachidesk.manga.impl.util.storage.ImageResponse
|
import suwayomi.tachidesk.manga.impl.util.storage.ImageResponse
|
||||||
import suwayomi.tachidesk.manga.model.table.ChapterTable
|
import suwayomi.tachidesk.manga.model.table.ChapterTable
|
||||||
import suwayomi.tachidesk.manga.model.table.MangaTable
|
import suwayomi.tachidesk.manga.model.table.MangaTable
|
||||||
|
import suwayomi.tachidesk.server.ServerConfig
|
||||||
import suwayomi.tachidesk.server.serverConfig
|
import suwayomi.tachidesk.server.serverConfig
|
||||||
import suwayomi.tachidesk.util.ConversionUtil
|
import suwayomi.tachidesk.util.ConversionUtil
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -30,6 +30,7 @@ import java.io.InputStream
|
|||||||
import javax.imageio.IIOImage
|
import javax.imageio.IIOImage
|
||||||
import javax.imageio.ImageIO
|
import javax.imageio.ImageIO
|
||||||
import javax.imageio.ImageWriteParam
|
import javax.imageio.ImageWriteParam
|
||||||
|
import javax.imageio.ImageWriter
|
||||||
|
|
||||||
sealed class FileType {
|
sealed class FileType {
|
||||||
data class RegularFile(
|
data class RegularFile(
|
||||||
@@ -175,7 +176,7 @@ abstract class ChaptersFilesProvider<Type : FileType>(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
maybeConvertChapterImages(downloadCacheFolder)
|
maybeConvertPages(downloadCacheFolder)
|
||||||
|
|
||||||
handleSuccessfulDownload()
|
handleSuccessfulDownload()
|
||||||
|
|
||||||
@@ -197,63 +198,103 @@ abstract class ChaptersFilesProvider<Type : FileType>(
|
|||||||
|
|
||||||
abstract fun getAsArchiveStream(): Pair<InputStream, Long>
|
abstract fun getAsArchiveStream(): Pair<InputStream, Long>
|
||||||
|
|
||||||
private fun maybeConvertChapterImages(chapterCacheFolder: File) {
|
private fun maybeConvertPages(chapterCacheFolder: File) {
|
||||||
if (chapterCacheFolder.isDirectory) {
|
val conversions = serverConfig.downloadConversions.value
|
||||||
val conv = serverConfig.downloadConversions.value
|
|
||||||
|
if (!chapterCacheFolder.isDirectory || conversions.isEmpty()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val pages =
|
||||||
chapterCacheFolder
|
chapterCacheFolder
|
||||||
.listFiles()
|
.listFiles()
|
||||||
.orEmpty()
|
.orEmpty()
|
||||||
.filter { it.name != COMIC_INFO_FILE }
|
.filter { it.name != COMIC_INFO_FILE }
|
||||||
.forEach {
|
|
||||||
val imageType = MimeUtils.guessMimeTypeFromExtension(it.extension) ?: return@forEach
|
|
||||||
val targetConversion =
|
|
||||||
conv.getOrElse(imageType) {
|
|
||||||
conv.getOrElse("default") {
|
|
||||||
logger.debug { "Skipping conversion of $it since no conversion specified" }
|
|
||||||
return@forEach
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val targetMime = targetConversion.target
|
|
||||||
if (imageType == targetMime || targetMime == "none") return@forEach // nothing to do
|
|
||||||
logger.debug { "Converting $it to $targetMime" }
|
|
||||||
val targetExtension = MimeUtils.guessExtensionFromMimeType(targetMime) ?: targetMime.removePrefix("image/")
|
|
||||||
|
|
||||||
val outFile = File(it.parentFile, it.nameWithoutExtension + "." + targetExtension)
|
val pagesByMimeType =
|
||||||
|
pages
|
||||||
|
.groupBy { MimeUtils.guessMimeTypeFromExtension(it.extension) }
|
||||||
|
.mapValues { it.value.map { it.nameWithoutExtension } }
|
||||||
|
|
||||||
val writers = ImageIO.getImageWritersByMIMEType(targetMime)
|
logger.debug { "maybeConvertPages: pagesByMimeType= $pagesByMimeType; conversions= $conversions" }
|
||||||
val writer =
|
|
||||||
try {
|
|
||||||
writers.next()
|
|
||||||
} catch (_: NoSuchElementException) {
|
|
||||||
logger.warn { "Conversion aborted: No reader for target format $targetMime" }
|
|
||||||
return@forEach
|
|
||||||
}
|
|
||||||
val writerParams = writer.defaultWriteParam
|
|
||||||
targetConversion.compressionLevel?.let {
|
|
||||||
writerParams.compressionMode = ImageWriteParam.MODE_EXPLICIT
|
|
||||||
writerParams.compressionQuality = it.toFloat()
|
|
||||||
}
|
|
||||||
val success =
|
|
||||||
try {
|
|
||||||
ImageIO.createImageOutputStream(outFile).use { outStream ->
|
|
||||||
writer.setOutput(outStream)
|
|
||||||
|
|
||||||
val inImage = ConversionUtil.readImage(it) ?: return@use false
|
pages.forEach { page ->
|
||||||
writer.write(null, IIOImage(inImage, null, null), writerParams)
|
val imageType = MimeUtils.guessMimeTypeFromExtension(page.extension) ?: return@forEach
|
||||||
|
|
||||||
true
|
val defaultConversion = conversions["default"]
|
||||||
}
|
val conversion = conversions[imageType]
|
||||||
} catch (e: Exception) {
|
val targetConversion = conversion ?: defaultConversion ?: return@forEach
|
||||||
logger.warn(e) { "Conversion aborted: for image $it" }
|
|
||||||
false
|
val (targetMime) = targetConversion
|
||||||
}
|
val requiresConversion = imageType != targetMime && targetMime != "none"
|
||||||
writer.dispose()
|
if (!requiresConversion) {
|
||||||
if (success) {
|
return@forEach
|
||||||
it.delete()
|
}
|
||||||
} else {
|
|
||||||
outFile.delete()
|
convertPage(page, targetConversion)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun convertPage(
|
||||||
|
page: File,
|
||||||
|
conversion: ServerConfig.DownloadConversion,
|
||||||
|
) {
|
||||||
|
val (targetMime, compressionLevel) = conversion
|
||||||
|
|
||||||
|
val targetExtension =
|
||||||
|
MimeUtils.guessExtensionFromMimeType(targetMime) ?: targetMime.removePrefix("image/")
|
||||||
|
|
||||||
|
val convertedPage = File(page.parentFile, page.nameWithoutExtension + "." + targetExtension)
|
||||||
|
|
||||||
|
val conversionWriter = getConversionWriter(targetMime, compressionLevel)
|
||||||
|
if (conversionWriter == null) {
|
||||||
|
logger.warn { "Conversion aborted: No reader for target format $targetMime" }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val (writer, writerParams) = conversionWriter
|
||||||
|
|
||||||
|
val success =
|
||||||
|
try {
|
||||||
|
ImageIO.createImageOutputStream(convertedPage).use { outStream ->
|
||||||
|
writer.setOutput(outStream)
|
||||||
|
|
||||||
|
val inImage = ConversionUtil.readImage(page) ?: return@use false
|
||||||
|
writer.write(null, IIOImage(inImage, null, null), writerParams)
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logger.warn(e) { "Conversion aborted: for image $page" }
|
||||||
|
false
|
||||||
|
}
|
||||||
|
writer.dispose()
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
page.delete()
|
||||||
|
} else {
|
||||||
|
convertedPage.delete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getConversionWriter(
|
||||||
|
targetMime: String,
|
||||||
|
compressionLevel: Double?,
|
||||||
|
): Pair<ImageWriter, ImageWriteParam>? {
|
||||||
|
val writers = ImageIO.getImageWritersByMIMEType(targetMime)
|
||||||
|
val writer =
|
||||||
|
try {
|
||||||
|
writers.next()
|
||||||
|
} catch (_: NoSuchElementException) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val writerParams = writer.defaultWriteParam
|
||||||
|
compressionLevel?.let {
|
||||||
|
writerParams.compressionMode = ImageWriteParam.MODE_EXPLICIT
|
||||||
|
writerParams.compressionQuality = it.toFloat()
|
||||||
|
}
|
||||||
|
|
||||||
|
return writer to writerParams
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user