Fix gallery browsing
This commit is contained in:
parent
47966d89f2
commit
2b7c0e8e80
@ -249,6 +249,9 @@ dependencies {
|
|||||||
|
|
||||||
//RxJava 2 interop for Realm (EXH)
|
//RxJava 2 interop for Realm (EXH)
|
||||||
implementation 'com.lvla.android:rxjava2-interop-kt:0.2.1'
|
implementation 'com.lvla.android:rxjava2-interop-kt:0.2.1'
|
||||||
|
|
||||||
|
//Debug network interceptor (EXH)
|
||||||
|
devImplementation "com.squareup.okhttp3:logging-interceptor:3.9.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
|
@ -106,7 +106,7 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name="exh.ui.intercept.InterceptActivity"
|
android:name="exh.ui.intercept.InterceptActivity"
|
||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
android:label="Tachiyomi">
|
android:label="TachiyomiEH">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW"/>
|
<action android:name="android.intent.action.VIEW"/>
|
||||||
|
|
||||||
|
@ -124,4 +124,12 @@ object PreferenceKeys {
|
|||||||
const val eh_showSyncIntro = "eh_show_sync_intro"
|
const val eh_showSyncIntro = "eh_show_sync_intro"
|
||||||
|
|
||||||
const val eh_readOnlySync = "eh_sync_read_only"
|
const val eh_readOnlySync = "eh_sync_read_only"
|
||||||
|
|
||||||
|
const val eh_useOrigImages = "eh_useOrigImages"
|
||||||
|
|
||||||
|
const val eh_ehSettingsProfile = "eh_ehSettingsProfile"
|
||||||
|
|
||||||
|
const val eh_exhSettingsProfile = "eh_exhSettingsProfile"
|
||||||
|
|
||||||
|
const val eh_enableExHentai = "enable_exhentai"
|
||||||
}
|
}
|
||||||
|
@ -171,7 +171,7 @@ class PreferencesHelper(val context: Context) {
|
|||||||
fun migrateFlags() = rxPrefs.getInteger("migrate_flags", Int.MAX_VALUE)
|
fun migrateFlags() = rxPrefs.getInteger("migrate_flags", Int.MAX_VALUE)
|
||||||
|
|
||||||
// --> EH
|
// --> EH
|
||||||
fun enableExhentai() = rxPrefs.getBoolean("enable_exhentai", false)
|
fun enableExhentai() = rxPrefs.getBoolean(Keys.eh_enableExHentai, false)
|
||||||
|
|
||||||
fun secureEXH() = rxPrefs.getBoolean("secure_exh", true)
|
fun secureEXH() = rxPrefs.getBoolean("secure_exh", true)
|
||||||
|
|
||||||
@ -181,6 +181,8 @@ class PreferencesHelper(val context: Context) {
|
|||||||
|
|
||||||
fun useJapaneseTitle() = rxPrefs.getBoolean("use_jp_title", false)
|
fun useJapaneseTitle() = rxPrefs.getBoolean("use_jp_title", false)
|
||||||
|
|
||||||
|
fun eh_useOriginalImages() = rxPrefs.getBoolean(Keys.eh_useOrigImages, false)
|
||||||
|
|
||||||
fun ehSearchSize() = rxPrefs.getString("ex_search_size", "rc_0")
|
fun ehSearchSize() = rxPrefs.getString("ex_search_size", "rc_0")
|
||||||
|
|
||||||
fun thumbnailRows() = rxPrefs.getString("ex_thumb_rows", "tr_2")
|
fun thumbnailRows() = rxPrefs.getString("ex_thumb_rows", "tr_2")
|
||||||
@ -195,6 +197,8 @@ class PreferencesHelper(val context: Context) {
|
|||||||
fun memberIdVal() = rxPrefs.getString("eh_ipb_member_id", null)
|
fun memberIdVal() = rxPrefs.getString("eh_ipb_member_id", null)
|
||||||
fun passHashVal() = rxPrefs.getString("eh_ipb_pass_hash", null)
|
fun passHashVal() = rxPrefs.getString("eh_ipb_pass_hash", null)
|
||||||
fun igneousVal() = rxPrefs.getString("eh_igneous", null)
|
fun igneousVal() = rxPrefs.getString("eh_igneous", null)
|
||||||
|
fun eh_ehSettingsProfile() = rxPrefs.getInteger(Keys.eh_ehSettingsProfile, -1)
|
||||||
|
fun eh_exhSettingsProfile() = rxPrefs.getInteger(Keys.eh_exhSettingsProfile, -1)
|
||||||
|
|
||||||
//Lock
|
//Lock
|
||||||
fun lockHash() = rxPrefs.getString("lock_hash", null)
|
fun lockHash() = rxPrefs.getString("lock_hash", null)
|
||||||
@ -205,7 +209,7 @@ class PreferencesHelper(val context: Context) {
|
|||||||
|
|
||||||
fun lockUseFingerprint() = rxPrefs.getBoolean("lock_finger", false)
|
fun lockUseFingerprint() = rxPrefs.getBoolean("lock_finger", false)
|
||||||
|
|
||||||
fun eh_useHighQualityThumbs() = rxPrefs.getBoolean(Keys.eh_nh_useHighQualityThumbs, false)
|
fun eh_nh_useHighQualityThumbs() = rxPrefs.getBoolean(Keys.eh_nh_useHighQualityThumbs, false)
|
||||||
|
|
||||||
fun eh_showSyncIntro() = rxPrefs.getBoolean(Keys.eh_showSyncIntro, true)
|
fun eh_showSyncIntro() = rxPrefs.getBoolean(Keys.eh_showSyncIntro, true)
|
||||||
|
|
||||||
|
@ -21,10 +21,7 @@ import exh.util.UriFilter
|
|||||||
import exh.util.UriGroup
|
import exh.util.UriGroup
|
||||||
import exh.util.ignore
|
import exh.util.ignore
|
||||||
import exh.util.urlImportFetchSearchManga
|
import exh.util.urlImportFetchSearchManga
|
||||||
import okhttp3.CacheControl
|
import okhttp3.*
|
||||||
import okhttp3.Headers
|
|
||||||
import okhttp3.Request
|
|
||||||
import okhttp3.Response
|
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
@ -42,11 +39,14 @@ class EHentai(override val id: Long,
|
|||||||
else
|
else
|
||||||
"http"
|
"http"
|
||||||
|
|
||||||
override val baseUrl: String
|
val domain: String
|
||||||
get() = if(exh)
|
get() = if(exh)
|
||||||
"$schema://exhentai.org"
|
"exhentai.org"
|
||||||
else
|
else
|
||||||
"$schema://e-hentai.org"
|
"e-hentai.org"
|
||||||
|
|
||||||
|
override val baseUrl: String
|
||||||
|
get() = "$schema://$domain"
|
||||||
|
|
||||||
override val lang = "all"
|
override val lang = "all"
|
||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
@ -68,7 +68,7 @@ class EHentai(override val id: Long,
|
|||||||
//Get title
|
//Get title
|
||||||
it.select(".itd .it5 a").first()?.apply {
|
it.select(".itd .it5 a").first()?.apply {
|
||||||
title = text()
|
title = text()
|
||||||
setUrlWithoutDomain(addParam(attr("href"), "nw", "always"))
|
setUrlWithoutDomain(ExGalleryMetadata.normalizeUrl(attr("href")))
|
||||||
}
|
}
|
||||||
//Get image
|
//Get image
|
||||||
it.select(".itd .it2").first()?.apply {
|
it.select(".itd .it2").first()?.apply {
|
||||||
@ -81,7 +81,6 @@ class EHentai(override val id: Long,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
//Add to page if required
|
//Add to page if required
|
||||||
val hasNextPage = select("a[onclick=return false]").last()?.let {
|
val hasNextPage = select("a[onclick=return false]").last()?.let {
|
||||||
@ -330,62 +329,32 @@ class EHentai(override val id: Long,
|
|||||||
return Pair(result as List<ParsedManga>, favNames!!)
|
return Pair(result as List<ParsedManga>, favNames!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
val cookiesHeader by lazy {
|
fun spPref() = if(exh)
|
||||||
|
prefs.eh_exhSettingsProfile()
|
||||||
|
else
|
||||||
|
prefs.eh_ehSettingsProfile()
|
||||||
|
|
||||||
|
fun rawCookies(sp: Int): Map<String, String> {
|
||||||
val cookies: MutableMap<String, String> = mutableMapOf()
|
val cookies: MutableMap<String, String> = mutableMapOf()
|
||||||
if(prefs.enableExhentai().getOrDefault()) {
|
if(prefs.enableExhentai().getOrDefault()) {
|
||||||
cookies[LoginController.MEMBER_ID_COOKIE] = prefs.memberIdVal().get()!!
|
cookies[LoginController.MEMBER_ID_COOKIE] = prefs.memberIdVal().get()!!
|
||||||
cookies[LoginController.PASS_HASH_COOKIE] = prefs.passHashVal().get()!!
|
cookies[LoginController.PASS_HASH_COOKIE] = prefs.passHashVal().get()!!
|
||||||
cookies[LoginController.IGNEOUS_COOKIE] = prefs.igneousVal().get()!!
|
cookies[LoginController.IGNEOUS_COOKIE] = prefs.igneousVal().get()!!
|
||||||
|
cookies["sp"] = sp.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
//Setup settings
|
//Session-less list display mode (for users without ExHentai)
|
||||||
val settings = mutableListOf<String?>()
|
cookies["sl"] = "dm_0"
|
||||||
//Image quality
|
|
||||||
settings.add(when(prefs.imageQuality()
|
|
||||||
.getOrDefault()
|
|
||||||
.toLowerCase()) {
|
|
||||||
"ovrs_2400" -> "xr_2400"
|
|
||||||
"ovrs_1600" -> "xr_1600"
|
|
||||||
"high" -> "xr_1280"
|
|
||||||
"med" -> "xr_980"
|
|
||||||
"low" -> "xr_780"
|
|
||||||
"auto" -> null
|
|
||||||
else -> null
|
|
||||||
})
|
|
||||||
//Use Hentai@Home
|
|
||||||
settings.add(if(prefs.useHentaiAtHome().getOrDefault())
|
|
||||||
null
|
|
||||||
else
|
|
||||||
"uh_n")
|
|
||||||
//Japanese titles
|
|
||||||
settings.add(if(prefs.useJapaneseTitle().getOrDefault())
|
|
||||||
"tl_j"
|
|
||||||
else
|
|
||||||
null)
|
|
||||||
//Do not show popular right now pane as we can't parse it
|
|
||||||
settings.add("prn_n")
|
|
||||||
//Paging size
|
|
||||||
settings.add(prefs.ehSearchSize().getOrDefault())
|
|
||||||
//Thumbnail rows
|
|
||||||
settings.add(prefs.thumbnailRows().getOrDefault())
|
|
||||||
|
|
||||||
cookies.put("uconfig", buildSettings(settings))
|
return cookies
|
||||||
|
|
||||||
buildCookies(cookies)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun cookiesHeader(sp: Int = spPref().getOrDefault())
|
||||||
|
= buildCookies(rawCookies(sp))
|
||||||
|
|
||||||
//Headers
|
//Headers
|
||||||
override fun headersBuilder()
|
override fun headersBuilder()
|
||||||
= super.headersBuilder().add("Cookie", cookiesHeader)!!
|
= super.headersBuilder().add("Cookie", cookiesHeader())!!
|
||||||
|
|
||||||
fun buildSettings(settings: List<String?>): String {
|
|
||||||
return settings.filterNotNull().joinToString(separator = "-")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun buildCookies(cookies: Map<String, String>)
|
|
||||||
= cookies.entries.joinToString(separator = "; ", postfix = ";") {
|
|
||||||
"${URLEncoder.encode(it.key, "UTF-8")}=${URLEncoder.encode(it.value, "UTF-8")}"
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addParam(url: String, param: String, value: String)
|
fun addParam(url: String, param: String, value: String)
|
||||||
= Uri.parse(url)
|
= Uri.parse(url)
|
||||||
@ -394,11 +363,13 @@ class EHentai(override val id: Long,
|
|||||||
.toString()
|
.toString()
|
||||||
|
|
||||||
override val client = network.client.newBuilder()
|
override val client = network.client.newBuilder()
|
||||||
|
.cookieJar(CookieJar.NO_COOKIES)
|
||||||
.addInterceptor { chain ->
|
.addInterceptor { chain ->
|
||||||
val newReq = chain
|
val newReq = chain
|
||||||
.request()
|
.request()
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.addHeader("Cookie", cookiesHeader)
|
.removeHeader("Cookie")
|
||||||
|
.addHeader("Cookie", cookiesHeader())
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
chain.proceed(newReq)
|
chain.proceed(newReq)
|
||||||
@ -470,5 +441,11 @@ class EHentai(override val id: Long,
|
|||||||
companion object {
|
companion object {
|
||||||
val QUERY_PREFIX = "?f_apply=Apply+Filter"
|
val QUERY_PREFIX = "?f_apply=Apply+Filter"
|
||||||
val TR_SUFFIX = "TR"
|
val TR_SUFFIX = "TR"
|
||||||
|
|
||||||
|
fun buildCookies(cookies: Map<String, String>)
|
||||||
|
= cookies.entries.joinToString(separator = "; ", postfix = ";") {
|
||||||
|
"${URLEncoder.encode(it.key, "UTF-8")}=${URLEncoder.encode(it.value, "UTF-8")}"
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,10 +5,12 @@ import android.widget.Toast
|
|||||||
import com.afollestad.materialdialogs.MaterialDialog
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
import com.bluelinelabs.conductor.RouterTransaction
|
import com.bluelinelabs.conductor.RouterTransaction
|
||||||
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler
|
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler
|
||||||
|
import com.f2prateek.rx.preferences.Preference
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys
|
import eu.kanade.tachiyomi.data.preference.PreferenceKeys
|
||||||
import eu.kanade.tachiyomi.util.toast
|
import eu.kanade.tachiyomi.util.toast
|
||||||
import exh.favorites.FavoritesIntroDialog
|
import exh.favorites.FavoritesIntroDialog
|
||||||
import exh.favorites.LocalFavoritesStorage
|
import exh.favorites.LocalFavoritesStorage
|
||||||
|
import exh.uconfig.ConfiguringDialogController
|
||||||
import exh.ui.login.LoginController
|
import exh.ui.login.LoginController
|
||||||
import exh.util.trans
|
import exh.util.trans
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
@ -19,13 +21,22 @@ import rx.schedulers.Schedulers
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class SettingsEhController : SettingsController() {
|
class SettingsEhController : SettingsController() {
|
||||||
|
private fun Preference<*>.reconfigureOnChange() {
|
||||||
|
asObservable()
|
||||||
|
.skip(1) //Skip first as it is emitted immediately
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribeUntilDestroy {
|
||||||
|
ConfiguringDialogController().showDialog(router)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun setupPreferenceScreen(screen: PreferenceScreen) = with(screen) {
|
override fun setupPreferenceScreen(screen: PreferenceScreen) = with(screen) {
|
||||||
title = "E-Hentai"
|
title = "E-Hentai"
|
||||||
|
|
||||||
switchPreference {
|
switchPreference {
|
||||||
title = "Enable ExHentai"
|
title = "Enable ExHentai"
|
||||||
summaryOff = "Requires login"
|
summaryOff = "Requires login"
|
||||||
key = "enable_exhentai"
|
key = PreferenceKeys.eh_enableExHentai
|
||||||
isPersistent = false
|
isPersistent = false
|
||||||
defaultValue = false
|
defaultValue = false
|
||||||
preferences.enableExhentai()
|
preferences.enableExhentai()
|
||||||
@ -33,8 +44,8 @@ class SettingsEhController : SettingsController() {
|
|||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribeUntilDestroy {
|
.subscribeUntilDestroy {
|
||||||
isChecked = it
|
isChecked = it
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange { newVal ->
|
onChange { newVal ->
|
||||||
newVal as Boolean
|
newVal as Boolean
|
||||||
@ -55,7 +66,9 @@ class SettingsEhController : SettingsController() {
|
|||||||
summary = "Do you wish to load images through the Hentai@Home Network? Disabling this option will reduce the amount of pages you are able to view"
|
summary = "Do you wish to load images through the Hentai@Home Network? Disabling this option will reduce the amount of pages you are able to view"
|
||||||
key = "enable_hah"
|
key = "enable_hah"
|
||||||
defaultValue = true
|
defaultValue = true
|
||||||
}
|
|
||||||
|
preferences.useHentaiAtHome().reconfigureOnChange()
|
||||||
|
}.dependency = PreferenceKeys.eh_enableExHentai
|
||||||
|
|
||||||
switchPreference {
|
switchPreference {
|
||||||
title = "Show Japanese titles in search results"
|
title = "Show Japanese titles in search results"
|
||||||
@ -63,7 +76,19 @@ class SettingsEhController : SettingsController() {
|
|||||||
summaryOff = "Currently showing English/Romanized titles in search results. Clear the chapter cache after changing this (in the Advanced section)"
|
summaryOff = "Currently showing English/Romanized titles in search results. Clear the chapter cache after changing this (in the Advanced section)"
|
||||||
key = "use_jp_title"
|
key = "use_jp_title"
|
||||||
defaultValue = false
|
defaultValue = false
|
||||||
}
|
|
||||||
|
preferences.useJapaneseTitle().reconfigureOnChange()
|
||||||
|
}.dependency = PreferenceKeys.eh_enableExHentai
|
||||||
|
|
||||||
|
switchPreference {
|
||||||
|
title = "Use original images"
|
||||||
|
summaryOn = "Currently using original images"
|
||||||
|
summaryOff = "Currently using resampled images"
|
||||||
|
key = PreferenceKeys.eh_useOrigImages
|
||||||
|
defaultValue = false
|
||||||
|
|
||||||
|
preferences.eh_useOriginalImages().reconfigureOnChange()
|
||||||
|
}.dependency = PreferenceKeys.eh_enableExHentai
|
||||||
|
|
||||||
switchPreference {
|
switchPreference {
|
||||||
defaultValue = true
|
defaultValue = true
|
||||||
@ -93,45 +118,9 @@ class SettingsEhController : SettingsController() {
|
|||||||
"med",
|
"med",
|
||||||
"low"
|
"low"
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
listPreference {
|
preferences.imageQuality().reconfigureOnChange()
|
||||||
title = "Search result count per page"
|
}.dependency = PreferenceKeys.eh_enableExHentai
|
||||||
summary = "Requires the 'Paging Enlargement' hath perk"
|
|
||||||
defaultValue = "rc_0"
|
|
||||||
key = "ex_search_size"
|
|
||||||
entries = arrayOf(
|
|
||||||
"25 results",
|
|
||||||
"50 results",
|
|
||||||
"100 results",
|
|
||||||
"200 results"
|
|
||||||
)
|
|
||||||
entryValues = arrayOf(
|
|
||||||
"rc_0",
|
|
||||||
"rc_1",
|
|
||||||
"rc_2",
|
|
||||||
"rc_3"
|
|
||||||
)
|
|
||||||
}.dependency = "enable_exhentai"
|
|
||||||
|
|
||||||
listPreference {
|
|
||||||
defaultValue = "tr_2"
|
|
||||||
title = "Thumbnail rows"
|
|
||||||
summary = "Affects loading speeds. It is recommended to set this to the maximum size your hath perks allow"
|
|
||||||
key = "ex_thumb_rows"
|
|
||||||
entries = arrayOf(
|
|
||||||
"4",
|
|
||||||
"10 (requires 'More Thumbs' hath perk)",
|
|
||||||
"20 (requires 'Thumbs Up' hath perk)",
|
|
||||||
"40 (requires 'All Thumbs' hath perk)"
|
|
||||||
)
|
|
||||||
entryValues = arrayOf(
|
|
||||||
"tr_2",
|
|
||||||
"tr_5",
|
|
||||||
"tr_10",
|
|
||||||
"tr_20"
|
|
||||||
)
|
|
||||||
}.dependency = "enable_exhentai"
|
|
||||||
|
|
||||||
preferenceCategory {
|
preferenceCategory {
|
||||||
title = "Favorites sync"
|
title = "Favorites sync"
|
||||||
|
@ -11,7 +11,9 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
|||||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.source.online.all.EHentai
|
import eu.kanade.tachiyomi.source.online.all.EHentai
|
||||||
|
import eu.kanade.tachiyomi.util.launchUI
|
||||||
import eu.kanade.tachiyomi.util.powerManager
|
import eu.kanade.tachiyomi.util.powerManager
|
||||||
|
import eu.kanade.tachiyomi.util.toast
|
||||||
import eu.kanade.tachiyomi.util.wifiManager
|
import eu.kanade.tachiyomi.util.wifiManager
|
||||||
import exh.EH_METADATA_SOURCE_ID
|
import exh.EH_METADATA_SOURCE_ID
|
||||||
import exh.EXH_SOURCE_ID
|
import exh.EXH_SOURCE_ID
|
||||||
@ -117,6 +119,11 @@ class FavoritesSyncHelper(val context: Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val theContext = context
|
||||||
|
launchUI {
|
||||||
|
theContext.toast("Sync complete!")
|
||||||
|
}
|
||||||
} catch(e: IgnoredException) {
|
} catch(e: IgnoredException) {
|
||||||
//Do not display error as this error has already been reported
|
//Do not display error as this error has already been reported
|
||||||
Timber.w(e, "Ignoring exception!")
|
Timber.w(e, "Ignoring exception!")
|
||||||
|
@ -160,8 +160,12 @@ open class ExGalleryMetadata : RealmObject(), SearchableGalleryMetadata {
|
|||||||
companion object {
|
companion object {
|
||||||
private fun splitGalleryUrl(url: String)
|
private fun splitGalleryUrl(url: String)
|
||||||
= url.let {
|
= url.let {
|
||||||
Uri.parse(it).pathSegments
|
//Only parse URL if is full URL
|
||||||
.filterNot(String::isNullOrBlank)
|
val pathSegments = if(it.startsWith("http"))
|
||||||
|
Uri.parse(it).pathSegments
|
||||||
|
else
|
||||||
|
it.split('/')
|
||||||
|
pathSegments.filterNot(String::isNullOrBlank)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun galleryId(url: String) = splitGalleryUrl(url).let { it[it.size - 2] }
|
fun galleryId(url: String) = splitGalleryUrl(url).let { it[it.size - 2] }
|
||||||
|
@ -89,7 +89,7 @@ open class NHentaiMetadata : RealmObject(), SearchableGalleryMetadata {
|
|||||||
if(mediaId != null)
|
if(mediaId != null)
|
||||||
NHentaiMetadata.typeToExtension(thumbnailImageType)?.let {
|
NHentaiMetadata.typeToExtension(thumbnailImageType)?.let {
|
||||||
manga.thumbnail_url = "https://t.nhentai.net/galleries/$mediaId/${
|
manga.thumbnail_url = "https://t.nhentai.net/galleries/$mediaId/${
|
||||||
if(Injekt.get<PreferencesHelper>().eh_useHighQualityThumbs().getOrDefault())
|
if(Injekt.get<PreferencesHelper>().eh_nh_useHighQualityThumbs().getOrDefault())
|
||||||
"cover"
|
"cover"
|
||||||
else
|
else
|
||||||
"thumb"
|
"thumb"
|
||||||
|
65
app/src/main/java/exh/uconfig/ConfiguringDialogController.kt
Normal file
65
app/src/main/java/exh/uconfig/ConfiguringDialogController.kt
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package exh.uconfig
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
|
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||||
|
import eu.kanade.tachiyomi.util.launchUI
|
||||||
|
import eu.kanade.tachiyomi.util.toast
|
||||||
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
|
class ConfiguringDialogController : DialogController() {
|
||||||
|
private var materialDialog: MaterialDialog? = null
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||||
|
return MaterialDialog.Builder(activity!!)
|
||||||
|
.title("Uploading settings to server")
|
||||||
|
.content("Please wait, this may take some time...")
|
||||||
|
.progress(true, 0)
|
||||||
|
.cancelable(false)
|
||||||
|
.build().also {
|
||||||
|
materialDialog = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAttach(view: View) {
|
||||||
|
super.onAttach(view)
|
||||||
|
thread {
|
||||||
|
try {
|
||||||
|
EHConfigurator().configureAll()
|
||||||
|
launchUI {
|
||||||
|
activity?.toast("Settings successfully uploaded!")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
activity?.let {
|
||||||
|
it.runOnUiThread {
|
||||||
|
MaterialDialog.Builder(it)
|
||||||
|
.title("Configuration failed!")
|
||||||
|
.content("An error occurred during the configuration process: " + e.message)
|
||||||
|
.positiveText("Ok")
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
launchUI {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView(view: View) {
|
||||||
|
super.onDestroyView(view)
|
||||||
|
materialDialog = null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
|
||||||
|
super.onRestoreInstanceState(savedInstanceState)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun finish() {
|
||||||
|
router.popController(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
125
app/src/main/java/exh/uconfig/EHConfigurator.kt
Normal file
125
app/src/main/java/exh/uconfig/EHConfigurator.kt
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
package exh.uconfig
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
|
import eu.kanade.tachiyomi.source.online.all.EHentai
|
||||||
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import exh.EH_SOURCE_ID
|
||||||
|
import exh.EXH_SOURCE_ID
|
||||||
|
import okhttp3.FormBody
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Request
|
||||||
|
import timber.log.Timber
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
|
class EHConfigurator {
|
||||||
|
private val prefs: PreferencesHelper by injectLazy()
|
||||||
|
private val sources: SourceManager by injectLazy()
|
||||||
|
|
||||||
|
private val configuratorClient = OkHttpClient.Builder().build()
|
||||||
|
|
||||||
|
private fun EHentai.requestWithCreds(sp: Int = 1) = Request.Builder()
|
||||||
|
.addHeader("Cookie", cookiesHeader(sp))
|
||||||
|
|
||||||
|
private fun EHentai.execProfileActions(action: String,
|
||||||
|
name: String,
|
||||||
|
set: String,
|
||||||
|
sp: Int)
|
||||||
|
= configuratorClient.newCall(requestWithCreds(sp)
|
||||||
|
.url(uconfigUrl)
|
||||||
|
.post(FormBody.Builder()
|
||||||
|
.add("profile_action", action)
|
||||||
|
.add("profile_name", name)
|
||||||
|
.add("profile_set", set)
|
||||||
|
.build())
|
||||||
|
.build())
|
||||||
|
.execute().asJsoup()
|
||||||
|
|
||||||
|
private val EHentai.uconfigUrl get() = baseUrl + UCONFIG_URL
|
||||||
|
|
||||||
|
fun configureAll() {
|
||||||
|
val ehSource = sources.get(EH_SOURCE_ID) as EHentai
|
||||||
|
val exhSource = sources.get(EXH_SOURCE_ID) as EHentai
|
||||||
|
|
||||||
|
//Get hath perks
|
||||||
|
val perksPage = configuratorClient.newCall(ehSource.requestWithCreds()
|
||||||
|
.url(HATH_PERKS_URL)
|
||||||
|
.build())
|
||||||
|
.execute().asJsoup()
|
||||||
|
|
||||||
|
val hathPerks = EHHathPerksResponse()
|
||||||
|
|
||||||
|
perksPage.select(".stuffbox tr").forEach {
|
||||||
|
val name = it.child(0).text().toLowerCase()
|
||||||
|
val purchased = it.child(2).getElementsByTag("form").isEmpty()
|
||||||
|
|
||||||
|
when(name) {
|
||||||
|
//Thumbnail rows
|
||||||
|
"more thumbs" -> hathPerks.moreThumbs = purchased
|
||||||
|
"thumbs up" -> hathPerks.thumbsUp = purchased
|
||||||
|
"all thumbs" -> hathPerks.allThumbs = purchased
|
||||||
|
|
||||||
|
//Pagination sizing
|
||||||
|
"paging enlargement i" -> hathPerks.pagingEnlargementI = purchased
|
||||||
|
"paging enlargement ii" -> hathPerks.pagingEnlargementII = purchased
|
||||||
|
"paging enlargement iii" -> hathPerks.pagingEnlargementIII = purchased
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timber.d("Hath perks: $hathPerks")
|
||||||
|
|
||||||
|
configure(ehSource, hathPerks)
|
||||||
|
configure(exhSource, hathPerks)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun configure(source: EHentai, hathPerks: EHHathPerksResponse) {
|
||||||
|
//Delete old app profiles
|
||||||
|
val scanReq = source.requestWithCreds().url(source.uconfigUrl).build()
|
||||||
|
val resp = configuratorClient.newCall(scanReq).execute().asJsoup()
|
||||||
|
var lastDoc = resp
|
||||||
|
resp.select(PROFILE_SELECTOR).forEach {
|
||||||
|
if(it.text() == PROFILE_NAME) {
|
||||||
|
val id = it.attr("value")
|
||||||
|
//Delete old profile
|
||||||
|
lastDoc = source.execProfileActions("delete", "", id, id.toInt())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Find available profile slot
|
||||||
|
val availableProfiles = (1 .. 3).toMutableList()
|
||||||
|
lastDoc.select(PROFILE_SELECTOR).forEach {
|
||||||
|
availableProfiles.remove(it.attr("value").toInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
//No profile slots left :(
|
||||||
|
if(availableProfiles.isEmpty())
|
||||||
|
throw IllegalStateException("You are out of profile slots on ${source.name}, please delete a profile!")
|
||||||
|
|
||||||
|
//Create profile in available slot
|
||||||
|
val slot = availableProfiles.first()
|
||||||
|
source.execProfileActions("create",
|
||||||
|
PROFILE_NAME,
|
||||||
|
slot.toString(),
|
||||||
|
1)
|
||||||
|
|
||||||
|
//Build new profile
|
||||||
|
val form = EhUConfigBuilder().build(hathPerks)
|
||||||
|
|
||||||
|
//Send new profile to server
|
||||||
|
configuratorClient.newCall(source.requestWithCreds(sp = slot)
|
||||||
|
.url(source.uconfigUrl)
|
||||||
|
.post(form)
|
||||||
|
.build()).execute()
|
||||||
|
|
||||||
|
//Persist slot
|
||||||
|
source.spPref().set(slot)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val PROFILE_NAME = "TachiyomiEH App"
|
||||||
|
private const val UCONFIG_URL = "/uconfig.php"
|
||||||
|
//Always use E-H here as EXH does not have a perks page
|
||||||
|
private const val HATH_PERKS_URL = "https://e-hentai.org/hathperks.php"
|
||||||
|
private const val PROFILE_SELECTOR = "[name=profile_set] > option"
|
||||||
|
}
|
||||||
|
}
|
15
app/src/main/java/exh/uconfig/EHHathPerksResponse.kt
Normal file
15
app/src/main/java/exh/uconfig/EHHathPerksResponse.kt
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package exh.uconfig
|
||||||
|
|
||||||
|
class EHHathPerksResponse {
|
||||||
|
var moreThumbs = false
|
||||||
|
var thumbsUp = false
|
||||||
|
var allThumbs = false
|
||||||
|
|
||||||
|
var pagingEnlargementI = false
|
||||||
|
var pagingEnlargementII = false
|
||||||
|
var pagingEnlargementIII = false
|
||||||
|
|
||||||
|
override fun toString()
|
||||||
|
= "EHHathPerksResponse(moreThumbs=$moreThumbs, thumbsUp=$thumbsUp, allThumbs=$allThumbs, pagingEnlargementI=$pagingEnlargementI, pagingEnlargementII=$pagingEnlargementII, pagingEnlargementIII=$pagingEnlargementIII)"
|
||||||
|
}
|
||||||
|
|
142
app/src/main/java/exh/uconfig/EhUConfigBuilder.kt
Normal file
142
app/src/main/java/exh/uconfig/EhUConfigBuilder.kt
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
package exh.uconfig
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
|
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||||
|
import okhttp3.FormBody
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
|
class EhUConfigBuilder {
|
||||||
|
private val prefs: PreferencesHelper by injectLazy()
|
||||||
|
|
||||||
|
fun build(hathPerks: EHHathPerksResponse): FormBody {
|
||||||
|
val configItems = mutableListOf<ConfigItem>()
|
||||||
|
|
||||||
|
configItems += when(prefs.imageQuality()
|
||||||
|
.getOrDefault()
|
||||||
|
.toLowerCase()) {
|
||||||
|
"ovrs_2400" -> Entry.ImageSize.`2400`
|
||||||
|
"ovrs_1600" -> Entry.ImageSize.`1600`
|
||||||
|
"high" -> Entry.ImageSize.`1280`
|
||||||
|
"med" -> Entry.ImageSize.`980`
|
||||||
|
"low" -> Entry.ImageSize.`780`
|
||||||
|
"auto" -> Entry.ImageSize.AUTO
|
||||||
|
else -> Entry.ImageSize.AUTO
|
||||||
|
}
|
||||||
|
|
||||||
|
configItems += if(prefs.useHentaiAtHome().getOrDefault())
|
||||||
|
Entry.UseHentaiAtHome.YES
|
||||||
|
else
|
||||||
|
Entry.UseHentaiAtHome.NO
|
||||||
|
|
||||||
|
configItems += if(prefs.useJapaneseTitle().getOrDefault())
|
||||||
|
Entry.TitleDisplayLanguage.JAPANESE
|
||||||
|
else
|
||||||
|
Entry.TitleDisplayLanguage.DEFAULT
|
||||||
|
|
||||||
|
configItems += if(prefs.eh_useOriginalImages().getOrDefault())
|
||||||
|
Entry.UseOriginalImages.YES
|
||||||
|
else
|
||||||
|
Entry.UseOriginalImages.NO
|
||||||
|
|
||||||
|
configItems += when {
|
||||||
|
hathPerks.allThumbs -> Entry.ThumbnailRows.`40`
|
||||||
|
hathPerks.thumbsUp -> Entry.ThumbnailRows.`20`
|
||||||
|
hathPerks.moreThumbs -> Entry.ThumbnailRows.`10`
|
||||||
|
else -> Entry.ThumbnailRows.`4`
|
||||||
|
}
|
||||||
|
|
||||||
|
configItems += when {
|
||||||
|
hathPerks.pagingEnlargementIII -> Entry.SearchResultsCount.`200`
|
||||||
|
hathPerks.pagingEnlargementII -> Entry.SearchResultsCount.`100`
|
||||||
|
hathPerks.pagingEnlargementI -> Entry.SearchResultsCount.`50`
|
||||||
|
else -> Entry.SearchResultsCount.`25`
|
||||||
|
}
|
||||||
|
|
||||||
|
configItems += Entry.DisplayMode()
|
||||||
|
configItems += Entry.UseMPV()
|
||||||
|
configItems += Entry.ShowPopularRightNowPane()
|
||||||
|
|
||||||
|
//Actually build form body
|
||||||
|
val formBody = FormBody.Builder()
|
||||||
|
configItems.forEach {
|
||||||
|
formBody.add(it.key, it.value)
|
||||||
|
}
|
||||||
|
formBody.add("apply", "Apply")
|
||||||
|
return formBody.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Entry {
|
||||||
|
enum class UseHentaiAtHome(override val value: String): ConfigItem {
|
||||||
|
YES("0"),
|
||||||
|
NO("1");
|
||||||
|
|
||||||
|
override val key = "uh"
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class ImageSize(override val value: String): ConfigItem {
|
||||||
|
AUTO("0"),
|
||||||
|
`2400`("5"),
|
||||||
|
`1600`("4"),
|
||||||
|
`1280`("3"),
|
||||||
|
`980`("2"),
|
||||||
|
`780`("1");
|
||||||
|
|
||||||
|
override val key = "xr"
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class TitleDisplayLanguage(override val value: String): ConfigItem {
|
||||||
|
DEFAULT("0"),
|
||||||
|
JAPANESE("1");
|
||||||
|
|
||||||
|
override val key = "tl"
|
||||||
|
}
|
||||||
|
|
||||||
|
//Locked to list mode as that's what the parser and toplists use
|
||||||
|
class DisplayMode: ConfigItem {
|
||||||
|
override val key = "dm"
|
||||||
|
override val value = "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class SearchResultsCount(override val value: String): ConfigItem {
|
||||||
|
`25`("0"),
|
||||||
|
`50`("1"),
|
||||||
|
`100`("2"),
|
||||||
|
`200`("3");
|
||||||
|
|
||||||
|
override val key = "rc"
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class ThumbnailRows(override val value: String): ConfigItem {
|
||||||
|
`4`("0"),
|
||||||
|
`10`("1"),
|
||||||
|
`20`("2"),
|
||||||
|
`40`("3");
|
||||||
|
|
||||||
|
override val key = "tr"
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class UseOriginalImages(override val value: String): ConfigItem {
|
||||||
|
NO("0"),
|
||||||
|
YES("1");
|
||||||
|
|
||||||
|
override val key = "oi"
|
||||||
|
}
|
||||||
|
|
||||||
|
//Locked to no MPV as that's what the parser uses
|
||||||
|
class UseMPV: ConfigItem {
|
||||||
|
override val key = "qb"
|
||||||
|
override val value = "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
//Locked to no popular pane as we can't parse it
|
||||||
|
class ShowPopularRightNowPane: ConfigItem {
|
||||||
|
override val key = "pp"
|
||||||
|
override val value = "1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ConfigItem {
|
||||||
|
val key: String
|
||||||
|
val value: String
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user