Refactor repository creation

This commit is contained in:
Koitharu
2021-01-20 20:27:47 +02:00
parent bb1dd74277
commit 9054f5720f
7 changed files with 77 additions and 39 deletions

View File

@@ -93,7 +93,7 @@ class DownloadService : BaseService() {
checkNotNull(destination) { getString(R.string.cannot_find_available_storage) } checkNotNull(destination) { getString(R.string.cannot_find_available_storage) }
var output: MangaZip? = null var output: MangaZip? = null
try { try {
val repo = manga.source.repository val repo = mangaRepositoryOf(manga.source)
val cover = runCatching { val cover = runCatching {
imageLoader.execute( imageLoader.execute(
ImageRequest.Builder(this@DownloadService) ImageRequest.Builder(this@DownloadService)

View File

@@ -3,16 +3,20 @@ package org.koitharu.kotatsu.reader.domain
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.net.Uri import android.net.Uri
import android.util.ArrayMap import androidx.collection.LongSparseArray
import androidx.collection.set
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.sync.withLock
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import org.koitharu.kotatsu.core.model.RequestDraft import org.koin.core.component.KoinComponent
import org.koitharu.kotatsu.core.model.MangaPage
import org.koitharu.kotatsu.core.network.CommonHeaders import org.koitharu.kotatsu.core.network.CommonHeaders
import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.local.data.PagesCache import org.koitharu.kotatsu.local.data.PagesCache
import org.koitharu.kotatsu.utils.CacheUtils import org.koitharu.kotatsu.utils.CacheUtils
import org.koitharu.kotatsu.utils.ext.await import org.koitharu.kotatsu.utils.ext.await
import org.koitharu.kotatsu.utils.ext.mangaRepositoryOf
import java.io.File import java.io.File
import java.util.zip.ZipFile import java.util.zip.ZipFile
@@ -20,45 +24,61 @@ class PageLoader(
scope: CoroutineScope, scope: CoroutineScope,
private val okHttp: OkHttpClient, private val okHttp: OkHttpClient,
private val cache: PagesCache private val cache: PagesCache
) : CoroutineScope by scope { ) : CoroutineScope by scope, KoinComponent {
private val tasks = ArrayMap<String, Deferred<File>>() private var repository: MangaRepository? = null
private val tasks = LongSparseArray<Deferred<File>>()
private val convertLock = Mutex() private val convertLock = Mutex()
suspend fun loadFile(requestDraft: RequestDraft, force: Boolean): File { suspend fun loadPage(page: MangaPage, force: Boolean): File {
if (!force) { if (!force) {
cache[requestDraft.url]?.let { cache[page.url]?.let {
return it return it
} }
} }
val task = var task = tasks[page.id]
tasks[requestDraft.url]?.takeUnless { it.isCancelled || (force && it.isCompleted) } if (force) {
return (task ?: loadAsync(requestDraft).also { tasks[requestDraft.url] = it }).await() task?.cancel()
} else if (task?.isCancelled == false) {
return task.await()
}
task = loadAsync(page)
tasks[page.id] = task
return task.await()
} }
private fun loadAsync(requestDraft: RequestDraft) = async(Dispatchers.IO) { private fun loadAsync(page: MangaPage): Deferred<File> {
val uri = Uri.parse(requestDraft.url) var repo = repository
if (uri.scheme == "cbz") { if (repo?.javaClass != page.source.cls) {
val zip = ZipFile(uri.schemeSpecificPart) repo = mangaRepositoryOf(page.source)
val entry = zip.getEntry(uri.fragment) repository = repo
zip.getInputStream(entry).use { }
cache.put(requestDraft.url, it) return async(Dispatchers.IO) {
} val requestDraft = repo.getPageRequest(page)
} else { check(requestDraft.isValid) { "Cannot obtain full image url" }
val request = requestDraft.newBuilder() val uri = Uri.parse(requestDraft.url)
.header(CommonHeaders.ACCEPT, "image/webp,image/png;q=0.9,image/jpeg,*/*;q=0.8") if (uri.scheme == "cbz") {
.cacheControl(CacheUtils.CONTROL_DISABLED) val zip = ZipFile(uri.schemeSpecificPart)
.build() val entry = zip.getEntry(uri.fragment)
okHttp.newCall(request).await().use { response -> zip.getInputStream(entry).use {
check(response.isSuccessful) {
"Invalid response: ${response.code} ${response.message}"
}
val body = checkNotNull(response.body) {
"Null response"
}
body.byteStream().use {
cache.put(requestDraft.url, it) cache.put(requestDraft.url, it)
} }
} else {
val request = requestDraft.newBuilder()
.header(CommonHeaders.ACCEPT, "image/webp,image/png;q=0.9,image/jpeg,*/*;q=0.8")
.cacheControl(CacheUtils.CONTROL_DISABLED)
.build()
okHttp.newCall(request).await().use { response ->
check(response.isSuccessful) {
"Invalid response: ${response.code} ${response.message}"
}
val body = checkNotNull(response.body) {
"Null response"
}
body.byteStream().use {
cache.put(requestDraft.url, it)
}
}
} }
} }
} }

View File

@@ -88,11 +88,7 @@ class PageHolderDelegate(
error = null error = null
callback.onLoadingStarted() callback.onLoadingStarted()
try { try {
val file = withContext(Dispatchers.IO) { val file = loader.loadPage(data, force)
val pageRequest = data.source.repository.getPageRequest(data)
check(pageRequest.isValid) { "Cannot obtain full image url" }
loader.loadFile(pageRequest, force)
}
this@PageHolderDelegate.file = file this@PageHolderDelegate.file = file
state = State.LOADED state = State.LOADED
callback.onImageReady(file.toUri()) callback.onImageReady(file.toUri())

View File

@@ -18,6 +18,7 @@ import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.databinding.SheetPagesBinding import org.koitharu.kotatsu.databinding.SheetPagesBinding
import org.koitharu.kotatsu.list.ui.MangaListSpanResolver import org.koitharu.kotatsu.list.ui.MangaListSpanResolver
import org.koitharu.kotatsu.reader.ui.thumbnails.adapter.PageThumbnailAdapter import org.koitharu.kotatsu.reader.ui.thumbnails.adapter.PageThumbnailAdapter
import org.koitharu.kotatsu.utils.ext.mangaRepositoryOf
import org.koitharu.kotatsu.utils.ext.resolveDp import org.koitharu.kotatsu.utils.ext.resolveDp
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
import org.koitharu.kotatsu.utils.ext.withArgs import org.koitharu.kotatsu.utils.ext.withArgs
@@ -36,7 +37,7 @@ class PagesThumbnailsSheet : BaseBottomSheet<SheetPagesBinding>(),
return return
} }
val current = arguments?.getInt(ARG_CURRENT, -1) ?: -1 val current = arguments?.getInt(ARG_CURRENT, -1) ?: -1
val repository = pages.first().source.repository val repository = mangaRepositoryOf(pages.first().source)
thumbnails = pages.mapIndexed { i, x -> thumbnails = pages.mapIndexed { i, x ->
PageThumbnail( PageThumbnail(
number = i + 1, number = i + 1,

View File

@@ -9,6 +9,7 @@ import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
import org.koitharu.kotatsu.core.prefs.SourceSettings import org.koitharu.kotatsu.core.prefs.SourceSettings
import org.koitharu.kotatsu.settings.utils.EditTextSummaryProvider import org.koitharu.kotatsu.settings.utils.EditTextSummaryProvider
import org.koitharu.kotatsu.utils.ext.mangaRepositoryOf
import org.koitharu.kotatsu.utils.ext.withArgs import org.koitharu.kotatsu.utils.ext.withArgs
class SourceSettingsFragment : PreferenceFragmentCompat() { class SourceSettingsFragment : PreferenceFragmentCompat() {
@@ -24,7 +25,7 @@ class SourceSettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
preferenceManager.sharedPreferencesName = source.name preferenceManager.sharedPreferencesName = source.name
val repo = source.repository as? RemoteMangaRepository ?: return val repo = mangaRepositoryOf(source) as? RemoteMangaRepository ?: return
val keys = repo.onCreatePreferences() val keys = repo.onCreatePreferences()
addPreferencesFromResource(R.xml.pref_source) addPreferencesFromResource(R.xml.pref_source)
for (i in 0 until preferenceScreen.preferenceCount) { for (i in 0 until preferenceScreen.preferenceCount) {

View File

@@ -21,6 +21,7 @@ import org.koitharu.kotatsu.core.model.MangaChapter
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.details.ui.DetailsActivity import org.koitharu.kotatsu.details.ui.DetailsActivity
import org.koitharu.kotatsu.tracker.domain.TrackingRepository import org.koitharu.kotatsu.tracker.domain.TrackingRepository
import org.koitharu.kotatsu.utils.ext.mangaRepositoryOf
import org.koitharu.kotatsu.utils.ext.toBitmapOrNull import org.koitharu.kotatsu.utils.ext.toBitmapOrNull
import org.koitharu.kotatsu.utils.ext.toUriOrNull import org.koitharu.kotatsu.utils.ext.toUriOrNull
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@@ -51,7 +52,7 @@ class TrackWorker(context: Context, workerParams: WorkerParameters) :
var success = 0 var success = 0
for (track in tracks) { for (track in tracks) {
val details = runCatching { val details = runCatching {
track.manga.source.repository.getDetails(track.manga) mangaRepositoryOf(track.manga.source).getDetails(track.manga)
}.getOrNull() }.getOrNull()
val chapters = details?.chapters ?: continue val chapters = details?.chapters ?: continue
when { when {

View File

@@ -0,0 +1,19 @@
package org.koitharu.kotatsu.utils.ext
import android.content.ComponentCallbacks
import org.koin.android.ext.android.get
import org.koin.core.component.KoinComponent
import org.koin.core.component.get
import org.koin.core.qualifier.named
import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.parser.MangaRepository
@Suppress("NOTHING_TO_INLINE")
inline fun ComponentCallbacks.mangaRepositoryOf(source: MangaSource): MangaRepository {
return get(named(source))
}
@Suppress("NOTHING_TO_INLINE")
inline fun KoinComponent.mangaRepositoryOf(source: MangaSource): MangaRepository {
return get(named(source))
}