Load pages from cbz

This commit is contained in:
Koitharu
2020-02-11 21:01:25 +02:00
parent a15f196a6b
commit faf8e57619
5 changed files with 110 additions and 22 deletions

View File

@@ -10,6 +10,7 @@ import org.koitharu.kotatsu.core.model.*
import org.koitharu.kotatsu.domain.MangaLoaderContext
import org.koitharu.kotatsu.domain.local.MangaIndex
import org.koitharu.kotatsu.domain.local.MangaZip
import org.koitharu.kotatsu.utils.AlphanumComparator
import org.koitharu.kotatsu.utils.ext.longHashCode
import org.koitharu.kotatsu.utils.ext.readText
import org.koitharu.kotatsu.utils.ext.safe
@@ -43,7 +44,7 @@ class LocalMangaRepository(loaderContext: MangaLoaderContext) : BaseMangaReposit
.filter { x -> !x.isDirectory && x.name.substringBefore('.').matches(pattern) }
} else {
zip.entries().asSequence().filter { x -> !x.isDirectory }
}
}.toList().sortedWith(compareBy(AlphanumComparator()) { x -> x.name})
return entries.map { x ->
val uri = zipUri(file, x.name)
MangaPage(
@@ -51,7 +52,7 @@ class LocalMangaRepository(loaderContext: MangaLoaderContext) : BaseMangaReposit
url = uri,
source = MangaSource.LOCAL
)
}.toList()
}
}
private fun getDetails(file: File): Manga {

View File

@@ -11,7 +11,8 @@ import org.koitharu.kotatsu.core.model.MangaPage
import org.koitharu.kotatsu.ui.common.list.BaseViewHolder
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
class PageHolder(parent: ViewGroup, private val loader: PageLoader) : BaseViewHolder<MangaPage, Unit>(parent, R.layout.item_page),
class PageHolder(parent: ViewGroup, private val loader: PageLoader) :
BaseViewHolder<MangaPage, Unit>(parent, R.layout.item_page),
SubsamplingScaleImageView.OnImageEventListener {
init {
@@ -26,16 +27,20 @@ class PageHolder(parent: ViewGroup, private val loader: PageLoader) : BaseViewHo
progressBar.isVisible = true
ssiv.recycle()
loader.load(data.url) {
ssiv.setImage(ImageSource.uri(it.toUri()))
val uri = it.getOrNull()?.toUri()
if (uri != null) {
ssiv.setImage(ImageSource.uri(uri))
}
val error = it.exceptionOrNull()
if (error != null) {
onError(error)
}
}
}
override fun onReady() = Unit
override fun onImageLoadError(e: Exception) {
textView_error.text = e.getDisplayMessage(context.resources)
layout_error.isVisible = true
}
override fun onImageLoadError(e: Exception) = onError(e)
override fun onImageLoaded() {
progressBar.isVisible = false
@@ -46,4 +51,10 @@ class PageHolder(parent: ViewGroup, private val loader: PageLoader) : BaseViewHo
override fun onPreviewReleased() = Unit
override fun onPreviewLoadError(e: Exception?) = Unit
private fun onError(e: Throwable) {
textView_error.text = e.getDisplayMessage(context.resources)
layout_error.isVisible = true
progressBar.isVisible = false
}
}

View File

@@ -1,6 +1,6 @@
package org.koitharu.kotatsu.ui.reader
import android.content.Context
import android.net.Uri
import kotlinx.coroutines.*
import okhttp3.OkHttpClient
import okhttp3.Request
@@ -9,9 +9,10 @@ import org.koin.core.inject
import org.koitharu.kotatsu.core.local.PagesCache
import org.koitharu.kotatsu.utils.ext.await
import java.io.File
import java.util.zip.ZipFile
import kotlin.coroutines.CoroutineContext
class PageLoader(context: Context) : KoinComponent, CoroutineScope, DisposableHandle {
class PageLoader : KoinComponent, CoroutineScope, DisposableHandle {
private val job = SupervisorJob()
private val tasks = HashMap<String, Job>()
@@ -21,9 +22,11 @@ class PageLoader(context: Context) : KoinComponent, CoroutineScope, DisposableHa
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
fun load(url: String, callback: (File) -> Unit) = launch {
val result = withContext(Dispatchers.IO) {
loadFile(url, false)
fun load(url: String, force: Boolean = false, callback: (Result<File>) -> Unit) = launch {
val result = runCatching {
withContext(Dispatchers.IO) {
loadFile(url, force)
}
}
callback(result)
}
@@ -31,17 +34,27 @@ class PageLoader(context: Context) : KoinComponent, CoroutineScope, DisposableHa
private suspend fun loadFile(url: String, force: Boolean): File {
if (!force) {
cache[url]?.let {
return it
}
}
val request = Request.Builder()
.url(url)
.get()
.build()
return okHttp.newCall(request).await().use { response ->
cache.put(url) { out ->
response.body!!.byteStream().copyTo(out)
val uri = Uri.parse(url)
return if (uri.scheme == "cbz") {
val zip = ZipFile(uri.schemeSpecificPart)
val entry = zip.getEntry(uri.fragment)
zip.getInputStream(entry).use {
cache.put(url) { out ->
it.copyTo(out)
}
}
} else {
val request = Request.Builder()
.url(url)
.get()
.build()
okHttp.newCall(request).await().use { response ->
cache.put(url) { out ->
response.body!!.byteStream().copyTo(out)
}
}
}
}

View File

@@ -56,7 +56,7 @@ class ReaderActivity : BaseFullscreenActivity(), ReaderView, GridTouchHelper.OnG
insets
}
loader = PageLoader(this)
loader = PageLoader()
adapter = PagesAdapter(loader)
pager.adapter = adapter
presenter.loadChapter(state)

View File

@@ -0,0 +1,63 @@
package org.koitharu.kotatsu.utils
class AlphanumComparator : Comparator<String> {
override fun compare(s1: String?, s2: String?): Int {
if (s1 == null || s2 == null) {
return 0
}
var thisMarker = 0
var thatMarker = 0
val s1Length = s1.length
val s2Length = s2.length
while (thisMarker < s1Length && thatMarker < s2Length) {
val thisChunk = getChunk(s1, s1Length, thisMarker)
thisMarker += thisChunk.length
val thatChunk = getChunk(s2, s2Length, thatMarker)
thatMarker += thatChunk.length
// If both chunks contain numeric characters, sort them numerically
var result = 0
if (thisChunk[0].isDigit() && thatChunk[0].isDigit()) { // Simple chunk comparison by length.
val thisChunkLength = thisChunk.length
result = thisChunkLength - thatChunk.length
// If equal, the first different number counts
if (result == 0) {
for (i in 0 until thisChunkLength) {
result = thisChunk[i] - thatChunk[i]
if (result != 0) {
return result
}
}
}
} else {
result = thisChunk.compareTo(thatChunk)
}
if (result != 0) return result
}
return s1Length - s2Length
}
private fun getChunk(s: String, slength: Int, marker: Int): String {
var marker = marker
val chunk = StringBuilder()
var c = s[marker]
chunk.append(c)
marker++
if (c.isDigit()) {
while (marker < slength) {
c = s[marker]
if (!c.isDigit()) break
chunk.append(c)
marker++
}
} else {
while (marker < slength) {
c = s[marker]
if (c.isDigit()) break
chunk.append(c)
marker++
}
}
return chunk.toString()
}
}