Delegate NHentai, to continue using NHentai download the extension, SY requires NHentai version 1.2.28
This commit is contained in:
parent
5a1bc6e25b
commit
3fa5322133
@ -187,8 +187,6 @@ object PreferenceKeys {
|
||||
|
||||
const val eh_lock_manually = "eh_lock_manually"
|
||||
|
||||
const val eh_nh_useHighQualityThumbs = "eh_nh_hq_thumbs"
|
||||
|
||||
const val eh_showSyncIntro = "eh_show_sync_intro"
|
||||
|
||||
const val eh_readOnlySync = "eh_sync_read_only"
|
||||
|
@ -312,8 +312,6 @@ class PreferencesHelper(val context: Context) {
|
||||
fun eh_sessionCookie() = flowPrefs.getString(Keys.eh_sessionCookie, "")
|
||||
fun eh_hathPerksCookies() = flowPrefs.getString(Keys.eh_hathPerksCookie, "")
|
||||
|
||||
fun eh_nh_useHighQualityThumbs() = flowPrefs.getBoolean(Keys.eh_nh_useHighQualityThumbs, false)
|
||||
|
||||
fun eh_showSyncIntro() = flowPrefs.getBoolean(Keys.eh_showSyncIntro, true)
|
||||
|
||||
fun eh_readOnlySync() = flowPrefs.getBoolean(Keys.eh_readOnlySync, false)
|
||||
|
@ -21,7 +21,6 @@ import eu.kanade.tachiyomi.util.system.toast
|
||||
import exh.EH_SOURCE_ID
|
||||
import exh.EXH_SOURCE_ID
|
||||
import exh.MERGED_SOURCE_ID
|
||||
import exh.NHENTAI_SOURCE_ID
|
||||
import exh.source.BlacklistedSources
|
||||
import kotlinx.coroutines.async
|
||||
import rx.Observable
|
||||
@ -79,7 +78,6 @@ class ExtensionManager(
|
||||
return when (source.id) {
|
||||
EH_SOURCE_ID -> context.getDrawable(R.mipmap.ic_ehentai_source)
|
||||
EXH_SOURCE_ID -> context.getDrawable(R.mipmap.ic_ehentai_source)
|
||||
NHENTAI_SOURCE_ID -> context.getDrawable(R.mipmap.ic_nhentai_source)
|
||||
MERGED_SOURCE_ID -> context.getDrawable(R.mipmap.ic_merged_source)
|
||||
else -> null
|
||||
}
|
||||
|
@ -140,7 +140,6 @@ open class SourceManager(private val context: Context) {
|
||||
if (prefs.enableExhentai().get()) {
|
||||
exSrcs += EHentai(EXH_SOURCE_ID, true, context)
|
||||
}
|
||||
exSrcs += NHentai(context)
|
||||
return exSrcs
|
||||
}
|
||||
// SY <--
|
||||
@ -230,6 +229,13 @@ open class SourceManager(private val context: Context) {
|
||||
PERV_EDEN_IT_SOURCE_ID,
|
||||
"eu.kanade.tachiyomi.extension.it.perveden.Perveden",
|
||||
PervEden::class
|
||||
),
|
||||
DelegatedSource(
|
||||
"NHentai",
|
||||
fillInSourceId,
|
||||
"eu.kanade.tachiyomi.extension.all.nhentai.NHentai",
|
||||
NHentai::class,
|
||||
true
|
||||
)
|
||||
).associateBy { it.originalSourceQualifiedClassName }
|
||||
|
||||
|
301
app/src/main/java/eu/kanade/tachiyomi/source/online/all/NHentai.kt
Executable file → Normal file
301
app/src/main/java/eu/kanade/tachiyomi/source/online/all/NHentai.kt
Executable file → Normal file
@ -8,116 +8,38 @@ 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.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
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import exh.NHENTAI_SOURCE_ID
|
||||
import exh.metadata.metadata.NHentaiSearchMetadata
|
||||
import exh.metadata.metadata.NHentaiSearchMetadata.Companion.TAG_TYPE_DEFAULT
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.TAG_TYPE_VIRTUAL
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||
import exh.metadata.metadata.base.RaisedTag
|
||||
import exh.source.DelegatedHttpSource
|
||||
import exh.ui.metadata.adapters.NHentaiDescriptionAdapter
|
||||
import exh.util.urlImportFetchSearchManga
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import rx.Observable
|
||||
|
||||
/**
|
||||
* NHentai source
|
||||
*/
|
||||
|
||||
class NHentai(val context: Context) : HttpSource(), LewdSource<NHentaiSearchMetadata, Response>, UrlImportableSource {
|
||||
open class NHentai(delegate: HttpSource, val context: Context) :
|
||||
DelegatedHttpSource(delegate),
|
||||
LewdSource<NHentaiSearchMetadata, Response>,
|
||||
UrlImportableSource {
|
||||
override val metaClass = NHentaiSearchMetadata::class
|
||||
|
||||
override fun fetchPopularManga(page: Int): Observable<MangasPage> {
|
||||
// TODO There is currently no way to get the most popular mangas
|
||||
// TODO Instead, we delegate this to the latest updates thing to avoid confusing users with an empty screen
|
||||
return fetchLatestUpdates(page)
|
||||
}
|
||||
|
||||
override fun popularMangaRequest(page: Int) = throw UnsupportedOperationException()
|
||||
|
||||
override fun popularMangaParse(response: Response) = throw UnsupportedOperationException()
|
||||
override val lang = if (delegate.lang == "other") "all" else delegate.lang
|
||||
override val id: Long
|
||||
get() = if (delegate.lang == "other") otherId else delegate.id
|
||||
|
||||
// Support direct URL importing
|
||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
||||
val trimmedIdQuery = query.trim().removePrefix("id:")
|
||||
val newQuery = if (trimmedIdQuery.toIntOrNull() ?: -1 >= 0) {
|
||||
"$baseUrl/g/$trimmedIdQuery/"
|
||||
} else query
|
||||
|
||||
return urlImportFetchSearchManga(context, newQuery) {
|
||||
searchMangaRequestObservable(page, query, filters).flatMap {
|
||||
client.newCall(it).asObservableSuccess()
|
||||
}.map { response ->
|
||||
searchMangaParse(response)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun searchMangaRequestObservable(page: Int, query: String, filters: FilterList): Observable<Request> {
|
||||
val filterList = if (filters.isEmpty()) getFilterList() else filters
|
||||
val advQuery = combineQuery(filterList)
|
||||
val favoriteFilter = filterList.findInstance<FavoriteFilter>()
|
||||
val isOkayToSort = filterList.findInstance<UploadedFilter>()?.state?.isBlank() ?: true
|
||||
|
||||
val url: HttpUrl.Builder
|
||||
|
||||
if (favoriteFilter?.state == true) {
|
||||
url = "$baseUrl/favorites".toHttpUrlOrNull()!!.newBuilder()
|
||||
.addQueryParameter("q", "$query $advQuery")
|
||||
.addQueryParameter("page", page.toString())
|
||||
} else {
|
||||
url = "$baseUrl/search".toHttpUrlOrNull()!!.newBuilder()
|
||||
.addQueryParameter("q", "$query $advQuery")
|
||||
.addQueryParameter("page", page.toString())
|
||||
|
||||
if (isOkayToSort) {
|
||||
filterList.findInstance<SortFilter>()?.let { f ->
|
||||
url.addQueryParameter("sort", f.toUriPart())
|
||||
}
|
||||
}
|
||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> =
|
||||
urlImportFetchSearchManga(context, query) {
|
||||
super.fetchSearchManga(page, query, filters)
|
||||
}
|
||||
|
||||
return client.newCall(nhGet(url.toString()))
|
||||
.asObservableSuccess()
|
||||
.map { nhGet(url.toString(), page) }
|
||||
}
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList) = throw UnsupportedOperationException()
|
||||
|
||||
override fun searchMangaParse(response: Response) = parseResultPage(response)
|
||||
|
||||
override fun latestUpdatesRequest(page: Int): Request {
|
||||
val uri = Uri.parse(baseUrl).buildUpon()
|
||||
uri.appendQueryParameter("page", page.toString())
|
||||
return nhGet(uri.toString(), page)
|
||||
}
|
||||
|
||||
override fun latestUpdatesParse(response: Response) = parseResultPage(response)
|
||||
|
||||
override fun mangaDetailsParse(response: Response) = throw UnsupportedOperationException()
|
||||
|
||||
/**
|
||||
* Returns an observable with the updated details for a manga. Normally it's not needed to
|
||||
* override this method.
|
||||
*
|
||||
* @param manga the manga to be updated.
|
||||
*/
|
||||
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
|
||||
return client.newCall(mangaDetailsRequest(manga))
|
||||
.asObservableSuccess()
|
||||
@ -132,37 +54,10 @@ class NHentai(val context: Context) : HttpSource(), LewdSource<NHentaiSearchMeta
|
||||
}
|
||||
}
|
||||
|
||||
override fun mangaDetailsRequest(manga: SManga) = nhGet(baseUrl + manga.url)
|
||||
|
||||
private fun parseResultPage(response: Response): MangasPage {
|
||||
val doc = response.asJsoup()
|
||||
|
||||
// TODO Parse lang + tags
|
||||
|
||||
val mangas = doc.select(".gallery > a").map {
|
||||
SManga.create().apply {
|
||||
url = it.attr("href")
|
||||
|
||||
title = it.selectFirst(".caption").text()
|
||||
|
||||
// last() is a hack to ignore the lazy-loader placeholder image on the front page
|
||||
thumbnail_url = it.select("img").last().attr("src")
|
||||
// In some pages, the thumbnail url does not include the protocol
|
||||
if (!thumbnail_url!!.startsWith("https:")) thumbnail_url = "https:$thumbnail_url"
|
||||
}
|
||||
}
|
||||
|
||||
val hasNextPage = if (!response.request.url.queryParameterNames.contains(REVERSE_PARAM)) {
|
||||
doc.selectFirst(".next") != null
|
||||
} else {
|
||||
response.request.url.queryParameter(REVERSE_PARAM)!!.toBoolean()
|
||||
}
|
||||
|
||||
return MangasPage(mangas, hasNextPage)
|
||||
}
|
||||
|
||||
override fun parseIntoMetadata(metadata: NHentaiSearchMetadata, input: Response) {
|
||||
val json = GALLERY_JSON_REGEX.find(input.body!!.string())!!.groupValues[1].replace(UNICODE_ESCAPE_REGEX) { it.groupValues[1].toInt(radix = 16).toChar().toString() }
|
||||
val json = GALLERY_JSON_REGEX.find(input.body!!.string())!!.groupValues[1].replace(
|
||||
UNICODE_ESCAPE_REGEX
|
||||
) { it.groupValues[1].toInt(radix = 16).toChar().toString() }
|
||||
val obj = JsonParser.parseString(json).asJsonObject
|
||||
|
||||
with(metadata) {
|
||||
@ -199,166 +94,12 @@ class NHentai(val context: Context) : HttpSource(), LewdSource<NHentaiSearchMeta
|
||||
tags.clear()
|
||||
}?.forEach {
|
||||
if (it.first != null && it.second != null) {
|
||||
tags.add(RaisedTag(it.first!!, it.second!!, if (it.first == "category") TAG_TYPE_VIRTUAL else TAG_TYPE_DEFAULT))
|
||||
tags.add(RaisedTag(it.first!!, it.second!!, if (it.first == "category") RaisedSearchMetadata.TAG_TYPE_VIRTUAL else NHentaiSearchMetadata.TAG_TYPE_DEFAULT))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getOrLoadMetadata(mangaId: Long?, nhId: Long) = getOrLoadMetadata(mangaId) {
|
||||
client.newCall(nhGet(baseUrl + NHentaiSearchMetadata.nhIdToPath(nhId)))
|
||||
.asObservableSuccess()
|
||||
.toSingle()
|
||||
}
|
||||
|
||||
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> = Observable.just(
|
||||
listOf(
|
||||
SChapter.create().apply {
|
||||
url = manga.url
|
||||
name = "Chapter"
|
||||
chapter_number = 1f
|
||||
getOrLoadMetadata(mangaId, NHentaiSearchMetadata.nhUrlToId(manga.url)).toBlocking().value().uploadDate?.let { date_upload = it * 1000 }
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
override fun fetchPageList(chapter: SChapter): Observable<List<Page>> = getOrLoadMetadata(chapter.mangaId, NHentaiSearchMetadata.nhUrlToId(chapter.url)).map { metadata ->
|
||||
if (metadata.mediaId == null) {
|
||||
emptyList()
|
||||
} else {
|
||||
metadata.pageImageTypes.mapIndexed { index, s ->
|
||||
val imageUrl = imageUrlFromType(metadata.mediaId!!, index + 1, s)
|
||||
Page(index, imageUrl!!, imageUrl)
|
||||
}
|
||||
}
|
||||
}.toObservable()
|
||||
|
||||
override fun fetchImageUrl(page: Page) = Observable.just(page.imageUrl!!)!!
|
||||
|
||||
private fun imageUrlFromType(mediaId: String, page: Int, t: String) = NHentaiSearchMetadata.typeToExtension(t)?.let {
|
||||
"https://i.nhentai.net/galleries/$mediaId/$page.$it"
|
||||
}
|
||||
|
||||
override fun chapterListParse(response: Response): List<SChapter> {
|
||||
throw NotImplementedError("Unused method called!")
|
||||
}
|
||||
|
||||
override fun pageListParse(response: Response): List<Page> {
|
||||
throw NotImplementedError("Unused method called!")
|
||||
}
|
||||
|
||||
override fun imageUrlParse(response: Response): String {
|
||||
throw NotImplementedError("Unused method called!")
|
||||
}
|
||||
|
||||
private fun combineQuery(filters: FilterList): String {
|
||||
val stringBuilder = StringBuilder()
|
||||
val advSearch = filters.filterIsInstance<AdvSearchEntryFilter>().flatMap { filter ->
|
||||
val splitState = filter.state.split(",").map(String::trim).filterNot(String::isBlank)
|
||||
splitState.map {
|
||||
AdvSearchEntry(filter.name, it.removePrefix("-"), it.startsWith("-"))
|
||||
}
|
||||
}
|
||||
|
||||
advSearch.forEach { entry ->
|
||||
if (entry.exclude) stringBuilder.append("-")
|
||||
stringBuilder.append("${entry.name}:")
|
||||
stringBuilder.append(entry.text)
|
||||
stringBuilder.append(" ")
|
||||
}
|
||||
|
||||
val langFilter = filters.filterIsInstance<FilterLang>().firstOrNull()
|
||||
if (langFilter != null) {
|
||||
val language = SOURCE_LANG_LIST.first { it.first == langFilter.values[langFilter.state] }.second
|
||||
if (!language.isBlank()) {
|
||||
stringBuilder.append("language:$language")
|
||||
}
|
||||
}
|
||||
|
||||
return stringBuilder.toString()
|
||||
}
|
||||
|
||||
data class AdvSearchEntry(val name: String, val text: String, val exclude: Boolean)
|
||||
|
||||
override fun getFilterList(): FilterList = FilterList(
|
||||
Filter.Header("Separate tags with commas (,)"),
|
||||
Filter.Header("Prepend with dash (-) to exclude"),
|
||||
TagFilter(),
|
||||
CategoryFilter(),
|
||||
GroupFilter(),
|
||||
ArtistFilter(),
|
||||
ParodyFilter(),
|
||||
CharactersFilter(),
|
||||
Filter.Header("Uploaded valid units are h, d, w, m, y."),
|
||||
Filter.Header("example: (>20d)"),
|
||||
UploadedFilter(),
|
||||
|
||||
Filter.Separator(),
|
||||
SortFilter(),
|
||||
Filter.Header("Sort is ignored if favorites only"),
|
||||
FavoriteFilter(),
|
||||
FilterLang()
|
||||
)
|
||||
|
||||
class TagFilter : AdvSearchEntryFilter("Tags")
|
||||
class CategoryFilter : AdvSearchEntryFilter("Categories")
|
||||
class GroupFilter : AdvSearchEntryFilter("Groups")
|
||||
class ArtistFilter : AdvSearchEntryFilter("Artists")
|
||||
class ParodyFilter : AdvSearchEntryFilter("Parodies")
|
||||
class CharactersFilter : AdvSearchEntryFilter("Characters")
|
||||
class UploadedFilter : AdvSearchEntryFilter("Uploaded")
|
||||
open class AdvSearchEntryFilter(name: String) : Filter.Text(name)
|
||||
|
||||
private class FavoriteFilter : Filter.CheckBox("Show favorites only", false)
|
||||
|
||||
// language filtering
|
||||
private class FilterLang : Filter.Select<String>("Language", SOURCE_LANG_LIST.map { it.first }.toTypedArray())
|
||||
|
||||
private class SortFilter : UriPartFilter(
|
||||
"Sort By",
|
||||
arrayOf(
|
||||
Pair("Popular: All Time", "popular"),
|
||||
Pair("Popular: Week", "popular-week"),
|
||||
Pair("Popular: Today", "popular-today"),
|
||||
Pair("Recent", "date")
|
||||
)
|
||||
)
|
||||
|
||||
private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) :
|
||||
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
|
||||
fun toUriPart() = vals[state].second
|
||||
}
|
||||
|
||||
private inline fun <reified T> Iterable<*>.findInstance() = find { it is T } as? T
|
||||
|
||||
private val appName by lazy {
|
||||
context.getString(R.string.app_name)
|
||||
}
|
||||
|
||||
private fun nhGet(url: String, tag: Any? = null) = GET(url)
|
||||
.newBuilder()
|
||||
.header(
|
||||
"User-Agent",
|
||||
"Mozilla/5.0 (X11; Linux x86_64) " +
|
||||
"AppleWebKit/537.36 (KHTML, like Gecko) " +
|
||||
"Chrome/56.0.2924.87 " +
|
||||
"Safari/537.36 " +
|
||||
"$appName/${BuildConfig.VERSION_CODE}"
|
||||
)
|
||||
.tag(tag).build()
|
||||
|
||||
override val id = NHENTAI_SOURCE_ID
|
||||
|
||||
override val lang = "all"
|
||||
|
||||
override val name = "nhentai"
|
||||
|
||||
override val baseUrl = NHentaiSearchMetadata.BASE_URL
|
||||
|
||||
override val supportsLatest = true
|
||||
|
||||
// === URL IMPORT STUFF
|
||||
|
||||
override val matchingHosts = listOf(
|
||||
"nhentai.net"
|
||||
)
|
||||
@ -376,15 +117,9 @@ class NHentai(val context: Context) : HttpSource(), LewdSource<NHentaiSearchMeta
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val otherId = 7309872737163460316L
|
||||
|
||||
private val GALLERY_JSON_REGEX = Regex(".parse\\(\"(.*)\"\\);")
|
||||
private val UNICODE_ESCAPE_REGEX = Regex("\\\\u([0-9a-fA-F]{4})")
|
||||
private const val REVERSE_PARAM = "TEH_REVERSE"
|
||||
|
||||
private val SOURCE_LANG_LIST = listOf(
|
||||
Pair("All", ""),
|
||||
Pair("English", "english"),
|
||||
Pair("Japanese", "japanese"),
|
||||
Pair("Chinese", "chinese")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -45,9 +45,11 @@ import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import exh.EH_SOURCE_ID
|
||||
import exh.EXH_SOURCE_ID
|
||||
import exh.NHENTAI_SOURCE_ID
|
||||
import exh.PERV_EDEN_EN_SOURCE_ID
|
||||
import exh.PERV_EDEN_IT_SOURCE_ID
|
||||
import exh.favorites.FavoritesIntroDialog
|
||||
import exh.favorites.FavoritesSyncStatus
|
||||
import exh.nHentaiSourceIds
|
||||
import exh.ui.LoaderManager
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlinx.android.synthetic.main.main_activity.tabs
|
||||
@ -521,7 +523,7 @@ class LibraryController(
|
||||
binding.actionToolbar.findItem(R.id.action_download_unread)?.isVisible = selectedMangas.any { it.source != LocalSource.ID }
|
||||
|
||||
// SY -->
|
||||
binding.actionToolbar.findItem(R.id.action_clean)?.isVisible = selectedMangas.any { it.source == EH_SOURCE_ID || it.source == EXH_SOURCE_ID || it.source == NHENTAI_SOURCE_ID }
|
||||
binding.actionToolbar.findItem(R.id.action_clean)?.isVisible = selectedMangas.any { it.source == EH_SOURCE_ID || it.source == EXH_SOURCE_ID || it.source in nHentaiSourceIds || it.source == PERV_EDEN_EN_SOURCE_ID || it.source == PERV_EDEN_IT_SOURCE_ID }
|
||||
// SY <--
|
||||
}
|
||||
return false
|
||||
@ -640,7 +642,7 @@ class LibraryController(
|
||||
|
||||
// SY -->
|
||||
private fun cleanTitles() {
|
||||
val mangas = selectedMangas.filter { it.source == EH_SOURCE_ID || it.source == EXH_SOURCE_ID || it.source == NHENTAI_SOURCE_ID }.toList()
|
||||
val mangas = selectedMangas.filter { it.source == EH_SOURCE_ID || it.source == EXH_SOURCE_ID || it.source in nHentaiSourceIds }.toList()
|
||||
presenter.cleanTitles(mangas)
|
||||
destroyActionModeIfNeeded()
|
||||
}
|
||||
|
@ -44,7 +44,6 @@ import eu.kanade.tachiyomi.util.lang.launchUI
|
||||
import exh.EH_SOURCE_ID
|
||||
import exh.EXHMigrations
|
||||
import exh.EXH_SOURCE_ID
|
||||
import exh.NHENTAI_SOURCE_ID
|
||||
import exh.eh.EHentaiUpdateWorker
|
||||
import exh.source.BlacklistedSources
|
||||
import exh.uconfig.WarnConfigureDialogController
|
||||
@ -209,9 +208,6 @@ class MainActivity : BaseActivity<MainActivityBinding>() {
|
||||
if (EXH_SOURCE_ID !in BlacklistedSources.HIDDEN_SOURCES) {
|
||||
BlacklistedSources.HIDDEN_SOURCES += EXH_SOURCE_ID
|
||||
}
|
||||
if (NHENTAI_SOURCE_ID !in BlacklistedSources.HIDDEN_SOURCES) {
|
||||
BlacklistedSources.HIDDEN_SOURCES += NHENTAI_SOURCE_ID
|
||||
}
|
||||
}
|
||||
// SY -->
|
||||
|
||||
|
@ -38,7 +38,6 @@ import eu.kanade.tachiyomi.util.system.powerManager
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import exh.EH_SOURCE_ID
|
||||
import exh.EXH_SOURCE_ID
|
||||
import exh.NHENTAI_SOURCE_ID
|
||||
import exh.debug.SettingsDebugController
|
||||
import exh.log.EHLogLevel
|
||||
import exh.source.BlacklistedSources
|
||||
@ -177,9 +176,6 @@ class SettingsAdvancedController : SettingsController() {
|
||||
if (EXH_SOURCE_ID !in BlacklistedSources.HIDDEN_SOURCES) {
|
||||
BlacklistedSources.HIDDEN_SOURCES += EXH_SOURCE_ID
|
||||
}
|
||||
if (NHENTAI_SOURCE_ID !in BlacklistedSources.HIDDEN_SOURCES) {
|
||||
BlacklistedSources.HIDDEN_SOURCES += NHENTAI_SOURCE_ID
|
||||
}
|
||||
} else {
|
||||
if (EH_SOURCE_ID in BlacklistedSources.HIDDEN_SOURCES) {
|
||||
BlacklistedSources.HIDDEN_SOURCES -= EH_SOURCE_ID
|
||||
@ -187,9 +183,6 @@ class SettingsAdvancedController : SettingsController() {
|
||||
if (EXH_SOURCE_ID in BlacklistedSources.HIDDEN_SOURCES) {
|
||||
BlacklistedSources.HIDDEN_SOURCES -= EXH_SOURCE_ID
|
||||
}
|
||||
if (NHENTAI_SOURCE_ID in BlacklistedSources.HIDDEN_SOURCES) {
|
||||
BlacklistedSources.HIDDEN_SOURCES -= NHENTAI_SOURCE_ID
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
@ -73,12 +73,6 @@ class SettingsMainController : SettingsController() {
|
||||
titleRes = R.string.pref_category_eh
|
||||
onClick { navigateTo(SettingsEhController()) }
|
||||
}
|
||||
preference {
|
||||
iconRes = R.drawable.eh_ic_nhlogo_color
|
||||
iconTint = tintColor
|
||||
titleRes = R.string.pref_category_nh
|
||||
onClick { navigateTo(SettingsNhController()) }
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
preference {
|
||||
|
@ -1,26 +0,0 @@
|
||||
package eu.kanade.tachiyomi.ui.setting
|
||||
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys
|
||||
import eu.kanade.tachiyomi.util.preference.defaultValue
|
||||
import eu.kanade.tachiyomi.util.preference.summaryRes
|
||||
import eu.kanade.tachiyomi.util.preference.switchPreference
|
||||
import eu.kanade.tachiyomi.util.preference.titleRes
|
||||
|
||||
/**
|
||||
* nhentai Settings fragment
|
||||
*/
|
||||
|
||||
class SettingsNhController : SettingsController() {
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) = with(screen) {
|
||||
titleRes = R.string.pref_category_nh
|
||||
|
||||
switchPreference {
|
||||
titleRes = R.string.high_quality_thumbnails
|
||||
summaryRes = R.string.high_quality_thumbnails_summary
|
||||
key = PreferenceKeys.eh_nh_useHighQualityThumbs
|
||||
defaultValue = false
|
||||
}
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ package exh
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.online.all.Hitomi
|
||||
import eu.kanade.tachiyomi.source.online.all.NHentai
|
||||
import eu.kanade.tachiyomi.source.online.all.PervEden
|
||||
import eu.kanade.tachiyomi.source.online.english.EightMuses
|
||||
import eu.kanade.tachiyomi.source.online.english.HBrowse
|
||||
@ -20,7 +21,6 @@ const val EH_SOURCE_ID = LEWD_SOURCE_SERIES + 1
|
||||
const val EXH_SOURCE_ID = LEWD_SOURCE_SERIES + 2
|
||||
const val PERV_EDEN_EN_SOURCE_ID = 4673633799850248749
|
||||
const val PERV_EDEN_IT_SOURCE_ID = 1433898225963724122
|
||||
const val NHENTAI_SOURCE_ID = LEWD_SOURCE_SERIES + 7
|
||||
const val HENTAI_CAFE_SOURCE_ID = 260868874183818481
|
||||
const val PURURIN_SOURCE_ID = 2221515250486218861
|
||||
const val TSUMINO_SOURCE_ID = 6707338697138388238
|
||||
@ -35,10 +35,12 @@ private val DELEGATED_LEWD_SOURCES = listOf(
|
||||
HBrowse::class,
|
||||
EightMuses::class,
|
||||
Hitomi::class,
|
||||
PervEden::class
|
||||
PervEden::class,
|
||||
NHentai::class
|
||||
)
|
||||
|
||||
private val hitomiClass = listOf(Hitomi::class)
|
||||
private val nHentaiClass = listOf(NHentai::class)
|
||||
|
||||
// Used to speed up isLewdSource
|
||||
val lewdDelegatedSourceIds = SourceManager.currentDelegatedSources.filter {
|
||||
@ -49,6 +51,10 @@ val hitomiSourceIds = SourceManager.currentDelegatedSources.filter {
|
||||
it.value.newSourceClass in hitomiClass
|
||||
}.map { it.value.sourceId }.sorted()
|
||||
|
||||
val nHentaiSourceIds = SourceManager.currentDelegatedSources.filter {
|
||||
it.value.newSourceClass in nHentaiClass
|
||||
}.map { it.value.sourceId }.sorted()
|
||||
|
||||
// This method MUST be fast!
|
||||
fun isLewdSource(source: Long) = source in 6900..6999 ||
|
||||
lewdDelegatedSourceIds.binarySearch(source) >= 0
|
||||
@ -56,13 +62,13 @@ fun isLewdSource(source: Long) = source in 6900..6999 ||
|
||||
val LIBRARY_UPDATE_EXCLUDED_SOURCES = listOf(
|
||||
EH_SOURCE_ID,
|
||||
EXH_SOURCE_ID,
|
||||
NHENTAI_SOURCE_ID,
|
||||
HENTAI_CAFE_SOURCE_ID,
|
||||
TSUMINO_SOURCE_ID,
|
||||
PURURIN_SOURCE_ID,
|
||||
*hitomiSourceIds.toTypedArray()
|
||||
*hitomiSourceIds.toTypedArray(),
|
||||
*nHentaiSourceIds.toTypedArray()
|
||||
)
|
||||
|
||||
fun Source.isEhBasedSource() = id == EH_SOURCE_ID || id == EXH_SOURCE_ID
|
||||
|
||||
fun Source.isNamespaceSource() = id == EH_SOURCE_ID || id == EXH_SOURCE_ID || id == NHENTAI_SOURCE_ID || id in hitomiSourceIds || id == PURURIN_SOURCE_ID || id == TSUMINO_SOURCE_ID || id == EIGHTMUSES_SOURCE_ID || id == HBROWSE_SOURCE_ID
|
||||
fun Source.isNamespaceSource() = id == EH_SOURCE_ID || id == EXH_SOURCE_ID || id in nHentaiSourceIds || id in hitomiSourceIds || id == PURURIN_SOURCE_ID || id == TSUMINO_SOURCE_ID || id == EIGHTMUSES_SOURCE_ID || id == HBROWSE_SOURCE_ID
|
||||
|
@ -18,6 +18,7 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.updater.UpdaterJob
|
||||
import eu.kanade.tachiyomi.extension.ExtensionUpdateJob
|
||||
import eu.kanade.tachiyomi.source.online.all.Hitomi
|
||||
import eu.kanade.tachiyomi.source.online.all.NHentai
|
||||
import exh.source.BlacklistedSources
|
||||
import java.io.File
|
||||
import java.net.URI
|
||||
@ -128,10 +129,22 @@ object EXHMigrations {
|
||||
.affectsTables(MangaTable.TABLE)
|
||||
.build()
|
||||
)
|
||||
db.lowLevel().executeSQL(
|
||||
RawQuery.builder()
|
||||
.query(
|
||||
"""
|
||||
UPDATE ${MangaTable.TABLE}
|
||||
SET ${MangaTable.COL_SOURCE} = ${NHentai.otherId}
|
||||
WHERE ${MangaTable.COL_SOURCE} = 6907
|
||||
""".trimIndent()
|
||||
)
|
||||
.affectsTables(MangaTable.TABLE)
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// if (oldVersion < 1) { }
|
||||
// if (oldVersion < 1) { } (1 is current release version)
|
||||
// do stuff here when releasing changed crap
|
||||
|
||||
// TODO BE CAREFUL TO NOT FUCK UP MergedSources IF CHANGING URLs
|
||||
@ -155,6 +168,13 @@ object EXHMigrations {
|
||||
manga.source = PERV_EDEN_IT_SOURCE_ID
|
||||
}
|
||||
|
||||
if (manga.source == 6907L) {
|
||||
// Migrate the old source to the delegated one
|
||||
manga.source = NHentai.otherId
|
||||
// Migrate nhentai URLs
|
||||
manga.url = getUrlWithoutDomain(manga.url)
|
||||
}
|
||||
|
||||
// Migrate HentaiCafe source IDs
|
||||
if (manga.source == 6908L) {
|
||||
manga.source = HENTAI_CAFE_SOURCE_ID
|
||||
@ -173,16 +193,6 @@ object EXHMigrations {
|
||||
manga.source = HBROWSE_SOURCE_ID
|
||||
}
|
||||
|
||||
// Migrate nhentai URLs
|
||||
if (manga.source == NHENTAI_SOURCE_ID) {
|
||||
manga.url = getUrlWithoutDomain(manga.url)
|
||||
}
|
||||
|
||||
// Allow importing of nhentai extension backups
|
||||
if (manga.source in BlacklistedSources.NHENTAI_EXT_SOURCES) {
|
||||
manga.source = NHENTAI_SOURCE_ID
|
||||
}
|
||||
|
||||
// Allow importing of EHentai extension backups
|
||||
if (manga.source in BlacklistedSources.EHENTAI_EXT_SOURCES) {
|
||||
manga.source = EH_SOURCE_ID
|
||||
|
@ -2,13 +2,11 @@ package exh.metadata.metadata
|
||||
|
||||
import android.content.Context
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import exh.metadata.EX_DATE_FORMAT
|
||||
import exh.metadata.ONGOING_SUFFIX
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||
import java.util.Date
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class NHentaiSearchMetadata : RaisedSearchMetadata() {
|
||||
@ -41,13 +39,8 @@ class NHentaiSearchMetadata : RaisedSearchMetadata() {
|
||||
nhId?.let { manga.url = nhIdToPath(it) }
|
||||
|
||||
if (mediaId != null) {
|
||||
val hqThumbs = Injekt.get<PreferencesHelper>().eh_nh_useHighQualityThumbs().get()
|
||||
typeToExtension(if (hqThumbs) coverImageType else thumbnailImageType)?.let {
|
||||
manga.thumbnail_url = "https://t.nhentai.net/galleries/$mediaId/${if (hqThumbs) {
|
||||
"cover"
|
||||
} else {
|
||||
"thumb"
|
||||
}}.$it"
|
||||
typeToExtension(coverImageType)?.let {
|
||||
manga.thumbnail_url = "https://t.nhentai.net/galleries/$mediaId/cover.$it"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,11 +3,6 @@ package exh.source
|
||||
import exh.MERGED_SOURCE_ID
|
||||
|
||||
object BlacklistedSources {
|
||||
val NHENTAI_EXT_SOURCES = listOf(
|
||||
3122156392225024195,
|
||||
4726175775739752699,
|
||||
2203215402871965477
|
||||
)
|
||||
val EHENTAI_EXT_SOURCES = listOf(
|
||||
8100626124886895451,
|
||||
57122881048805941,
|
||||
@ -28,12 +23,10 @@ object BlacklistedSources {
|
||||
6140480779421365791
|
||||
)
|
||||
|
||||
val BLACKLISTED_EXT_SOURCES = NHENTAI_EXT_SOURCES +
|
||||
EHENTAI_EXT_SOURCES
|
||||
val BLACKLISTED_EXT_SOURCES = EHENTAI_EXT_SOURCES
|
||||
|
||||
val BLACKLISTED_EXTENSIONS = listOf(
|
||||
"eu.kanade.tachiyomi.extension.all.ehentai",
|
||||
"eu.kanade.tachiyomi.extension.all.nhentai"
|
||||
"eu.kanade.tachiyomi.extension.all.ehentai"
|
||||
)
|
||||
|
||||
var HIDDEN_SOURCES = listOf(
|
||||
|
@ -4,7 +4,7 @@ import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import exh.EH_SOURCE_ID
|
||||
import exh.EXH_SOURCE_ID
|
||||
import exh.NHENTAI_SOURCE_ID
|
||||
import exh.nHentaiSourceIds
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
@ -12,7 +12,7 @@ fun Manga.isLewd(): Boolean {
|
||||
val sourceName = Injekt.get<SourceManager>().get(source)?.name
|
||||
val currentTags = getGenres() ?: emptyList()
|
||||
|
||||
if (source == EH_SOURCE_ID || source == EXH_SOURCE_ID || source == NHENTAI_SOURCE_ID) {
|
||||
if (source == EH_SOURCE_ID || source == EXH_SOURCE_ID || source in nHentaiSourceIds) {
|
||||
return !currentTags.any { tag -> isNonHentaiTag(tag) }
|
||||
}
|
||||
|
||||
|
@ -3,21 +3,21 @@ package exh.util
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import exh.EH_SOURCE_ID
|
||||
import exh.EXH_SOURCE_ID
|
||||
import exh.NHENTAI_SOURCE_ID
|
||||
import exh.PURURIN_SOURCE_ID
|
||||
import exh.TSUMINO_SOURCE_ID
|
||||
import exh.hitomiSourceIds
|
||||
import exh.metadata.metadata.base.RaisedTag
|
||||
import exh.nHentaiSourceIds
|
||||
import java.util.Locale
|
||||
|
||||
class SourceTagsUtil {
|
||||
fun getWrappedTag(sourceId: Long, namespace: String? = null, tag: String? = null, fullTag: String? = null): String? {
|
||||
return if (sourceId == EXH_SOURCE_ID || sourceId == EH_SOURCE_ID || sourceId == NHENTAI_SOURCE_ID || sourceId in hitomiSourceIds) {
|
||||
return if (sourceId == EXH_SOURCE_ID || sourceId == EH_SOURCE_ID || sourceId in nHentaiSourceIds || sourceId in hitomiSourceIds) {
|
||||
val parsed = if (fullTag != null) parseTag(fullTag) else if (namespace != null && tag != null) RaisedTag(namespace, tag, TAG_TYPE_DEFAULT) else null
|
||||
if (parsed?.namespace != null) {
|
||||
when (sourceId) {
|
||||
in hitomiSourceIds -> wrapTagHitomi(parsed.namespace, parsed.name.substringBefore('|').trim())
|
||||
NHENTAI_SOURCE_ID -> wrapTagNHentai(parsed.namespace, parsed.name.substringBefore('|').trim())
|
||||
in nHentaiSourceIds -> wrapTagNHentai(parsed.namespace, parsed.name.substringBefore('|').trim())
|
||||
PURURIN_SOURCE_ID -> parsed.name.substringBefore('|').trim()
|
||||
TSUMINO_SOURCE_ID -> parsed.name.substringBefore('|').trim()
|
||||
else -> wrapTag(parsed.namespace, parsed.name.substringBefore('|').trim())
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 738 B |
Binary file not shown.
Before Width: | Height: | Size: 529 B |
Binary file not shown.
Before Width: | Height: | Size: 840 B |
Binary file not shown.
Before Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.6 KiB |
@ -24,7 +24,6 @@
|
||||
<!-- Subsections -->
|
||||
<string name="pref_category_all_sources">Todas as fontes</string>
|
||||
<string name="pref_category_eh">E-Hentai</string>
|
||||
<string name="pref_category_nh">nhentai</string>
|
||||
<string name="pref_category_fork">Configurações do fork</string>
|
||||
|
||||
<!-- EH Settings -->
|
||||
@ -136,10 +135,6 @@
|
||||
<!-- Library settings -->
|
||||
<string name="pref_skip_pre_migration_summary">Use as últimas fontes e preferências da pré-migração salvas para migrar em massa</string>
|
||||
|
||||
<!-- Other Settings -->
|
||||
<string name="high_quality_thumbnails">Usar miniaturas de alta qualidade</string>
|
||||
<string name="high_quality_thumbnails_summary">Pode carregar os resultados da pesquisa mais lentamente</string>
|
||||
|
||||
<!-- Reader Settings -->
|
||||
<string name="download_threads">Downloads simultâneos</string>
|
||||
<string name="download_threads_summary">Valores maiores podem acelerar significativamente o download, mas podem também causar banimentos. O valor recomendado é 2 ou 3. Valor atual: %s</string>
|
||||
|
@ -29,7 +29,6 @@
|
||||
<!-- Subsections -->
|
||||
<string name="pref_category_all_sources">All Sources</string>
|
||||
<string name="pref_category_eh">E-Hentai</string>
|
||||
<string name="pref_category_nh">nhentai</string>
|
||||
<string name="pref_category_fork">Fork Settings</string>
|
||||
|
||||
<!-- EH Settings -->
|
||||
@ -151,10 +150,6 @@
|
||||
<!-- Library settings -->
|
||||
<string name="pref_skip_pre_migration_summary">Use last saved pre-migration preferences and sources to mass migrate</string>
|
||||
|
||||
<!-- Other Settings -->
|
||||
<string name="high_quality_thumbnails">Use high-quality thumbnails</string>
|
||||
<string name="high_quality_thumbnails_summary">May slow down search results</string>
|
||||
|
||||
<!-- Reader Settings -->
|
||||
<string name="download_threads">Download threads</string>
|
||||
<string name="download_threads_summary">Higher values can speed up image downloading significantly, but can also trigger bans. Recommended value is 2 or 3. Current value is: %s</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user