mirror of
https://github.com/mihonapp/mihon.git
synced 2025-11-13 12:38:58 +01:00
Release v6.1.3
Make search engine synchronous Offload some search engine tasks to background threads Minor search engine speedups
This commit is contained in:
@@ -62,7 +62,8 @@ open class App : Application() {
|
||||
Realm.init(this)
|
||||
val config = RealmConfiguration.Builder()
|
||||
.name("gallery-metadata.realm")
|
||||
.schemaVersion(1)
|
||||
.schemaVersion(2)
|
||||
.deleteRealmIfMigrationNeeded()
|
||||
.build()
|
||||
Realm.setDefaultConfiguration(config)
|
||||
|
||||
|
||||
@@ -3,16 +3,16 @@ package eu.kanade.tachiyomi.ui.library
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import exh.*
|
||||
import exh.metadata.loadAllMetadata
|
||||
import exh.metadata.models.ExGalleryMetadata
|
||||
import exh.metadata.models.NHentaiMetadata
|
||||
import exh.metadata.models.PervEdenGalleryMetadata
|
||||
import exh.metadata.models.SearchableGalleryMetadata
|
||||
import exh.metadata.queryMetadataFromManga
|
||||
import exh.metadata.syncMangaIds
|
||||
import exh.search.SearchEngine
|
||||
import exh.util.defRealm
|
||||
import rx.Observable
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.schedulers.Schedulers
|
||||
import io.realm.RealmResults
|
||||
import timber.log.Timber
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
/**
|
||||
@@ -20,18 +20,17 @@ import kotlin.concurrent.thread
|
||||
*
|
||||
* @param view the fragment containing this adapter.
|
||||
*/
|
||||
class LibraryCategoryAdapter(view: LibraryCategoryView) :
|
||||
class LibraryCategoryAdapter(val view: LibraryCategoryView) :
|
||||
FlexibleAdapter<LibraryItem>(null, view, true) {
|
||||
// --> EH
|
||||
private val searchEngine = SearchEngine()
|
||||
// <-- EH
|
||||
|
||||
/**
|
||||
* The list of manga in this category.
|
||||
*/
|
||||
private var mangas: List<LibraryItem> = emptyList()
|
||||
|
||||
// --> EH
|
||||
private val searchEngine = SearchEngine()
|
||||
// <-- EH
|
||||
|
||||
/**
|
||||
* Sets a list of manga in the adapter.
|
||||
*
|
||||
@@ -41,6 +40,17 @@ class LibraryCategoryAdapter(view: LibraryCategoryView) :
|
||||
// A copy of manga always unfiltered.
|
||||
mangas = list.toList()
|
||||
|
||||
// Sync manga IDs in background (EH)
|
||||
thread {
|
||||
//Wait 1s to reduce UI stutter during animations
|
||||
Thread.sleep(1000)
|
||||
defRealm {
|
||||
it.syncMangaIds(list.map {
|
||||
it.manga
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
performFilter()
|
||||
}
|
||||
|
||||
@@ -54,44 +64,95 @@ class LibraryCategoryAdapter(view: LibraryCategoryView) :
|
||||
}
|
||||
|
||||
fun performFilter() {
|
||||
Observable.fromCallable {
|
||||
defRealm { realm ->
|
||||
//TODO Wrap in try catch
|
||||
if(searchText.isNotBlank()) {
|
||||
try {
|
||||
val parsedQuery = searchEngine.parseQuery(searchText)
|
||||
val metadata = realm.loadAllMetadata().map {
|
||||
Pair(it.key, searchEngine.filterResults(it.value, parsedQuery))
|
||||
}
|
||||
mangas.filter { manga ->
|
||||
val metadata = view.meta!!.map {
|
||||
val meta: RealmResults<out SearchableGalleryMetadata> = if (it.value.isNotEmpty())
|
||||
searchEngine.filterResults(it.value.where(),
|
||||
parsedQuery,
|
||||
it.value.first().titleFields)
|
||||
.findAllSorted(SearchableGalleryMetadata::mangaId.name)
|
||||
else
|
||||
it.value
|
||||
Pair(it.key, meta)
|
||||
}.toMap()
|
||||
// --> Possible data set compare algorithm?
|
||||
// var curUnfilteredMetaIndex = 0
|
||||
// var curFilteredMetaIndex = 0
|
||||
// val res = mangas.sortedBy { it.manga.id }.filter { manga ->
|
||||
val res = mangas.filter { manga ->
|
||||
// --> EH
|
||||
if (isLewdSource(manga.manga.source)) {
|
||||
val hasMeta
|
||||
= realm.queryMetadataFromManga(manga.manga).count() > 0
|
||||
if(hasMeta)
|
||||
metadata.any {
|
||||
when (manga.manga.source) {
|
||||
EH_SOURCE_ID,
|
||||
EXH_SOURCE_ID ->
|
||||
if (it.first != ExGalleryMetadata::class)
|
||||
return@any false
|
||||
PERV_EDEN_IT_SOURCE_ID,
|
||||
PERV_EDEN_EN_SOURCE_ID ->
|
||||
if (it.first != PervEdenGalleryMetadata::class)
|
||||
return@any false
|
||||
NHENTAI_SOURCE_ID ->
|
||||
if (it.first != NHentaiMetadata::class)
|
||||
return@any false
|
||||
try {
|
||||
if (isLewdSource(manga.manga.source)) {
|
||||
val unfilteredMeta: RealmResults<out SearchableGalleryMetadata>?
|
||||
val filteredMeta: RealmResults<out SearchableGalleryMetadata>?
|
||||
when (manga.manga.source) {
|
||||
EH_SOURCE_ID,
|
||||
EXH_SOURCE_ID -> {
|
||||
unfilteredMeta = view.meta!![ExGalleryMetadata::class]
|
||||
filteredMeta = metadata[ExGalleryMetadata::class]
|
||||
}
|
||||
PERV_EDEN_IT_SOURCE_ID,
|
||||
PERV_EDEN_EN_SOURCE_ID -> {
|
||||
unfilteredMeta = view.meta!![PervEdenGalleryMetadata::class]
|
||||
filteredMeta = metadata[PervEdenGalleryMetadata::class]
|
||||
}
|
||||
NHENTAI_SOURCE_ID -> {
|
||||
unfilteredMeta = view.meta!![NHentaiMetadata::class]
|
||||
filteredMeta = metadata[NHentaiMetadata::class]
|
||||
}
|
||||
else -> {
|
||||
unfilteredMeta = null
|
||||
filteredMeta = null
|
||||
}
|
||||
return@filter realm.queryMetadataFromManga(manga.manga, it.second.where()).count() > 0
|
||||
}
|
||||
|
||||
/*
|
||||
--> Possible data set compare algorithm?
|
||||
|
||||
var atUnfilteredMeta = unfilteredMeta?.getOrNull(curUnfilteredMetaIndex)
|
||||
|
||||
while(atUnfilteredMeta?.mangaId != null
|
||||
&& atUnfilteredMeta.mangaId!! < manga.manga.id!!) {
|
||||
curUnfilteredMetaIndex++
|
||||
atUnfilteredMeta = unfilteredMeta?.getOrNull(curUnfilteredMetaIndex)
|
||||
}
|
||||
|
||||
if(atUnfilteredMeta?.mangaId == manga.manga.id) {
|
||||
var atFilteredMeta = filteredMeta?.getOrNull(curFilteredMetaIndex)
|
||||
while(atFilteredMeta?.mangaId != null
|
||||
&& atFilteredMeta.mangaId!! < manga.manga.id!!) {
|
||||
curFilteredMetaIndex++
|
||||
atFilteredMeta = filteredMeta?.getOrNull(curFilteredMetaIndex)
|
||||
}
|
||||
|
||||
return@filter atFilteredMeta?.mangaId == manga.manga.id
|
||||
}*/
|
||||
val hasMeta = unfilteredMeta
|
||||
?.where()
|
||||
?.equalTo(SearchableGalleryMetadata::mangaId.name, manga.manga.id)
|
||||
?.count() ?: 0 > 0
|
||||
if (hasMeta)
|
||||
return@filter filteredMeta!!.where()
|
||||
.equalTo(SearchableGalleryMetadata::mangaId.name, manga.manga.id)
|
||||
.count() > 0
|
||||
}
|
||||
} catch(e: Exception) {
|
||||
Timber.w(e, "Could not filter manga!", manga.manga)
|
||||
}
|
||||
manga.filter(searchText)
|
||||
// <-- EH
|
||||
}
|
||||
updateDataSet(res)
|
||||
} catch(e: Exception) {
|
||||
Timber.w(e, "Could not filter mangas!")
|
||||
updateDataSet(mangas)
|
||||
}
|
||||
}.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
updateDataSet(it)
|
||||
}
|
||||
} else {
|
||||
updateDataSet(mangas)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,9 +16,14 @@ import eu.kanade.tachiyomi.util.inflate
|
||||
import eu.kanade.tachiyomi.util.plusAssign
|
||||
import eu.kanade.tachiyomi.util.toast
|
||||
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
||||
import exh.metadata.loadAllMetadata
|
||||
import exh.metadata.models.SearchableGalleryMetadata
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmResults
|
||||
import kotlinx.android.synthetic.main.library_category.view.*
|
||||
import rx.subscriptions.CompositeSubscription
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Fragment containing the library manga for a certain category.
|
||||
@@ -59,6 +64,14 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
||||
*/
|
||||
private var subscriptions = CompositeSubscription()
|
||||
|
||||
// --> EH
|
||||
// Cached Realm instance
|
||||
var realm: Realm? = null
|
||||
|
||||
// Cached metadata (auto-updating)
|
||||
var meta: Map<KClass<out SearchableGalleryMetadata>, RealmResults<out SearchableGalleryMetadata>>? = null
|
||||
// <-- EH
|
||||
|
||||
fun onCreate(controller: LibraryController) {
|
||||
this.controller = controller
|
||||
|
||||
@@ -102,6 +115,12 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
||||
fun onBind(category: Category) {
|
||||
this.category = category
|
||||
|
||||
// Cache Realm (EH)
|
||||
realm?.close()
|
||||
realm = Realm.getDefaultInstance()?.apply {
|
||||
meta = loadAllMetadata()
|
||||
}
|
||||
|
||||
adapter.mode = if (controller.selectedMangas.isNotEmpty()) {
|
||||
FlexibleAdapter.MODE_MULTI
|
||||
} else {
|
||||
@@ -126,8 +145,22 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
||||
subscriptions.clear()
|
||||
}
|
||||
|
||||
override fun onAttachedToWindow() {
|
||||
// --> EH
|
||||
realm?.close()
|
||||
realm = Realm.getDefaultInstance()?.apply {
|
||||
meta = loadAllMetadata()
|
||||
}
|
||||
// <-- EH
|
||||
super.onAttachedToWindow()
|
||||
}
|
||||
|
||||
override fun onDetachedFromWindow() {
|
||||
subscriptions.clear()
|
||||
// --> EH
|
||||
meta = null
|
||||
realm?.close()
|
||||
// <-- EH
|
||||
super.onDetachedFromWindow()
|
||||
}
|
||||
|
||||
|
||||
@@ -346,7 +346,7 @@ class LibraryController(
|
||||
|
||||
// Debounce search (EH)
|
||||
searchView.queryTextChanges()
|
||||
.debounce(200, TimeUnit.MILLISECONDS)
|
||||
.debounce(350, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeUntilDestroy {
|
||||
query = it.toString()
|
||||
|
||||
@@ -12,9 +12,23 @@ import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.util.inflate
|
||||
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
||||
import exh.*
|
||||
import exh.metadata.ehMetaQueryFromUrl
|
||||
import exh.metadata.models.ExGalleryMetadata
|
||||
import exh.metadata.models.NHentaiMetadata
|
||||
import exh.metadata.models.PervEdenGalleryMetadata
|
||||
import exh.metadata.models.SearchableGalleryMetadata
|
||||
import exh.metadata.nhentaiMetaQueryFromUrl
|
||||
import exh.metadata.pervEdenMetaQueryFromUrl
|
||||
import exh.search.SearchEngine
|
||||
import exh.util.defRealm
|
||||
import io.realm.RealmQuery
|
||||
import kotlinx.android.synthetic.main.catalogue_grid_item.view.*
|
||||
|
||||
class LibraryItem(val manga: Manga) : AbstractFlexibleItem<LibraryHolder>(), IFilterable {
|
||||
// --> EH
|
||||
private val searchEngine = SearchEngine()
|
||||
// <-- EH
|
||||
|
||||
override fun getLayoutRes(): Int {
|
||||
return R.layout.catalogue_grid_item
|
||||
@@ -53,6 +67,38 @@ class LibraryItem(val manga: Manga) : AbstractFlexibleItem<LibraryHolder>(), IFi
|
||||
* @return true if the manga should be included, false otherwise.
|
||||
*/
|
||||
override fun filter(constraint: String): Boolean {
|
||||
defRealm { realm ->
|
||||
if (isLewdSource(manga.source)) {
|
||||
val titleFields: List<String>?
|
||||
var query: RealmQuery<out SearchableGalleryMetadata>?
|
||||
when (manga.source) {
|
||||
EH_SOURCE_ID -> {
|
||||
titleFields = ExGalleryMetadata.TITLE_FIELDS
|
||||
query = realm.ehMetaQueryFromUrl(manga.url, false)
|
||||
}
|
||||
EXH_SOURCE_ID -> {
|
||||
titleFields = ExGalleryMetadata.TITLE_FIELDS
|
||||
query = realm.ehMetaQueryFromUrl(manga.url, true)
|
||||
}
|
||||
PERV_EDEN_IT_SOURCE_ID,
|
||||
PERV_EDEN_EN_SOURCE_ID -> {
|
||||
titleFields = PervEdenGalleryMetadata.TITLE_FIELDS
|
||||
query = realm.pervEdenMetaQueryFromUrl(manga.url, manga.source)
|
||||
}
|
||||
NHENTAI_SOURCE_ID -> {
|
||||
titleFields = NHentaiMetadata.TITLE_FIELDS
|
||||
query = realm.nhentaiMetaQueryFromUrl(manga.url)
|
||||
}
|
||||
else -> return@defRealm
|
||||
}
|
||||
val hasMeta = query!!.count() > 0
|
||||
if(hasMeta) {
|
||||
val parsedQuery = searchEngine.parseQuery(constraint)
|
||||
query = searchEngine.filterResults(query, parsedQuery, titleFields)
|
||||
return@filter query.count() > 0
|
||||
}
|
||||
}
|
||||
}
|
||||
return manga.title.contains(constraint, true) ||
|
||||
(manga.author?.contains(constraint, true) ?: false)
|
||||
}
|
||||
|
||||
@@ -31,12 +31,14 @@ import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||
import eu.kanade.tachiyomi.ui.recent_updates.RecentChaptersController
|
||||
import eu.kanade.tachiyomi.ui.recently_read.RecentlyReadController
|
||||
import eu.kanade.tachiyomi.ui.setting.SettingsMainController
|
||||
import exh.metadata.loadAllMetadata
|
||||
import exh.ui.batchadd.BatchAddController
|
||||
import exh.ui.lock.LockChangeHandler
|
||||
import exh.ui.lock.LockController
|
||||
import exh.ui.lock.lockEnabled
|
||||
import exh.ui.lock.notifyLockSecurity
|
||||
import exh.ui.migration.MetadataFetchDialog
|
||||
import exh.util.defRealm
|
||||
import kotlinx.android.synthetic.main.main_activity.*
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
@@ -168,9 +170,12 @@ class MainActivity : BaseActivity() {
|
||||
ChangelogDialogController().showDialog(router)
|
||||
}
|
||||
|
||||
// Migrate metadata to Realm (EH)
|
||||
if(!preferences.migrateLibraryAsked2().getOrDefault())
|
||||
MetadataFetchDialog().askMigration(this, false)
|
||||
// Migrate metadata if empty (EH)
|
||||
if(!defRealm {
|
||||
it.loadAllMetadata().any {
|
||||
it.value.isNotEmpty()
|
||||
}
|
||||
}) MetadataFetchDialog().askMigration(this, false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user