Refactor repository creation
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
19
app/src/main/java/org/koitharu/kotatsu/utils/ext/KoinExt.kt
Normal file
19
app/src/main/java/org/koitharu/kotatsu/utils/ext/KoinExt.kt
Normal 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))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user