mirror of
https://github.com/gotson/komga.git
synced 2025-12-19 06:53:55 +01:00
feat(komga): support for RAR5 via libarchive
This commit is contained in:
parent
7dd05a5037
commit
4c1301f45e
5 changed files with 76 additions and 3 deletions
|
|
@ -89,6 +89,7 @@ dependencies {
|
|||
implementation("org.apache.tika:tika-core:2.9.1")
|
||||
implementation("org.apache.commons:commons-compress:1.24.0")
|
||||
implementation("com.github.junrar:junrar:7.5.5")
|
||||
implementation("com.github.gotson.nightcompress:nightcompress:0.2.0")
|
||||
implementation("org.apache.pdfbox:pdfbox:2.0.28")
|
||||
implementation("net.grey-panther:natural-comparator:1.1")
|
||||
implementation("org.jsoup:jsoup:1.16.2")
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ enum class MediaType(val type: String, val profile: MediaProfile, val fileExtens
|
|||
ZIP("application/zip", MediaProfile.DIVINA, "cbz", "application/vnd.comicbook+zip"),
|
||||
RAR_GENERIC("application/x-rar-compressed", MediaProfile.DIVINA, "cbr", "application/vnd.comicbook-rar"),
|
||||
RAR_4("application/x-rar-compressed; version=4", MediaProfile.DIVINA, "cbr", "application/vnd.comicbook-rar"),
|
||||
RAR_5("application/x-rar-compressed; version=5", MediaProfile.DIVINA, "cbr", "application/vnd.comicbook-rar"),
|
||||
EPUB("application/epub+zip", MediaProfile.EPUB, "epub"),
|
||||
PDF("application/pdf", MediaProfile.PDF, "pdf"),
|
||||
;
|
||||
|
|
|
|||
|
|
@ -91,7 +91,8 @@ class BookAnalyzer(
|
|||
|
||||
private fun analyzeDivina(book: Book, mediaType: MediaType, analyzeDimensions: Boolean): Media {
|
||||
val entries = try {
|
||||
divinaExtractors.getValue(mediaType.type).getEntries(book.path, analyzeDimensions)
|
||||
divinaExtractors[mediaType.type]?.getEntries(book.path, analyzeDimensions)
|
||||
?: return Media(status = Media.Status.UNSUPPORTED)
|
||||
} catch (ex: MediaUnsupportedException) {
|
||||
return Media(status = Media.Status.UNSUPPORTED, comment = ex.code)
|
||||
} catch (ex: Exception) {
|
||||
|
|
|
|||
|
|
@ -50,10 +50,10 @@ class BookConverter(
|
|||
private val historicalEventRepository: HistoricalEventRepository,
|
||||
) {
|
||||
|
||||
private val convertibleTypes = listOf(MediaType.RAR_4.type)
|
||||
private val convertibleTypes = listOf(MediaType.RAR_4.type, MediaType.RAR_5.type)
|
||||
|
||||
private val mediaTypeToExtension =
|
||||
listOf(MediaType.RAR_4, MediaType.ZIP, MediaType.PDF, MediaType.EPUB)
|
||||
listOf(MediaType.RAR_4, MediaType.RAR_5, MediaType.ZIP, MediaType.PDF, MediaType.EPUB)
|
||||
.associate { it.type to it.fileExtension }
|
||||
|
||||
private val failedConversions = mutableListOf<String>()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
package org.gotson.komga.infrastructure.mediacontainer.divina
|
||||
|
||||
import com.github.gotson.nightcompress.Archive
|
||||
import mu.KotlinLogging
|
||||
import net.greypanther.natsort.CaseInsensitiveSimpleNaturalComparator
|
||||
import org.gotson.komga.domain.model.MediaContainerEntry
|
||||
import org.gotson.komga.domain.model.MediaType
|
||||
import org.gotson.komga.infrastructure.image.ImageAnalyzer
|
||||
import org.gotson.komga.infrastructure.mediacontainer.ContentDetector
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import java.nio.file.Path
|
||||
|
||||
|
||||
private val logger = KotlinLogging.logger {}
|
||||
|
||||
@Configuration
|
||||
class Rar5Configuration : BeanDefinitionRegistryPostProcessor {
|
||||
override fun postProcessBeanFactory(beanFactory: ConfigurableListableBeanFactory) {}
|
||||
|
||||
override fun postProcessBeanDefinitionRegistry(registry: BeanDefinitionRegistry) {
|
||||
try {
|
||||
if (Archive.isAvailable()) {
|
||||
val builder = BeanDefinitionBuilder.genericBeanDefinition(Rar5Extractor::class.java).setLazyInit(true)
|
||||
registry.registerBeanDefinition("rar5Extractor", builder.beanDefinition)
|
||||
logger.info { "Rar5 extractor is enabled" }
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
logger.warn(e) { "Rar5 extractor count not be loaded" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Rar5Extractor(
|
||||
private val contentDetector: ContentDetector,
|
||||
private val imageAnalyzer: ImageAnalyzer,
|
||||
) : DivinaExtractor {
|
||||
|
||||
private val natSortComparator: Comparator<String> = CaseInsensitiveSimpleNaturalComparator.getInstance()
|
||||
|
||||
override fun mediaTypes(): List<String> = listOf(MediaType.RAR_5.type)
|
||||
|
||||
override fun getEntries(path: Path, analyzeDimensions: Boolean): List<MediaContainerEntry> =
|
||||
Archive(path).use { rar ->
|
||||
generateSequence { rar.nextEntry }
|
||||
.map { entry ->
|
||||
try {
|
||||
val buffer = rar.inputStream.use { it.readBytes() }
|
||||
val mediaType = buffer.inputStream().use { contentDetector.detectMediaType(it) }
|
||||
val dimension = if (analyzeDimensions && contentDetector.isImage(mediaType))
|
||||
buffer.inputStream().use { imageAnalyzer.getDimension(it) }
|
||||
else
|
||||
null
|
||||
val fileSize = entry.size
|
||||
MediaContainerEntry(name = entry.name, mediaType = mediaType, dimension = dimension, fileSize = fileSize)
|
||||
} catch (e: Exception) {
|
||||
logger.warn(e) { "Could not analyze entry: ${entry.name}" }
|
||||
MediaContainerEntry(name = entry.name, comment = e.message)
|
||||
}
|
||||
}
|
||||
.sortedWith(compareBy(natSortComparator) { it.name })
|
||||
.toList()
|
||||
}
|
||||
|
||||
override fun getEntryStream(path: Path, entryName: String): ByteArray =
|
||||
Archive.getInputStream(path, entryName).use { it?.readBytes() ?: ByteArray(0) }
|
||||
}
|
||||
Loading…
Reference in a new issue