mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-06-30 09:24:34 -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
|
||||
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
|
||||
implementation("net.sourceforge.htmlunit:htmlunit:2.56.0")
|
||||
@@ -75,6 +75,9 @@ dependencies {
|
||||
}
|
||||
|
||||
application {
|
||||
applicationDefaultJvmArgs = listOf(
|
||||
"-Djunrar.extractor.thread-keep-alive-seconds=30"
|
||||
)
|
||||
mainClass.set(MainClass)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,11 +5,11 @@ import com.github.junrar.rarfile.FileHeader
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder
|
||||
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.PipedInputStream
|
||||
import java.io.PipedOutputStream
|
||||
import java.util.concurrent.Executors
|
||||
import java.io.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)
|
||||
|
||||
/**
|
||||
* 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
|
||||
* comparator.
|
||||
*/
|
||||
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
|
||||
.filter { !it.isDirectory && ImageUtil.isImage(it.fileName) { archive.getInputStream(it) } }
|
||||
.sortedWith { f1, f2 -> f1.fileName.compareToCaseInsensitiveNaturalOrder(f2.fileName) }
|
||||
.mapIndexed { i, header ->
|
||||
val streamFn = { getStream(header) }
|
||||
val streamFn = { archive.getInputStream(header) }
|
||||
|
||||
ReaderPage(i).apply {
|
||||
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