Migrate to realm for metadata

This commit is contained in:
NerdNumber9
2017-08-25 17:31:38 -04:00
parent bb6b88a703
commit cd291f0a27
31 changed files with 1394 additions and 588 deletions

View File

@@ -10,11 +10,14 @@ import eu.kanade.tachiyomi.data.backup.BackupCreatorJob
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
import eu.kanade.tachiyomi.data.updater.UpdateCheckerJob
import eu.kanade.tachiyomi.util.LocaleHelper
import io.paperdb.Paper
import io.realm.Realm
import io.realm.RealmConfiguration
import timber.log.Timber
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.InjektScope
import uy.kohesive.injekt.registry.default.DefaultRegistrar
import java.io.File
import kotlin.concurrent.thread
open class App : Application() {
@@ -26,7 +29,7 @@ open class App : Application() {
if (BuildConfig.DEBUG) Timber.plant(Timber.DebugTree())
setupJobManager()
Paper.init(this) //Setup metadata DB (EH)
setupRealm() //Setup metadata DB (EH)
Reprint.initialize(this) //Setup fingerprint (EH)
LocaleHelper.updateConfiguration(this, resources.configuration)
@@ -55,4 +58,25 @@ open class App : Application() {
}
}
private fun setupRealm() {
Realm.init(this)
val config = RealmConfiguration.Builder()
.name("gallery-metadata.realm")
.schemaVersion(1)
.build()
Realm.setDefaultConfiguration(config)
//Delete old paper db files
listOf(
File(filesDir, "gallery-ex"),
File(filesDir, "gallery-perveden"),
File(filesDir, "gallery-nhentai")
).forEach {
if(it.exists()) {
thread {
it.deleteRecursively()
}
}
}
}
}

View File

@@ -180,14 +180,12 @@ class PreferencesHelper(val context: Context) {
fun thumbnailRows() = rxPrefs.getString("ex_thumb_rows", "tr_2")
fun migrateLibraryAsked() = rxPrefs.getBoolean("ex_migrate_library", false)
fun migrateLibraryAsked2() = rxPrefs.getBoolean("ex_migrate_library2", false)
fun migrationStatus() = rxPrefs.getInteger("migration_status", MigrationStatus.NOT_INITIALIZED)
fun hasPerformedURLMigration() = rxPrefs.getBoolean("performed_url_migration", false)
fun hasPerformedSourceMigration() = rxPrefs.getBoolean("performed_source_migration", false)
//EH Cookies
fun memberIdVal() = rxPrefs.getString("eh_ipb_member_id", null)
fun passHashVal() = rxPrefs.getString("eh_ipb_pass_hash", null)

View File

@@ -10,7 +10,6 @@ import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.source.online.all.EHentai
import eu.kanade.tachiyomi.source.online.all.EHentaiMetadata
import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.source.online.YamlHttpSource
import eu.kanade.tachiyomi.source.online.all.NHentai
@@ -88,13 +87,11 @@ open class SourceManager(private val context: Context) {
)
private fun createEHSources(): List<Source> {
val exSrcs = mutableListOf(
EHentai(EH_SOURCE_ID, false, context),
EHentaiMetadata(EH_METADATA_SOURCE_ID, false, context)
val exSrcs = mutableListOf<HttpSource>(
EHentai(EH_SOURCE_ID, false, context)
)
if(prefs.enableExhentai().getOrDefault()) {
exSrcs += EHentai(EXH_SOURCE_ID, true, context)
exSrcs += EHentaiMetadata(EXH_METADATA_SOURCE_ID, true, context)
}
exSrcs += PervEden(PERV_EDEN_EN_SOURCE_ID, "en")
exSrcs += PervEden(PERV_EDEN_IT_SOURCE_ID, "it")

View File

@@ -20,14 +20,13 @@ import uy.kohesive.injekt.injectLazy
import java.net.URLEncoder
import java.util.*
import exh.ui.login.LoginController
import exh.util.UriFilter
import exh.util.UriGroup
import okhttp3.CacheControl
import okhttp3.Headers
import okhttp3.Request
import org.jsoup.nodes.Document
import exh.GalleryAdder
import exh.util.urlImportFetchSearchManga
import exh.util.*
import io.realm.Realm
class EHentai(override val id: Long,
val exh: Boolean,
@@ -50,8 +49,6 @@ class EHentai(override val id: Long,
val prefs: PreferencesHelper by injectLazy()
val metadataHelper = MetadataHelper()
val galleryAdder = GalleryAdder()
/**
@@ -168,10 +165,10 @@ class EHentai(override val id: Long,
override fun latestUpdatesParse(response: Response) = genericMangaParse(response)
fun exGet(url: String, page: Int? = null, additionalHeaders: Headers? = null, cache: Boolean = true)
= GET(page?.let {
addParam(url, "page", Integer.toString(page - 1))
} ?: url, additionalHeaders?.let {
val headers = headers.newBuilder()
= GET(page?.let {
addParam(url, "page", Integer.toString(page - 1))
} ?: url, additionalHeaders?.let {
val headers = headers.newBuilder()
it.toMultimap().forEach { (t, u) ->
u.forEach {
headers.add(t, it)
@@ -188,86 +185,90 @@ class EHentai(override val id: Long,
/**
* Parse gallery page to metadata model
*/
override fun mangaDetailsParse(response: Response) = with(response.asJsoup()) {
val metdata = ExGalleryMetadata()
with(metdata) {
url = response.request().url().encodedPath()
exh = this@EHentai.exh
title = select("#gn").text().nullIfBlank()?.trim()
override fun mangaDetailsParse(response: Response)
= with(response.asJsoup()) {
realmTrans { realm ->
val url = response.request().url().encodedPath()!!
val gId = ExGalleryMetadata.galleryId(url)
val gToken = ExGalleryMetadata.galleryToken(url)
altTitle = select("#gj").text().nullIfBlank()?.trim()
val metdata = (realm.loadEh(gId, gToken, exh)
?: realm.createUUIDObj(ExGalleryMetadata::class.java))
with(metdata) {
this.url = url
this.gId = gId
this.gToken = gToken
thumbnailUrl = select("#gd1 div").attr("style").nullIfBlank()?.let {
it.substring(it.indexOf('(') + 1 until it.lastIndexOf(')'))
}
exh = this@EHentai.exh
title = select("#gn").text().nullIfBlank()?.trim()
genre = select(".ic").parents().attr("href").nullIfBlank()?.trim()?.substringAfterLast('/')
altTitle = select("#gj").text().nullIfBlank()?.trim()
uploader = select("#gdn").text().nullIfBlank()?.trim()
thumbnailUrl = select("#gd1 div").attr("style").nullIfBlank()?.let {
it.substring(it.indexOf('(') + 1 until it.lastIndexOf(')'))
}
genre = select(".ic").parents().attr("href").nullIfBlank()?.trim()?.substringAfterLast('/')
//Parse the table
select("#gdd tr").forEach {
it.select(".gdt1")
.text()
.nullIfBlank()
?.trim()
?.let { left ->
it.select(".gdt2")
.text()
.nullIfBlank()
?.trim()
?.let { right ->
ignore {
when (left.removeSuffix(":")
.toLowerCase()) {
"posted" -> datePosted = EX_DATE_FORMAT.parse(right).time
"visible" -> visible = right.nullIfBlank()
"language" -> {
language = right.removeSuffix(TR_SUFFIX).trim().nullIfBlank()
translated = right.endsWith(TR_SUFFIX, true)
uploader = select("#gdn").text().nullIfBlank()?.trim()
//Parse the table
select("#gdd tr").forEach {
it.select(".gdt1")
.text()
.nullIfBlank()
?.trim()
?.let { left ->
it.select(".gdt2")
.text()
.nullIfBlank()
?.trim()
?.let { right ->
ignore {
when (left.removeSuffix(":")
.toLowerCase()) {
"posted" -> datePosted = EX_DATE_FORMAT.parse(right).time
"visible" -> visible = right.nullIfBlank()
"language" -> {
language = right.removeSuffix(TR_SUFFIX).trim().nullIfBlank()
translated = right.endsWith(TR_SUFFIX, true)
}
"file size" -> size = parseHumanReadableByteCount(right)?.toLong()
"length" -> length = right.removeSuffix("pages").trim().nullIfBlank()?.toInt()
"favorited" -> favorites = right.removeSuffix("times").trim().nullIfBlank()?.toInt()
}
"file size" -> size = parseHumanReadableByteCount(right)?.toLong()
"length" -> length = right.removeSuffix("pages").trim().nullIfBlank()?.toInt()
"favorited" -> favorites = right.removeSuffix("times").trim().nullIfBlank()?.toInt()
}
}
}
}
}
//Parse ratings
ignore {
averageRating = select("#rating_label")
.text()
.removePrefix("Average:")
.trim()
.nullIfBlank()
?.toDouble()
ratingCount = select("#rating_count")
.text()
.trim()
.nullIfBlank()
?.toInt()
}
//Parse tags
tags.clear()
select("#taglist tr").forEach {
val namespace = it.select(".tc").text().removeSuffix(":")
val currentTags = it.select("div").map {
Tag(it.text().trim(),
it.hasClass("gtl"))
}
}
tags.put(namespace, ArrayList(currentTags))
}
//Save metadata
metadataHelper.writeGallery(this, id)
//Parse ratings
ignore {
averageRating = select("#rating_label")
.text()
.removePrefix("Average:")
.trim()
.nullIfBlank()
?.toDouble()
ratingCount = select("#rating_count")
.text()
.trim()
.nullIfBlank()
?.toInt()
}
//Copy metadata to manga
SManga.create().let {
copyTo(it)
it
//Parse tags
tags.clear()
select("#taglist tr").forEach {
val namespace = it.select(".tc").text().removeSuffix(":")
tags.addAll(it.select("div").map {
Tag(namespace, it.text().trim(), it.hasClass("gtl"))
})
}
//Copy metadata to manga
SManga.create().apply {
copyTo(this)
}
}
}
}

View File

@@ -1,127 +0,0 @@
package eu.kanade.tachiyomi.source.online.all
import android.content.Context
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.source.model.*
import eu.kanade.tachiyomi.source.online.HttpSource
import exh.metadata.MetadataHelper
import exh.metadata.copyTo
import exh.metadata.models.ExGalleryMetadata
import exh.search.SearchEngine
import okhttp3.Response
import rx.Observable
/**
* Offline metadata store source
*
* TODO This no longer fakes an online source because of technical reasons.
* If we still want offline search, we must find out a way to rearchitecture the source system so it supports
* online source faking again.
*/
class EHentaiMetadata(override val id: Long,
val exh: Boolean,
val context: Context) : HttpSource() {
override fun popularMangaRequest(page: Int)
= throw UnsupportedOperationException("Unused method called!")
override fun popularMangaParse(response: Response)
= throw UnsupportedOperationException("Unused method called!")
override fun searchMangaRequest(page: Int, query: String, filters: FilterList)
= throw UnsupportedOperationException("Unused method called!")
override fun searchMangaParse(response: Response)
= throw UnsupportedOperationException("Unused method called!")
override fun latestUpdatesRequest(page: Int)
= throw UnsupportedOperationException("Unused method called!")
override fun latestUpdatesParse(response: Response)
= throw UnsupportedOperationException("Unused method called!")
override fun mangaDetailsParse(response: Response)
= throw UnsupportedOperationException("Unused method called!")
override fun chapterListParse(response: Response)
= throw UnsupportedOperationException("Unused method called!")
override fun pageListParse(response: Response)
= throw UnsupportedOperationException("Unused method called!")
override fun imageUrlParse(response: Response)
= throw UnsupportedOperationException("Unused method called!")
val metadataHelper = MetadataHelper()
val internalEx = EHentai(id - 2, exh, context)
val searchEngine = SearchEngine()
override val baseUrl: String
get() = throw UnsupportedOperationException()
override val lang: String
get() = "advanced"
override val supportsLatest: Boolean
get() = true
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>>
= Observable.just(listOf(Chapter.create().apply {
url = manga.url
name = "ONLINE - Chapter"
chapter_number = 1f
}))
override fun fetchPageList(chapter: SChapter) = internalEx.fetchPageList(chapter)
override fun fetchImageUrl(page: Page) = internalEx.fetchImageUrl(page)
fun List<ExGalleryMetadata>.mapToManga() = filter { it.exh == exh }
.map {
Manga.create(id).apply {
it.copyTo(this)
source = this@EHentaiMetadata.id
}
}
fun sortedByTimeGalleries() = metadataHelper.getAllGalleries().sortedByDescending {
it.datePosted ?: 0
}
override fun fetchPopularManga(page: Int)
= Observable.fromCallable {
MangasPage(metadataHelper.getAllGalleries().sortedByDescending {
it.ratingCount ?: 0
}.mapToManga(), false)
}!!
override fun fetchSearchManga(page: Int, query: String, filters: FilterList)
= Observable.fromCallable {
val genreGroup = filters.find {
it is EHentai.GenreGroup
}!! as EHentai.GenreGroup
val disableGenreFilter = genreGroup.state.find(EHentai.GenreOption::state) == null
val parsed = searchEngine.parseQuery(query)
MangasPage(sortedByTimeGalleries().filter { manga ->
disableGenreFilter || genreGroup.state.find {
it.state && it.genreId == manga.genre
} != null
}.filter {
searchEngine.matches(it, parsed)
}.mapToManga(), false)
}!!
override fun fetchLatestUpdates(page: Int)
= Observable.fromCallable {
MangasPage(sortedByTimeGalleries().mapToManga(), false)
}!!
override fun fetchMangaDetails(manga: SManga) = Observable.fromCallable {
//Hack to convert the gallery into an online gallery when favoriting it or reading it
metadataHelper.fetchEhMetadata(manga.url, exh)?.copyTo(manga)
manga
}!!
override fun getFilterList() = FilterList(EHentai.GenreGroup())
override val name: String
get() = if(exh) {
"ExHentai"
} else {
"E-Hentai"
} + " - METADATA"
}

View File

@@ -17,10 +17,15 @@ import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.source.model.*
import eu.kanade.tachiyomi.source.online.HttpSource
import exh.NHENTAI_SOURCE_ID
import exh.metadata.MetadataHelper
import exh.metadata.copyTo
import exh.metadata.loadNhentai
import exh.metadata.loadNhentaiAsync
import exh.metadata.models.NHentaiMetadata
import exh.metadata.models.PageImageType
import exh.metadata.models.Tag
import exh.util.createUUIDObj
import exh.util.defRealm
import exh.util.realmTrans
import exh.util.urlImportFetchSearchManga
import okhttp3.Request
import okhttp3.Response
@@ -108,62 +113,73 @@ class NHentai(context: Context) : HttpSource() {
return MangasPage(emptyList(), false)
}
fun rawParseGallery(obj: JsonObject) = NHentaiMetadata().apply {
uploadDate = obj.get("upload_date")?.notNull()?.long
fun rawParseGallery(obj: JsonObject) = realmTrans { realm ->
val nhId = obj.get("id").asLong
favoritesCount = obj.get("num_favorites")?.notNull()?.long
(realm.loadNhentai(nhId)
?: realm.createUUIDObj(NHentaiMetadata::class.java)).apply {
this.nhId = nhId
mediaId = obj.get("media_id")?.notNull()?.string
uploadDate = obj.get("upload_date")?.notNull()?.long
obj.get("title")?.asJsonObject?.let {
japaneseTitle = it.get("japanese")?.notNull()?.string
shortTitle = it.get("pretty")?.notNull()?.string
englishTitle = it.get("english")?.notNull()?.string
}
favoritesCount = obj.get("num_favorites")?.notNull()?.long
obj.get("images")?.asJsonObject?.let {
coverImageType = it.get("cover")?.get("t")?.notNull()?.asString
it.get("pages")?.asJsonArray?.map {
it?.asJsonObject?.get("t")?.notNull()?.asString
}?.filterNotNull()?.let {
pageImageTypes.clear()
pageImageTypes.addAll(it)
mediaId = obj.get("media_id")?.notNull()?.string
obj.get("title")?.asJsonObject?.let {
japaneseTitle = it.get("japanese")?.notNull()?.string
shortTitle = it.get("pretty")?.notNull()?.string
englishTitle = it.get("english")?.notNull()?.string
}
thumbnailImageType = it.get("thumbnail")?.get("t")?.notNull()?.asString
}
scanlator = obj.get("scanlator")?.notNull()?.asString
obj.get("images")?.asJsonObject?.let {
coverImageType = it.get("cover")?.get("t")?.notNull()?.asString
it.get("pages")?.asJsonArray?.map {
it?.asJsonObject?.get("t")?.notNull()?.asString
}?.filterNotNull()?.map {
PageImageType(it)
}?.let {
pageImageTypes.clear()
pageImageTypes.addAll(it)
}
thumbnailImageType = it.get("thumbnail")?.get("t")?.notNull()?.asString
}
id = obj.get("id")?.asLong
scanlator = obj.get("scanlator")?.notNull()?.asString
obj.get("tags")?.asJsonArray?.map {
val asObj = it.asJsonObject
Pair(asObj.get("type")?.string, asObj.get("name")?.string)
}?.apply {
tags.clear()
}?.forEach {
if(it.first != null && it.second != null)
tags.getOrPut(it.first!!, { ArrayList() }).add(Tag(it.second!!, false))
obj.get("tags")?.asJsonArray?.map {
val asObj = it.asJsonObject
Pair(asObj.get("type")?.string, asObj.get("name")?.string)
}?.apply {
tags.clear()
}?.forEach {
if(it.first != null && it.second != null)
tags.add(Tag(it.first!!, it.second!!, false))
}
}
}
fun parseGallery(obj: JsonObject) = rawParseGallery(obj).let {
metadataHelper.writeGallery(it, id)
SManga.create().apply {
it.copyTo(this)
}
}
fun lazyLoadMetadata(url: String) =
Observable.fromCallable {
metadataHelper.fetchNhentaiMetadata(url)
?: client.newCall(urlToDetailsRequest(url))
.asObservableSuccess()
.map {
rawParseGallery(jsonParser.parse(it.body()!!.string()).asJsonObject)
}.toBlocking().first()
}!!
defRealm { realm ->
realm.loadNhentaiAsync(NHentaiMetadata.nhIdFromUrl(url))
.flatMap {
if(it == null)
client.newCall(urlToDetailsRequest(url))
.asObservableSuccess()
.map {
rawParseGallery(jsonParser.parse(it.body()!!.string())
.asJsonObject)
}.first()
else
Observable.just(it)
}.map { realm.copyFromRealm(it) }
}
override fun fetchChapterList(manga: SManga)
= lazyLoadMetadata(manga.url).map {
@@ -181,7 +197,7 @@ class NHentai(context: Context) : HttpSource() {
if(metadata.mediaId == null) emptyList()
else
metadata.pageImageTypes.mapIndexed { index, s ->
val imageUrl = imageUrlFromType(metadata.mediaId!!, index + 1, s)
val imageUrl = imageUrlFromType(metadata.mediaId!!, index + 1, s.type!!)
Page(index, imageUrl!!, imageUrl)
}
}!!
@@ -231,14 +247,10 @@ class NHentai(context: Context) : HttpSource() {
val jsonParser by lazy {
JsonParser()
}
val metadataHelper by lazy {
MetadataHelper()
}
}
fun JsonElement.notNull() =
if(this is JsonNull)
null
else this
if(this is JsonNull)
null
else this
}

View File

@@ -6,12 +6,15 @@ import eu.kanade.tachiyomi.source.model.*
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.ChapterRecognition
import eu.kanade.tachiyomi.util.asJsoup
import exh.metadata.MetadataHelper
import exh.metadata.copyTo
import exh.metadata.loadPervEden
import exh.metadata.models.PervEdenGalleryMetadata
import exh.metadata.models.PervEdenTitle
import exh.metadata.models.Tag
import exh.util.UriFilter
import exh.util.UriGroup
import exh.util.createUUIDObj
import exh.util.realmTrans
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
@@ -27,8 +30,6 @@ class PervEden(override val id: Long, override val lang: String) : ParsedHttpSou
override val name = "Perv Eden"
override val baseUrl = "http://www.perveden.com"
val metadataHelper by lazy { MetadataHelper() }
override fun popularMangaSelector() = "#topManga > ul > li"
override fun popularMangaFromElement(element: Element): SManga {
@@ -99,72 +100,68 @@ class PervEden(override val id: Long, override val lang: String) : ParsedHttpSou
}
override fun mangaDetailsParse(document: Document): SManga {
val metadata = PervEdenGalleryMetadata()
with(metadata) {
url = document.location()
realmTrans { realm ->
val url = document.location()
val metadata = (realm.loadPervEden(PervEdenGalleryMetadata.pvIdFromUrl(url), id)
?: realm.createUUIDObj(PervEdenGalleryMetadata::class.java))
with(metadata) {
this.url = url
lang = this@PervEden.lang
lang = this@PervEden.lang
title = document.getElementsByClass("manga-title").first()?.text()
title = document.getElementsByClass("manga-title").first()?.text()
thumbnailUrl = "http:" + document.getElementsByClass("mangaImage2").first()?.child(0)?.attr("src")
thumbnailUrl = "http:" + document.getElementsByClass("mangaImage2").first()?.child(0)?.attr("src")
val rightBoxElement = document.select(".rightBox:not(.info)").first()
val rightBoxElement = document.select(".rightBox:not(.info)").first()
tags.clear()
var inStatus: String? = null
rightBoxElement.childNodes().forEach {
if(it is Element && it.tagName().toLowerCase() == "h4") {
inStatus = it.text().trim()
} else {
when(inStatus) {
"Alternative name(s)" -> {
if(it is TextNode) {
val text = it.text().trim()
if(!text.isBlank())
altTitles.add(text)
tags.clear()
var inStatus: String? = null
rightBoxElement.childNodes().forEach {
if(it is Element && it.tagName().toLowerCase() == "h4") {
inStatus = it.text().trim()
} else {
when(inStatus) {
"Alternative name(s)" -> {
if(it is TextNode) {
val text = it.text().trim()
if(!text.isBlank())
altTitles.add(PervEdenTitle(this, text))
}
}
}
"Artist" -> {
if(it is Element && it.tagName() == "a") {
artist = it.text()
tags.getOrPut("artist", {
ArrayList()
}).add(Tag(it.text().toLowerCase(), false))
"Artist" -> {
if(it is Element && it.tagName() == "a") {
artist = it.text()
tags.add(Tag("artist", it.text().toLowerCase(), false))
}
}
}
"Genres" -> {
if(it is Element && it.tagName() == "a")
tags.getOrPut("genre", {
ArrayList()
}).add(Tag(it.text().toLowerCase(), false))
}
"Type" -> {
if(it is TextNode) {
val text = it.text().trim()
if(!text.isBlank())
type = text
"Genres" -> {
if(it is Element && it.tagName() == "a")
tags.add(Tag("genre", it.text().toLowerCase(), false))
}
}
"Status" -> {
if(it is TextNode) {
val text = it.text().trim()
if(!text.isBlank())
status = text
"Type" -> {
if(it is TextNode) {
val text = it.text().trim()
if(!text.isBlank())
type = text
}
}
"Status" -> {
if(it is TextNode) {
val text = it.text().trim()
if(!text.isBlank())
status = text
}
}
}
}
}
}
rating = document.getElementById("rating-score")?.attr("value")?.toFloat()
rating = document.getElementById("rating-score")?.attr("value")?.toFloat()
//Save metadata
Timber.d("LNG: " + metadata.lang)
metadataHelper.writeGallery(this, id)
return SManga.create().apply {
copyTo(this)
return SManga.create().apply {
copyTo(this)
}
}
}
}
@@ -197,12 +194,12 @@ class PervEden(override val id: Long, override val lang: String) : ParsedHttpSou
}
override fun pageListParse(document: Document)
= document.getElementById("pageSelect").getElementsByTag("option").map {
Page(it.attr("data-page").toInt() - 1, baseUrl + it.attr("value"))
}
= document.getElementById("pageSelect").getElementsByTag("option").map {
Page(it.attr("data-page").toInt() - 1, baseUrl + it.attr("value"))
}
override fun imageUrlParse(document: Document)
= "http:" + document.getElementById("mainImg").attr("src")!!
= "http:" + document.getElementById("mainImg").attr("src")!!
override fun getFilterList() = FilterList (
AuthorFilter(),

View File

@@ -2,6 +2,18 @@ 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.queryMetadataFromManga
import exh.search.SearchEngine
import exh.util.defRealm
import rx.Observable
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
import kotlin.concurrent.thread
/**
* Adapter storing a list of manga in a certain category.
@@ -16,7 +28,9 @@ class LibraryCategoryAdapter(view: LibraryCategoryView) :
*/
private var mangas: List<LibraryItem> = emptyList()
var asyncSearchText: String? = null
// --> EH
private val searchEngine = SearchEngine()
// <-- EH
/**
* Sets a list of manga in the adapter.
@@ -40,9 +54,42 @@ class LibraryCategoryAdapter(view: LibraryCategoryView) :
}
fun performFilter() {
updateDataSet(mangas.filter {
it.filter(searchText)
})
Observable.fromCallable {
defRealm { realm ->
val parsedQuery = searchEngine.parseQuery(searchText)
val metadata = realm.loadAllMetadata().map {
Pair(it.key, searchEngine.filterResults(it.value, parsedQuery))
}
mangas.filter { manga ->
// --> EH
if (isLewdSource(manga.manga.source)) {
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
}
realm.queryMetadataFromManga(manga.manga, it.second.where()).count() > 0
}
} else {
manga.filter(searchText)
}
// <-- EH
}
}
}.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
updateDataSet(it)
}
}
}

View File

@@ -39,10 +39,12 @@ import eu.kanade.tachiyomi.widget.DrawerSwipeCloseListener
import kotlinx.android.synthetic.main.main_activity.*
import kotlinx.android.synthetic.main.library_controller.view.*
import rx.Subscription
import rx.android.schedulers.AndroidSchedulers
import timber.log.Timber
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.io.IOException
import java.util.concurrent.TimeUnit
class LibraryController(
@@ -342,7 +344,11 @@ class LibraryController(
// Mutate the filter icon because it needs to be tinted and the resource is shared.
menu.findItem(R.id.action_filter).icon.mutate()
searchView.queryTextChanges().subscribeUntilDestroy {
// Debounce search (EH)
searchView.queryTextChanges()
.debounce(200, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribeUntilDestroy {
query = it.toString()
searchRelay.call(query)
}

View File

@@ -12,18 +12,10 @@ 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.isLewdSource
import exh.metadata.MetadataHelper
import exh.search.SearchEngine
import kotlinx.android.synthetic.main.catalogue_grid_item.view.*
class LibraryItem(val manga: Manga) : AbstractFlexibleItem<LibraryHolder>(), IFilterable {
// --> EH
private val searchEngine = SearchEngine()
private val metadataHelper = MetadataHelper()
// <-- EH
override fun getLayoutRes(): Int {
return R.layout.catalogue_grid_item
}
@@ -61,15 +53,6 @@ class LibraryItem(val manga: Manga) : AbstractFlexibleItem<LibraryHolder>(), IFi
* @return true if the manga should be included, false otherwise.
*/
override fun filter(constraint: String): Boolean {
// --> EH
if(!isLewdSource(manga.source)) {
//Use gallery search engine for EH manga
metadataHelper.fetchMetadata(manga.url, manga.source)?.let {
return searchEngine.matches(it, searchEngine.parseQuery(constraint))
}
}
// <-- EH
return manga.title.contains(constraint, true) ||
(manga.author?.contains(constraint, true) ?: false)
}

View File

@@ -17,6 +17,7 @@ import com.bluelinelabs.conductor.changehandler.FadeChangeHandler
import eu.kanade.tachiyomi.Migrations
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
import eu.kanade.tachiyomi.ui.base.controller.DialogController
import eu.kanade.tachiyomi.ui.base.controller.NoToolbarElevationController
@@ -35,6 +36,7 @@ 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 kotlinx.android.synthetic.main.main_activity.*
import uy.kohesive.injekt.injectLazy
@@ -165,6 +167,10 @@ class MainActivity : BaseActivity() {
if (Migrations.upgrade(preferences)) {
ChangelogDialogController().showDialog(router)
}
// Migrate metadata to Realm (EH)
if(!preferences.migrateLibraryAsked2().getOrDefault())
MetadataFetchDialog().askMigration(this)
}
}