Optimize imports, disallow wildcard imports because of klint, run linter
This commit is contained in:
parent
f18891a07e
commit
23ac3d18e5
@ -43,7 +43,6 @@ class CategoryPutResolver : DefaultPutResolver<Category>() {
|
||||
put(COL_FLAGS, obj.flags)
|
||||
val orderString = obj.mangaOrder.joinToString("/")
|
||||
put(COL_MANGA_ORDER, orderString)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,4 @@ class MangaUrlPutResolver : PutResolver<Manga>() {
|
||||
fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
|
||||
put(MangaTable.COL_URL, manga.url)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,6 @@ object CategoryTable {
|
||||
$COL_MANGA_ORDER TEXT NOT NULL
|
||||
)"""
|
||||
|
||||
|
||||
val addMangaOrder: String
|
||||
get() = "ALTER TABLE $TABLE ADD COLUMN $COL_MANGA_ORDER TEXT"
|
||||
}
|
||||
|
@ -9,11 +9,11 @@ import eu.kanade.tachiyomi.source.model.SManga
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||
import exh.metadata.metadata.base.getFlatMetadataForManga
|
||||
import exh.metadata.metadata.base.insertFlatMetadata
|
||||
import kotlin.reflect.KClass
|
||||
import rx.Completable
|
||||
import rx.Single
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* LEWD!
|
||||
|
@ -3,7 +3,12 @@ package eu.kanade.tachiyomi.source.online.all
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import com.elvishew.xlog.XLog
|
||||
import com.github.salomonbrys.kotson.*
|
||||
import com.github.salomonbrys.kotson.array
|
||||
import com.github.salomonbrys.kotson.get
|
||||
import com.github.salomonbrys.kotson.int
|
||||
import com.github.salomonbrys.kotson.obj
|
||||
import com.github.salomonbrys.kotson.set
|
||||
import com.github.salomonbrys.kotson.string
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParser
|
||||
@ -13,7 +18,12 @@ import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.network.asObservableWithAsyncStacktrace
|
||||
import eu.kanade.tachiyomi.source.model.*
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.source.online.LewdSource
|
||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||
@ -36,23 +46,30 @@ import exh.util.UriFilter
|
||||
import exh.util.UriGroup
|
||||
import exh.util.ignore
|
||||
import exh.util.urlImportFetchSearchManga
|
||||
import java.net.URLEncoder
|
||||
import java.util.ArrayList
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import okhttp3.*
|
||||
import okhttp3.CacheControl
|
||||
import okhttp3.CookieJar
|
||||
import okhttp3.Headers
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.Request
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import org.jsoup.nodes.TextNode
|
||||
import rx.Observable
|
||||
import rx.Single
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.net.URLEncoder
|
||||
import java.util.*
|
||||
|
||||
// TODO Consider gallery updating when doing tabbed browsing
|
||||
class EHentai(override val id: Long,
|
||||
class EHentai(
|
||||
override val id: Long,
|
||||
val exh: Boolean,
|
||||
val context: Context) : HttpSource(), LewdSource<EHentaiSearchMetadata, Document>, UrlImportableSource {
|
||||
val context: Context
|
||||
) : HttpSource(), LewdSource<EHentaiSearchMetadata, Document>, UrlImportableSource {
|
||||
override val metaClass = EHentaiSearchMetadata::class
|
||||
|
||||
val schema: String
|
||||
@ -111,8 +128,8 @@ class EHentai(override val id: Long,
|
||||
val parsedLocation = doc.location().toHttpUrlOrNull()
|
||||
|
||||
// Add to page if required
|
||||
val hasNextPage = if (parsedLocation == null
|
||||
|| !parsedLocation.queryParameterNames.contains(REVERSE_PARAM)) {
|
||||
val hasNextPage = if (parsedLocation == null ||
|
||||
!parsedLocation.queryParameterNames.contains(REVERSE_PARAM)) {
|
||||
select("a[onclick=return false]").last()?.let {
|
||||
it.text() == ">"
|
||||
} ?: false
|
||||
@ -212,8 +229,11 @@ class EHentai(override val id: Long,
|
||||
}
|
||||
}!!
|
||||
|
||||
private fun fetchChapterPage(chapter: SChapter, np: String,
|
||||
pastUrls: List<String> = emptyList()): Observable<List<String>> {
|
||||
private fun fetchChapterPage(
|
||||
chapter: SChapter,
|
||||
np: String,
|
||||
pastUrls: List<String> = emptyList()
|
||||
): Observable<List<String>> {
|
||||
val urls = ArrayList(pastUrls)
|
||||
return chapterPageCall(np).flatMap {
|
||||
val jsoup = it.asJsoup()
|
||||
@ -407,8 +427,8 @@ class EHentai(override val id: Long,
|
||||
}
|
||||
|
||||
lastUpdateCheck = System.currentTimeMillis()
|
||||
if (datePosted != null
|
||||
&& lastUpdateCheck - datePosted!! > EHentaiUpdateWorkerConstants.GALLERY_AGE_TIME) {
|
||||
if (datePosted != null &&
|
||||
lastUpdateCheck - datePosted!! > EHentaiUpdateWorkerConstants.GALLERY_AGE_TIME) {
|
||||
aged = true
|
||||
XLog.d("aged %s - too old", title)
|
||||
}
|
||||
@ -713,7 +733,6 @@ class EHentai(override val id: Long,
|
||||
return "${uri.scheme}://${uri.host}/g/${obj["gid"].int}/${obj["token"].string}/"
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
private const val QUERY_PREFIX = "?f_apply=Apply+Filter"
|
||||
private const val TR_SUFFIX = "TR"
|
||||
@ -738,6 +757,5 @@ class EHentai(override val id: Long,
|
||||
fun buildCookies(cookies: Map<String, String>) = cookies.entries.joinToString(separator = "; ") {
|
||||
"${URLEncoder.encode(it.key, "UTF-8")}=${URLEncoder.encode(it.value, "UTF-8")}"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,11 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.source.model.*
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.source.online.LewdSource
|
||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||
@ -24,6 +28,8 @@ import exh.metadata.metadata.HitomiSearchMetadata.Companion.TAG_TYPE_DEFAULT
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.TAG_TYPE_VIRTUAL
|
||||
import exh.metadata.metadata.base.RaisedTag
|
||||
import exh.util.urlImportFetchSearchManga
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
@ -32,8 +38,6 @@ import rx.Observable
|
||||
import rx.Single
|
||||
import rx.schedulers.Schedulers
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Man, I hate this source :(
|
||||
@ -61,8 +65,8 @@ class Hitomi : HttpSource(), LewdSource<HitomiSearchMetadata, Document>, UrlImpo
|
||||
private var tagIndexVersionCacheTime: Long = 0
|
||||
private fun tagIndexVersion(): Single<Long> {
|
||||
val sCachedTagIndexVersion = cachedTagIndexVersion
|
||||
return if (sCachedTagIndexVersion == null
|
||||
|| tagIndexVersionCacheTime + INDEX_VERSION_CACHE_TIME_MS < System.currentTimeMillis()) {
|
||||
return if (sCachedTagIndexVersion == null ||
|
||||
tagIndexVersionCacheTime + INDEX_VERSION_CACHE_TIME_MS < System.currentTimeMillis()) {
|
||||
HitomiNozomi.getIndexVersion(client, "tagindex").subscribeOn(Schedulers.io()).doOnNext {
|
||||
cachedTagIndexVersion = it
|
||||
tagIndexVersionCacheTime = System.currentTimeMillis()
|
||||
@ -76,8 +80,8 @@ class Hitomi : HttpSource(), LewdSource<HitomiSearchMetadata, Document>, UrlImpo
|
||||
private var galleryIndexVersionCacheTime: Long = 0
|
||||
private fun galleryIndexVersion(): Single<Long> {
|
||||
val sCachedGalleryIndexVersion = cachedGalleryIndexVersion
|
||||
return if (sCachedGalleryIndexVersion == null
|
||||
|| galleryIndexVersionCacheTime + INDEX_VERSION_CACHE_TIME_MS < System.currentTimeMillis()) {
|
||||
return if (sCachedGalleryIndexVersion == null ||
|
||||
galleryIndexVersionCacheTime + INDEX_VERSION_CACHE_TIME_MS < System.currentTimeMillis()) {
|
||||
HitomiNozomi.getIndexVersion(client, "galleriesindex").subscribeOn(Schedulers.io()).doOnNext {
|
||||
cachedGalleryIndexVersion = it
|
||||
galleryIndexVersionCacheTime = System.currentTimeMillis()
|
||||
@ -307,7 +311,6 @@ class Hitomi : HttpSource(), LewdSource<HitomiSearchMetadata, Document>, UrlImpo
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns an observable with the updated details for a manga. Normally it's not needed to
|
||||
* override this method.
|
||||
@ -423,5 +426,4 @@ class Hitomi : HttpSource(), LewdSource<HitomiSearchMetadata, Document>, UrlImpo
|
||||
SimpleDateFormat("yyyy-MM-dd HH:mm:ss'-05'", Locale.US)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,13 +2,22 @@ package eu.kanade.tachiyomi.source.online.all
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import com.github.salomonbrys.kotson.*
|
||||
import com.github.salomonbrys.kotson.get
|
||||
import com.github.salomonbrys.kotson.nullArray
|
||||
import com.github.salomonbrys.kotson.nullLong
|
||||
import com.github.salomonbrys.kotson.nullObj
|
||||
import com.github.salomonbrys.kotson.nullString
|
||||
import com.google.gson.JsonParser
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.source.model.*
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.source.online.LewdSource
|
||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||
@ -305,7 +314,6 @@ class NHentai(context: Context) : HttpSource(), LewdSource<NHentaiSearchMetadata
|
||||
Pair("Chinese", " chinese")
|
||||
)
|
||||
|
||||
|
||||
val jsonParser by lazy {
|
||||
JsonParser()
|
||||
}
|
||||
|
@ -3,7 +3,12 @@ package eu.kanade.tachiyomi.source.online.all
|
||||
import android.net.Uri
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.source.model.*
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.LewdSource
|
||||
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||
@ -17,14 +22,15 @@ import exh.metadata.metadata.base.RaisedTag
|
||||
import exh.util.UriFilter
|
||||
import exh.util.UriGroup
|
||||
import exh.util.urlImportFetchSearchManga
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import java.util.TimeZone
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import org.jsoup.nodes.TextNode
|
||||
import rx.Observable
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
// TODO Transform into delegated source
|
||||
class PervEden(override val id: Long, val pvLang: PervEdenLang) : ParsedHttpSource(),
|
||||
|
@ -2,10 +2,14 @@ package eu.kanade.tachiyomi.source.online.english
|
||||
|
||||
import android.net.Uri
|
||||
import com.kizitonwose.time.hours
|
||||
import hu.akarnokd.rxjava.interop.RxJavaInterop
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.source.model.*
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.source.online.LewdSource
|
||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||
@ -17,13 +21,18 @@ import exh.util.CachedField
|
||||
import exh.util.NakedTrie
|
||||
import exh.util.await
|
||||
import exh.util.urlImportFetchSearchManga
|
||||
import hu.akarnokd.rxjava.interop.RxJavaInterop
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.rx2.asSingle
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.*
|
||||
import okhttp3.Headers
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
|
@ -4,12 +4,16 @@ import android.net.Uri
|
||||
import com.github.salomonbrys.kotson.array
|
||||
import com.github.salomonbrys.kotson.string
|
||||
import com.google.gson.JsonParser
|
||||
import hu.akarnokd.rxjava.interop.RxJavaInterop
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.network.asObservable
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.source.model.*
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.source.online.LewdSource
|
||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||
@ -23,7 +27,9 @@ import exh.search.Text
|
||||
import exh.util.await
|
||||
import exh.util.dropBlank
|
||||
import exh.util.urlImportFetchSearchManga
|
||||
import hu.akarnokd.rxjava.interop.RxJavaInterop
|
||||
import info.debatty.java.stringsimilarity.Levenshtein
|
||||
import kotlin.math.ceil
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.async
|
||||
@ -36,7 +42,6 @@ import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import rx.Observable
|
||||
import rx.schedulers.Schedulers
|
||||
import kotlin.math.ceil
|
||||
|
||||
class HBrowse : HttpSource(), LewdSource<HBrowseSearchMetadata, Document>, UrlImportableSource {
|
||||
/**
|
||||
@ -182,7 +187,6 @@ class HBrowse : HttpSource(), LewdSource<HBrowseSearchMetadata, Document>, UrlIm
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
"/result"
|
||||
} else {
|
||||
"/search"
|
||||
|
@ -4,29 +4,25 @@ import android.net.Uri
|
||||
import com.google.gson.JsonParser
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.source.online.LewdSource
|
||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||
import eu.kanade.tachiyomi.util.system.asJsoup
|
||||
import exh.metadata.metadata.TsuminoSearchMetadata
|
||||
import exh.metadata.metadata.TsuminoSearchMetadata.Companion.BASE_URL
|
||||
import exh.metadata.metadata.TsuminoSearchMetadata.Companion.TAG_TYPE_DEFAULT
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.TAG_TYPE_VIRTUAL
|
||||
import exh.metadata.metadata.base.RaisedTag
|
||||
import exh.source.DelegatedHttpSource
|
||||
import exh.util.dropBlank
|
||||
import exh.util.trimAll
|
||||
import exh.util.urlImportFetchSearchManga
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import org.jsoup.nodes.Document
|
||||
import rx.Observable
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
class Tsumino(delegate: HttpSource) : DelegatedHttpSource(delegate),
|
||||
LewdSource<TsuminoSearchMetadata, Document>, UrlImportableSource {
|
||||
override val metaClass = TsuminoSearchMetadata::class;
|
||||
override val metaClass = TsuminoSearchMetadata::class
|
||||
override val lang = "en"
|
||||
|
||||
// Support direct URL importing
|
||||
|
@ -1,7 +1,6 @@
|
||||
package eu.kanade.tachiyomi.ui.browse.source.filter
|
||||
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractExpandableHeaderItem
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
|
@ -5,21 +5,24 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable
|
||||
import eu.kanade.tachiyomi.ui.category.CategoryAdapter
|
||||
import exh.isLewdSource
|
||||
import exh.metadata.sql.tables.SearchMetadataTable
|
||||
import exh.search.SearchEngine
|
||||
import exh.util.await
|
||||
import exh.util.cancellable
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.ensureActive
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import eu.davidea.flexibleadapter.SelectableAdapter
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.kanade.tachiyomi.ui.category.CategoryAdapter
|
||||
|
||||
/**
|
||||
* Adapter storing a list of manga in a certain category.
|
||||
|
@ -1,8 +1,8 @@
|
||||
package eu.kanade.tachiyomi.ui.library
|
||||
|
||||
import android.view.View
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
|
||||
|
||||
@ -26,7 +26,6 @@ abstract class LibraryHolder(
|
||||
*/
|
||||
abstract fun onSetValues(item: LibraryItem)
|
||||
|
||||
|
||||
/**
|
||||
* Called when an item is released.
|
||||
*
|
||||
@ -36,5 +35,4 @@ abstract class LibraryHolder(
|
||||
super.onItemReleased(position)
|
||||
(adapter as? LibraryCategoryAdapter)?.onItemReleaseListener?.onItemReleased(position)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -235,4 +235,3 @@ class MangaInfoPresenter(
|
||||
return toInsert
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,17 @@ import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.util.preference.*
|
||||
import eu.kanade.tachiyomi.util.preference.defaultValue
|
||||
import eu.kanade.tachiyomi.util.preference.entriesRes
|
||||
import eu.kanade.tachiyomi.util.preference.intListPreference
|
||||
import eu.kanade.tachiyomi.util.preference.listPreference
|
||||
import eu.kanade.tachiyomi.util.preference.multiSelectListPreference
|
||||
import eu.kanade.tachiyomi.util.preference.onChange
|
||||
import eu.kanade.tachiyomi.util.preference.onClick
|
||||
import eu.kanade.tachiyomi.util.preference.preference
|
||||
import eu.kanade.tachiyomi.util.preference.preferenceCategory
|
||||
import eu.kanade.tachiyomi.util.preference.summaryRes
|
||||
import eu.kanade.tachiyomi.util.preference.switchPreference
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import exh.EH_SOURCE_ID
|
||||
import exh.EXH_SOURCE_ID
|
||||
@ -34,6 +44,7 @@ import exh.ui.login.LoginController
|
||||
import exh.util.await
|
||||
import exh.util.trans
|
||||
import humanize.Humanize
|
||||
import java.util.Date
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
@ -41,7 +52,6 @@ import kotlinx.coroutines.withContext
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.schedulers.Schedulers
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* EH Settings fragment
|
||||
|
@ -53,7 +53,7 @@ private val lewdDelegatedSourceIds = SourceManager.DELEGATED_SOURCES.filter {
|
||||
}.map { it.value.sourceId }.sorted()
|
||||
|
||||
// This method MUST be fast!
|
||||
fun isLewdSource(source: Long) = source in 6900..6999
|
||||
|| lewdDelegatedSourceIds.binarySearch(source) >= 0
|
||||
fun isLewdSource(source: Long) = source in 6900..6999 ||
|
||||
lewdDelegatedSourceIds.binarySearch(source) >= 0
|
||||
|
||||
fun Source.isEhBasedSource() = id == EH_SOURCE_ID || id == EXH_SOURCE_ID
|
||||
|
@ -2,6 +2,8 @@ package exh
|
||||
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
|
||||
data class EXHSavedSearch(val name: String,
|
||||
data class EXHSavedSearch(
|
||||
val name: String,
|
||||
val query: String,
|
||||
val filterList: FilterList)
|
||||
val filterList: FilterList
|
||||
)
|
||||
|
@ -16,10 +16,12 @@ class GalleryAdder {
|
||||
|
||||
private val sourceManager: SourceManager by injectLazy()
|
||||
|
||||
fun addGallery(url: String,
|
||||
fun addGallery(
|
||||
url: String,
|
||||
fav: Boolean = false,
|
||||
forceSource: UrlImportableSource? = null,
|
||||
throttleFunc: () -> Unit = {}): GalleryAddEvent {
|
||||
throttleFunc: () -> Unit = {}
|
||||
): GalleryAddEvent {
|
||||
XLog.d("Importing gallery (url: %s, fav: %s, forceSource: %s)...", url, fav, forceSource)
|
||||
try {
|
||||
val uri = Uri.parse(url)
|
||||
@ -120,8 +122,10 @@ sealed class GalleryAddEvent {
|
||||
abstract val galleryUrl: String
|
||||
open val galleryTitle: String? = null
|
||||
|
||||
class Success(override val galleryUrl: String,
|
||||
val manga: Manga): GalleryAddEvent() {
|
||||
class Success(
|
||||
override val galleryUrl: String,
|
||||
val manga: Manga
|
||||
) : GalleryAddEvent() {
|
||||
override val galleryTitle = manga.title
|
||||
override val logMessage = "Added gallery: $galleryTitle"
|
||||
}
|
||||
@ -131,8 +135,10 @@ sealed class GalleryAddEvent {
|
||||
override val logMessage = "Unknown gallery type for gallery: $galleryUrl"
|
||||
}
|
||||
|
||||
open class Error(override val galleryUrl: String,
|
||||
override val logMessage: String): Fail()
|
||||
open class Error(
|
||||
override val galleryUrl: String,
|
||||
override val logMessage: String
|
||||
) : Fail()
|
||||
|
||||
class NotFound(galleryUrl: String) :
|
||||
Error(galleryUrl, "Gallery does not exist: $galleryUrl")
|
||||
|
@ -9,20 +9,19 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.util.system.jobScheduler
|
||||
import exh.EH_SOURCE_ID
|
||||
import exh.EXH_SOURCE_ID
|
||||
import exh.EXHMigrations
|
||||
import exh.EXH_SOURCE_ID
|
||||
import exh.eh.EHentaiUpdateWorker
|
||||
import exh.metadata.metadata.EHentaiSearchMetadata
|
||||
import exh.metadata.metadata.base.getFlatMetadataForManga
|
||||
import exh.metadata.metadata.base.insertFlatMetadata
|
||||
import exh.util.await
|
||||
import exh.util.cancellable
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.flow.mapNotNull
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
object DebugFunctions {
|
||||
val app: Application by injectLazy()
|
||||
|
@ -8,8 +8,12 @@ import android.widget.HorizontalScrollView
|
||||
import android.widget.TextView
|
||||
import androidx.preference.PreferenceScreen
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import eu.kanade.tachiyomi.ui.setting.*
|
||||
import eu.kanade.tachiyomi.util.preference.*
|
||||
import eu.kanade.tachiyomi.ui.setting.SettingsController
|
||||
import eu.kanade.tachiyomi.util.preference.defaultValue
|
||||
import eu.kanade.tachiyomi.util.preference.onClick
|
||||
import eu.kanade.tachiyomi.util.preference.preference
|
||||
import eu.kanade.tachiyomi.util.preference.preferenceCategory
|
||||
import eu.kanade.tachiyomi.util.preference.switchPreference
|
||||
import kotlin.reflect.KVisibility
|
||||
import kotlin.reflect.full.declaredFunctions
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
package exh.eh
|
||||
|
||||
class EHentaiThrottleManager(private val max: Int = THROTTLE_MAX,
|
||||
private val inc: Int = THROTTLE_INC) {
|
||||
class EHentaiThrottleManager(
|
||||
private val max: Int = THROTTLE_MAX,
|
||||
private val inc: Int = THROTTLE_INC
|
||||
) {
|
||||
private var lastThrottleTime: Long = 0
|
||||
var throttleTime: Long = 0
|
||||
private set
|
||||
|
@ -8,10 +8,10 @@ import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
||||
import exh.metadata.metadata.EHentaiSearchMetadata
|
||||
import exh.metadata.metadata.base.getFlatMetadataForManga
|
||||
import java.io.File
|
||||
import rx.Observable
|
||||
import rx.Single
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.File
|
||||
|
||||
data class ChapterChain(val manga: Manga, val chapters: List<Chapter>)
|
||||
|
||||
@ -75,9 +75,9 @@ class EHentaiUpdateHelper(context: Context) {
|
||||
|
||||
chain.chapters.map { chapter ->
|
||||
// Convert old style chapters to new style chapters if possible
|
||||
if(chapter.date_upload <= 0
|
||||
&& meta?.datePosted != null
|
||||
&& meta?.title != null) {
|
||||
if (chapter.date_upload <= 0 &&
|
||||
meta?.datePosted != null &&
|
||||
meta?.title != null) {
|
||||
chapter.name = meta!!.title!!
|
||||
chapter.date_upload = meta!!.datePosted!!
|
||||
}
|
||||
|
@ -20,8 +20,8 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.online.all.EHentai
|
||||
import eu.kanade.tachiyomi.util.system.jobScheduler
|
||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
||||
import eu.kanade.tachiyomi.util.system.jobScheduler
|
||||
import exh.EH_SOURCE_ID
|
||||
import exh.EXH_SOURCE_ID
|
||||
import exh.debug.DebugToggles
|
||||
@ -31,15 +31,20 @@ import exh.metadata.metadata.base.getFlatMetadataForManga
|
||||
import exh.metadata.metadata.base.insertFlatMetadata
|
||||
import exh.util.await
|
||||
import exh.util.cancellable
|
||||
import kotlinx.coroutines.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.cancelAndJoin
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.flow.mapNotNull
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import rx.schedulers.Schedulers
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
class EHentaiUpdateWorker : JobService(), CoroutineScope {
|
||||
@ -215,8 +220,8 @@ class EHentaiUpdateWorker: JobService(), CoroutineScope {
|
||||
val (acceptedRoot, discardedRoots, hasNew) =
|
||||
updateHelper.findAcceptedRootAndDiscardOthers(manga.source, chapters).await()
|
||||
|
||||
if((new.isNotEmpty() && manga.id == acceptedRoot.manga.id)
|
||||
|| (hasNew && updatedManga.none { it.id == acceptedRoot.manga.id })) {
|
||||
if ((new.isNotEmpty() && manga.id == acceptedRoot.manga.id) ||
|
||||
(hasNew && updatedManga.none { it.id == acceptedRoot.manga.id })) {
|
||||
updatedManga += acceptedRoot.manga
|
||||
}
|
||||
|
||||
@ -290,9 +295,11 @@ class EHentaiUpdateWorker: JobService(), CoroutineScope {
|
||||
else JOB_ID_UPDATE_BACKGROUND, componentName())
|
||||
}
|
||||
|
||||
private fun Context.periodicBackgroundJobInfo(period: Long,
|
||||
private fun Context.periodicBackgroundJobInfo(
|
||||
period: Long,
|
||||
requireCharging: Boolean,
|
||||
requireUnmetered: Boolean): JobInfo {
|
||||
requireUnmetered: Boolean
|
||||
): JobInfo {
|
||||
return baseBackgroundJobInfo(false)
|
||||
.setPeriodic(period)
|
||||
.setPersisted(true)
|
||||
|
@ -3,9 +3,6 @@ package exh.eh
|
||||
import android.util.SparseArray
|
||||
import androidx.core.util.AtomicFile
|
||||
import com.elvishew.xlog.XLog
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import java.io.Closeable
|
||||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
@ -13,6 +10,18 @@ import java.io.InputStream
|
||||
import java.nio.ByteBuffer
|
||||
import kotlin.concurrent.thread
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.NonCancellable
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.cancelAndJoin
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
/**
|
||||
* In memory Int -> Obj lookup table implementation that
|
||||
|
@ -5,7 +5,7 @@ import io.realm.RealmObject
|
||||
import io.realm.annotations.Index
|
||||
import io.realm.annotations.PrimaryKey
|
||||
import io.realm.annotations.RealmClass
|
||||
import java.util.*
|
||||
import java.util.UUID
|
||||
|
||||
@RealmClass
|
||||
open class FavoriteEntry : RealmObject() {
|
||||
|
@ -17,18 +17,21 @@ import eu.kanade.tachiyomi.util.lang.launchUI
|
||||
import eu.kanade.tachiyomi.util.system.powerManager
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import eu.kanade.tachiyomi.util.system.wifiManager
|
||||
import exh.*
|
||||
import exh.EH_SOURCE_ID
|
||||
import exh.EXH_SOURCE_ID
|
||||
import exh.GalleryAddEvent
|
||||
import exh.GalleryAdder
|
||||
import exh.eh.EHentaiThrottleManager
|
||||
import exh.eh.EHentaiUpdateWorker
|
||||
import exh.util.ignore
|
||||
import exh.util.trans
|
||||
import kotlin.concurrent.thread
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.Request
|
||||
import rx.subjects.BehaviorSubject
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
class FavoritesSyncHelper(val context: Context) {
|
||||
private val db: DatabaseHelper by injectLazy()
|
||||
@ -385,8 +388,8 @@ class FavoritesSyncHelper(val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
fun needWarnThrottle()
|
||||
= throttleManager.throttleTime >= THROTTLE_WARN
|
||||
fun needWarnThrottle() =
|
||||
throttleManager.throttleTime >= THROTTLE_WARN
|
||||
|
||||
class IgnoredException : RuntimeException()
|
||||
|
||||
@ -399,8 +402,10 @@ sealed class FavoritesSyncStatus(val message: String) {
|
||||
class Error(message: String) : FavoritesSyncStatus(message)
|
||||
class Idle : FavoritesSyncStatus("Waiting for sync to start")
|
||||
sealed class BadLibraryState(message: String) : FavoritesSyncStatus(message) {
|
||||
class MangaInMultipleCategories(val manga: Manga,
|
||||
val categories: List<Category>):
|
||||
class MangaInMultipleCategories(
|
||||
val manga: Manga,
|
||||
val categories: List<Category>
|
||||
) :
|
||||
BadLibraryState("The gallery: ${manga.title} is in more than one category (${categories.joinToString { it.name }})!")
|
||||
}
|
||||
class Initializing : FavoritesSyncStatus("Initializing sync")
|
||||
|
@ -20,8 +20,8 @@ class LocalFavoritesStorage {
|
||||
|
||||
fun getRealm() = Realm.getInstance(realmConfig)
|
||||
|
||||
fun getChangedDbEntries(realm: Realm)
|
||||
= getChangedEntries(realm,
|
||||
fun getChangedDbEntries(realm: Realm) =
|
||||
getChangedEntries(realm,
|
||||
parseToFavoriteEntries(
|
||||
loadDbCategories(
|
||||
db.getFavoriteMangas()
|
||||
@ -31,8 +31,8 @@ class LocalFavoritesStorage {
|
||||
)
|
||||
)
|
||||
|
||||
fun getChangedRemoteEntries(realm: Realm, entries: List<EHentai.ParsedManga>)
|
||||
= getChangedEntries(realm,
|
||||
fun getChangedRemoteEntries(realm: Realm, entries: List<EHentai.ParsedManga>) =
|
||||
getChangedEntries(realm,
|
||||
parseToFavoriteEntries(
|
||||
entries.asSequence().map {
|
||||
Pair(it.fav, it.manga.apply {
|
||||
@ -80,18 +80,18 @@ class LocalFavoritesStorage {
|
||||
return ChangeSet(added, removed)
|
||||
}
|
||||
|
||||
private fun Realm.queryRealmForEntry(entry: FavoriteEntry)
|
||||
= where(FavoriteEntry::class.java)
|
||||
private fun Realm.queryRealmForEntry(entry: FavoriteEntry) =
|
||||
where(FavoriteEntry::class.java)
|
||||
.equalTo(FavoriteEntry::gid.name, entry.gid)
|
||||
.equalTo(FavoriteEntry::token.name, entry.token)
|
||||
.equalTo(FavoriteEntry::category.name, entry.category)
|
||||
.findFirst()
|
||||
|
||||
private fun queryListForEntry(list: List<FavoriteEntry>, entry: FavoriteEntry)
|
||||
= list.find {
|
||||
it.gid == entry.gid
|
||||
&& it.token == entry.token
|
||||
&& it.category == entry.category
|
||||
private fun queryListForEntry(list: List<FavoriteEntry>, entry: FavoriteEntry) =
|
||||
list.find {
|
||||
it.gid == entry.gid &&
|
||||
it.token == entry.token &&
|
||||
it.category == entry.category
|
||||
}
|
||||
|
||||
private fun loadDbCategories(manga: Sequence<Manga>): Sequence<Pair<Int, Manga>> {
|
||||
@ -105,8 +105,8 @@ class LocalFavoritesStorage {
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseToFavoriteEntries(manga: Sequence<Pair<Int, Manga>>)
|
||||
= manga.filter {
|
||||
private fun parseToFavoriteEntries(manga: Sequence<Pair<Int, Manga>>) =
|
||||
manga.filter {
|
||||
validateDbManga(it.second)
|
||||
}.mapNotNull {
|
||||
FavoriteEntry().apply {
|
||||
@ -120,13 +120,15 @@ class LocalFavoritesStorage {
|
||||
}
|
||||
}
|
||||
|
||||
private fun validateDbManga(manga: Manga)
|
||||
= manga.favorite && (manga.source == EH_SOURCE_ID || manga.source == EXH_SOURCE_ID)
|
||||
private fun validateDbManga(manga: Manga) =
|
||||
manga.favorite && (manga.source == EH_SOURCE_ID || manga.source == EXH_SOURCE_ID)
|
||||
|
||||
companion object {
|
||||
const val MAX_CATEGORIES = 9
|
||||
}
|
||||
}
|
||||
|
||||
data class ChangeSet(val added: List<FavoriteEntry>,
|
||||
val removed: List<FavoriteEntry>)
|
||||
data class ChangeSet(
|
||||
val added: List<FavoriteEntry>,
|
||||
val removed: List<FavoriteEntry>
|
||||
)
|
||||
|
@ -4,28 +4,32 @@ import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.asObservable
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import exh.metadata.metadata.HitomiSearchMetadata.Companion.LTN_BASE_URL
|
||||
import java.security.MessageDigest
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import org.vepta.vdm.ByteCursor
|
||||
import rx.Observable
|
||||
import rx.Single
|
||||
import java.security.MessageDigest
|
||||
|
||||
private typealias HashedTerm = ByteArray
|
||||
|
||||
private data class DataPair(val offset: Long, val length: Int)
|
||||
private data class Node(val keys: List<ByteArray>,
|
||||
private data class Node(
|
||||
val keys: List<ByteArray>,
|
||||
val datas: List<DataPair>,
|
||||
val subnodeAddresses: List<Long>)
|
||||
val subnodeAddresses: List<Long>
|
||||
)
|
||||
|
||||
/**
|
||||
* Kotlin port of the hitomi.la search algorithm
|
||||
* @author NerdNumber9
|
||||
*/
|
||||
class HitomiNozomi(private val client: OkHttpClient,
|
||||
class HitomiNozomi(
|
||||
private val client: OkHttpClient,
|
||||
private val tagIndexVersion: Long,
|
||||
private val galleriesIndexVersion: Long) {
|
||||
private val galleriesIndexVersion: Long
|
||||
) {
|
||||
fun getGalleryIdsForQuery(query: String): Single<List<Int>> {
|
||||
val replacedQuery = query.replace('_', ' ')
|
||||
|
||||
@ -90,9 +94,9 @@ class HitomiNozomi(private val client: OkHttpClient,
|
||||
|
||||
val expectedLength = numberOfGalleryIds * 4 + 4
|
||||
|
||||
if(numberOfGalleryIds > 10000000
|
||||
|| numberOfGalleryIds <= 0
|
||||
|| inbuf.size != expectedLength) {
|
||||
if (numberOfGalleryIds > 10000000 ||
|
||||
numberOfGalleryIds <= 0 ||
|
||||
inbuf.size != expectedLength) {
|
||||
return@map emptyList<Int>()
|
||||
}
|
||||
|
||||
@ -234,7 +238,6 @@ class HitomiNozomi(private val client: OkHttpClient,
|
||||
.build())
|
||||
}
|
||||
|
||||
|
||||
fun getIndexVersion(httpClient: OkHttpClient, name: String): Observable<Long> {
|
||||
return httpClient.newCall(GET("$LTN_BASE_URL/$name/version?_=${System.currentTimeMillis()}"))
|
||||
.asObservableSuccess()
|
||||
|
@ -4,11 +4,11 @@ import android.content.Context
|
||||
import android.text.Html
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import com.ms_square.debugoverlay.DataObserver
|
||||
import com.ms_square.debugoverlay.OverlayModule
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
|
@ -1,7 +1,7 @@
|
||||
package exh.metadata
|
||||
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* Metadata utils
|
||||
@ -35,7 +35,6 @@ fun parseHumanReadableByteCount(arg0: String): Double? {
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
fun String?.nullIfBlank(): String? = if (isNullOrBlank())
|
||||
null
|
||||
else
|
||||
|
@ -4,12 +4,14 @@ import android.net.Uri
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import exh.metadata.*
|
||||
import exh.metadata.EX_DATE_FORMAT
|
||||
import exh.metadata.ONGOING_SUFFIX
|
||||
import exh.metadata.humanReadableByteCount
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||
import exh.plusAssign
|
||||
import java.util.Date
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.*
|
||||
|
||||
class EHentaiSearchMetadata : RaisedSearchMetadata() {
|
||||
var gId: String?
|
||||
@ -114,8 +116,8 @@ class EHentaiSearchMetadata : RaisedSearchMetadata() {
|
||||
const val EH_GENRE_NAMESPACE = "genre"
|
||||
private const val EH_ARTIST_NAMESPACE = "artist"
|
||||
|
||||
private fun splitGalleryUrl(url: String)
|
||||
= url.let {
|
||||
private fun splitGalleryUrl(url: String) =
|
||||
url.let {
|
||||
// Only parse URL if is full URL
|
||||
val pathSegments = if (it.startsWith("http"))
|
||||
Uri.parse(it).pathSegments
|
||||
@ -129,10 +131,10 @@ class EHentaiSearchMetadata : RaisedSearchMetadata() {
|
||||
fun galleryToken(url: String) =
|
||||
splitGalleryUrl(url)[2]
|
||||
|
||||
fun normalizeUrl(url: String)
|
||||
= idAndTokenToUrl(galleryId(url), galleryToken(url))
|
||||
fun normalizeUrl(url: String) =
|
||||
idAndTokenToUrl(galleryId(url), galleryToken(url))
|
||||
|
||||
fun idAndTokenToUrl(id: String, token: String)
|
||||
= "/g/$id/$token/?nw=always"
|
||||
fun idAndTokenToUrl(id: String, token: String) =
|
||||
"/g/$id/$token/?nw=always"
|
||||
}
|
||||
}
|
@ -34,7 +34,6 @@ class EightMusesSearchMetadata : RaisedSearchMetadata() {
|
||||
manga.description = listOf(titleDesc.toString(), tagsDesc.toString())
|
||||
.filter(String::isNotBlank)
|
||||
.joinToString(separator = "\n")
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -49,7 +49,7 @@ class HentaiCafeSearchMetadata : RaisedSearchMetadata() {
|
||||
|
||||
const val BASE_URL = "https://hentai.cafe"
|
||||
|
||||
fun hcIdFromUrl(url: String)
|
||||
= url.split("/").last { it.isNotBlank() }
|
||||
fun hcIdFromUrl(url: String) =
|
||||
url.split("/").last { it.isNotBlank() }
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ import eu.kanade.tachiyomi.source.model.SManga
|
||||
import exh.metadata.EX_DATE_FORMAT
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||
import exh.plusAssign
|
||||
import java.util.*
|
||||
import java.util.Date
|
||||
|
||||
class HitomiSearchMetadata : RaisedSearchMetadata() {
|
||||
var url get() = hlId?.let { urlFromHlId(it) }
|
||||
@ -92,10 +92,10 @@ class HitomiSearchMetadata: RaisedSearchMetadata() {
|
||||
const val LTN_BASE_URL = "https://ltn.hitomi.la"
|
||||
const val BASE_URL = "https://hitomi.la"
|
||||
|
||||
fun hlIdFromUrl(url: String)
|
||||
= url.split('/').last().split('-').last().substringBeforeLast('.')
|
||||
fun hlIdFromUrl(url: String) =
|
||||
url.split('/').last().split('-').last().substringBeforeLast('.')
|
||||
|
||||
fun urlFromHlId(id: String)
|
||||
= "$BASE_URL/galleries/$id.html"
|
||||
fun urlFromHlId(id: String) =
|
||||
"$BASE_URL/galleries/$id.html"
|
||||
}
|
||||
}
|
||||
|
@ -3,12 +3,14 @@ package exh.metadata.metadata
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import exh.metadata.*
|
||||
import exh.metadata.EX_DATE_FORMAT
|
||||
import exh.metadata.ONGOING_SUFFIX
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||
import exh.metadata.nullIfBlank
|
||||
import exh.plusAssign
|
||||
import java.util.Date
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.*
|
||||
|
||||
class NHentaiSearchMetadata : RaisedSearchMetadata() {
|
||||
var url get() = nhId?.let { BASE_URL + nhIdToPath(it) }
|
||||
@ -112,8 +114,8 @@ class NHentaiSearchMetadata : RaisedSearchMetadata() {
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun nhUrlToId(url: String)
|
||||
= url.split("/").last { it.isNotBlank() }.toLong()
|
||||
fun nhUrlToId(url: String) =
|
||||
url.split("/").last { it.isNotBlank() }.toLong()
|
||||
|
||||
fun nhIdToPath(id: Long) = "/g/$id/"
|
||||
}
|
||||
|
@ -80,15 +80,14 @@ class PervEdenSearchMetadata : RaisedSearchMetadata() {
|
||||
.joinToString(separator = "\n")
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
private const val TITLE_TYPE_MAIN = 0
|
||||
private const val TITLE_TYPE_ALT = 1
|
||||
|
||||
const val TAG_TYPE_DEFAULT = 0
|
||||
|
||||
private fun splitGalleryUrl(url: String)
|
||||
= url.let {
|
||||
private fun splitGalleryUrl(url: String) =
|
||||
url.let {
|
||||
Uri.parse(it).pathSegments.filterNot(String::isNullOrBlank)
|
||||
}
|
||||
|
||||
@ -102,8 +101,8 @@ enum class PervEdenLang(val id: Long) {
|
||||
it(PERV_EDEN_IT_SOURCE_ID);
|
||||
|
||||
companion object {
|
||||
fun source(id: Long)
|
||||
= values().find { it.id == id }
|
||||
fun source(id: Long) =
|
||||
values().find { it.id == id }
|
||||
?: throw IllegalArgumentException("Unknown source ID: $id!")
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import eu.kanade.tachiyomi.source.model.SManga
|
||||
import exh.metadata.EX_DATE_FORMAT
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||
import exh.plusAssign
|
||||
import java.util.*
|
||||
import java.util.Date
|
||||
|
||||
class TsuminoSearchMetadata : RaisedSearchMetadata() {
|
||||
var tmId: Int? = null
|
||||
@ -76,8 +76,8 @@ class TsuminoSearchMetadata : RaisedSearchMetadata() {
|
||||
|
||||
val BASE_URL = "https://www.tsumino.com"
|
||||
|
||||
fun tmIdFromUrl(url: String)
|
||||
= Uri.parse(url).lastPathSegment
|
||||
fun tmIdFromUrl(url: String) =
|
||||
Uri.parse(url).lastPathSegment
|
||||
|
||||
fun mangaUrlFromId(id: String) = "/Book/Info/$id"
|
||||
|
||||
|
@ -5,9 +5,9 @@ import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import exh.metadata.sql.models.SearchMetadata
|
||||
import exh.metadata.sql.models.SearchTag
|
||||
import exh.metadata.sql.models.SearchTitle
|
||||
import kotlin.reflect.KClass
|
||||
import rx.Completable
|
||||
import rx.Single
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
data class FlatMetadata(
|
||||
val metadata: SearchMetadata,
|
||||
@ -16,8 +16,8 @@ data class FlatMetadata(
|
||||
) {
|
||||
inline fun <reified T : RaisedSearchMetadata> raise(): T = raise(T::class)
|
||||
|
||||
fun <T : RaisedSearchMetadata> raise(clazz: KClass<T>)
|
||||
= RaisedSearchMetadata.raiseFlattenGson
|
||||
fun <T : RaisedSearchMetadata> raise(clazz: KClass<T>) =
|
||||
RaisedSearchMetadata.raiseFlattenGson
|
||||
.fromJson(metadata.extra, clazz.java).apply {
|
||||
fillBaseFields(this@FlatMetadata)
|
||||
}
|
||||
|
@ -35,12 +35,12 @@ abstract class RaisedSearchMetadata {
|
||||
|
||||
abstract fun copyTo(manga: SManga)
|
||||
|
||||
fun tagsToGenreString()
|
||||
= tags.filter { it.type != TAG_TYPE_VIRTUAL }
|
||||
fun tagsToGenreString() =
|
||||
tags.filter { it.type != TAG_TYPE_VIRTUAL }
|
||||
.joinToString { (if (it.namespace != null) "${it.namespace}: " else "") + it.name }
|
||||
|
||||
fun tagsToDescription()
|
||||
= StringBuilder("Tags:\n").apply {
|
||||
fun tagsToDescription() =
|
||||
StringBuilder("Tags:\n").apply {
|
||||
// BiConsumer only available in Java 8, don't bother calling forEach directly on 'tags'
|
||||
val groupedTags = tags.filter { it.type != TAG_TYPE_VIRTUAL }.groupBy {
|
||||
it.namespace
|
||||
@ -125,8 +125,8 @@ abstract class RaisedSearchMetadata {
|
||||
* @param property the metadata for the property.
|
||||
* @return the property value.
|
||||
*/
|
||||
override fun getValue(thisRef: RaisedSearchMetadata, property: KProperty<*>)
|
||||
= thisRef.getTitleOfType(type)
|
||||
override fun getValue(thisRef: RaisedSearchMetadata, property: KProperty<*>) =
|
||||
thisRef.getTitleOfType(type)
|
||||
|
||||
/**
|
||||
* Sets the value of the property for the given object.
|
||||
@ -134,8 +134,8 @@ abstract class RaisedSearchMetadata {
|
||||
* @param property the metadata for the property.
|
||||
* @param value the value to set.
|
||||
*/
|
||||
override fun setValue(thisRef: RaisedSearchMetadata, property: KProperty<*>, value: String?)
|
||||
= thisRef.replaceTitleOfType(type, value)
|
||||
override fun setValue(thisRef: RaisedSearchMetadata, property: KProperty<*>, value: String?) =
|
||||
thisRef.replaceTitleOfType(type, value)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package exh.metadata.metadata.base
|
||||
|
||||
data class RaisedTag(val namespace: String?,
|
||||
data class RaisedTag(
|
||||
val namespace: String?,
|
||||
val name: String,
|
||||
val type: Int)
|
||||
val type: Int
|
||||
)
|
||||
|
@ -3,7 +3,6 @@ package exh.metadata.sql.queries
|
||||
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
|
||||
import com.pushtorefresh.storio.sqlite.queries.Query
|
||||
import eu.kanade.tachiyomi.data.database.DbProvider
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import exh.metadata.sql.models.SearchMetadata
|
||||
import exh.metadata.sql.tables.SearchMetadataTable
|
||||
|
||||
|
@ -4,8 +4,6 @@ import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
|
||||
import com.pushtorefresh.storio.sqlite.queries.Query
|
||||
import eu.kanade.tachiyomi.data.database.DbProvider
|
||||
import eu.kanade.tachiyomi.data.database.inTransaction
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import exh.metadata.sql.models.SearchMetadata
|
||||
import exh.metadata.sql.models.SearchTitle
|
||||
import exh.metadata.sql.tables.SearchTitleTable
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
package exh.search
|
||||
|
||||
class Namespace(var namespace: String,
|
||||
var tag: Text? = null) : QueryComponent()
|
||||
class Namespace(
|
||||
var namespace: String,
|
||||
var tag: Text? = null
|
||||
) : QueryComponent()
|
||||
|
@ -7,8 +7,10 @@ import exh.metadata.sql.tables.SearchTitleTable
|
||||
class SearchEngine {
|
||||
private val queryCache = mutableMapOf<String, List<QueryComponent>>()
|
||||
|
||||
fun textToSubQueries(namespace: String?,
|
||||
component: Text?): Pair<String, List<String>>? {
|
||||
fun textToSubQueries(
|
||||
namespace: String?,
|
||||
component: Text?
|
||||
): Pair<String, List<String>>? {
|
||||
val maybeLenientComponent = component?.let {
|
||||
if (!it.exact)
|
||||
it.asLenientTagQueries()
|
||||
@ -97,7 +99,6 @@ class SearchEngine {
|
||||
completeParams += pair.second
|
||||
}
|
||||
|
||||
|
||||
exclude.forEach {
|
||||
wheres += """
|
||||
(meta.${SearchMetadataTable.COL_MANGA_ID} NOT IN ${it.first})
|
||||
@ -197,7 +198,6 @@ class SearchEngine {
|
||||
return string.replace("\\", "\\\\")
|
||||
.replace("_", "\\_")
|
||||
.replace("%", "\\%")
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,13 +8,19 @@ import eu.kanade.tachiyomi.source.model.SManga
|
||||
import exh.ui.smartsearch.SmartSearchPresenter
|
||||
import exh.util.await
|
||||
import info.debatty.java.stringsimilarity.NormalizedLevenshtein
|
||||
import kotlinx.coroutines.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.supervisorScope
|
||||
import rx.schedulers.Schedulers
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class SmartSearchEngine(parentContext: CoroutineContext,
|
||||
val extraSearchParams: String? = null): CoroutineScope {
|
||||
class SmartSearchEngine(
|
||||
parentContext: CoroutineContext,
|
||||
val extraSearchParams: String? = null
|
||||
) : CoroutineScope {
|
||||
override val coroutineContext: CoroutineContext = parentContext + Job() + Dispatchers.Default
|
||||
|
||||
private val db: DatabaseHelper by injectLazy()
|
||||
|
@ -1,12 +1,15 @@
|
||||
package exh.source
|
||||
|
||||
import eu.kanade.tachiyomi.source.model.*
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import rx.Observable
|
||||
import java.lang.RuntimeException
|
||||
|
||||
abstract class DelegatedHttpSource(val delegate: HttpSource) : HttpSource() {
|
||||
/**
|
||||
@ -14,16 +17,16 @@ abstract class DelegatedHttpSource(val delegate: HttpSource): HttpSource() {
|
||||
*
|
||||
* @param page the page number to retrieve.
|
||||
*/
|
||||
override fun popularMangaRequest(page: Int)
|
||||
= throw UnsupportedOperationException("Should never be called!")
|
||||
override fun popularMangaRequest(page: Int) =
|
||||
throw UnsupportedOperationException("Should never be called!")
|
||||
|
||||
/**
|
||||
* Parses the response from the site and returns a [MangasPage] object.
|
||||
*
|
||||
* @param response the response from the site.
|
||||
*/
|
||||
override fun popularMangaParse(response: Response)
|
||||
= throw UnsupportedOperationException("Should never be called!")
|
||||
override fun popularMangaParse(response: Response) =
|
||||
throw UnsupportedOperationException("Should never be called!")
|
||||
|
||||
/**
|
||||
* Returns the request for the search manga given the page.
|
||||
@ -32,64 +35,64 @@ abstract class DelegatedHttpSource(val delegate: HttpSource): HttpSource() {
|
||||
* @param query the search query.
|
||||
* @param filters the list of filters to apply.
|
||||
*/
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList)
|
||||
= throw UnsupportedOperationException("Should never be called!")
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList) =
|
||||
throw UnsupportedOperationException("Should never be called!")
|
||||
|
||||
/**
|
||||
* Parses the response from the site and returns a [MangasPage] object.
|
||||
*
|
||||
* @param response the response from the site.
|
||||
*/
|
||||
override fun searchMangaParse(response: Response)
|
||||
= throw UnsupportedOperationException("Should never be called!")
|
||||
override fun searchMangaParse(response: Response) =
|
||||
throw UnsupportedOperationException("Should never be called!")
|
||||
|
||||
/**
|
||||
* Returns the request for latest manga given the page.
|
||||
*
|
||||
* @param page the page number to retrieve.
|
||||
*/
|
||||
override fun latestUpdatesRequest(page: Int)
|
||||
= throw UnsupportedOperationException("Should never be called!")
|
||||
override fun latestUpdatesRequest(page: Int) =
|
||||
throw UnsupportedOperationException("Should never be called!")
|
||||
|
||||
/**
|
||||
* Parses the response from the site and returns a [MangasPage] object.
|
||||
*
|
||||
* @param response the response from the site.
|
||||
*/
|
||||
override fun latestUpdatesParse(response: Response)
|
||||
= throw UnsupportedOperationException("Should never be called!")
|
||||
override fun latestUpdatesParse(response: Response) =
|
||||
throw UnsupportedOperationException("Should never be called!")
|
||||
|
||||
/**
|
||||
* Parses the response from the site and returns the details of a manga.
|
||||
*
|
||||
* @param response the response from the site.
|
||||
*/
|
||||
override fun mangaDetailsParse(response: Response)
|
||||
= throw UnsupportedOperationException("Should never be called!")
|
||||
override fun mangaDetailsParse(response: Response) =
|
||||
throw UnsupportedOperationException("Should never be called!")
|
||||
|
||||
/**
|
||||
* Parses the response from the site and returns a list of chapters.
|
||||
*
|
||||
* @param response the response from the site.
|
||||
*/
|
||||
override fun chapterListParse(response: Response)
|
||||
= throw UnsupportedOperationException("Should never be called!")
|
||||
override fun chapterListParse(response: Response) =
|
||||
throw UnsupportedOperationException("Should never be called!")
|
||||
|
||||
/**
|
||||
* Parses the response from the site and returns a list of pages.
|
||||
*
|
||||
* @param response the response from the site.
|
||||
*/
|
||||
override fun pageListParse(response: Response)
|
||||
= throw UnsupportedOperationException("Should never be called!")
|
||||
override fun pageListParse(response: Response) =
|
||||
throw UnsupportedOperationException("Should never be called!")
|
||||
|
||||
/**
|
||||
* Parses the response from the site and returns the absolute url to the source image.
|
||||
*
|
||||
* @param response the response from the site.
|
||||
*/
|
||||
override fun imageUrlParse(response: Response)
|
||||
= throw UnsupportedOperationException("Should never be called!")
|
||||
override fun imageUrlParse(response: Response) =
|
||||
throw UnsupportedOperationException("Should never be called!")
|
||||
|
||||
/**
|
||||
* Base url of the website without the trailing slash, like: http://mysite.com
|
||||
@ -236,8 +239,8 @@ abstract class DelegatedHttpSource(val delegate: HttpSource): HttpSource() {
|
||||
override fun getFilterList() = delegate.getFilterList()
|
||||
|
||||
private fun ensureDelegateCompatible() {
|
||||
if(versionId != delegate.versionId
|
||||
|| lang != delegate.lang) {
|
||||
if (versionId != delegate.versionId ||
|
||||
lang != delegate.lang) {
|
||||
throw IncompatibleDelegateException("Delegate source is not compatible (versionId: $versionId <=> ${delegate.versionId}, lang: $lang <=> ${delegate.lang})!")
|
||||
}
|
||||
}
|
||||
|
@ -2,13 +2,19 @@ package exh.source
|
||||
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.source.model.*
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import okhttp3.Response
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class EnhancedHttpSource(val originalSource: HttpSource,
|
||||
val enchancedSource: HttpSource): HttpSource() {
|
||||
class EnhancedHttpSource(
|
||||
val originalSource: HttpSource,
|
||||
val enchancedSource: HttpSource
|
||||
) : HttpSource() {
|
||||
private val prefs: PreferencesHelper by injectLazy()
|
||||
|
||||
/**
|
||||
@ -16,16 +22,16 @@ class EnhancedHttpSource(val originalSource: HttpSource,
|
||||
*
|
||||
* @param page the page number to retrieve.
|
||||
*/
|
||||
override fun popularMangaRequest(page: Int)
|
||||
= throw UnsupportedOperationException("Should never be called!")
|
||||
override fun popularMangaRequest(page: Int) =
|
||||
throw UnsupportedOperationException("Should never be called!")
|
||||
|
||||
/**
|
||||
* Parses the response from the site and returns a [MangasPage] object.
|
||||
*
|
||||
* @param response the response from the site.
|
||||
*/
|
||||
override fun popularMangaParse(response: Response)
|
||||
= throw UnsupportedOperationException("Should never be called!")
|
||||
override fun popularMangaParse(response: Response) =
|
||||
throw UnsupportedOperationException("Should never be called!")
|
||||
|
||||
/**
|
||||
* Returns the request for the search manga given the page.
|
||||
@ -34,64 +40,64 @@ class EnhancedHttpSource(val originalSource: HttpSource,
|
||||
* @param query the search query.
|
||||
* @param filters the list of filters to apply.
|
||||
*/
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList)
|
||||
= throw UnsupportedOperationException("Should never be called!")
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList) =
|
||||
throw UnsupportedOperationException("Should never be called!")
|
||||
|
||||
/**
|
||||
* Parses the response from the site and returns a [MangasPage] object.
|
||||
*
|
||||
* @param response the response from the site.
|
||||
*/
|
||||
override fun searchMangaParse(response: Response)
|
||||
= throw UnsupportedOperationException("Should never be called!")
|
||||
override fun searchMangaParse(response: Response) =
|
||||
throw UnsupportedOperationException("Should never be called!")
|
||||
|
||||
/**
|
||||
* Returns the request for latest manga given the page.
|
||||
*
|
||||
* @param page the page number to retrieve.
|
||||
*/
|
||||
override fun latestUpdatesRequest(page: Int)
|
||||
= throw UnsupportedOperationException("Should never be called!")
|
||||
override fun latestUpdatesRequest(page: Int) =
|
||||
throw UnsupportedOperationException("Should never be called!")
|
||||
|
||||
/**
|
||||
* Parses the response from the site and returns a [MangasPage] object.
|
||||
*
|
||||
* @param response the response from the site.
|
||||
*/
|
||||
override fun latestUpdatesParse(response: Response)
|
||||
= throw UnsupportedOperationException("Should never be called!")
|
||||
override fun latestUpdatesParse(response: Response) =
|
||||
throw UnsupportedOperationException("Should never be called!")
|
||||
|
||||
/**
|
||||
* Parses the response from the site and returns the details of a manga.
|
||||
*
|
||||
* @param response the response from the site.
|
||||
*/
|
||||
override fun mangaDetailsParse(response: Response)
|
||||
= throw UnsupportedOperationException("Should never be called!")
|
||||
override fun mangaDetailsParse(response: Response) =
|
||||
throw UnsupportedOperationException("Should never be called!")
|
||||
|
||||
/**
|
||||
* Parses the response from the site and returns a list of chapters.
|
||||
*
|
||||
* @param response the response from the site.
|
||||
*/
|
||||
override fun chapterListParse(response: Response)
|
||||
= throw UnsupportedOperationException("Should never be called!")
|
||||
override fun chapterListParse(response: Response) =
|
||||
throw UnsupportedOperationException("Should never be called!")
|
||||
|
||||
/**
|
||||
* Parses the response from the site and returns a list of pages.
|
||||
*
|
||||
* @param response the response from the site.
|
||||
*/
|
||||
override fun pageListParse(response: Response)
|
||||
= throw UnsupportedOperationException("Should never be called!")
|
||||
override fun pageListParse(response: Response) =
|
||||
throw UnsupportedOperationException("Should never be called!")
|
||||
|
||||
/**
|
||||
* Parses the response from the site and returns the absolute url to the source image.
|
||||
*
|
||||
* @param response the response from the site.
|
||||
*/
|
||||
override fun imageUrlParse(response: Response)
|
||||
= throw UnsupportedOperationException("Should never be called!")
|
||||
override fun imageUrlParse(response: Response) =
|
||||
throw UnsupportedOperationException("Should never be called!")
|
||||
|
||||
/**
|
||||
* Base url of the website without the trailing slash, like: http://mysite.com
|
||||
@ -146,8 +152,8 @@ class EnhancedHttpSource(val originalSource: HttpSource,
|
||||
* @param query the search query.
|
||||
* @param filters the list of filters to apply.
|
||||
*/
|
||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList)
|
||||
= source().fetchSearchManga(page, query, filters)
|
||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList) =
|
||||
source().fetchSearchManga(page, query, filters)
|
||||
|
||||
/**
|
||||
* Returns an observable containing a page with a list of latest manga updates.
|
||||
@ -202,8 +208,8 @@ class EnhancedHttpSource(val originalSource: HttpSource,
|
||||
* @param chapter the chapter to be added.
|
||||
* @param manga the manga of the chapter.
|
||||
*/
|
||||
override fun prepareNewChapter(chapter: SChapter, manga: SManga)
|
||||
= source().prepareNewChapter(chapter, manga)
|
||||
override fun prepareNewChapter(chapter: SChapter, manga: SManga) =
|
||||
source().prepareNewChapter(chapter, manga)
|
||||
|
||||
/**
|
||||
* Returns the list of filters for the source.
|
||||
|
@ -7,8 +7,8 @@ import com.afollestad.materialdialogs.MaterialDialog
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.util.lang.launchUI
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import timber.log.Timber
|
||||
import kotlin.concurrent.thread
|
||||
import timber.log.Timber
|
||||
|
||||
class ConfiguringDialogController : DialogController() {
|
||||
private var materialDialog: MaterialDialog? = null
|
||||
@ -62,4 +62,3 @@ class ConfiguringDialogController : DialogController() {
|
||||
router.popController(this)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,11 +24,13 @@ class EHConfigurator {
|
||||
private fun EHentai.requestWithCreds(sp: Int = 1) = Request.Builder()
|
||||
.addHeader("Cookie", cookiesHeader(sp))
|
||||
|
||||
private fun EHentai.execProfileActions(action: String,
|
||||
private fun EHentai.execProfileActions(
|
||||
action: String,
|
||||
name: String,
|
||||
set: String,
|
||||
sp: Int)
|
||||
= configuratorClient.newCall(requestWithCreds(sp)
|
||||
sp: Int
|
||||
) =
|
||||
configuratorClient.newCall(requestWithCreds(sp)
|
||||
.url(uconfigUrl)
|
||||
.post(FormBody.Builder()
|
||||
.add("profile_action", action)
|
||||
|
@ -9,7 +9,6 @@ class EHHathPerksResponse {
|
||||
var pagingEnlargementII = false
|
||||
var pagingEnlargementIII = false
|
||||
|
||||
override fun toString()
|
||||
= "EHHathPerksResponse(moreThumbs=$moreThumbs, thumbsUp=$thumbsUp, allThumbs=$allThumbs, pagingEnlargementI=$pagingEnlargementI, pagingEnlargementII=$pagingEnlargementII, pagingEnlargementIII=$pagingEnlargementIII)"
|
||||
override fun toString() =
|
||||
"EHHathPerksResponse(moreThumbs=$moreThumbs, thumbsUp=$thumbsUp, allThumbs=$allThumbs, pagingEnlargementI=$pagingEnlargementI, pagingEnlargementII=$pagingEnlargementII, pagingEnlargementIII=$pagingEnlargementIII)"
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
package exh.ui
|
||||
|
||||
import java.util.UUID
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
|
||||
typealias LoadingHandle = String
|
||||
|
||||
|
@ -6,11 +6,11 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.LayoutRes
|
||||
import eu.kanade.tachiyomi.ui.base.controller.BaseController
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
abstract class BaseExhController(bundle: Bundle? = null) : BaseController(bundle), CoroutineScope {
|
||||
abstract val layoutId: Int
|
||||
|
@ -1,6 +1,5 @@
|
||||
package exh.ui.batchadd
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
@ -7,16 +7,18 @@ import android.webkit.WebView
|
||||
import androidx.annotation.RequiresApi
|
||||
import eu.kanade.tachiyomi.util.system.asJsoup
|
||||
import exh.ui.captcha.BrowserActionActivity.Companion.CROSS_WINDOW_SCRIPT_INNER
|
||||
import java.nio.charset.Charset
|
||||
import org.jsoup.nodes.DataNode
|
||||
import org.jsoup.nodes.Element
|
||||
import java.nio.charset.Charset
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
class AutoSolvingWebViewClient(activity: BrowserActionActivity,
|
||||
class AutoSolvingWebViewClient(
|
||||
activity: BrowserActionActivity,
|
||||
verifyComplete: (String) -> Boolean,
|
||||
injectScript: String?,
|
||||
headers: Map<String, String>)
|
||||
: HeadersInjectingWebViewClient(activity, verifyComplete, injectScript, headers) {
|
||||
headers: Map<String, String>
|
||||
) :
|
||||
HeadersInjectingWebViewClient(activity, verifyComplete, injectScript, headers) {
|
||||
|
||||
override fun shouldInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? {
|
||||
// Inject our custom script into the recaptcha iframes
|
||||
|
@ -4,9 +4,11 @@ import android.os.Build
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
|
||||
open class BasicWebViewClient(protected val activity: BrowserActionActivity,
|
||||
open class BasicWebViewClient(
|
||||
protected val activity: BrowserActionActivity,
|
||||
protected val verifyComplete: (String) -> Boolean,
|
||||
private val injectScript: String?) : WebViewClient() {
|
||||
private val injectScript: String?
|
||||
) : WebViewClient() {
|
||||
override fun onPageFinished(view: WebView, url: String) {
|
||||
super.onPageFinished(view, url)
|
||||
|
||||
|
@ -6,7 +6,12 @@ import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.SystemClock
|
||||
import android.view.MotionEvent
|
||||
import android.webkit.*
|
||||
import android.webkit.CookieManager
|
||||
import android.webkit.CookieSyncManager
|
||||
import android.webkit.JavascriptInterface
|
||||
import android.webkit.JsResult
|
||||
import android.webkit.WebChromeClient
|
||||
import android.webkit.WebView
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
@ -22,6 +27,9 @@ import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import exh.source.DelegatedHttpSource
|
||||
import exh.util.melt
|
||||
import java.io.Serializable
|
||||
import java.net.URL
|
||||
import java.util.UUID
|
||||
import kotlinx.android.synthetic.main.eh_activity_captcha.*
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
@ -33,10 +41,6 @@ import rx.Single
|
||||
import rx.schedulers.Schedulers
|
||||
import timber.log.Timber
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.Serializable
|
||||
import java.net.URL
|
||||
import java.util.*
|
||||
import kotlin.collections.HashMap
|
||||
|
||||
class BrowserActionActivity : AppCompatActivity() {
|
||||
private val sourceManager: SourceManager by injectLazy()
|
||||
@ -72,8 +76,8 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
it.value.joinToString(",")
|
||||
} ?: emptyMap()) + (intent.getSerializableExtra(HEADERS_EXTRA) as? HashMap<String, String> ?: emptyMap())
|
||||
|
||||
val cookies: HashMap<String, String>?
|
||||
= intent.getSerializableExtra(COOKIES_EXTRA) as? HashMap<String, String>
|
||||
val cookies: HashMap<String, String>? =
|
||||
intent.getSerializableExtra(COOKIES_EXTRA) as? HashMap<String, String>
|
||||
val script: String? = intent.getStringExtra(SCRIPT_EXTRA)
|
||||
val url: String? = intent.getStringExtra(URL_EXTRA)
|
||||
val actionName = intent.getStringExtra(ACTION_NAME_EXTRA)
|
||||
@ -120,8 +124,8 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
// Wait for both inner scripts to be loaded
|
||||
if (loadedInners >= 2) {
|
||||
// Attempt to autosolve captcha
|
||||
if(preferencesHelper.eh_autoSolveCaptchas().getOrDefault()
|
||||
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
if (preferencesHelper.eh_autoSolveCaptchas().getOrDefault() &&
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
webview.post {
|
||||
// 10 seconds to auto-solve captcha
|
||||
strictValidationStartTime = System.currentTimeMillis() + 1000 * 10
|
||||
@ -415,7 +419,6 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
doStageCheckbox(loopId)
|
||||
}
|
||||
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
@JavascriptInterface
|
||||
fun validateCaptchaCallback(result: Boolean, loopId: String) {
|
||||
@ -434,8 +437,8 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
}
|
||||
} else {
|
||||
val savedStrictValidationStartTime = strictValidationStartTime
|
||||
if(savedStrictValidationStartTime != null
|
||||
&& System.currentTimeMillis() > savedStrictValidationStartTime) {
|
||||
if (savedStrictValidationStartTime != null &&
|
||||
System.currentTimeMillis() > savedStrictValidationStartTime) {
|
||||
captchaSolveFail()
|
||||
} else {
|
||||
webview.postDelayed({
|
||||
@ -624,12 +627,14 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
|
||||
fun launchCaptcha(context: Context,
|
||||
fun launchCaptcha(
|
||||
context: Context,
|
||||
source: ActionCompletionVerifier,
|
||||
cookies: Map<String, String>,
|
||||
script: String?,
|
||||
url: String,
|
||||
autoSolveSubmitBtnSelector: String? = null) {
|
||||
autoSolveSubmitBtnSelector: String? = null
|
||||
) {
|
||||
val intent = baseIntent(context).apply {
|
||||
putExtra(SOURCE_ID_EXTRA, source.id)
|
||||
putExtra(COOKIES_EXTRA, HashMap(cookies))
|
||||
@ -641,9 +646,11 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
fun launchUniversal(context: Context,
|
||||
fun launchUniversal(
|
||||
context: Context,
|
||||
source: HttpSource,
|
||||
url: String) {
|
||||
url: String
|
||||
) {
|
||||
val intent = baseIntent(context).apply {
|
||||
putExtra(SOURCE_ID_EXTRA, source.id)
|
||||
putExtra(URL_EXTRA, url)
|
||||
@ -652,9 +659,11 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
fun launchUniversal(context: Context,
|
||||
fun launchUniversal(
|
||||
context: Context,
|
||||
sourceId: Long,
|
||||
url: String) {
|
||||
url: String
|
||||
) {
|
||||
val intent = baseIntent(context).apply {
|
||||
putExtra(SOURCE_ID_EXTRA, sourceId)
|
||||
putExtra(URL_EXTRA, url)
|
||||
@ -663,11 +672,13 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
fun launchAction(context: Context,
|
||||
fun launchAction(
|
||||
context: Context,
|
||||
completionVerifier: ActionCompletionVerifier,
|
||||
script: String?,
|
||||
url: String,
|
||||
actionName: String) {
|
||||
actionName: String
|
||||
) {
|
||||
val intent = baseIntent(context).apply {
|
||||
putExtra(SOURCE_ID_EXTRA, completionVerifier.id)
|
||||
putExtra(SCRIPT_EXTRA, script)
|
||||
@ -678,12 +689,14 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
fun launchAction(context: Context,
|
||||
fun launchAction(
|
||||
context: Context,
|
||||
completionVerifier: (String) -> Boolean,
|
||||
script: String?,
|
||||
url: String,
|
||||
actionName: String,
|
||||
headers: Map<String, String>? = emptyMap()) {
|
||||
headers: Map<String, String>? = emptyMap()
|
||||
) {
|
||||
val intent = baseIntent(context).apply {
|
||||
putExtra(HEADERS_EXTRA, HashMap(headers))
|
||||
putExtra(VERIFY_LAMBDA_EXTRA, completionVerifier as Serializable)
|
||||
@ -708,4 +721,3 @@ class NoopActionCompletionVerifier(private val source: HttpSource): DelegatedHtt
|
||||
interface ActionCompletionVerifier : Source {
|
||||
fun verifyComplete(url: String): Boolean
|
||||
}
|
||||
|
||||
|
@ -7,11 +7,13 @@ import android.webkit.WebView
|
||||
import androidx.annotation.RequiresApi
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
open class HeadersInjectingWebViewClient(activity: BrowserActionActivity,
|
||||
open class HeadersInjectingWebViewClient(
|
||||
activity: BrowserActionActivity,
|
||||
verifyComplete: (String) -> Boolean,
|
||||
injectScript: String?,
|
||||
private val headers: Map<String, String>)
|
||||
: BasicWebViewClient(activity, verifyComplete, injectScript) {
|
||||
private val headers: Map<String, String>
|
||||
) :
|
||||
BasicWebViewClient(activity, verifyComplete, injectScript) {
|
||||
|
||||
override fun shouldInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? {
|
||||
// Temp disabled as it's unreliable
|
||||
|
@ -3,8 +3,8 @@ package exh.ui.intercept
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import exh.GalleryAddEvent
|
||||
import exh.GalleryAdder
|
||||
import rx.subjects.BehaviorSubject
|
||||
import kotlin.concurrent.thread
|
||||
import rx.subjects.BehaviorSubject
|
||||
|
||||
class InterceptActivityPresenter : BasePresenter<InterceptActivity>() {
|
||||
private val galleryAdder = GalleryAdder()
|
||||
|
@ -28,13 +28,13 @@ class FingerLockPreference @JvmOverloads constructor(context: Context, attrs: At
|
||||
val prefs: PreferencesHelper by injectLazy()
|
||||
|
||||
val fingerprintSupported
|
||||
get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
||||
&& Reprint.isHardwarePresent()
|
||||
&& Reprint.hasFingerprintRegistered()
|
||||
get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
|
||||
Reprint.isHardwarePresent() &&
|
||||
Reprint.hasFingerprintRegistered()
|
||||
|
||||
val useFingerprint
|
||||
get() = fingerprintSupported
|
||||
&& prefs.eh_lockUseFingerprint().getOrDefault()
|
||||
get() = fingerprintSupported &&
|
||||
prefs.eh_lockUseFingerprint().getOrDefault()
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
override fun onAttached() {
|
||||
|
@ -1,6 +1,5 @@
|
||||
package exh.ui.lock
|
||||
|
||||
import android.content.Intent
|
||||
import android.view.WindowManager
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.bluelinelabs.conductor.Router
|
||||
@ -8,7 +7,6 @@ import com.bluelinelabs.conductor.RouterTransaction
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.Date
|
||||
|
||||
object LockActivityDelegate {
|
||||
private val preferences by injectLazy<PreferencesHelper>()
|
||||
@ -20,7 +18,6 @@ object LockActivityDelegate {
|
||||
.popChangeHandler(LockChangeHandler(animate)))
|
||||
}
|
||||
|
||||
|
||||
fun onCreate(activity: FragmentActivity) {
|
||||
preferences.secureScreen().asObservable()
|
||||
.subscribe {
|
||||
@ -42,5 +39,4 @@ object LockActivityDelegate {
|
||||
private fun isAppLocked(router: Router): Boolean {
|
||||
return router.backstack.lastOrNull()?.controller() is LockController
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||
import com.bluelinelabs.conductor.changehandler.AnimatorChangeHandler
|
||||
import java.util.*
|
||||
import java.util.ArrayList
|
||||
|
||||
class LockChangeHandler : AnimatorChangeHandler {
|
||||
constructor() : super()
|
||||
@ -36,6 +36,4 @@ class LockChangeHandler : AnimatorChangeHandler {
|
||||
|
||||
override fun copy(): ControllerChangeHandler =
|
||||
LockChangeHandler(animationDuration, removesFromViewOnPush())
|
||||
|
||||
}
|
||||
|
||||
|
@ -22,8 +22,8 @@ class LockController : NucleusController<LockPresenter>() {
|
||||
|
||||
val prefs: PreferencesHelper by injectLazy()
|
||||
|
||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup)
|
||||
= inflater.inflate(R.layout.activity_lock, container, false)!!
|
||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup) =
|
||||
inflater.inflate(R.layout.activity_lock, container, false)!!
|
||||
|
||||
override fun createPresenter() = LockPresenter()
|
||||
|
||||
|
@ -8,12 +8,12 @@ import com.afollestad.materialdialogs.MaterialDialog
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.util.preference.onChange
|
||||
import java.math.BigInteger
|
||||
import java.security.SecureRandom
|
||||
import rx.Observable
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.schedulers.Schedulers
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.math.BigInteger
|
||||
import java.security.SecureRandom
|
||||
|
||||
class LockPreference @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||
SwitchPreferenceCompat(context, attrs) {
|
||||
|
@ -11,9 +11,8 @@ class LockPresenter: BasePresenter<LockController>() {
|
||||
val prefs: PreferencesHelper by injectLazy()
|
||||
|
||||
val useFingerprint
|
||||
get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
||||
&& Reprint.isHardwarePresent()
|
||||
&& Reprint.hasFingerprintRegistered()
|
||||
&& prefs.eh_lockUseFingerprint().getOrDefault()
|
||||
get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
|
||||
Reprint.isHardwarePresent() &&
|
||||
Reprint.hasFingerprintRegistered() &&
|
||||
prefs.eh_lockUseFingerprint().getOrDefault()
|
||||
}
|
||||
|
||||
|
@ -13,11 +13,10 @@ import com.elvishew.xlog.XLog
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.security.MessageDigest
|
||||
import kotlin.experimental.and
|
||||
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
/**
|
||||
* Password hashing utils
|
||||
@ -40,22 +39,24 @@ fun sha512(passwordToHash: String, salt: String): String {
|
||||
/**
|
||||
* Check if lock is enabled
|
||||
*/
|
||||
fun lockEnabled(prefs: PreferencesHelper = Injekt.get())
|
||||
= prefs.eh_lockHash().get() != null
|
||||
&& prefs.eh_lockSalt().get() != null
|
||||
&& prefs.eh_lockLength().getOrDefault() != -1
|
||||
fun lockEnabled(prefs: PreferencesHelper = Injekt.get()) =
|
||||
prefs.eh_lockHash().get() != null &&
|
||||
prefs.eh_lockSalt().get() != null &&
|
||||
prefs.eh_lockLength().getOrDefault() != -1
|
||||
|
||||
/**
|
||||
* Check if the lock will function properly
|
||||
*
|
||||
* @return true if action is required, false if lock is working properly
|
||||
*/
|
||||
fun notifyLockSecurity(context: Context,
|
||||
prefs: PreferencesHelper = Injekt.get()): Boolean {
|
||||
fun notifyLockSecurity(
|
||||
context: Context,
|
||||
prefs: PreferencesHelper = Injekt.get()
|
||||
): Boolean {
|
||||
return false
|
||||
if (!prefs.eh_lockManually().getOrDefault()
|
||||
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
|
||||
&& !hasAccessToUsageStats(context)) {
|
||||
if (!prefs.eh_lockManually().getOrDefault() &&
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP &&
|
||||
!hasAccessToUsageStats(context)) {
|
||||
MaterialDialog.Builder(context)
|
||||
.title("Permission required")
|
||||
.content("${context.getString(R.string.app_name)} requires the usage stats permission to detect when you leave the app. " +
|
||||
|
@ -12,14 +12,14 @@ import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||
import eu.kanade.tachiyomi.util.view.gone
|
||||
import eu.kanade.tachiyomi.util.lang.launchUI
|
||||
import eu.kanade.tachiyomi.util.view.gone
|
||||
import eu.kanade.tachiyomi.util.view.visible
|
||||
import exh.uconfig.WarnConfigureDialogController
|
||||
import java.net.HttpCookie
|
||||
import kotlinx.android.synthetic.main.eh_activity_login.view.*
|
||||
import timber.log.Timber
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.net.HttpCookie
|
||||
|
||||
/**
|
||||
* LoginController
|
||||
@ -105,8 +105,8 @@ class LoginController : NucleusController<LoginPresenter>() {
|
||||
val parsedUrl = Uri.parse(url)
|
||||
if (parsedUrl.host.equals("forums.e-hentai.org", ignoreCase = true)) {
|
||||
// Hide distracting content
|
||||
if(!parsedUrl.queryParameterNames.contains(PARAM_SKIP_INJECT)
|
||||
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
|
||||
if (!parsedUrl.queryParameterNames.contains(PARAM_SKIP_INJECT) &&
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
|
||||
view.evaluateJavascript(HIDE_JS, null)
|
||||
|
||||
// Check login result
|
||||
@ -138,9 +138,9 @@ class LoginController : NucleusController<LoginPresenter>() {
|
||||
fun checkLoginCookies(url: String): Boolean {
|
||||
getCookies(url)?.let { parsed ->
|
||||
return parsed.filter {
|
||||
(it.name.equals(MEMBER_ID_COOKIE, ignoreCase = true)
|
||||
|| it.name.equals(PASS_HASH_COOKIE, ignoreCase = true))
|
||||
&& it.value.isNotBlank()
|
||||
(it.name.equals(MEMBER_ID_COOKIE, ignoreCase = true) ||
|
||||
it.name.equals(PASS_HASH_COOKIE, ignoreCase = true)) &&
|
||||
it.value.isNotBlank()
|
||||
}.count() >= 2
|
||||
}
|
||||
return false
|
||||
@ -177,8 +177,8 @@ class LoginController : NucleusController<LoginPresenter>() {
|
||||
return false
|
||||
}
|
||||
|
||||
fun getCookies(url: String): List<HttpCookie>?
|
||||
= CookieManager.getInstance().getCookie(url)?.let {
|
||||
fun getCookies(url: String): List<HttpCookie>? =
|
||||
CookieManager.getInstance().getCookie(url)?.let {
|
||||
it.split("; ").flatMap {
|
||||
HttpCookie.parse(it)
|
||||
}
|
||||
|
@ -2,6 +2,4 @@ package exh.ui.login
|
||||
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
|
||||
class LoginPresenter: BasePresenter<LoginController>() {
|
||||
|
||||
}
|
||||
class LoginPresenter : BasePresenter<LoginController>()
|
||||
|
@ -12,9 +12,9 @@ import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import exh.EXH_SOURCE_ID
|
||||
import exh.isLewdSource
|
||||
import kotlin.concurrent.thread
|
||||
import timber.log.Timber
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
class MetadataFetchDialog {
|
||||
|
||||
@ -132,7 +132,6 @@ class MetadataFetchDialog {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun adviseMigrationLater(activity: Activity) {
|
||||
|
@ -4,8 +4,10 @@ import android.os.Bundle
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import exh.debug.DebugFunctions.sourceManager
|
||||
|
||||
class MigrationSourceAdapter(val items: List<MigrationSourceItem>,
|
||||
val controller: MigrationDesignController): FlexibleAdapter<MigrationSourceItem>(
|
||||
class MigrationSourceAdapter(
|
||||
val items: List<MigrationSourceItem>,
|
||||
val controller: MigrationDesignController
|
||||
) : FlexibleAdapter<MigrationSourceItem>(
|
||||
items,
|
||||
controller,
|
||||
true
|
||||
|
@ -1,12 +1,12 @@
|
||||
package exh.ui.migration.manga.design
|
||||
|
||||
import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG
|
||||
import android.view.View
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
|
||||
import eu.kanade.tachiyomi.util.view.getRound
|
||||
import kotlinx.android.synthetic.main.eh_source_item.*
|
||||
import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG
|
||||
|
||||
class MigrationSourceHolder(view: View, val adapter: FlexibleAdapter<MigrationSourceItem>) :
|
||||
BaseFlexibleViewHolder(view, adapter) {
|
||||
|
@ -25,10 +25,12 @@ class MigrationSourceItem(val source: HttpSource, var sourceEnabled: Boolean): A
|
||||
* @param position The position of this item in the adapter.
|
||||
* @param payloads List of partial changes.
|
||||
*/
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<androidx.recyclerview.widget.RecyclerView.ViewHolder>>,
|
||||
override fun bindViewHolder(
|
||||
adapter: FlexibleAdapter<IFlexible<androidx.recyclerview.widget.RecyclerView.ViewHolder>>,
|
||||
holder: MigrationSourceHolder,
|
||||
position: Int,
|
||||
payloads: List<Any?>?) {
|
||||
payloads: List<Any?>?
|
||||
) {
|
||||
holder.bind(source, sourceEnabled)
|
||||
}
|
||||
|
||||
|
@ -6,14 +6,17 @@ import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import exh.util.DeferredField
|
||||
import exh.util.await
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.ConflatedBroadcastChannel
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.channels.ConflatedBroadcastChannel
|
||||
|
||||
class MigratingManga(private val db: DatabaseHelper,
|
||||
class MigratingManga(
|
||||
private val db: DatabaseHelper,
|
||||
private val sourceManager: SourceManager,
|
||||
val mangaId: Long,
|
||||
parentContext: CoroutineContext) {
|
||||
parentContext: CoroutineContext
|
||||
) {
|
||||
val searchResult = DeferredField<Long?>()
|
||||
|
||||
// <MAX, PROGRESS>
|
||||
|
@ -22,20 +22,27 @@ import eu.kanade.tachiyomi.util.view.inflate
|
||||
import eu.kanade.tachiyomi.util.view.visible
|
||||
import exh.MERGED_SOURCE_ID
|
||||
import exh.util.await
|
||||
import kotlinx.android.synthetic.main.eh_manga_card.view.*
|
||||
import kotlinx.android.synthetic.main.eh_migration_process_item.view.*
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.DateFormat
|
||||
import java.text.DecimalFormat
|
||||
import java.util.*
|
||||
import java.util.Date
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlinx.android.synthetic.main.eh_manga_card.view.*
|
||||
import kotlinx.android.synthetic.main.eh_migration_process_item.view.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class MigrationProcedureAdapter(val controller: MigrationProcedureController,
|
||||
class MigrationProcedureAdapter(
|
||||
val controller: MigrationProcedureController,
|
||||
val migratingManga: List<MigratingManga>,
|
||||
override val coroutineContext: CoroutineContext) : androidx.viewpager.widget.PagerAdapter(), CoroutineScope {
|
||||
override val coroutineContext: CoroutineContext
|
||||
) : androidx.viewpager.widget.PagerAdapter(), CoroutineScope {
|
||||
private val db: DatabaseHelper by injectLazy()
|
||||
private val gson: Gson by injectLazy()
|
||||
private val sourceManager: SourceManager by injectLazy()
|
||||
@ -96,9 +103,11 @@ class MigrationProcedureAdapter(val controller: MigrationProcedureController,
|
||||
}
|
||||
}
|
||||
|
||||
private fun migrateMangaInternal(prevManga: Manga,
|
||||
private fun migrateMangaInternal(
|
||||
prevManga: Manga,
|
||||
manga: Manga,
|
||||
replace: Boolean) {
|
||||
replace: Boolean
|
||||
) {
|
||||
db.inTransaction {
|
||||
// Update chapters read
|
||||
if (MigrationFlags.hasChapters(controller.config.migrationFlags)) {
|
||||
|
@ -15,13 +15,21 @@ import eu.kanade.tachiyomi.util.system.toast
|
||||
import exh.smartsearch.SmartSearchEngine
|
||||
import exh.ui.base.BaseExhController
|
||||
import exh.util.await
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import kotlinx.android.synthetic.main.eh_migration_process.*
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Semaphore
|
||||
import kotlinx.coroutines.sync.withPermit
|
||||
import kotlinx.coroutines.withContext
|
||||
import rx.schedulers.Schedulers
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
// TODO Will probably implode if activity is fully destroyed
|
||||
class MigrationProcedureController(bundle: Bundle? = null) : BaseExhController(bundle), CoroutineScope {
|
||||
|
@ -14,7 +14,13 @@ import eu.kanade.tachiyomi.ui.catalogue.browse.BrowseCatalogueController
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import kotlinx.android.synthetic.main.eh_smart_search.*
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.NonCancellable
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class SmartSearchController(bundle: Bundle? = null) : NucleusController<SmartSearchPresenter>(), CoroutineScope {
|
||||
|
@ -8,8 +8,13 @@ import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.ui.catalogue.CatalogueController
|
||||
import exh.smartsearch.SmartSearchEngine
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class SmartSearchPresenter(private val source: CatalogueSource?, private val config: CatalogueController.SmartSearchConfig?) :
|
||||
BasePresenter<SmartSearchController>(), CoroutineScope {
|
||||
@ -48,7 +53,6 @@ class SmartSearchPresenter(private val source: CatalogueSource?, private val con
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
package exh.util
|
||||
|
||||
import kotlin.coroutines.coroutineContext
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.ensureActive
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlin.coroutines.coroutineContext
|
||||
|
||||
@FlowPreview
|
||||
fun <T> Flow<T>.cancellable() = onEach {
|
||||
|
@ -112,7 +112,6 @@ private inline class IteratorShim<E>(private val iterator: Iterator<E>) : FakeMu
|
||||
override fun next() = iterator.next()
|
||||
}
|
||||
|
||||
|
||||
interface FakeMutableIterator<E> : MutableIterator<E> {
|
||||
/**
|
||||
* Removes from the underlying collection the last element returned by this iterator.
|
||||
|
@ -1,7 +1,10 @@
|
||||
package exh.util
|
||||
|
||||
import io.realm.*
|
||||
import java.util.*
|
||||
import io.realm.Case
|
||||
import io.realm.RealmModel
|
||||
import io.realm.RealmQuery
|
||||
import io.realm.RealmResults
|
||||
import java.util.Date
|
||||
|
||||
/**
|
||||
* Realm query with logging
|
||||
@ -9,14 +12,16 @@ import java.util.*
|
||||
* @author nulldev
|
||||
*/
|
||||
|
||||
inline fun <reified E : RealmModel> RealmQuery<out E>.beginLog(clazz: Class<out E>? =
|
||||
E::class.java): LoggingRealmQuery<out E>
|
||||
= LoggingRealmQuery.fromQuery(this, clazz)
|
||||
inline fun <reified E : RealmModel> RealmQuery<out E>.beginLog(
|
||||
clazz: Class<out E>? =
|
||||
E::class.java
|
||||
): LoggingRealmQuery<out E> =
|
||||
LoggingRealmQuery.fromQuery(this, clazz)
|
||||
|
||||
class LoggingRealmQuery<E : RealmModel>(val query: RealmQuery<E>) {
|
||||
companion object {
|
||||
fun <E : RealmModel> fromQuery(q: RealmQuery<out E>, clazz: Class<out E>?)
|
||||
= LoggingRealmQuery(q).apply {
|
||||
fun <E : RealmModel> fromQuery(q: RealmQuery<out E>, clazz: Class<out E>?) =
|
||||
LoggingRealmQuery(q).apply {
|
||||
log += "SELECT * FROM ${clazz?.name ?: "???"} WHERE"
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
package exh.util
|
||||
|
||||
import android.util.SparseArray
|
||||
import java.util.*
|
||||
import java.util.AbstractMap
|
||||
import java.util.LinkedList
|
||||
|
||||
class NakedTrieNode<T>(val key: Int, var parent: NakedTrieNode<T>?) {
|
||||
val children = SparseArray<NakedTrieNode<T>>(1)
|
||||
|
@ -8,8 +8,8 @@ import org.jsoup.nodes.Document
|
||||
|
||||
fun Response.interceptAsHtml(block: (Document) -> Unit): Response {
|
||||
val body = body
|
||||
if (body?.contentType()?.type == "text"
|
||||
&& body.contentType()?.subtype == "html") {
|
||||
if (body?.contentType()?.type == "text" &&
|
||||
body.contentType()?.subtype == "html") {
|
||||
val bodyString = body.string()
|
||||
val rebuiltResponse = newBuilder()
|
||||
.body(ResponseBody.create(body.contentType(), bodyString))
|
||||
|
@ -3,7 +3,7 @@ package exh.util
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmModel
|
||||
import io.realm.log.RealmLog
|
||||
import java.util.*
|
||||
import java.util.UUID
|
||||
|
||||
inline fun <T> realmTrans(block: (Realm) -> T): T {
|
||||
return defRealm {
|
||||
@ -49,9 +49,8 @@ inline fun <T> Realm.useTrans(block: (Realm) -> T): T {
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : RealmModel> Realm.createUUIDObj(clazz: Class<T>)
|
||||
= createObject(clazz, UUID.randomUUID().toString())!!
|
||||
|
||||
inline fun <reified T : RealmModel> Realm.createUUIDObj()
|
||||
= createUUIDObj(T::class.java)
|
||||
fun <T : RealmModel> Realm.createUUIDObj(clazz: Class<T>) =
|
||||
createObject(clazz, UUID.randomUUID().toString())!!
|
||||
|
||||
inline fun <reified T : RealmModel> Realm.createUUIDObj() =
|
||||
createUUIDObj(T::class.java)
|
||||
|
@ -2,10 +2,14 @@ package exh.util
|
||||
|
||||
import com.pushtorefresh.storio.operations.PreparedOperation
|
||||
import com.pushtorefresh.storio.sqlite.operations.get.PreparedGetObject
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import rx.*
|
||||
import rx.subjects.ReplaySubject
|
||||
import kotlin.coroutines.resumeWithException
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import rx.Completable
|
||||
import rx.Observable
|
||||
import rx.Scheduler
|
||||
import rx.Single
|
||||
import rx.Subscription
|
||||
import rx.subjects.ReplaySubject
|
||||
|
||||
/**
|
||||
* Transform a cold single to a hot single
|
||||
|
@ -1,6 +1,17 @@
|
||||
package xyz.nulldev.ts.api.http.serializer
|
||||
|
||||
import com.github.salomonbrys.kotson.*
|
||||
import com.github.salomonbrys.kotson.bool
|
||||
import com.github.salomonbrys.kotson.byte
|
||||
import com.github.salomonbrys.kotson.char
|
||||
import com.github.salomonbrys.kotson.double
|
||||
import com.github.salomonbrys.kotson.float
|
||||
import com.github.salomonbrys.kotson.get
|
||||
import com.github.salomonbrys.kotson.int
|
||||
import com.github.salomonbrys.kotson.long
|
||||
import com.github.salomonbrys.kotson.obj
|
||||
import com.github.salomonbrys.kotson.set
|
||||
import com.github.salomonbrys.kotson.short
|
||||
import com.github.salomonbrys.kotson.string
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
|
Loading…
x
Reference in New Issue
Block a user