diff --git a/app/build.gradle.kts b/app/build.gradle.kts index fb45ebec4..4de8c3a8c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -30,8 +30,8 @@ android { defaultConfig { applicationId = "app.komikku" - versionCode = 71 - versionName = "1.12.2" + versionCode = 72 + versionName = "1.13.0" buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"") buildConfigField("String", "COMMIT_SHA", "\"${getGitSha()}\"") diff --git a/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt b/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt index 6754a77a7..f281e580a 100644 --- a/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt +++ b/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt @@ -25,7 +25,7 @@ class SourcePreferences( fun incognitoExtensions() = preferenceStore.getStringSet("incognito_extensions", emptySet()) - fun pinnedSources() = preferenceStore.getStringSet("pinned_catalogues", emptySet()) + fun pinnedSources() = preferenceStore.getStringSet(pinnedSourcesPrefKey, emptySet()) fun lastUsedSource() = preferenceStore.getLong( Preference.appStateKey("last_catalogue_source"), @@ -109,3 +109,5 @@ class SourcePreferences( fun relatedMangas() = preferenceStore.getBoolean("related_mangas", true) // KMK <-- } + +const val pinnedSourcesPrefKey = "pinned_catalogues" diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/NamespaceTags.kt b/app/src/main/java/eu/kanade/presentation/manga/components/NamespaceTags.kt index 0477f9565..c077e17aa 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/NamespaceTags.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/NamespaceTags.kt @@ -31,8 +31,8 @@ import eu.kanade.tachiyomi.source.online.all.EHentai import exh.metadata.metadata.EHentaiSearchMetadata import exh.metadata.metadata.RaisedSearchMetadata import exh.metadata.metadata.base.RaisedTag -import exh.source.EH_SOURCE_ID import exh.source.EXH_SOURCE_ID +import exh.source.isEhBasedSource import exh.util.SourceTagsUtil import androidx.compose.material3.SuggestionChipDefaults as SuggestionChipDefaultsM3 @@ -64,7 +64,7 @@ value class SearchMetadataChips( } else { SourceTagsUtil.getWrappedTag(source.id, fullTag = it.name) } ?: it.name, - border = if (source.id == EXH_SOURCE_ID || source.id == EH_SOURCE_ID) { + border = if (source.isEhBasedSource()) { when (it.type) { EHentaiSearchMetadata.TAG_TYPE_NORMAL -> 2 EHentaiSearchMetadata.TAG_TYPE_LIGHT -> 1 diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt index cc20d6d8d..5a159a325 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt @@ -72,9 +72,6 @@ import eu.kanade.tachiyomi.util.system.toast import exh.debug.SettingsDebugScreen import exh.log.EHLogLevel import exh.pref.DelegateSourcePreferences -import exh.source.BlacklistedSources -import exh.source.EH_SOURCE_ID -import exh.source.EXH_SOURCE_ID import exh.util.toAnnotatedString import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentMapOf @@ -740,16 +737,17 @@ object SettingsAdvancedScreen : SearchableSettings { title = stringResource(SYMR.strings.toggle_hentai_features), subtitle = stringResource(SYMR.strings.toggle_hentai_features_summary), onValueChanged = { - if (it) { - BlacklistedSources.HIDDEN_SOURCES += EH_SOURCE_ID - BlacklistedSources.HIDDEN_SOURCES += EXH_SOURCE_ID - } else { - BlacklistedSources.HIDDEN_SOURCES -= EH_SOURCE_ID - BlacklistedSources.HIDDEN_SOURCES -= EXH_SOURCE_ID - } true }, ), + Preference.PreferenceItem.SwitchPreference( + pref = sourcePreferences.enableSourceBlacklist(), + title = stringResource(SYMR.strings.enable_source_blacklist), + subtitle = stringResource( + SYMR.strings.enable_source_blacklist_summary, + stringResource(MR.strings.app_name), + ), + ), Preference.PreferenceItem.SwitchPreference( pref = delegateSourcePreferences.delegateSources(), title = stringResource(SYMR.strings.toggle_delegated_sources), @@ -770,14 +768,6 @@ object SettingsAdvancedScreen : SearchableSettings { })" }.toMap().toImmutableMap(), ), - Preference.PreferenceItem.SwitchPreference( - pref = sourcePreferences.enableSourceBlacklist(), - title = stringResource(SYMR.strings.enable_source_blacklist), - subtitle = stringResource( - SYMR.strings.enable_source_blacklist_summary, - stringResource(MR.strings.app_name), - ), - ), kotlin.run { var enableEncryptDatabase by rememberSaveable { mutableStateOf(false) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/FeedRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/FeedRestorer.kt index cac304d9f..cf8687d28 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/FeedRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/FeedRestorer.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.data.backup.restore.restorers import eu.kanade.tachiyomi.data.backup.models.BackupFeed +import exh.EXHMigrations import exh.util.nullIfBlank import tachiyomi.data.DatabaseHandler import uy.kohesive.injekt.Injekt @@ -20,7 +21,11 @@ class FeedRestorer( saved_searchQueries.selectAll() } - backupFeeds.filter { backupFeed -> + backupFeeds.map { + // KMK --> + EXHMigrations.migrateBackupFeed(it) + // KMK <-- + }.filter { backupFeed -> // Filter out source's global Popular/Latest feed already existed backupFeed.savedSearch == null && currentFeeds.none { currentFeed -> diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/PreferenceRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/PreferenceRestorer.kt index b70280c55..3d371088f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/PreferenceRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/PreferenceRestorer.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.data.backup.restore.restorers import android.content.Context +import eu.kanade.domain.source.service.pinnedSourcesPrefKey import eu.kanade.tachiyomi.data.backup.create.BackupCreateJob import eu.kanade.tachiyomi.data.backup.models.BackupPreference import eu.kanade.tachiyomi.data.backup.models.BackupSourcePreferences @@ -12,6 +13,7 @@ import eu.kanade.tachiyomi.data.backup.models.StringPreferenceValue import eu.kanade.tachiyomi.data.backup.models.StringSetPreferenceValue import eu.kanade.tachiyomi.data.library.LibraryUpdateJob import eu.kanade.tachiyomi.source.sourcePreferences +import exh.EXHMigrations import tachiyomi.core.common.preference.AndroidPreferenceStore import tachiyomi.core.common.preference.PreferenceStore import uy.kohesive.injekt.Injekt @@ -70,7 +72,15 @@ class PreferenceRestorer( } is StringSetPreferenceValue -> { if (prefs[key] is Set<*>?) { - preferenceStore.getStringSet(key).set(value.value) + preferenceStore.getStringSet(key).set( + // KMK --> + if (key == pinnedSourcesPrefKey) { + EXHMigrations.migratePinnedSources(value.value) + } else { + // KMK <-- + value.value + }, + ) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/SavedSearchRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/SavedSearchRestorer.kt index 8e4735a6f..a90413894 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/SavedSearchRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/SavedSearchRestorer.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.data.backup.restore.restorers import eu.kanade.tachiyomi.data.backup.models.BackupSavedSearch +import exh.EXHMigrations import exh.util.nullIfBlank import tachiyomi.data.DatabaseHandler import uy.kohesive.injekt.Injekt @@ -22,7 +23,11 @@ class SavedSearchRestorer( // KMK <-- } - backupSavedSearches.filter { backupSavedSearch -> + backupSavedSearches.map { + // KMK --> + EXHMigrations.migrateBackupSavedSearch(it) + // KMK <-- + }.filter { backupSavedSearch -> currentSavedSearches.none { currentSavedSearch -> currentSavedSearch.source == backupSavedSearch.source && currentSavedSearch.name == backupSavedSearch.name && diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt index 3970490a6..1b74d07b5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt @@ -17,8 +17,8 @@ import eu.kanade.tachiyomi.extension.util.ExtensionLoader import eu.kanade.tachiyomi.util.system.toast import exh.log.xLogD import exh.source.BlacklistedSources -import exh.source.EH_SOURCE_ID -import exh.source.EXH_SOURCE_ID +import exh.source.EHENTAI_EXT_SOURCES +import exh.source.EXHENTAI_EXT_SOURCES import exh.source.MERGED_SOURCE_ID import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob @@ -33,6 +33,7 @@ import kotlinx.coroutines.flow.stateIn import logcat.LogPriority import tachiyomi.core.common.util.lang.withUIContext import tachiyomi.core.common.util.system.logcat +import tachiyomi.domain.UnsortedPreferences import tachiyomi.domain.source.model.StubSource import tachiyomi.i18n.MR import uy.kohesive.injekt.Injekt @@ -116,8 +117,10 @@ class ExtensionManager( // SY --> return when (sourceId) { - EH_SOURCE_ID -> ContextCompat.getDrawable(context, R.mipmap.ic_ehentai_source) - EXH_SOURCE_ID -> ContextCompat.getDrawable(context, R.mipmap.ic_exhentai_source) + // KMK --> + in EHENTAI_EXT_SOURCES -> ContextCompat.getDrawable(context, R.mipmap.ic_ehentai_source) + in EXHENTAI_EXT_SOURCES -> ContextCompat.getDrawable(context, R.mipmap.ic_exhentai_source) + // KMK <-- MERGED_SOURCE_ID -> ContextCompat.getDrawable(context, R.mipmap.ic_merged_source) else -> null } @@ -166,8 +169,17 @@ class ExtensionManager( } } - private fun Extension.isBlacklisted(blacklistEnabled: Boolean = preferences.enableSourceBlacklist().get()): Boolean { - return pkgName in BlacklistedSources.BLACKLISTED_EXTENSIONS && blacklistEnabled + private fun Extension.isBlacklisted( + blacklistEnabled: Boolean = preferences.enableSourceBlacklist().get(), + // KMK --> + isHentaiEnabled: Boolean = Injekt.get().isHentaiEnabled().get(), + // KMK <-- + ): Boolean { + return pkgName in BlacklistedSources.BLACKLISTED_EXTENSIONS && + blacklistEnabled && + // KMK --> + isHentaiEnabled + // KMK <-- } // EXH <-- diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionApi.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionApi.kt index 913f1046a..2c174922f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionApi.kt @@ -23,6 +23,9 @@ import tachiyomi.core.common.preference.Preference import tachiyomi.core.common.preference.PreferenceStore import tachiyomi.core.common.util.lang.withIOContext import tachiyomi.core.common.util.system.logcat +import tachiyomi.domain.UnsortedPreferences +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy import java.time.Instant import kotlin.time.Duration.Companion.days @@ -179,8 +182,15 @@ internal class ExtensionApi { // SY --> private fun Extension.isBlacklisted( blacklistEnabled: Boolean = sourcePreferences.enableSourceBlacklist().get(), + // KMK --> + isHentaiEnabled: Boolean = Injekt.get().isHentaiEnabled().get(), + // KMK <-- ): Boolean { - return pkgName in BlacklistedSources.BLACKLISTED_EXTENSIONS && blacklistEnabled + return pkgName in BlacklistedSources.BLACKLISTED_EXTENSIONS && + blacklistEnabled && + // KMK --> + isHentaiEnabled + // KMK <-- } // SY <-- } diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/AndroidSourceManager.kt b/app/src/main/java/eu/kanade/tachiyomi/source/AndroidSourceManager.kt index a5ae68a1d..432321b9a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/AndroidSourceManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/AndroidSourceManager.kt @@ -15,9 +15,9 @@ import eu.kanade.tachiyomi.source.online.english.Tsumino import exh.log.xLogD import exh.source.BlacklistedSources import exh.source.DelegatedHttpSource -import exh.source.EH_SOURCE_ID +import exh.source.EHENTAI_EXT_SOURCES import exh.source.EIGHTMUSES_SOURCE_ID -import exh.source.EXH_SOURCE_ID +import exh.source.EXHENTAI_EXT_SOURCES import exh.source.EnhancedHttpSource import exh.source.HBROWSE_SOURCE_ID import exh.source.MERGED_SOURCE_ID @@ -79,8 +79,13 @@ class AndroidSourceManager( .combine(preferences.enableExhentai().changes()) { extensions, enableExhentai -> extensions to enableExhentai } + // KMK --> + .combine( + preferences.isHentaiEnabled().changes(), + ) { (a, b), c -> Triple(a, b, c) } + // KMK <-- // SY <-- - .collectLatest { (extensions, enableExhentai) -> + .collectLatest { (extensions, enableExhentai/* KMK --> */, isHentaiEnabled/* KMK <-- */) -> val mutableMap = ConcurrentHashMap( mapOf( LocalSource.ID to LocalSource( @@ -93,16 +98,24 @@ class AndroidSourceManager( ), ), ).apply { - // SY --> - put(EH_SOURCE_ID, EHentai(EH_SOURCE_ID, false, context)) - if (enableExhentai) { - put(EXH_SOURCE_ID, EHentai(EXH_SOURCE_ID, true, context)) + // KMK --> + if (isHentaiEnabled) { + EHENTAI_EXT_SOURCES.forEach { (id, lang) -> + put(id, EHentai(id, false, context, lang)) + } + if (enableExhentai) { + EXHENTAI_EXT_SOURCES.forEach { (id, lang) -> + put(id, EHentai(id, true, context, lang)) + } + } + // SY --> + put(MERGED_SOURCE_ID, MergedSource()) + // SY <-- } - put(MERGED_SOURCE_ID, MergedSource()) - // SY <-- + // KMK <-- } extensions.forEach { extension -> - extension.sources.mapNotNull { it.toInternalSource() }.forEach { + extension.sources.mapNotNull { it.toInternalSource(/* KMK --> */isHentaiEnabled/* KMK <-- */) }.forEach { mutableMap[it.id] = it registerStubSource(StubSource.from(it)) } @@ -123,7 +136,11 @@ class AndroidSourceManager( } } - private fun Source.toInternalSource(): Source? { + private fun Source.toInternalSource( + // KMK --> + isHentaiEnabled: Boolean, + // KMK <-- + ): Source? { // EXH --> val sourceQName = this::class.qualifiedName val factories = DELEGATED_SOURCES.entries @@ -158,7 +175,12 @@ class AndroidSourceManager( this } - return if (id in BlacklistedSources.BLACKLISTED_EXT_SOURCES) { + return if ( + // KMK --> + isHentaiEnabled && + // KMK <-- + id in BlacklistedSources.BLACKLISTED_EXT_SOURCES + ) { xLogD( "Removing blacklisted source: (id: %s, name: %s, lang: %s)!", id, diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentai.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentai.kt index ad8c9485b..3b596da88 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentai.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentai.kt @@ -97,7 +97,13 @@ class EHentai( override val id: Long, val exh: Boolean, val context: Context, + // KMK --> + override val lang: String = "all", + // KMK <-- ) : HttpSource(), + // KMK --> + EhBasedSource, + // KMK <-- MetadataSource, UrlImportableSource, NamespaceSource, @@ -114,9 +120,19 @@ class EHentai( override val baseUrl: String get() = "https://$domain" - override val lang = "all" override val supportsLatest = true + // KMK --> + private val ehLang = languageMapping[lang] + + // true if lang is a "natural human language" + private fun isLangNatural(): Boolean = lang !in listOf("none", "other", "all") + + private fun languageTag(): String { + return "language:$ehLang" + } + // KMK <-- + private val preferences: UnsortedPreferences by injectLazy() private val updateHelper: EHentaiUpdateHelper by injectLazy() @@ -273,7 +289,6 @@ class EHentai( private fun getDateTag(element: Element?): Long? { val text = element?.text()?.nullIfBlank() return if (text != null) { - println(text) val date = ZonedDateTime.parse(text, MetadataUtil.EX_DATE_FORMAT.withZone(ZoneOffset.UTC)) date?.toInstant()?.toEpochMilli() } else { @@ -467,9 +482,18 @@ class EHentai( return if (it.text() == ">") it.attr("href") else null } - override fun popularMangaRequest(page: Int): Request { - return exGet("$baseUrl/popular") - } + override fun popularMangaRequest(page: Int) = + // KMK --> + if (isLangNatural()) { + exGet("$baseUrl/?f_search=${languageTag()}&f_srdd=5&f_sr=on", page) + } else { + if (page > 1) { + exGet("$baseUrl/?f_srdd=5&f_sr=on", page - 1) + } else { + // KMK <-- + exGet("$baseUrl/popular") + } + } private fun Observable.checkValid(): Observable = map { it.checkValid() @@ -565,7 +589,14 @@ class EHentai( ) } - override fun latestUpdatesRequest(page: Int) = exGet(baseUrl, page) + override fun latestUpdatesRequest(page: Int) = + // KMK --> + if (isLangNatural()) { + exGet("$baseUrl/?f_search=${languageTag()}", page) + } else { + // KMK <-- + exGet(baseUrl, page) + } override fun popularMangaParse(response: Response) = genericMangaParse(response) override fun searchMangaParse(response: Response) = genericMangaParse(response) @@ -911,7 +942,7 @@ class EHentai( // Session-less extended display mode (for users without ExHentai) cookies["sl"] = "dm_2" - // Ignore all content warnings + // Ignore all content warnings ("Offensive For Everyone") cookies["nw"] = "1" return cookies @@ -1382,5 +1413,27 @@ class EHentai( fun buildCookies(cookies: Map) = cookies.entries.joinToString(separator = "; ") { "${URLEncoder.encode(it.key, "UTF-8")}=${URLEncoder.encode(it.value, "UTF-8")}" } + + // KMK --> + val languageMapping = mapOf( + "ja" to "japanese", + "en" to "english", + "zh" to "chinese", + "nl" to "dutch", + "fr" to "french", + "de" to "german", + "hu" to "hungarian", + "it" to "italian", + "ko" to "korean", + "pl" to "polish", + "pt-BR" to "portuguese", + "ru" to "russian", + "es" to "spanish", + "th" to "thai", + "vi" to "vietnamese", + "none" to "n/a", + "other" to "other", + ) + // KMK <-- } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/NHentai.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/NHentai.kt index 754894b7d..bbef567a0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/NHentai.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/NHentai.kt @@ -21,7 +21,6 @@ import exh.metadata.metadata.NHentaiSearchMetadata import exh.metadata.metadata.RaisedSearchMetadata import exh.metadata.metadata.base.RaisedTag import exh.source.DelegatedHttpSource -import exh.source.NHENTAI_SOURCE_ID import exh.util.trimOrNull import exh.util.urlImportFetchSearchManga import exh.util.urlImportFetchSearchMangaSuspend @@ -239,8 +238,6 @@ class NHentai(delegate: HttpSource, val context: Context) : } companion object { - const val otherId = NHENTAI_SOURCE_ID - private val jsonParser = Json { ignoreUnknownKeys = true } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt index f0ffdacc0..2bed5b784 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt @@ -998,31 +998,21 @@ class LibraryScreenModel( unfiltered.asFlow().cancellable().filter { item -> val mangaId = item.libraryManga.manga.id val sourceId = item.libraryManga.manga.source - if (isMetadataSource(sourceId)) { - if (mangaWithMetaIds.binarySearch(mangaId) < 0) { - // No meta? Filter using title - filterManga( - queries = parsedQuery, - libraryManga = item.libraryManga, - tracks = tracks[mangaId], - source = sources[sourceId], - loggedInTrackServices = loggedInTrackServices, - ) - } else { - val tags = getSearchTags.await(mangaId) - val titles = getSearchTitles.await(mangaId) - filterManga( - queries = parsedQuery, - libraryManga = item.libraryManga, - tracks = tracks[mangaId], - source = sources[sourceId], - checkGenre = false, - searchTags = tags, - searchTitles = titles, - loggedInTrackServices = loggedInTrackServices, - ) - } + if (isMetadataSource(sourceId) && mangaWithMetaIds.binarySearch(mangaId) >= 0) { + val tags = getSearchTags.await(mangaId) + val titles = getSearchTitles.await(mangaId) + filterManga( + queries = parsedQuery, + libraryManga = item.libraryManga, + tracks = tracks[mangaId], + source = sources[sourceId], + checkGenre = false, + searchTags = tags, + searchTitles = titles, + loggedInTrackServices = loggedInTrackServices, + ) } else { + // No meta? Filter using title filterManga( queries = parsedQuery, libraryManga = item.libraryManga, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt index 59b00f9f3..fd461bab5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt @@ -94,9 +94,6 @@ import eu.kanade.tachiyomi.util.view.setComposeContent import exh.debug.DebugToggles import exh.eh.EHentaiUpdateWorker import exh.log.DebugModeOverlay -import exh.source.BlacklistedSources -import exh.source.EH_SOURCE_ID -import exh.source.EXH_SOURCE_ID import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.collectLatest @@ -400,13 +397,6 @@ class MainActivity : BaseActivity() { chapterCache.clear() } } - - // SY --> - if (!unsortedPreferences.isHentaiEnabled().get()) { - BlacklistedSources.HIDDEN_SOURCES += EH_SOURCE_ID - BlacklistedSources.HIDDEN_SOURCES += EXH_SOURCE_ID - } - // SY --> } // KMK --> diff --git a/app/src/main/java/exh/EXHMigrations.kt b/app/src/main/java/exh/EXHMigrations.kt index 76789e776..e296fc7c8 100644 --- a/app/src/main/java/exh/EXHMigrations.kt +++ b/app/src/main/java/exh/EXHMigrations.kt @@ -1,7 +1,11 @@ package exh -import exh.source.BlacklistedSources +import eu.kanade.tachiyomi.data.backup.models.BackupFeed +import eu.kanade.tachiyomi.data.backup.models.BackupSavedSearch +import exh.source.EH_OLD_ID import exh.source.EH_SOURCE_ID +import exh.source.EXH_OLD_ID +import exh.source.EXH_SOURCE_ID import exh.source.HBROWSE_OLD_ID import exh.source.HBROWSE_SOURCE_ID import exh.source.NHENTAI_OLD_ID @@ -42,16 +46,101 @@ object EXHMigrations { ) } + // KMK --> // Allow importing of EHentai extension backups - if (newManga.source in BlacklistedSources.EHENTAI_EXT_SOURCES) { + if (newManga.source == EH_OLD_ID) { newManga = newManga.copy( source = EH_SOURCE_ID, ) } + if (newManga.source == EXH_OLD_ID) { + newManga = newManga.copy( + source = EXH_SOURCE_ID, + ) + } + // KMK <-- return newManga } + // KMK --> + /** + * Migrate old source ID of delegated sources in old backup + */ + fun migrateBackupSavedSearch(savedSearch: BackupSavedSearch): BackupSavedSearch { + return when (savedSearch.source) { + NHENTAI_OLD_ID -> savedSearch.copy( + source = NHENTAI_SOURCE_ID, + ) + TSUMINO_OLD_ID -> savedSearch.copy( + source = TSUMINO_SOURCE_ID, + ) + HBROWSE_OLD_ID -> savedSearch.copy( + source = HBROWSE_SOURCE_ID, + ) + EH_OLD_ID -> savedSearch.copy( + source = EH_SOURCE_ID, + ) + EXH_OLD_ID -> savedSearch.copy( + source = EXH_SOURCE_ID, + ) + else -> savedSearch + } + } + + /** + * Migrate old source ID of delegated sources in old backup + */ + fun migrateBackupFeed(feed: BackupFeed): BackupFeed { + return when (feed.source) { + NHENTAI_OLD_ID -> feed.copy( + source = NHENTAI_SOURCE_ID, + ) + TSUMINO_OLD_ID -> feed.copy( + source = TSUMINO_SOURCE_ID, + ) + HBROWSE_OLD_ID -> feed.copy( + source = HBROWSE_SOURCE_ID, + ) + EH_OLD_ID -> feed.copy( + source = EH_SOURCE_ID, + ) + EXH_OLD_ID -> feed.copy( + source = EXH_SOURCE_ID, + ) + else -> feed + } + } + + /** + * Migrate old source ID of delegated sources in old backup + */ + fun migratePinnedSources(pinnedSources: Set): Set { + var pinned = pinnedSources + if (NHENTAI_OLD_ID.toString() in pinned) { + pinned = pinned.minus(NHENTAI_OLD_ID.toString()) + .plus(NHENTAI_SOURCE_ID.toString()) + } + if (TSUMINO_OLD_ID.toString() in pinned) { + pinned = pinned.minus(TSUMINO_OLD_ID.toString()) + .plus(TSUMINO_SOURCE_ID.toString()) + } + if (HBROWSE_OLD_ID.toString() in pinned) { + pinned = pinned.minus(HBROWSE_OLD_ID.toString()) + .plus(HBROWSE_SOURCE_ID.toString()) + } + if (EH_OLD_ID.toString() in pinned) { + pinned = pinned.minus(EH_OLD_ID.toString()) + .plus(EH_SOURCE_ID.toString()) + } + if (EXH_OLD_ID.toString() in pinned) { + pinned = pinned.minus(EXH_OLD_ID.toString()) + .plus(EXH_SOURCE_ID.toString()) + } + return pinned + } + // KMK --> + private fun getUrlWithoutDomain(orig: String): String { return try { val uri = URI(orig) diff --git a/app/src/main/java/exh/source/BlacklistedSources.kt b/app/src/main/java/exh/source/BlacklistedSources.kt index 1559394bd..92393d3b0 100644 --- a/app/src/main/java/exh/source/BlacklistedSources.kt +++ b/app/src/main/java/exh/source/BlacklistedSources.kt @@ -1,27 +1,7 @@ package exh.source object BlacklistedSources { - val EHENTAI_EXT_SOURCES = longArrayOf( - 8100626124886895451, - 57122881048805941, - 4678440076103929247, - 1876021963378735852, - 3955189842350477641, - 4348288691341764259, - 773611868725221145, - 5759417018342755550, - 825187715438990384, - 6116711405602166104, - 7151438547982231541, - 2171445159732592630, - 3032959619549451093, - 5980349886941016589, - 6073266008352078708, - 5499077866612745456, - 6140480779421365791, - ) - - val BLACKLISTED_EXT_SOURCES = EHENTAI_EXT_SOURCES + val BLACKLISTED_EXT_SOURCES = EHENTAI_EXT_SOURCES.keys val BLACKLISTED_EXTENSIONS = arrayOf( "eu.kanade.tachiyomi.extension.all.ehentai", diff --git a/app/src/main/java/mihon/core/migration/MigrateUtils.kt b/app/src/main/java/mihon/core/migration/MigrateUtils.kt index d3e6592cd..2b18cac67 100644 --- a/app/src/main/java/mihon/core/migration/MigrateUtils.kt +++ b/app/src/main/java/mihon/core/migration/MigrateUtils.kt @@ -1,7 +1,9 @@ package mihon.core.migration +import eu.kanade.domain.source.service.SourcePreferences import kotlinx.coroutines.runBlocking import tachiyomi.core.common.preference.PreferenceStore +import tachiyomi.core.common.preference.getAndSet import tachiyomi.data.DatabaseHandler object MigrateUtils { @@ -9,7 +11,23 @@ object MigrateUtils { val handler = migrationContext.get() ?: return runBlocking { handler.await { ehQueries.migrateSource(newId, oldId) } + + // KMK --> + // Migrate saved searches & feeds + handler.await { ehQueries.migrateSourceSavedSearch(newId, oldId) } + handler.await { ehQueries.migrateSourceFeed(newId, oldId) } } + + // Also update pin + val preferences = migrationContext.get() ?: return + val isPinned = oldId.toString() in preferences.pinnedSources().get() + if (isPinned) { + preferences.pinnedSources().getAndSet { pinned -> + pinned.minus(oldId.toString()) + .plus(newId.toString()) + } + } + // KMK <-- } @Suppress("UNCHECKED_CAST") diff --git a/app/src/main/java/mihon/core/migration/migrations/EHentaiMigration.kt b/app/src/main/java/mihon/core/migration/migrations/EHentaiMigration.kt new file mode 100644 index 000000000..dc20dd2ec --- /dev/null +++ b/app/src/main/java/mihon/core/migration/migrations/EHentaiMigration.kt @@ -0,0 +1,21 @@ +package mihon.core.migration.migrations + +import exh.source.EH_OLD_ID +import exh.source.EH_SOURCE_ID +import exh.source.EXH_OLD_ID +import exh.source.EXH_SOURCE_ID +import mihon.core.migration.MigrateUtils +import mihon.core.migration.Migration +import mihon.core.migration.MigrationContext +import tachiyomi.core.common.util.lang.withIOContext + +class EHentaiMigration : Migration { + override val version: Float = 72f + + override suspend fun invoke(migrationContext: MigrationContext): Boolean = withIOContext { + MigrateUtils.updateSourceId(migrationContext, EH_SOURCE_ID, EH_OLD_ID) + MigrateUtils.updateSourceId(migrationContext, EXH_SOURCE_ID, EXH_OLD_ID) + + return@withIOContext true + } +} diff --git a/app/src/main/java/mihon/core/migration/migrations/Migrations.kt b/app/src/main/java/mihon/core/migration/migrations/Migrations.kt index 5fbb36465..22f37b347 100644 --- a/app/src/main/java/mihon/core/migration/migrations/Migrations.kt +++ b/app/src/main/java/mihon/core/migration/migrations/Migrations.kt @@ -49,5 +49,6 @@ val migrations: List OfficialExtensionRepositoryMigration(), IntegratedHentaiMigration(), SetupAppUpdateMigration(), + EHentaiMigration(), // KMK <-- ) diff --git a/data/src/main/sqldelight/tachiyomi/data/eh.sq b/data/src/main/sqldelight/tachiyomi/data/eh.sq index 3b4bf9220..7107f734d 100644 --- a/data/src/main/sqldelight/tachiyomi/data/eh.sq +++ b/data/src/main/sqldelight/tachiyomi/data/eh.sq @@ -6,6 +6,18 @@ UPDATE mangas SET source = :newId WHERE source = :oldId; +-- KMK --> +migrateSourceSavedSearch: +UPDATE saved_search +SET source = :newId +WHERE source = :oldId; + +migrateSourceFeed: +UPDATE feed_saved_search +SET source = :newId +WHERE source = :oldId; +-- KMK <-- + getChaptersByMangaIds: SELECT * FROM chapters WHERE manga_id IN :mangaIds; diff --git a/domain/src/main/java/exh/source/DomainSourceHelpers.kt b/domain/src/main/java/exh/source/DomainSourceHelpers.kt index 7fcbc4397..a7d06e830 100644 --- a/domain/src/main/java/exh/source/DomainSourceHelpers.kt +++ b/domain/src/main/java/exh/source/DomainSourceHelpers.kt @@ -1,6 +1,7 @@ package exh.source import eu.kanade.tachiyomi.source.Source +import eu.kanade.tachiyomi.source.online.all.EhBasedSource import tachiyomi.domain.manga.model.Manga // Used to speed up isLewdSource @@ -18,13 +19,21 @@ var LIBRARY_UPDATE_EXCLUDED_SOURCES = listOf( // This method MUST be fast! fun isMetadataSource(source: Long) = source in 6900..6999 || + // KMK --> + source == EH_SOURCE_ID || + source == EXH_SOURCE_ID || + // KMK <-- metadataDelegatedSourceIds.binarySearch(source) >= 0 -fun Source.isEhBasedSource() = id == EH_SOURCE_ID || id == EXH_SOURCE_ID +// KMK --> +fun Source.isEhBasedSource() = this is EhBasedSource && id in EHENTAI_EXT_SOURCES || id in EXHENTAI_EXT_SOURCES +// KMK <-- fun Source.isMdBasedSource() = id in mangaDexSourceIds -fun Manga.isEhBasedManga() = source == EH_SOURCE_ID || source == EXH_SOURCE_ID +// KMK --> +fun Manga.isEhBasedManga() = source in EHENTAI_EXT_SOURCES || source in EXHENTAI_EXT_SOURCES +// KMK <-- fun Source.getMainSource(): Source = if (this is EnhancedHttpSource) { this.source() diff --git a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/all/EhBasedSource.kt b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/all/EhBasedSource.kt new file mode 100644 index 000000000..409ed697e --- /dev/null +++ b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/all/EhBasedSource.kt @@ -0,0 +1,3 @@ +package eu.kanade.tachiyomi.source.online.all + +interface EhBasedSource diff --git a/source-api/src/commonMain/kotlin/exh/source/SourceIds.kt b/source-api/src/commonMain/kotlin/exh/source/SourceIds.kt index 2e68ea2d8..f1e3c7047 100644 --- a/source-api/src/commonMain/kotlin/exh/source/SourceIds.kt +++ b/source-api/src/commonMain/kotlin/exh/source/SourceIds.kt @@ -2,8 +2,12 @@ package exh.source // Lewd source IDs const val LEWD_SOURCE_SERIES = 6900L -const val EH_SOURCE_ID = LEWD_SOURCE_SERIES + 1 -const val EXH_SOURCE_ID = LEWD_SOURCE_SERIES + 2 + +// KMK --> +const val EH_SOURCE_ID = 1713178126840476467 // LEWD_SOURCE_SERIES + 1 +const val EXH_SOURCE_ID = 6225928719850211219 // LEWD_SOURCE_SERIES + 2 +// KMK <-- + const val NHENTAI_SOURCE_ID = 7309872737163460316L const val PURURIN_SOURCE_ID = 2221515250486218861L const val TSUMINO_SOURCE_ID = 6707338697138388238L @@ -11,11 +15,58 @@ const val EIGHTMUSES_SOURCE_ID = 1802675169972965535L const val HBROWSE_SOURCE_ID = 1401584337232758222L const val MERGED_SOURCE_ID = LEWD_SOURCE_SERIES + 69 +// KMK --> +const val EH_OLD_ID = 6901L +const val EXH_OLD_ID = 6902L +// KMK <-- + const val NHENTAI_OLD_ID = 6907L const val TSUMINO_OLD_ID = 6909L const val HBROWSE_OLD_ID = 6912L // KMK --> +val EHENTAI_EXT_SOURCES = mapOf( + 8100626124886895451 to "ja", // E-Hentai (Ja) + 57122881048805941 to "en", // E-Hentai (En) + 4678440076103929247 to "zh", // E-Hentai (Zh) + 1876021963378735852 to "nl", // E-Hentai (Nl) + 3955189842350477641 to "fr", // E-Hentai (Fr) + 4348288691341764259 to "de", // E-Hentai (De) + 773611868725221145 to "hu", // E-Hentai (Hu) + 5759417018342755550 to "it", // E-Hentai (It) + 825187715438990384 to "ko", // E-Hentai (Ko) + 6116711405602166104 to "pl", // E-Hentai (Pl) + 7151438547982231541 to "pt-BR", // E-Hentai (PtBr) + 2171445159732592630 to "ru", // E-Hentai (Ru) + 3032959619549451093 to "es", // E-Hentai (Es) + 5980349886941016589 to "th", // E-Hentai (Th) + 6073266008352078708 to "vi", // E-Hentai (Vi) + 5499077866612745456 to "none", // E-Hentai (None) + 6140480779421365791 to "other", // E-Hentai (Other) + EH_SOURCE_ID to "all", // E-Hentai (Multi) +) + +val EXHENTAI_EXT_SOURCES = mapOf( + 4069364610143267166 to "ja", // E-Hentai (Ja) + 6024400692103629868 to "en", // E-Hentai (En) + 1394807835077780591 to "zh", // E-Hentai (Zh) + 3403092744483051659 to "nl", // E-Hentai (Nl) + 2063958147920418330 to "fr", // E-Hentai (Fr) + 4277540540471304114 to "de", // E-Hentai (De) + 5580677059017993793 to "hu", // E-Hentai (Hu) + 6348816521182710144 to "it", // E-Hentai (It) + 933801322201782118 to "ko", // E-Hentai (Ko) + 250678340923599076 to "pl", // E-Hentai (Pl) + 7151438547982231541 to "pt-BR", // E-Hentai (PtBr) + 2298110591802103872 to "ru", // E-Hentai (Ru) + 1471697890032830855 to "es", // E-Hentai (Es) + 5297549186919793998 to "th", // E-Hentai (Th) + 1904260310237764859 to "vi", // E-Hentai (Vi) + 2351087900641384311 to "none", // E-Hentai (None) + 609703168489499116 to "other", // E-Hentai (Other) + EXH_SOURCE_ID to "all", // E-Hentai (Multi) +) + val COMICK_IDS = setOf( 982606170401027267, // all 2971557565147974499, // en