Update parsers

This commit is contained in:
Koitharu
2022-05-25 10:04:06 +03:00
parent 0c07e649bf
commit 4f3fef3bfe
13 changed files with 103 additions and 54 deletions

View File

@@ -64,9 +64,16 @@ android {
unitTests.returnDefaultValues = false
}
}
afterEvaluate {
compileDebugKotlin {
kotlinOptions {
freeCompilerArgs += ['-opt-in=kotlin.RequiresOptIn']
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
implementation('com.github.nv95:kotatsu-parsers:f46c5add46') {
implementation('com.github.nv95:kotatsu-parsers:ab87a50e9b') {
exclude group: 'org.json', module: 'json'
}

View File

@@ -1,6 +1,7 @@
package org.koitharu.kotatsu.core.parser
import java.util.*
import org.koitharu.kotatsu.parsers.InternalParsersApi
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
@@ -9,6 +10,7 @@ import org.koitharu.kotatsu.parsers.model.*
/**
* This parser is just for parser development, it should not be used in releases
*/
@OptIn(InternalParsersApi::class)
class DummyParser(override val context: MangaLoaderContext) : MangaParser(MangaSource.DUMMY) {
override val configKeyDomain: ConfigKey.Domain
@@ -25,7 +27,7 @@ class DummyParser(override val context: MangaLoaderContext) : MangaParser(MangaS
offset: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder?
sortOrder: SortOrder,
): List<Manga> {
TODO("Not yet implemented")
}

View File

@@ -0,0 +1,10 @@
package org.koitharu.kotatsu.core.model
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.util.toTitleCase
import java.util.*
fun MangaSource.getLocaleTitle(): String? {
val lc = Locale(locale ?: return null)
return lc.getDisplayLanguage(lc).toTitleCase(lc)
}

View File

@@ -1,11 +1,11 @@
package org.koitharu.kotatsu.core.parser
import java.lang.ref.WeakReference
import java.util.*
import org.koin.core.component.KoinComponent
import org.koin.core.component.get
import org.koitharu.kotatsu.local.domain.LocalMangaRepository
import org.koitharu.kotatsu.parsers.model.*
import java.lang.ref.WeakReference
import java.util.*
interface MangaRepository {
@@ -13,12 +13,9 @@ interface MangaRepository {
val sortOrders: Set<SortOrder>
suspend fun getList(
offset: Int,
query: String? = null,
tags: Set<MangaTag>? = null,
sortOrder: SortOrder? = null,
): List<Manga>
suspend fun getList(offset: Int, query: String?): List<Manga>
suspend fun getList(offset: Int, tags: Set<MangaTag>?, sortOrder: SortOrder?): List<Manga>
suspend fun getDetails(manga: Manga): Manga

View File

@@ -20,12 +20,13 @@ class RemoteMangaRepository(private val parser: MangaParser) : MangaRepository {
getConfig().defaultSortOrder = value
}
override suspend fun getList(
offset: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder?,
): List<Manga> = parser.getList(offset, query, tags, sortOrder)
override suspend fun getList(offset: Int, query: String?): List<Manga> {
return parser.getList(offset, query)
}
override suspend fun getList(offset: Int, tags: Set<MangaTag>?, sortOrder: SortOrder?): List<Manga> {
return parser.getList(offset, tags, sortOrder)
}
override suspend fun getDetails(manga: Manga): Manga = parser.getDetails(manga)

View File

@@ -37,28 +37,25 @@ class LocalMangaRepository(private val storageManager: LocalStorageManager) : Ma
private val filenameFilter = CbzFilter()
private val locks = CompositeMutex<Long>()
override suspend fun getList(
offset: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder?
): List<Manga> {
override suspend fun getList(offset: Int, query: String?): List<Manga> {
if (offset > 0) {
return emptyList()
}
val files = getAllFiles()
val list = coroutineScope {
val dispatcher = Dispatchers.IO.limitedParallelism(MAX_PARALLELISM)
files.map { file ->
getFromFileAsync(file, dispatcher)
}.awaitAll()
}.filterNotNullTo(ArrayList(files.size))
val list = getRawList()
if (!query.isNullOrEmpty()) {
list.retainAll { x ->
x.title.contains(query, ignoreCase = true) ||
x.altTitle?.contains(query, ignoreCase = true) == true
}
}
return list
}
override suspend fun getList(offset: Int, tags: Set<MangaTag>?, sortOrder: SortOrder?): List<Manga> {
if (offset > 0) {
return emptyList()
}
val list = getRawList()
if (!tags.isNullOrEmpty()) {
list.retainAll { x ->
x.tags.containsAll(tags)
@@ -244,7 +241,7 @@ class LocalMangaRepository(private val storageManager: LocalStorageManager) : Ma
}
}
override val sortOrders = emptySet<SortOrder>()
override val sortOrders = setOf(SortOrder.ALPHABETICAL)
override suspend fun getPageUrl(page: MangaPage) = page.url
@@ -295,6 +292,16 @@ class LocalMangaRepository(private val storageManager: LocalStorageManager) : Ma
locks.unlock(id)
}
private suspend fun getRawList(): ArrayList<Manga> {
val files = getAllFiles()
return coroutineScope {
val dispatcher = Dispatchers.IO.limitedParallelism(MAX_PARALLELISM)
files.map { file ->
getFromFileAsync(file, dispatcher)
}.awaitAll()
}.filterNotNullTo(ArrayList(files.size))
}
private suspend fun getAllFiles() = storageManager.getReadableDirs().flatMap { dir ->
dir.listFiles(filenameFilter)?.toList().orEmpty()
}

View File

@@ -3,7 +3,6 @@ package org.koitharu.kotatsu.local.ui
import android.net.Uri
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import java.io.IOException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
@@ -24,6 +23,7 @@ import org.koitharu.kotatsu.utils.SingleLiveEvent
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
import org.koitharu.kotatsu.utils.progress.Progress
import java.io.IOException
class LocalListViewModel(
private val repository: LocalMangaRepository,
@@ -115,7 +115,7 @@ class LocalListViewModel(
private suspend fun doRefresh() {
try {
listError.value = null
mangaList.value = repository.getList(0)
mangaList.value = repository.getList(0, null, null)
} catch (e: Throwable) {
listError.value = e
}

View File

@@ -17,7 +17,6 @@ import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.util.levenshteinDistance
import org.koitharu.kotatsu.search.ui.MangaSuggestionsProvider
@@ -35,7 +34,6 @@ class MangaSearchRepository(
MangaRepository(source).getList(
offset = 0,
query = query,
sortOrder = SortOrder.POPULARITY
)
}.getOrElse {
emptyList()
@@ -141,4 +139,4 @@ class MangaSearchRepository(
return false
}
}
}
}

View File

@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.settings.newsources
import androidx.lifecycle.MutableLiveData
import org.koitharu.kotatsu.base.ui.BaseViewModel
import org.koitharu.kotatsu.core.model.getLocaleTitle
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem
@@ -33,7 +34,7 @@ class NewSourcesViewModel(
sources.value = initialList.map {
SourceConfigItem.SourceItem(
source = it,
summary = null,
summary = it.getLocaleTitle(),
isEnabled = it.name !in hidden,
isDraggable = false,
)

View File

@@ -4,6 +4,7 @@ import androidx.core.os.LocaleListCompat
import androidx.lifecycle.MutableLiveData
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.BaseViewModel
import org.koitharu.kotatsu.core.model.getLocaleTitle
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.util.toTitleCase
@@ -82,7 +83,7 @@ class SourcesSettingsViewModel(
}
SourceConfigItem.SourceItem(
source = it,
summary = null,
summary = it.getLocaleTitle(),
isEnabled = it.name !in hiddenSources,
isDraggable = false,
)
@@ -105,7 +106,7 @@ class SourcesSettingsViewModel(
enabledSources.mapTo(result) {
SourceConfigItem.SourceItem(
source = it,
summary = getLocaleTitle(it.locale),
summary = it.getLocaleTitle(),
isEnabled = true,
isDraggable = true,
)
@@ -162,4 +163,4 @@ class SourcesSettingsViewModel(
}
}
}
}
}

View File

@@ -17,15 +17,17 @@ import org.koitharu.kotatsu.databinding.ItemSourceConfigBinding
import org.koitharu.kotatsu.databinding.ItemSourceConfigDraggableBinding
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem
import org.koitharu.kotatsu.utils.ext.enqueueWith
import org.koitharu.kotatsu.utils.ext.textAndVisible
fun sourceConfigHeaderDelegate() = adapterDelegateViewBinding<SourceConfigItem.Header, SourceConfigItem, ItemFilterHeaderBinding>(
{ layoutInflater, parent -> ItemFilterHeaderBinding.inflate(layoutInflater, parent, false) }
) {
fun sourceConfigHeaderDelegate() =
adapterDelegateViewBinding<SourceConfigItem.Header, SourceConfigItem, ItemFilterHeaderBinding>(
{ layoutInflater, parent -> ItemFilterHeaderBinding.inflate(layoutInflater, parent, false) }
) {
bind {
binding.textViewTitle.setText(item.titleResId)
bind {
binding.textViewTitle.setText(item.titleResId)
}
}
}
fun sourceConfigGroupDelegate(
listener: SourceConfigListener,
@@ -61,6 +63,7 @@ fun sourceConfigItemDelegate(
bind {
binding.textViewTitle.text = item.source.title
binding.switchToggle.isChecked = item.isEnabled
binding.textViewDescription.textAndVisible = item.summary
imageRequest = ImageRequest.Builder(context)
.data(item.faviconUrl)
.error(R.drawable.ic_favicon_fallback)

View File

@@ -3,8 +3,9 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="?android:listPreferredItemHeightSmall"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:minHeight="?android:listPreferredItemHeightSmall"
android:orientation="horizontal">
<ImageView
@@ -17,16 +18,35 @@
android:scaleType="fitCenter"
tools:src="@tools:sample/avatars" />
<TextView
android:id="@+id/textView_title"
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginVertical="8dp"
android:layout_marginStart="?android:listPreferredItemPaddingStart"
android:layout_marginEnd="?android:listPreferredItemPaddingEnd"
android:layout_weight="1"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:singleLine="true"
android:textAppearance="?attr/textAppearanceBodyLarge"
tools:text="@tools:sample/lorem[1]" />
android:orientation="vertical">
<TextView
android:id="@+id/textView_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?attr/textAppearanceBodyLarge"
tools:text="@tools:sample/lorem[15]" />
<TextView
android:id="@+id/textView_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?attr/textAppearanceBodySmall"
tools:text="English" />
</LinearLayout>
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/switch_toggle"

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/navigation_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -16,7 +17,8 @@
android:layout_marginTop="24dp"
android:layout_marginBottom="24dp"
android:contentDescription="@string/app_name"
android:src="@drawable/ic_totoro" />
android:src="@drawable/ic_totoro"
app:tint="?colorPrimary" />
<TextView
android:id="@+id/textView_title"