Delegate NHentai, to continue using NHentai download the extension, SY requires NHentai version 1.2.28

This commit is contained in:
Jobobby04 2020-08-12 00:19:51 -04:00
parent 5a1bc6e25b
commit 3fa5322133
23 changed files with 71 additions and 385 deletions

View File

@ -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"

View File

@ -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)

View File

@ -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
}

View File

@ -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 }

View 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")
)
}
}

View File

@ -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()
}

View File

@ -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 -->

View File

@ -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
}

View File

@ -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 {

View File

@ -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
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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"
}
}

View File

@ -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(

View File

@ -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) }
}

View File

@ -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

View File

@ -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>

View File

@ -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>