mirror of
https://github.com/mihonapp/mihon.git
synced 2025-03-13 08:10:07 +01:00
Release version v6.1.4
Offload metadata check to background thread Add search cache
This commit is contained in:
parent
1107b95ebd
commit
7053777997
@ -44,8 +44,8 @@ android {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 25
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
versionCode 6103
|
||||
versionName "v6.1.3-EH"
|
||||
versionCode 6104
|
||||
versionName "v6.1.4-EH"
|
||||
|
||||
buildConfigField "String", "COMMIT_COUNT", "\"${getCommitCount()}\""
|
||||
buildConfigField "String", "COMMIT_SHA", "\"${getGitSha()}\""
|
||||
|
@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.library
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import exh.*
|
||||
import exh.metadata.metadataClass
|
||||
import exh.metadata.models.ExGalleryMetadata
|
||||
import exh.metadata.models.NHentaiMetadata
|
||||
import exh.metadata.models.PervEdenGalleryMetadata
|
||||
@ -12,6 +13,7 @@ import exh.search.SearchEngine
|
||||
import exh.util.defRealm
|
||||
import io.realm.RealmResults
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
/**
|
||||
@ -42,11 +44,9 @@ class LibraryCategoryAdapter(val view: LibraryCategoryView) :
|
||||
// Sync manga IDs in background (EH)
|
||||
thread {
|
||||
//Wait 1s to reduce UI stutter during animations
|
||||
Thread.sleep(1000)
|
||||
Thread.sleep(2000)
|
||||
defRealm {
|
||||
it.syncMangaIds(list.map {
|
||||
it.manga
|
||||
})
|
||||
it.syncMangaIds(mangas)
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,93 +64,103 @@ class LibraryCategoryAdapter(val view: LibraryCategoryView) :
|
||||
|
||||
fun performFilter() {
|
||||
if(searchText.isNotBlank()) {
|
||||
if(cacheText != searchText) {
|
||||
globalSearchCache.clear()
|
||||
cacheText = searchText
|
||||
}
|
||||
|
||||
try {
|
||||
val parsedQuery = searchEngine.parseQuery(searchText)
|
||||
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
|
||||
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
|
||||
val thisCache = globalSearchCache.getOrPut(view.category.name, {
|
||||
SearchCache(mangas.size)
|
||||
})
|
||||
|
||||
if(thisCache.ready) {
|
||||
//Skip everything if cache matches our query exactly
|
||||
updateDataSet(mangas.filter {
|
||||
thisCache.cache[it.manga.id] ?: false
|
||||
})
|
||||
} else {
|
||||
thisCache.cache.clear()
|
||||
|
||||
val parsedQuery = searchEngine.parseQuery(searchText)
|
||||
var totalFilteredSize = 0
|
||||
|
||||
val metadata = view.controller.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).apply {
|
||||
totalFilteredSize += size
|
||||
}
|
||||
else
|
||||
it.value
|
||||
Pair(it.key, meta)
|
||||
}.toMap()
|
||||
|
||||
val out = ArrayList<LibraryItem>(mangas.size)
|
||||
|
||||
var lewdMatches = 0
|
||||
|
||||
for(manga in mangas) {
|
||||
// --> EH
|
||||
try {
|
||||
if (isLewdSource(manga.manga.source)) {
|
||||
//Stop matching lewd manga if we have matched them all already!
|
||||
if (lewdMatches >= totalFilteredSize)
|
||||
continue
|
||||
|
||||
val metaClass = manga.manga.metadataClass
|
||||
val unfilteredMeta = view.controller.meta!![metaClass]
|
||||
val filteredMeta = metadata[metaClass]
|
||||
|
||||
val hasMeta = manga.hasMetadata ?: (unfilteredMeta
|
||||
?.where()
|
||||
?.equalTo(SearchableGalleryMetadata::mangaId.name, manga.manga.id)
|
||||
?.count() ?: 0 > 0)
|
||||
|
||||
if (hasMeta) {
|
||||
if (filteredMeta!!.where()
|
||||
.equalTo(SearchableGalleryMetadata::mangaId.name, manga.manga.id)
|
||||
.count() > 0) {
|
||||
//Metadata match!
|
||||
lewdMatches++
|
||||
thisCache.cache[manga.manga.id!!] = true
|
||||
out += manga
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
--> 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)
|
||||
} catch (e: Exception) {
|
||||
Timber.w(e, "Could not filter manga!", manga.manga)
|
||||
}
|
||||
|
||||
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)
|
||||
//Fallback to regular filter
|
||||
val filterRes = manga.filter(searchText)
|
||||
thisCache.cache[manga.manga.id!!] = filterRes
|
||||
if(filterRes) out += manga
|
||||
// <-- EH
|
||||
}
|
||||
manga.filter(searchText)
|
||||
// <-- EH
|
||||
thisCache.ready = true
|
||||
updateDataSet(out)
|
||||
}
|
||||
updateDataSet(res)
|
||||
} catch(e: Exception) {
|
||||
Timber.w(e, "Could not filter mangas!")
|
||||
updateDataSet(mangas)
|
||||
}
|
||||
} else {
|
||||
globalSearchCache.clear()
|
||||
updateDataSet(mangas)
|
||||
}
|
||||
}
|
||||
|
||||
class SearchCache(size: Int) {
|
||||
var ready = false
|
||||
var cache = HashMap<Long, Boolean>(size)
|
||||
}
|
||||
|
||||
companion object {
|
||||
var cacheText: String? = null
|
||||
val globalSearchCache = ConcurrentHashMap<String, SearchCache>()
|
||||
}
|
||||
}
|
||||
|
@ -16,14 +16,9 @@ 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.
|
||||
@ -41,7 +36,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
||||
/**
|
||||
* The fragment containing this view.
|
||||
*/
|
||||
private lateinit var controller: LibraryController
|
||||
lateinit var controller: LibraryController
|
||||
|
||||
/**
|
||||
* Category for this view.
|
||||
@ -64,14 +59,6 @@ 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
|
||||
|
||||
@ -139,22 +126,9 @@ 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()
|
||||
}
|
||||
|
||||
@ -270,5 +244,4 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
||||
controller.setSelection(item.manga, !adapter.isSelected(position))
|
||||
controller.invalidateActionMode()
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -36,6 +36,10 @@ import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||
import eu.kanade.tachiyomi.util.inflate
|
||||
import eu.kanade.tachiyomi.util.toast
|
||||
import eu.kanade.tachiyomi.widget.DrawerSwipeCloseListener
|
||||
import exh.metadata.loadAllMetadata
|
||||
import exh.metadata.models.SearchableGalleryMetadata
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmResults
|
||||
import kotlinx.android.synthetic.main.main_activity.*
|
||||
import kotlinx.android.synthetic.main.library_controller.view.*
|
||||
import rx.Subscription
|
||||
@ -45,6 +49,7 @@ import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
|
||||
class LibraryController(
|
||||
@ -126,6 +131,13 @@ class LibraryController(
|
||||
|
||||
private var tabsVisibilitySubscription: Subscription? = null
|
||||
|
||||
// --> EH
|
||||
//Cached realm
|
||||
var realm: Realm? = null
|
||||
//Cached metadata
|
||||
var meta: Map<KClass<out SearchableGalleryMetadata>, RealmResults<out SearchableGalleryMetadata>>? = null
|
||||
// <-- EH
|
||||
|
||||
init {
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
@ -142,6 +154,16 @@ class LibraryController(
|
||||
return inflater.inflate(R.layout.library_controller, container, false)
|
||||
}
|
||||
|
||||
// --> EH
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup, savedViewState: Bundle?): View {
|
||||
//Load realm
|
||||
realm = Realm.getDefaultInstance()?.apply {
|
||||
meta = loadAllMetadata()
|
||||
}
|
||||
return super.onCreateView(inflater, container, savedViewState)
|
||||
}
|
||||
// <-- EH
|
||||
|
||||
override fun onViewCreated(view: View, savedViewState: Bundle?) {
|
||||
super.onViewCreated(view, savedViewState)
|
||||
|
||||
@ -183,6 +205,12 @@ class LibraryController(
|
||||
actionMode = null
|
||||
tabsVisibilitySubscription?.unsubscribe()
|
||||
tabsVisibilitySubscription = null
|
||||
|
||||
// --> EH
|
||||
//Clean up realm
|
||||
realm?.close()
|
||||
meta = null
|
||||
// <-- EH
|
||||
}
|
||||
|
||||
override fun createSecondaryDrawer(drawer: DrawerLayout): ViewGroup {
|
||||
|
@ -15,6 +15,10 @@ import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
||||
import kotlinx.android.synthetic.main.catalogue_grid_item.view.*
|
||||
|
||||
class LibraryItem(val manga: Manga) : AbstractFlexibleItem<LibraryHolder>(), IFilterable {
|
||||
// Temp metadata holder EH
|
||||
@Volatile
|
||||
var hasMetadata: Boolean? = null
|
||||
|
||||
override fun getLayoutRes(): Int {
|
||||
return R.layout.catalogue_grid_item
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package exh.metadata
|
||||
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.ui.library.LibraryItem
|
||||
import exh.*
|
||||
import exh.metadata.models.ExGalleryMetadata
|
||||
import exh.metadata.models.NHentaiMetadata
|
||||
@ -116,20 +117,32 @@ fun Realm.queryMetadataFromManga(manga: Manga,
|
||||
else -> throw IllegalArgumentException("Unknown source type!")
|
||||
}
|
||||
|
||||
fun Realm.syncMangaIds(mangas: List<Manga>) {
|
||||
fun Realm.syncMangaIds(mangas: List<LibraryItem>) {
|
||||
Timber.d("--> EH: Begin syncing ${mangas.size} manga IDs...")
|
||||
executeTransaction {
|
||||
mangas.filter {
|
||||
isLewdSource(it.source)
|
||||
isLewdSource(it.manga.source)
|
||||
}.forEach { manga ->
|
||||
try {
|
||||
queryMetadataFromManga(manga).findFirst()?.let { meta ->
|
||||
meta.mangaId = manga.id
|
||||
}
|
||||
manga.hasMetadata =
|
||||
queryMetadataFromManga(manga.manga).findFirst()?.let { meta ->
|
||||
meta.mangaId = manga.manga.id
|
||||
true
|
||||
} ?: false
|
||||
} catch(e: Exception) {
|
||||
Timber.w(e, "Error syncing manga IDs! Ignoring...")
|
||||
}
|
||||
}
|
||||
}
|
||||
Timber.d("--> EH: Finish syncing ${mangas.size} manga IDs!")
|
||||
}
|
||||
}
|
||||
|
||||
val Manga.metadataClass
|
||||
get() = when (source) {
|
||||
EH_SOURCE_ID,
|
||||
EXH_SOURCE_ID -> ExGalleryMetadata::class
|
||||
PERV_EDEN_IT_SOURCE_ID,
|
||||
PERV_EDEN_EN_SOURCE_ID -> PervEdenGalleryMetadata::class
|
||||
NHENTAI_SOURCE_ID -> NHentaiMetadata::class
|
||||
else -> null
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user