mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-03 19:04:39 -05:00
handle solid RAR archives (#339)
* Upgrade junrar version to 7.5.0 and set unrar.extractor.thread-keep-alive-seconds to 30 (default is 5) * #338 Read whole archive in case RAR file is solid (it is, it can't be decompressed at an arbitrary location).
This commit is contained in:
@@ -54,7 +54,7 @@ dependencies {
|
|||||||
|
|
||||||
// Disk & File
|
// Disk & File
|
||||||
implementation("net.lingala.zip4j:zip4j:2.9.1")
|
implementation("net.lingala.zip4j:zip4j:2.9.1")
|
||||||
implementation("com.github.junrar:junrar:7.4.0")
|
implementation("com.github.junrar:junrar:7.5.0")
|
||||||
|
|
||||||
// CloudflareInterceptor
|
// CloudflareInterceptor
|
||||||
implementation("net.sourceforge.htmlunit:htmlunit:2.56.0")
|
implementation("net.sourceforge.htmlunit:htmlunit:2.56.0")
|
||||||
@@ -75,6 +75,9 @@ dependencies {
|
|||||||
}
|
}
|
||||||
|
|
||||||
application {
|
application {
|
||||||
|
applicationDefaultJvmArgs = listOf(
|
||||||
|
"-Djunrar.extractor.thread-keep-alive-seconds=30"
|
||||||
|
)
|
||||||
mainClass.set(MainClass)
|
mainClass.set(MainClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ import com.github.junrar.rarfile.FileHeader
|
|||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder
|
import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder
|
||||||
import suwayomi.tachidesk.manga.impl.util.storage.ImageUtil
|
import suwayomi.tachidesk.manga.impl.util.storage.ImageUtil
|
||||||
import java.io.File
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.PipedInputStream
|
import java.io.File
|
||||||
import java.io.PipedOutputStream
|
|
||||||
import java.util.concurrent.Executors
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loader used to load a chapter from a .rar or .cbr file.
|
* Loader used to load a chapter from a .rar or .cbr file.
|
||||||
@@ -22,20 +22,40 @@ class RarPageLoader(file: File) : PageLoader {
|
|||||||
private val archive = Archive(file)
|
private val archive = Archive(file)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pool for copying compressed files to an input stream.
|
* The fully uncompressed files, to be used in case archive is solid.
|
||||||
*/
|
*/
|
||||||
private val pool = Executors.newFixedThreadPool(1)
|
private var archiveMap = mutableMapOf<FileHeader, InputStream>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an observable containing the pages found on this rar archive ordered with a natural
|
* Returns an observable containing the pages found on this rar archive ordered with a natural
|
||||||
* comparator.
|
* comparator.
|
||||||
*/
|
*/
|
||||||
override fun getPages(): List<ReaderPage> {
|
override fun getPages(): List<ReaderPage> {
|
||||||
|
if (archive.mainHeader.isSolid) {
|
||||||
|
// Solid means that we need to read all the file sequentially
|
||||||
|
for (header in archive.fileHeaders) {
|
||||||
|
val baos = ByteArrayOutputStream()
|
||||||
|
archive.extractFile(header, baos)
|
||||||
|
archiveMap[header] = ByteArrayInputStream(baos.toByteArray())
|
||||||
|
}
|
||||||
|
// After reading the full archive, proceed to filter and transform
|
||||||
|
return archive.fileHeaders
|
||||||
|
.filter { !it.isDirectory && ImageUtil.isImage(it.fileName) { archiveMap.getValue(it) } }
|
||||||
|
.sortedWith { f1, f2 -> f1.fileName.compareToCaseInsensitiveNaturalOrder(f2.fileName) }
|
||||||
|
.mapIndexed { i, header ->
|
||||||
|
val streamFn = { archiveMap.getValue(header) }
|
||||||
|
|
||||||
|
ReaderPage(i).apply {
|
||||||
|
stream = streamFn
|
||||||
|
status = Page.READY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return archive.fileHeaders
|
return archive.fileHeaders
|
||||||
.filter { !it.isDirectory && ImageUtil.isImage(it.fileName) { archive.getInputStream(it) } }
|
.filter { !it.isDirectory && ImageUtil.isImage(it.fileName) { archive.getInputStream(it) } }
|
||||||
.sortedWith { f1, f2 -> f1.fileName.compareToCaseInsensitiveNaturalOrder(f2.fileName) }
|
.sortedWith { f1, f2 -> f1.fileName.compareToCaseInsensitiveNaturalOrder(f2.fileName) }
|
||||||
.mapIndexed { i, header ->
|
.mapIndexed { i, header ->
|
||||||
val streamFn = { getStream(header) }
|
val streamFn = { archive.getInputStream(header) }
|
||||||
|
|
||||||
ReaderPage(i).apply {
|
ReaderPage(i).apply {
|
||||||
stream = streamFn
|
stream = streamFn
|
||||||
@@ -43,21 +63,4 @@ class RarPageLoader(file: File) : PageLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an input stream for the given [header].
|
|
||||||
*/
|
|
||||||
private fun getStream(header: FileHeader): InputStream {
|
|
||||||
val pipeIn = PipedInputStream()
|
|
||||||
val pipeOut = PipedOutputStream(pipeIn)
|
|
||||||
pool.execute {
|
|
||||||
try {
|
|
||||||
pipeOut.use {
|
|
||||||
archive.extractFile(header, it)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pipeIn
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user