Extract source api from app module (#8014)
* Extract source api from app module * Extract source online api from app module (cherry picked from commit 86fe85079413f8ed6e1109b46e6131a9b788b988) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt # core/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt # source-api/src/main/java/eu/kanade/tachiyomi/source/Source.kt # source-api/src/main/java/eu/kanade/tachiyomi/source/model/SManga.kt
This commit is contained in:
parent
b975b9b86f
commit
8a322ea28e
@ -133,6 +133,8 @@ android {
|
||||
|
||||
dependencies {
|
||||
implementation(project(":i18n"))
|
||||
implementation(project(":core"))
|
||||
implementation(project(":source-api"))
|
||||
|
||||
// Compose
|
||||
implementation(compose.activity)
|
||||
|
@ -20,6 +20,7 @@ import eu.kanade.domain.manga.interactor.GetExhFavoriteMangaWithMetadata
|
||||
import eu.kanade.domain.manga.interactor.GetFavoriteEntries
|
||||
import eu.kanade.domain.manga.interactor.GetFlatMetadataById
|
||||
import eu.kanade.domain.manga.interactor.GetIdsOfFavoriteMangaWithMetadata
|
||||
import eu.kanade.domain.manga.interactor.GetManga
|
||||
import eu.kanade.domain.manga.interactor.GetMangaBySource
|
||||
import eu.kanade.domain.manga.interactor.GetMergedManga
|
||||
import eu.kanade.domain.manga.interactor.GetMergedMangaById
|
||||
@ -65,6 +66,7 @@ import eu.kanade.domain.source.interactor.ToggleExcludeFromDataSaver
|
||||
import eu.kanade.domain.source.interactor.ToggleSources
|
||||
import eu.kanade.domain.source.repository.FeedSavedSearchRepository
|
||||
import eu.kanade.domain.source.repository.SavedSearchRepository
|
||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||
import uy.kohesive.injekt.api.InjektModule
|
||||
import uy.kohesive.injekt.api.InjektRegistrar
|
||||
import uy.kohesive.injekt.api.addFactory
|
||||
@ -100,6 +102,11 @@ class SYDomainModule : InjektModule {
|
||||
addFactory { ReorderSortTag(get(), get()) }
|
||||
addFactory { GetPagePreviews(get()) }
|
||||
|
||||
// Required for [MetadataSource]
|
||||
addFactory<MetadataSource.GetMangaId> { GetManga(get()) }
|
||||
addFactory<MetadataSource.GetFlatMetadataById> { GetFlatMetadataById(get()) }
|
||||
addFactory<MetadataSource.InsertFlatMetadata> { InsertFlatMetadata(get()) }
|
||||
|
||||
addSingletonFactory<MangaMetadataRepository> { MangaMetadataRepositoryImpl(get()) }
|
||||
addFactory { GetFlatMetadataById(get()) }
|
||||
addFactory { InsertFlatMetadata(get()) }
|
||||
|
@ -1,6 +1,7 @@
|
||||
package eu.kanade.domain.manga.interactor
|
||||
|
||||
import eu.kanade.domain.manga.repository.MangaMetadataRepository
|
||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
import exh.metadata.metadata.base.FlatMetadata
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@ -9,9 +10,9 @@ import logcat.LogPriority
|
||||
|
||||
class GetFlatMetadataById(
|
||||
private val mangaMetadataRepository: MangaMetadataRepository,
|
||||
) {
|
||||
) : MetadataSource.GetFlatMetadataById {
|
||||
|
||||
suspend fun await(id: Long): FlatMetadata? {
|
||||
override suspend fun await(id: Long): FlatMetadata? {
|
||||
return try {
|
||||
val meta = mangaMetadataRepository.getMetadataById(id)
|
||||
return if (meta != null) {
|
||||
|
@ -2,13 +2,14 @@ package eu.kanade.domain.manga.interactor
|
||||
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.domain.manga.repository.MangaRepository
|
||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import logcat.LogPriority
|
||||
|
||||
class GetManga(
|
||||
private val mangaRepository: MangaRepository,
|
||||
) {
|
||||
) : MetadataSource.GetMangaId {
|
||||
|
||||
suspend fun await(id: Long): Manga? {
|
||||
return try {
|
||||
@ -30,4 +31,10 @@ class GetManga(
|
||||
fun subscribe(url: String, sourceId: Long): Flow<Manga?> {
|
||||
return mangaRepository.getMangaByUrlAndSourceIdAsFlow(url, sourceId)
|
||||
}
|
||||
|
||||
// SY -->
|
||||
override suspend fun awaitId(url: String, sourceId: Long): Long? {
|
||||
return await(url, sourceId)?.id
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package eu.kanade.domain.manga.interactor
|
||||
|
||||
import eu.kanade.domain.manga.repository.MangaMetadataRepository
|
||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
import exh.metadata.metadata.base.FlatMetadata
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||
@ -8,7 +9,7 @@ import logcat.LogPriority
|
||||
|
||||
class InsertFlatMetadata(
|
||||
private val mangaMetadataRepository: MangaMetadataRepository,
|
||||
) {
|
||||
) : MetadataSource.InsertFlatMetadata {
|
||||
|
||||
suspend fun await(flatMetadata: FlatMetadata) {
|
||||
try {
|
||||
@ -18,7 +19,7 @@ class InsertFlatMetadata(
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun await(metadata: RaisedSearchMetadata) {
|
||||
override suspend fun await(metadata: RaisedSearchMetadata) {
|
||||
try {
|
||||
mangaMetadataRepository.insertMetadata(metadata)
|
||||
} catch (e: Exception) {
|
||||
|
@ -72,14 +72,33 @@ import eu.kanade.presentation.util.isScrollingUp
|
||||
import eu.kanade.presentation.util.plus
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.getNameForMangaInfo
|
||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||
import eu.kanade.tachiyomi.source.online.all.EHentai
|
||||
import eu.kanade.tachiyomi.source.online.all.Hitomi
|
||||
import eu.kanade.tachiyomi.source.online.all.MangaDex
|
||||
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
|
||||
import eu.kanade.tachiyomi.source.online.english.Pururin
|
||||
import eu.kanade.tachiyomi.source.online.english.Tsumino
|
||||
import eu.kanade.tachiyomi.ui.manga.ChapterItem
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||
import eu.kanade.tachiyomi.ui.manga.PagePreviewState
|
||||
import exh.source.MERGED_SOURCE_ID
|
||||
import exh.source.getMainSource
|
||||
import exh.ui.metadata.adapters.EHentaiDescription
|
||||
import exh.ui.metadata.adapters.EightMusesDescription
|
||||
import exh.ui.metadata.adapters.HBrowseDescription
|
||||
import exh.ui.metadata.adapters.HitomiDescription
|
||||
import exh.ui.metadata.adapters.MangaDexDescription
|
||||
import exh.ui.metadata.adapters.NHentaiDescription
|
||||
import exh.ui.metadata.adapters.PervEdenDescription
|
||||
import exh.ui.metadata.adapters.PururinDescription
|
||||
import exh.ui.metadata.adapters.TsuminoDescription
|
||||
|
||||
@Composable
|
||||
fun MangaScreen(
|
||||
@ -255,7 +274,7 @@ private fun MangaScreenSmallImpl(
|
||||
|
||||
val chapters = remember(state) { state.processedChapters.toList() }
|
||||
// SY -->
|
||||
val metadataSource = remember(state.source.id) { state.source.getMainSource<MetadataSource<*, *>>() }
|
||||
val metadataDescription = metadataDescription(state.source)
|
||||
// SY <--
|
||||
|
||||
val internalOnBackPressed = {
|
||||
@ -408,12 +427,12 @@ private fun MangaScreenSmallImpl(
|
||||
}
|
||||
|
||||
// SY -->
|
||||
if (metadataSource != null) {
|
||||
if (metadataDescription != null) {
|
||||
item(
|
||||
key = MangaScreenItem.METADATA_INFO,
|
||||
contentType = MangaScreenItem.METADATA_INFO,
|
||||
) {
|
||||
metadataSource.DescriptionComposable(
|
||||
metadataDescription(
|
||||
state = state,
|
||||
openMetadataViewer = onMetadataViewerClicked,
|
||||
search = { onSearch(it, false) },
|
||||
@ -540,7 +559,7 @@ fun MangaScreenLargeImpl(
|
||||
val chapters = remember(state) { state.processedChapters.toList() }
|
||||
|
||||
// SY -->
|
||||
val metadataSource = remember(state.source.id) { state.source.getMainSource<MetadataSource<*, *>>() }
|
||||
val metadataDescription = metadataDescription(state.source)
|
||||
// SY <--
|
||||
|
||||
val insetPadding = WindowInsets.systemBars.only(WindowInsetsSides.Horizontal).asPaddingValues()
|
||||
@ -681,7 +700,7 @@ fun MangaScreenLargeImpl(
|
||||
// SY <--
|
||||
)
|
||||
// SY -->
|
||||
metadataSource?.DescriptionComposable(
|
||||
metadataDescription?.invoke(
|
||||
state = state,
|
||||
openMetadataViewer = onMetadataViewerClicked,
|
||||
search = { onSearch(it, false) },
|
||||
@ -847,3 +866,42 @@ private fun onChapterItemClick(
|
||||
else -> onChapterClicked(chapterItem.chapter)
|
||||
}
|
||||
}
|
||||
|
||||
typealias MetadataDescriptionComposable = @Composable (state: MangaScreenState.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit) -> Unit
|
||||
|
||||
@Composable
|
||||
fun metadataDescription(source: Source): MetadataDescriptionComposable? {
|
||||
val metadataSource = remember(source.id) { source.getMainSource<MetadataSource<*, *>>() }
|
||||
return remember(metadataSource) {
|
||||
when (metadataSource) {
|
||||
is EHentai -> { state, openMetadataViewer, search ->
|
||||
EHentaiDescription(state, openMetadataViewer, search)
|
||||
}
|
||||
is Hitomi -> { state, openMetadataViewer, _ ->
|
||||
HitomiDescription(state, openMetadataViewer)
|
||||
}
|
||||
is MangaDex -> { state, openMetadataViewer, _ ->
|
||||
MangaDexDescription(state, openMetadataViewer)
|
||||
}
|
||||
is NHentai -> { state, openMetadataViewer, _ ->
|
||||
NHentaiDescription(state, openMetadataViewer)
|
||||
}
|
||||
is PervEden -> { state, openMetadataViewer, _ ->
|
||||
PervEdenDescription(state, openMetadataViewer)
|
||||
}
|
||||
is EightMuses -> { state, openMetadataViewer, _ ->
|
||||
EightMusesDescription(state, openMetadataViewer)
|
||||
}
|
||||
is HBrowse -> { state, openMetadataViewer, _ ->
|
||||
HBrowseDescription(state, openMetadataViewer)
|
||||
}
|
||||
is Pururin -> { state, openMetadataViewer, _ ->
|
||||
PururinDescription(state, openMetadataViewer)
|
||||
}
|
||||
is Tsumino -> { state, openMetadataViewer, _ ->
|
||||
TsuminoDescription(state, openMetadataViewer)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.library.CustomMangaManager
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.model.copyFrom
|
||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
import eu.kanade.tachiyomi.util.system.toLong
|
||||
|
@ -1,6 +1,10 @@
|
||||
package eu.kanade.tachiyomi.data.database.models
|
||||
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.library.CustomMangaManager
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
open class MangaImpl : Manga {
|
||||
@ -77,6 +81,19 @@ open class MangaImpl : Manga {
|
||||
private set
|
||||
var ogStatus: Int = 0
|
||||
private set
|
||||
|
||||
override val originalTitle: String
|
||||
get() = ogTitle
|
||||
override val originalAuthor: String?
|
||||
get() = ogAuthor ?: author
|
||||
override val originalArtist: String?
|
||||
get() = ogArtist ?: artist
|
||||
override val originalDescription: String?
|
||||
get() = ogDesc ?: description
|
||||
override val originalGenre: String?
|
||||
get() = ogGenre ?: genre
|
||||
override val originalStatus: Int
|
||||
get() = ogStatus
|
||||
// SY <--
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
@ -93,6 +110,18 @@ open class MangaImpl : Manga {
|
||||
}
|
||||
|
||||
// SY -->
|
||||
override fun copyFrom(other: SManga) {
|
||||
// EXH -->
|
||||
if (other.title.isNotBlank() && originalTitle != other.title) {
|
||||
val source = (this as? Manga)?.source
|
||||
if (source != null) {
|
||||
Injekt.get<DownloadManager>().renameMangaDir(originalTitle, other.originalTitle, source)
|
||||
}
|
||||
}
|
||||
// EXH <--
|
||||
super.copyFrom(other)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val customMangaManager: CustomMangaManager by injectLazy()
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerConfig
|
||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||
import eu.kanade.tachiyomi.util.system.isDevFlavor
|
||||
import eu.kanade.tachiyomi.util.system.isDynamicColorAvailable
|
||||
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
|
||||
import java.io.File
|
||||
import java.text.DateFormat
|
||||
|
@ -0,0 +1,58 @@
|
||||
package eu.kanade.tachiyomi.source
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
import eu.kanade.domain.source.model.SourceData
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
fun Source.icon(): Drawable? = Injekt.get<ExtensionManager>().getAppIconForSource(this)
|
||||
|
||||
fun Source.getPreferenceKey(): String = "source_$id"
|
||||
|
||||
fun Source.toSourceData(): SourceData = SourceData(id = id, lang = lang, name = name)
|
||||
|
||||
fun Source.getNameForMangaInfo(mergeSources: List<Source>?): String {
|
||||
val preferences = Injekt.get<PreferencesHelper>()
|
||||
val enabledLanguages = preferences.enabledLanguages().get()
|
||||
.filterNot { it in listOf("all", "other") }
|
||||
val hasOneActiveLanguages = enabledLanguages.size == 1
|
||||
val isInEnabledLanguages = lang in enabledLanguages
|
||||
return when {
|
||||
// SY -->
|
||||
!mergeSources.isNullOrEmpty() -> getMergedSourcesString(
|
||||
mergeSources,
|
||||
enabledLanguages,
|
||||
hasOneActiveLanguages,
|
||||
)
|
||||
// SY <--
|
||||
// For edge cases where user disables a source they got manga of in their library.
|
||||
hasOneActiveLanguages && !isInEnabledLanguages -> toString()
|
||||
// Hide the language tag when only one language is used.
|
||||
hasOneActiveLanguages && isInEnabledLanguages -> name
|
||||
else -> toString()
|
||||
}
|
||||
}
|
||||
|
||||
// SY -->
|
||||
private fun getMergedSourcesString(
|
||||
mergeSources: List<Source>,
|
||||
enabledLangs: List<String>,
|
||||
onlyName: Boolean,
|
||||
): String {
|
||||
return if (onlyName) {
|
||||
mergeSources.joinToString { source ->
|
||||
if (source.lang !in enabledLangs) {
|
||||
source.toString()
|
||||
} else {
|
||||
source.name
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mergeSources.joinToString()
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
|
||||
fun Source.isLocalOrStub(): Boolean = id == LocalSource.ID || this is SourceManager.StubSource
|
@ -133,6 +133,7 @@ class SourceManager(
|
||||
val enhancedSource = EnhancedHttpSource(
|
||||
this,
|
||||
delegate.newSourceClass.constructors.find { it.parameters.size == 2 }!!.call(this, context),
|
||||
::delegateSources,
|
||||
)
|
||||
|
||||
currentDelegatedSources[enhancedSource.originalSource.id] = DelegatedSource(
|
||||
@ -156,6 +157,8 @@ class SourceManager(
|
||||
// EXH <--
|
||||
}
|
||||
|
||||
private fun delegateSources() = preferences.delegateSources().get()
|
||||
|
||||
fun get(sourceKey: Long): Source? {
|
||||
return sourcesMap[sourceKey]
|
||||
}
|
||||
|
@ -0,0 +1,11 @@
|
||||
package eu.kanade.tachiyomi.source.model
|
||||
|
||||
import data.Chapters
|
||||
|
||||
fun SChapter.copyFrom(other: Chapters) {
|
||||
name = other.name
|
||||
url = other.url
|
||||
date_upload = other.date_upload
|
||||
chapter_number = other.chapter_number
|
||||
scanlator = other.scanlator
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package eu.kanade.tachiyomi.source.model
|
||||
|
||||
import data.Mangas
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
fun SManga.copyFrom(other: Mangas) {
|
||||
// EXH -->
|
||||
if (other.title.isNotBlank() && originalTitle != other.title) {
|
||||
val oldTitle = originalTitle
|
||||
title = other.title
|
||||
val source = (this as? Manga)?.source
|
||||
if (source != null) {
|
||||
Injekt.get<DownloadManager>().renameMangaDir(oldTitle, other.title, source)
|
||||
}
|
||||
}
|
||||
// EXH <--
|
||||
|
||||
if (other.author != null) {
|
||||
author = other.author
|
||||
}
|
||||
|
||||
if (other.artist != null) {
|
||||
artist = other.artist
|
||||
}
|
||||
|
||||
if (other.description != null) {
|
||||
description = other.description
|
||||
}
|
||||
|
||||
if (other.genre != null) {
|
||||
genre = other.genre.joinToString(separator = ", ")
|
||||
}
|
||||
|
||||
if (other.thumbnail_url != null) {
|
||||
thumbnail_url = other.thumbnail_url
|
||||
}
|
||||
|
||||
status = other.status.toInt()
|
||||
|
||||
if (!initialized) {
|
||||
initialized = other.initialized
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
package eu.kanade.tachiyomi.source.online
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
import eu.kanade.tachiyomi.ui.base.controller.BaseController
|
||||
|
||||
interface BrowseSourceFilterHeader : CatalogueSource {
|
||||
fun getFilterHeader(controller: BaseController<*>, onClick: () -> Unit): RecyclerView.Adapter<*>
|
||||
}
|
@ -4,7 +4,6 @@ import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.net.Uri
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.core.net.toUri
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
||||
@ -28,7 +27,6 @@ import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||
import eu.kanade.tachiyomi.source.online.NamespaceSource
|
||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import eu.kanade.tachiyomi.util.lang.runAsObservable
|
||||
import eu.kanade.tachiyomi.util.lang.withIOContext
|
||||
@ -51,7 +49,6 @@ import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.TAG_TYPE_VIRTUA
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.toGenreString
|
||||
import exh.metadata.metadata.base.RaisedTag
|
||||
import exh.ui.login.EhLoginActivity
|
||||
import exh.ui.metadata.adapters.EHentaiDescription
|
||||
import exh.util.UriFilter
|
||||
import exh.util.UriGroup
|
||||
import exh.util.asObservableWithAsyncStacktrace
|
||||
@ -1127,11 +1124,6 @@ class EHentai(
|
||||
return "${uri.scheme}://${uri.host}/g/${obj["gid"]!!.jsonPrimitive.int}/${obj["token"]!!.jsonPrimitive.content}/"
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun DescriptionComposable(state: MangaScreenState.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit) {
|
||||
EHentaiDescription(state, openMetadataViewer, search)
|
||||
}
|
||||
|
||||
override suspend fun getPagePreviewList(
|
||||
manga: SManga,
|
||||
page: Int,
|
||||
|
@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.source.online.all
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import androidx.compose.runtime.Composable
|
||||
import eu.kanade.tachiyomi.network.await
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
@ -11,13 +10,11 @@ import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||
import eu.kanade.tachiyomi.source.online.NamespaceSource
|
||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import exh.metadata.metadata.HitomiSearchMetadata
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||
import exh.metadata.metadata.base.RaisedTag
|
||||
import exh.source.DelegatedHttpSource
|
||||
import exh.ui.metadata.adapters.HitomiDescription
|
||||
import exh.util.urlImportFetchSearchManga
|
||||
import org.jsoup.nodes.Document
|
||||
import java.text.SimpleDateFormat
|
||||
@ -136,11 +133,6 @@ class Hitomi(delegate: HttpSource, val context: Context) :
|
||||
return "https://hitomi.la/manga/${uri.pathSegments[1].substringBefore('.')}.html"
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun DescriptionComposable(state: MangaScreenState.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit) {
|
||||
HitomiDescription(state, openMetadataViewer)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val otherId = 2703068117101782422L
|
||||
private val DATE_FORMAT by lazy {
|
||||
|
@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.source.online.all
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.net.Uri
|
||||
import androidx.compose.runtime.Composable
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
@ -14,7 +13,6 @@ import eu.kanade.tachiyomi.source.model.MetadataMangasPage
|
||||
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.BrowseSourceFilterHeader
|
||||
import eu.kanade.tachiyomi.source.online.FollowsSource
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.source.online.LoginSource
|
||||
@ -22,10 +20,7 @@ import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||
import eu.kanade.tachiyomi.source.online.NamespaceSource
|
||||
import eu.kanade.tachiyomi.source.online.RandomMangaSource
|
||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||
import eu.kanade.tachiyomi.ui.base.controller.BaseController
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||
import eu.kanade.tachiyomi.util.lang.runAsObservable
|
||||
import exh.md.MangaDexFabHeaderAdapter
|
||||
import exh.md.dto.MangaDto
|
||||
import exh.md.dto.StatisticsMangaDto
|
||||
import exh.md.handlers.ApiMangaParser
|
||||
@ -49,7 +44,6 @@ import exh.md.utils.MdLang
|
||||
import exh.md.utils.MdUtil
|
||||
import exh.metadata.metadata.MangaDexSearchMetadata
|
||||
import exh.source.DelegatedHttpSource
|
||||
import exh.ui.metadata.adapters.MangaDexDescription
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Response
|
||||
import rx.Observable
|
||||
@ -64,7 +58,6 @@ class MangaDex(delegate: HttpSource, val context: Context) :
|
||||
UrlImportableSource,
|
||||
FollowsSource,
|
||||
LoginSource,
|
||||
BrowseSourceFilterHeader,
|
||||
RandomMangaSource,
|
||||
NamespaceSource {
|
||||
override val lang: String = delegate.lang
|
||||
@ -217,11 +210,6 @@ class MangaDex(delegate: HttpSource, val context: Context) :
|
||||
// MetadataSource methods
|
||||
override val metaClass: KClass<MangaDexSearchMetadata> = MangaDexSearchMetadata::class
|
||||
|
||||
@Composable
|
||||
override fun DescriptionComposable(state: MangaScreenState.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit) {
|
||||
MangaDexDescription(state, openMetadataViewer)
|
||||
}
|
||||
|
||||
override suspend fun parseIntoMetadata(metadata: MangaDexSearchMetadata, input: Triple<MangaDto, List<String>, StatisticsMangaDto>) {
|
||||
apiMangaParser.parseIntoMetadata(metadata, input.first, input.second, input.third)
|
||||
}
|
||||
@ -272,11 +260,11 @@ class MangaDex(delegate: HttpSource, val context: Context) :
|
||||
return followsHandler.fetchAllFollows()
|
||||
}
|
||||
|
||||
override suspend fun updateFollowStatus(mangaID: String, followStatus: FollowStatus): Boolean {
|
||||
suspend fun updateFollowStatus(mangaID: String, followStatus: FollowStatus): Boolean {
|
||||
return followsHandler.updateFollowStatus(mangaID, followStatus)
|
||||
}
|
||||
|
||||
override suspend fun fetchTrackingInfo(url: String): Track {
|
||||
suspend fun fetchTrackingInfo(url: String): Track {
|
||||
return followsHandler.fetchTrackingInfo(url)
|
||||
}
|
||||
|
||||
@ -293,11 +281,6 @@ class MangaDex(delegate: HttpSource, val context: Context) :
|
||||
return mangaHandler.getTrackingInfo(track)
|
||||
}
|
||||
|
||||
// BrowseSourceFilterHeader method
|
||||
override fun getFilterHeader(controller: BaseController<*>, onClick: () -> Unit): MangaDexFabHeaderAdapter {
|
||||
return MangaDexFabHeaderAdapter(controller, this, onClick)
|
||||
}
|
||||
|
||||
// RandomMangaSource method
|
||||
override suspend fun fetchRandomMangaUrl(): String {
|
||||
return mangaHandler.fetchRandomMangaId()
|
||||
|
@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.source.online.all
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.net.Uri
|
||||
import androidx.compose.runtime.Composable
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.await
|
||||
import eu.kanade.tachiyomi.network.newCallWithProgress
|
||||
@ -16,12 +15,10 @@ import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||
import eu.kanade.tachiyomi.source.online.NamespaceSource
|
||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||
import exh.metadata.metadata.NHentaiSearchMetadata
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||
import exh.metadata.metadata.base.RaisedTag
|
||||
import exh.source.DelegatedHttpSource
|
||||
import exh.ui.metadata.adapters.NHentaiDescription
|
||||
import exh.util.trimOrNull
|
||||
import exh.util.urlImportFetchSearchManga
|
||||
import kotlinx.serialization.SerialName
|
||||
@ -175,11 +172,6 @@ class NHentai(delegate: HttpSource, val context: Context) :
|
||||
return "$baseUrl/g/${uri.pathSegments[1]}/"
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun DescriptionComposable(state: MangaScreenState.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit) {
|
||||
NHentaiDescription(state, openMetadataViewer)
|
||||
}
|
||||
|
||||
override suspend fun getPagePreviewList(manga: SManga, page: Int): PagePreviewPage {
|
||||
val metadata = fetchOrLoadMetadata(manga.id()) {
|
||||
client.newCall(mangaDetailsRequest(manga)).await()
|
||||
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.source.online.all
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.core.net.toUri
|
||||
import eu.kanade.tachiyomi.network.await
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
@ -10,13 +9,11 @@ import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import exh.metadata.metadata.PervEdenSearchMetadata
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||
import exh.metadata.metadata.base.RaisedTag
|
||||
import exh.source.DelegatedHttpSource
|
||||
import exh.ui.metadata.adapters.PervEdenDescription
|
||||
import exh.util.urlImportFetchSearchManga
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
@ -132,9 +129,4 @@ class PervEden(delegate: HttpSource, val context: Context) :
|
||||
}
|
||||
return newUri.toString()
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun DescriptionComposable(state: MangaScreenState.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit) {
|
||||
PervEdenDescription(state, openMetadataViewer)
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.source.online.english
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.core.net.toUri
|
||||
import eu.kanade.tachiyomi.network.await
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
@ -11,12 +10,10 @@ import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||
import eu.kanade.tachiyomi.source.online.NamespaceSource
|
||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import exh.metadata.metadata.EightMusesSearchMetadata
|
||||
import exh.metadata.metadata.base.RaisedTag
|
||||
import exh.source.DelegatedHttpSource
|
||||
import exh.ui.metadata.adapters.EightMusesDescription
|
||||
import exh.util.urlImportFetchSearchManga
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
@ -96,9 +93,4 @@ class EightMuses(delegate: HttpSource, val context: Context) :
|
||||
}
|
||||
return "/comics/album/${path.joinToString("/")}"
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun DescriptionComposable(state: MangaScreenState.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit) {
|
||||
EightMusesDescription(state, openMetadataViewer)
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.source.online.english
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import androidx.compose.runtime.Composable
|
||||
import eu.kanade.tachiyomi.network.await
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
@ -10,12 +9,10 @@ import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||
import eu.kanade.tachiyomi.source.online.NamespaceSource
|
||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import exh.metadata.metadata.HBrowseSearchMetadata
|
||||
import exh.metadata.metadata.base.RaisedTag
|
||||
import exh.source.DelegatedHttpSource
|
||||
import exh.ui.metadata.adapters.HBrowseDescription
|
||||
import exh.util.urlImportFetchSearchManga
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
@ -84,9 +81,4 @@ class HBrowse(delegate: HttpSource, val context: Context) :
|
||||
override suspend fun mapUrlToMangaUrl(uri: Uri): String? {
|
||||
return uri.pathSegments.firstOrNull()?.let { "/$it/c00001/" }
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun DescriptionComposable(state: MangaScreenState.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit) {
|
||||
HBrowseDescription(state, openMetadataViewer)
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.source.online.english
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.core.net.toUri
|
||||
import eu.kanade.tachiyomi.network.await
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
@ -12,13 +11,11 @@ import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||
import eu.kanade.tachiyomi.source.online.NamespaceSource
|
||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import exh.metadata.metadata.PururinSearchMetadata
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||
import exh.metadata.metadata.base.RaisedTag
|
||||
import exh.source.DelegatedHttpSource
|
||||
import exh.ui.metadata.adapters.PururinDescription
|
||||
import exh.util.dropBlank
|
||||
import exh.util.trimAll
|
||||
import exh.util.urlImportFetchSearchManga
|
||||
@ -116,9 +113,4 @@ class Pururin(delegate: HttpSource, val context: Context) :
|
||||
override suspend fun mapUrlToMangaUrl(uri: Uri): String {
|
||||
return "${PururinSearchMetadata.BASE_URL}/gallery/${uri.pathSegments.getOrNull(1)}/${uri.lastPathSegment}"
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun DescriptionComposable(state: MangaScreenState.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit) {
|
||||
PururinDescription(state, openMetadataViewer)
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.source.online.english
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import androidx.compose.runtime.Composable
|
||||
import eu.kanade.tachiyomi.network.await
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
@ -11,14 +10,12 @@ import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||
import eu.kanade.tachiyomi.source.online.NamespaceSource
|
||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import exh.metadata.metadata.TsuminoSearchMetadata
|
||||
import exh.metadata.metadata.TsuminoSearchMetadata.Companion.TAG_TYPE_DEFAULT
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.TAG_TYPE_VIRTUAL
|
||||
import exh.metadata.metadata.base.RaisedTag
|
||||
import exh.source.DelegatedHttpSource
|
||||
import exh.ui.metadata.adapters.TsuminoDescription
|
||||
import exh.util.dropBlank
|
||||
import exh.util.trimAll
|
||||
import exh.util.urlImportFetchSearchManga
|
||||
@ -141,9 +138,4 @@ class Tsumino(delegate: HttpSource, val context: Context) :
|
||||
val RATING_USERS_REGEX = "\\(([0-9].*) users".toRegex()
|
||||
val RATING_FAVORITES_REGEX = "/ ([0-9].*) favs".toRegex()
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun DescriptionComposable(state: MangaScreenState.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit) {
|
||||
TsuminoDescription(state, openMetadataViewer)
|
||||
}
|
||||
}
|
||||
|
@ -13,10 +13,11 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.kanade.tachiyomi.databinding.SourceFilterSheetBinding
|
||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
import eu.kanade.tachiyomi.source.online.BrowseSourceFilterHeader
|
||||
import eu.kanade.tachiyomi.source.online.all.MangaDex
|
||||
import eu.kanade.tachiyomi.ui.base.controller.BaseController
|
||||
import eu.kanade.tachiyomi.widget.SimpleNavigationView
|
||||
import eu.kanade.tachiyomi.widget.sheet.BaseBottomSheetDialog
|
||||
import exh.md.MangaDexFabHeaderAdapter
|
||||
import exh.savedsearches.EXHSavedSearch
|
||||
import exh.source.getMainSource
|
||||
|
||||
@ -117,8 +118,12 @@ class SourceFilterSheet(
|
||||
recycler.adapter = ConcatAdapter(
|
||||
listOfNotNull(
|
||||
controller?.let {
|
||||
source?.getMainSource<BrowseSourceFilterHeader>()
|
||||
?.getFilterHeader(it) { dismissSheet?.invoke() }
|
||||
source?.getMainSource<MangaDex>()
|
||||
?.let {
|
||||
MangaDexFabHeaderAdapter(controller, it) {
|
||||
dismissSheet?.invoke()
|
||||
}
|
||||
}
|
||||
},
|
||||
savedSearchesAdapter,
|
||||
adapter,
|
||||
|
@ -46,7 +46,7 @@ open class AutoComplete(val filter: Filter.AutoComplete) : AbstractFlexibleItem<
|
||||
// select from auto complete
|
||||
holder.autoComplete.setOnItemClickListener { adapterView, _, chipPosition, _ ->
|
||||
val name = adapterView.getItemAtPosition(chipPosition) as String
|
||||
if (name !in if (filter.excludePrefix != null && name.startsWith(filter.excludePrefix)) filter.skipAutoFillTags.map { filter.excludePrefix + it } else filter.skipAutoFillTags) {
|
||||
if (name !in if (filter.excludePrefix != null && name.startsWith(filter.excludePrefix!!)) filter.skipAutoFillTags.map { filter.excludePrefix + it } else filter.skipAutoFillTags) {
|
||||
holder.autoComplete.text = null
|
||||
addTag(name, holder)
|
||||
}
|
||||
@ -54,7 +54,7 @@ open class AutoComplete(val filter: Filter.AutoComplete) : AbstractFlexibleItem<
|
||||
|
||||
// done keyboard button is pressed
|
||||
holder.autoComplete.setOnEditorActionListener { textView, actionId, _ ->
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE && textView.text.toString() !in if (filter.excludePrefix != null && textView.text.toString().startsWith(filter.excludePrefix)) filter.skipAutoFillTags.map { filter.excludePrefix + it } else filter.skipAutoFillTags) {
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE && textView.text.toString() !in if (filter.excludePrefix != null && textView.text.toString().startsWith(filter.excludePrefix!!)) filter.skipAutoFillTags.map { filter.excludePrefix + it } else filter.skipAutoFillTags) {
|
||||
textView.text = null
|
||||
addTag(textView.text.toString(), holder)
|
||||
return@setOnEditorActionListener true
|
||||
|
@ -17,6 +17,7 @@ import eu.kanade.tachiyomi.util.preference.preferenceCategory
|
||||
import eu.kanade.tachiyomi.util.preference.switchPreference
|
||||
import eu.kanade.tachiyomi.util.preference.titleRes
|
||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||
import eu.kanade.tachiyomi.util.system.isDynamicColorAvailable
|
||||
import eu.kanade.tachiyomi.util.system.isTablet
|
||||
import eu.kanade.tachiyomi.widget.preference.ThemesPreference
|
||||
import java.util.Date
|
||||
|
@ -24,10 +24,8 @@ import android.util.TypedValue
|
||||
import android.view.Display
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.view.ContextThemeWrapper
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
@ -52,29 +50,6 @@ import kotlin.math.roundToInt
|
||||
|
||||
private const val TABLET_UI_MIN_SCREEN_WIDTH_DP = 720
|
||||
|
||||
/**
|
||||
* Display a toast in this context.
|
||||
*
|
||||
* @param resource the text resource.
|
||||
* @param duration the duration of the toast. Defaults to short.
|
||||
*/
|
||||
fun Context.toast(@StringRes resource: Int, duration: Int = Toast.LENGTH_SHORT, block: (Toast) -> Unit = {}): Toast {
|
||||
return toast(getString(resource), duration, block)
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a toast in this context.
|
||||
*
|
||||
* @param text the text to display.
|
||||
* @param duration the duration of the toast. Defaults to short.
|
||||
*/
|
||||
fun Context.toast(text: String?, duration: Int = Toast.LENGTH_SHORT, block: (Toast) -> Unit = {}): Toast {
|
||||
return Toast.makeText(applicationContext, text.orEmpty(), duration).also {
|
||||
block(it)
|
||||
it.show()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies a string to clipboard
|
||||
*
|
||||
|
@ -0,0 +1,8 @@
|
||||
package eu.kanade.tachiyomi.util.system
|
||||
|
||||
import android.os.Build
|
||||
import com.google.android.material.color.DynamicColors
|
||||
|
||||
val DeviceUtil.isDynamicColorAvailable by lazy {
|
||||
DynamicColors.isDynamicColorAvailable() || (DeviceUtil.isSamsung && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
|
||||
}
|
@ -12,8 +12,8 @@ import eu.kanade.tachiyomi.databinding.DescriptionAdapterEhBinding
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import exh.metadata.MetadataUtil
|
||||
import exh.metadata.bindDrawable
|
||||
import exh.metadata.metadata.EHentaiSearchMetadata
|
||||
import exh.ui.metadata.adapters.MetadataUIUtil.bindDrawable
|
||||
|
||||
@Composable
|
||||
fun EHentaiDescription(state: MangaScreenState.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit) {
|
||||
@ -29,7 +29,7 @@ fun EHentaiDescription(state: MangaScreenState.Success, openMetadataViewer: () -
|
||||
val binding = DescriptionAdapterEhBinding.bind(it)
|
||||
|
||||
binding.genre.text =
|
||||
meta.genre?.let { MetadataUtil.getGenreAndColour(context, it) }
|
||||
meta.genre?.let { MetadataUIUtil.getGenreAndColour(context, it) }
|
||||
?.let {
|
||||
binding.genre.setBackgroundColor(it.first)
|
||||
it.second
|
||||
@ -61,7 +61,7 @@ fun EHentaiDescription(state: MangaScreenState.Success, openMetadataViewer: () -
|
||||
val ratingFloat = meta.averageRating?.toFloat()
|
||||
binding.ratingBar.rating = ratingFloat ?: 0F
|
||||
@SuppressLint("SetTextI18n")
|
||||
binding.rating.text = (ratingFloat ?: 0F).toString() + " - " + MetadataUtil.getRatingString(context, ratingFloat?.times(2))
|
||||
binding.rating.text = (ratingFloat ?: 0F).toString() + " - " + MetadataUIUtil.getRatingString(context, ratingFloat?.times(2))
|
||||
|
||||
binding.moreInfo.bindDrawable(context, R.drawable.ic_info_24dp)
|
||||
|
||||
|
@ -10,8 +10,8 @@ import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.databinding.DescriptionAdapter8mBinding
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import exh.metadata.bindDrawable
|
||||
import exh.metadata.metadata.EightMusesSearchMetadata
|
||||
import exh.ui.metadata.adapters.MetadataUIUtil.bindDrawable
|
||||
|
||||
@Composable
|
||||
fun EightMusesDescription(state: MangaScreenState.Success, openMetadataViewer: () -> Unit) {
|
||||
|
@ -10,8 +10,8 @@ import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.databinding.DescriptionAdapterHbBinding
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import exh.metadata.bindDrawable
|
||||
import exh.metadata.metadata.HBrowseSearchMetadata
|
||||
import exh.ui.metadata.adapters.MetadataUIUtil.bindDrawable
|
||||
|
||||
@Composable
|
||||
fun HBrowseDescription(state: MangaScreenState.Success, openMetadataViewer: () -> Unit) {
|
||||
|
@ -11,8 +11,8 @@ import eu.kanade.tachiyomi.databinding.DescriptionAdapterHiBinding
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import exh.metadata.MetadataUtil
|
||||
import exh.metadata.bindDrawable
|
||||
import exh.metadata.metadata.HitomiSearchMetadata
|
||||
import exh.ui.metadata.adapters.MetadataUIUtil.bindDrawable
|
||||
import java.util.Date
|
||||
|
||||
@Composable
|
||||
@ -28,7 +28,7 @@ fun HitomiDescription(state: MangaScreenState.Success, openMetadataViewer: () ->
|
||||
if (meta == null || meta !is HitomiSearchMetadata) return@AndroidView
|
||||
val binding = DescriptionAdapterHiBinding.bind(it)
|
||||
|
||||
binding.genre.text = meta.genre?.let { MetadataUtil.getGenreAndColour(context, it) }?.let {
|
||||
binding.genre.text = meta.genre?.let { MetadataUIUtil.getGenreAndColour(context, it) }?.let {
|
||||
binding.genre.setBackgroundColor(it.first)
|
||||
it.second
|
||||
} ?: meta.genre ?: context.getString(R.string.unknown)
|
||||
|
@ -12,9 +12,9 @@ import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.databinding.DescriptionAdapterMdBinding
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import exh.metadata.MetadataUtil.getRatingString
|
||||
import exh.metadata.bindDrawable
|
||||
import exh.metadata.metadata.MangaDexSearchMetadata
|
||||
import exh.ui.metadata.adapters.MetadataUIUtil.bindDrawable
|
||||
import exh.ui.metadata.adapters.MetadataUIUtil.getRatingString
|
||||
import kotlin.math.round
|
||||
|
||||
@Composable
|
||||
|
73
app/src/main/java/exh/metadata/MetadataUtil.kt → app/src/main/java/exh/ui/metadata/adapters/MetadataUIUtil.kt
Executable file → Normal file
73
app/src/main/java/exh/metadata/MetadataUtil.kt → app/src/main/java/exh/ui/metadata/adapters/MetadataUIUtil.kt
Executable file → Normal file
@ -1,72 +1,17 @@
|
||||
package exh.metadata
|
||||
package exh.ui.metadata.adapters
|
||||
|
||||
import android.content.Context
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.FloatRange
|
||||
import androidx.core.content.ContextCompat
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.source.R
|
||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
import exh.util.SourceTagsUtil
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import kotlin.math.ln
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
/**
|
||||
* Metadata utils
|
||||
*/
|
||||
object MetadataUtil {
|
||||
fun humanReadableByteCount(bytes: Long, si: Boolean): String {
|
||||
val unit = if (si) 1000 else 1024
|
||||
if (bytes < unit) return "$bytes B"
|
||||
val exp = (ln(bytes.toDouble()) / ln(unit.toDouble())).toInt()
|
||||
val pre = (if (si) "kMGTPE" else "KMGTPE")[exp - 1] + if (si) "" else "i"
|
||||
return String.format("%.1f %sB", bytes / unit.toDouble().pow(exp.toDouble()), pre)
|
||||
}
|
||||
|
||||
private const val KB_FACTOR: Long = 1000
|
||||
private const val KIB_FACTOR: Long = 1024
|
||||
private const val MB_FACTOR = 1000 * KB_FACTOR
|
||||
private const val MIB_FACTOR = 1024 * KIB_FACTOR
|
||||
private const val GB_FACTOR = 1000 * MB_FACTOR
|
||||
private const val GIB_FACTOR = 1024 * MIB_FACTOR
|
||||
|
||||
fun parseHumanReadableByteCount(bytes: String): Double? {
|
||||
val ret = bytes.substringBefore(' ').toDouble()
|
||||
return when (bytes.substringAfter(' ')) {
|
||||
"GB" -> ret * GB_FACTOR
|
||||
"GiB" -> ret * GIB_FACTOR
|
||||
"MB" -> ret * MB_FACTOR
|
||||
"MiB" -> ret * MIB_FACTOR
|
||||
"KB" -> ret * KB_FACTOR
|
||||
"KiB" -> ret * KIB_FACTOR
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
val ONGOING_SUFFIX = arrayOf(
|
||||
"[ongoing]",
|
||||
"(ongoing)",
|
||||
"{ongoing}",
|
||||
"<ongoing>",
|
||||
"ongoing",
|
||||
"[incomplete]",
|
||||
"(incomplete)",
|
||||
"{incomplete}",
|
||||
"<incomplete>",
|
||||
"incomplete",
|
||||
"[wip]",
|
||||
"(wip)",
|
||||
"{wip}",
|
||||
"<wip>",
|
||||
"wip",
|
||||
)
|
||||
|
||||
val EX_DATE_FORMAT = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US)
|
||||
|
||||
object MetadataUIUtil {
|
||||
fun getRatingString(context: Context, @FloatRange(from = 0.0, to = 10.0) rating: Float? = null) = when (rating?.roundToInt()) {
|
||||
0 -> R.string.rating0
|
||||
1 -> R.string.rating1
|
||||
@ -103,12 +48,12 @@ object MetadataUtil {
|
||||
}?.let { (genreColor, stringId) ->
|
||||
genreColor.color to context.getString(stringId)
|
||||
}
|
||||
}
|
||||
|
||||
fun TextView.bindDrawable(context: Context, @DrawableRes drawable: Int) {
|
||||
ContextCompat.getDrawable(context, drawable)?.apply {
|
||||
setTint(context.getResourceColor(R.attr.colorAccent))
|
||||
setBounds(0, 0, 20.dpToPx, 20.dpToPx)
|
||||
setCompoundDrawables(this, null, null, null)
|
||||
fun TextView.bindDrawable(context: Context, @DrawableRes drawable: Int) {
|
||||
ContextCompat.getDrawable(context, drawable)?.apply {
|
||||
setTint(context.getResourceColor(R.attr.colorAccent))
|
||||
setBounds(0, 0, 20.dpToPx, 20.dpToPx)
|
||||
setCompoundDrawables(this, null, null, null)
|
||||
}
|
||||
}
|
||||
}
|
@ -12,8 +12,8 @@ import eu.kanade.tachiyomi.databinding.DescriptionAdapterNhBinding
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import exh.metadata.MetadataUtil
|
||||
import exh.metadata.bindDrawable
|
||||
import exh.metadata.metadata.NHentaiSearchMetadata
|
||||
import exh.ui.metadata.adapters.MetadataUIUtil.bindDrawable
|
||||
import java.util.Date
|
||||
|
||||
@Composable
|
||||
@ -32,7 +32,7 @@ fun NHentaiDescription(state: MangaScreenState.Success, openMetadataViewer: () -
|
||||
binding.genre.text = meta.tags.filter { it.namespace == NHentaiSearchMetadata.NHENTAI_CATEGORIES_NAMESPACE }.let { tags ->
|
||||
if (tags.isNotEmpty()) tags.joinToString(transform = { it.name }) else null
|
||||
}.let { categoriesString ->
|
||||
categoriesString?.let { MetadataUtil.getGenreAndColour(context, it) }?.let {
|
||||
categoriesString?.let { MetadataUIUtil.getGenreAndColour(context, it) }?.let {
|
||||
binding.genre.setBackgroundColor(it.first)
|
||||
it.second
|
||||
} ?: categoriesString ?: context.getString(R.string.unknown)
|
||||
|
@ -11,9 +11,8 @@ import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.databinding.DescriptionAdapterPeBinding
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import exh.metadata.MetadataUtil
|
||||
import exh.metadata.bindDrawable
|
||||
import exh.metadata.metadata.PervEdenSearchMetadata
|
||||
import exh.ui.metadata.adapters.MetadataUIUtil.bindDrawable
|
||||
import java.util.Locale
|
||||
import kotlin.math.round
|
||||
|
||||
@ -30,7 +29,7 @@ fun PervEdenDescription(state: MangaScreenState.Success, openMetadataViewer: ()
|
||||
if (meta == null || meta !is PervEdenSearchMetadata) return@AndroidView
|
||||
val binding = DescriptionAdapterPeBinding.bind(it)
|
||||
|
||||
binding.genre.text = meta.genre?.let { MetadataUtil.getGenreAndColour(context, it) }?.let {
|
||||
binding.genre.text = meta.genre?.let { MetadataUIUtil.getGenreAndColour(context, it) }?.let {
|
||||
binding.genre.setBackgroundColor(it.first)
|
||||
it.second
|
||||
} ?: meta.genre ?: context.getString(R.string.unknown)
|
||||
@ -45,7 +44,7 @@ fun PervEdenDescription(state: MangaScreenState.Success, openMetadataViewer: ()
|
||||
|
||||
binding.ratingBar.rating = meta.rating ?: 0F
|
||||
@SuppressLint("SetTextI18n")
|
||||
binding.rating.text = (round((meta.rating ?: 0F) * 100.0) / 100.0).toString() + " - " + MetadataUtil.getRatingString(context, meta.rating?.times(2))
|
||||
binding.rating.text = (round((meta.rating ?: 0F) * 100.0) / 100.0).toString() + " - " + MetadataUIUtil.getRatingString(context, meta.rating?.times(2))
|
||||
|
||||
binding.moreInfo.bindDrawable(context, R.drawable.ic_info_24dp)
|
||||
|
||||
|
@ -11,9 +11,8 @@ import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.databinding.DescriptionAdapterPuBinding
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import exh.metadata.MetadataUtil
|
||||
import exh.metadata.bindDrawable
|
||||
import exh.metadata.metadata.PururinSearchMetadata
|
||||
import exh.ui.metadata.adapters.MetadataUIUtil.bindDrawable
|
||||
import kotlin.math.round
|
||||
|
||||
@Composable
|
||||
@ -30,7 +29,7 @@ fun PururinDescription(state: MangaScreenState.Success, openMetadataViewer: () -
|
||||
val binding = DescriptionAdapterPuBinding.bind(it)
|
||||
|
||||
binding.genre.text = meta.tags.find { it.namespace == PururinSearchMetadata.TAG_NAMESPACE_CATEGORY }.let { genre ->
|
||||
genre?.let { MetadataUtil.getGenreAndColour(context, it.name) }?.let {
|
||||
genre?.let { MetadataUIUtil.getGenreAndColour(context, it.name) }?.let {
|
||||
binding.genre.setBackgroundColor(it.first)
|
||||
it.second
|
||||
} ?: genre?.name ?: context.getString(R.string.unknown)
|
||||
@ -47,7 +46,7 @@ fun PururinDescription(state: MangaScreenState.Success, openMetadataViewer: () -
|
||||
val ratingFloat = meta.averageRating?.toFloat()
|
||||
binding.ratingBar.rating = ratingFloat ?: 0F
|
||||
@SuppressLint("SetTextI18n")
|
||||
binding.rating.text = (round((ratingFloat ?: 0F) * 100.0) / 100.0).toString() + " - " + MetadataUtil.getRatingString(context, ratingFloat?.times(2))
|
||||
binding.rating.text = (round((ratingFloat ?: 0F) * 100.0) / 100.0).toString() + " - " + MetadataUIUtil.getRatingString(context, ratingFloat?.times(2))
|
||||
|
||||
binding.moreInfo.bindDrawable(context, R.drawable.ic_info_24dp)
|
||||
|
||||
|
@ -11,9 +11,8 @@ import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.databinding.DescriptionAdapterTsBinding
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import exh.metadata.MetadataUtil
|
||||
import exh.metadata.bindDrawable
|
||||
import exh.metadata.metadata.TsuminoSearchMetadata
|
||||
import exh.ui.metadata.adapters.MetadataUIUtil.bindDrawable
|
||||
import java.util.Date
|
||||
import kotlin.math.round
|
||||
|
||||
@ -30,7 +29,7 @@ fun TsuminoDescription(state: MangaScreenState.Success, openMetadataViewer: () -
|
||||
if (meta == null || meta !is TsuminoSearchMetadata) return@AndroidView
|
||||
val binding = DescriptionAdapterTsBinding.bind(it)
|
||||
|
||||
binding.genre.text = meta.category?.let { MetadataUtil.getGenreAndColour(context, it) }?.let {
|
||||
binding.genre.text = meta.category?.let { MetadataUIUtil.getGenreAndColour(context, it) }?.let {
|
||||
binding.genre.setBackgroundColor(it.first)
|
||||
it.second
|
||||
} ?: meta.category ?: context.getString(R.string.unknown)
|
||||
@ -47,7 +46,7 @@ fun TsuminoDescription(state: MangaScreenState.Success, openMetadataViewer: () -
|
||||
|
||||
binding.ratingBar.rating = meta.averageRating ?: 0F
|
||||
@SuppressLint("SetTextI18n")
|
||||
binding.rating.text = (round((meta.averageRating ?: 0F) * 100.0) / 100.0).toString() + " - " + MetadataUtil.getRatingString(context, meta.averageRating?.times(2))
|
||||
binding.rating.text = (round((meta.averageRating ?: 0F) * 100.0) / 100.0).toString() + " - " + MetadataUIUtil.getRatingString(context, meta.averageRating?.times(2))
|
||||
|
||||
binding.moreInfo.bindDrawable(context, R.drawable.ic_info_24dp)
|
||||
|
||||
|
@ -34,12 +34,12 @@ object SourceTagsUtil {
|
||||
}
|
||||
if (parsed?.namespace != null) {
|
||||
when (sourceId) {
|
||||
in hitomiSourceIds -> wrapTagHitomi(parsed.namespace, parsed.name.substringBefore('|').trim())
|
||||
in nHentaiSourceIds -> wrapTagNHentai(parsed.namespace, parsed.name.substringBefore('|').trim())
|
||||
in hitomiSourceIds -> wrapTagHitomi(parsed.namespace!!, parsed.name.substringBefore('|').trim())
|
||||
in nHentaiSourceIds -> wrapTagNHentai(parsed.namespace!!, parsed.name.substringBefore('|').trim())
|
||||
in mangaDexSourceIds -> parsed.name
|
||||
PURURIN_SOURCE_ID -> parsed.name.substringBefore('|').trim()
|
||||
TSUMINO_SOURCE_ID -> wrapTagTsumino(parsed.namespace, parsed.name.substringBefore('|').trim())
|
||||
else -> wrapTag(parsed.namespace, parsed.name.substringBefore('|').trim())
|
||||
TSUMINO_SOURCE_ID -> wrapTagTsumino(parsed.namespace!!, parsed.name.substringBefore('|').trim())
|
||||
else -> wrapTag(parsed.namespace!!, parsed.name.substringBefore('|').trim())
|
||||
}
|
||||
} else {
|
||||
null
|
||||
|
@ -1,12 +0,0 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package exh.util
|
||||
|
||||
import java.util.Locale
|
||||
|
||||
fun String.capitalize(locale: Locale = Locale.getDefault()) =
|
||||
replaceFirstChar { if (it.isLowerCase()) it.titlecase(locale) else it.toString() }
|
1
core/.gitignore
vendored
Normal file
1
core/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/build
|
50
core/build.gradle.kts
Normal file
50
core/build.gradle.kts
Normal file
@ -0,0 +1,50 @@
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
kotlin("android")
|
||||
kotlin("plugin.serialization")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "eu.kanade.tachiyomi.core"
|
||||
compileSdk = AndroidConfig.compileSdk
|
||||
|
||||
defaultConfig {
|
||||
minSdk = AndroidConfig.minSdk
|
||||
targetSdk = AndroidConfig.targetSdk
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_1_8.toString()
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":i18n"))
|
||||
|
||||
api(libs.logcat)
|
||||
|
||||
api(libs.rxjava)
|
||||
|
||||
api(libs.okhttp.core)
|
||||
api(libs.okhttp.logging)
|
||||
api(libs.okhttp.dnsoverhttps)
|
||||
api(libs.okio)
|
||||
|
||||
api(kotlinx.coroutines.core)
|
||||
api(kotlinx.serialization.json)
|
||||
|
||||
api(libs.injekt.core)
|
||||
|
||||
api(libs.preferencektx)
|
||||
|
||||
implementation(androidx.corektx)
|
||||
|
||||
// SY -->
|
||||
implementation(sylibs.xlog)
|
||||
// SY <--
|
||||
}
|
2
core/src/main/AndroidManifest.xml
Normal file
2
core/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest />
|
@ -1,22 +1,22 @@
|
||||
package eu.kanade.tachiyomi.network
|
||||
|
||||
import android.content.Context
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import androidx.preference.PreferenceManager
|
||||
import eu.kanade.tachiyomi.i18n.BuildConfig
|
||||
import eu.kanade.tachiyomi.network.interceptor.CloudflareInterceptor
|
||||
import eu.kanade.tachiyomi.network.interceptor.Http103Interceptor
|
||||
import eu.kanade.tachiyomi.network.interceptor.UserAgentInterceptor
|
||||
import okhttp3.Cache
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.File
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/* SY --> */
|
||||
open /* SY <-- */ class NetworkHelper(context: Context) {
|
||||
|
||||
private val preferences: PreferencesHelper by injectLazy()
|
||||
// TODO: Abstract preferences similar to 1.x
|
||||
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
private val cacheDir = File(context.cacheDir, "network_cache")
|
||||
private val cacheSize = 5L * 1024 * 1024 // 5 MiB
|
||||
@ -46,7 +46,7 @@ open /* SY <-- */ class NetworkHelper(context: Context) {
|
||||
builder.addNetworkInterceptor(httpLoggingInterceptor)
|
||||
}
|
||||
|
||||
when (preferences.dohProvider()) {
|
||||
when (preferences.getInt("doh_provider", -1)) {
|
||||
PREF_DOH_CLOUDFLARE -> builder.dohCloudflare()
|
||||
PREF_DOH_GOOGLE -> builder.dohGoogle()
|
||||
PREF_DOH_ADGUARD -> builder.dohAdGuard()
|
||||
@ -74,6 +74,6 @@ open /* SY <-- */ class NetworkHelper(context: Context) {
|
||||
}
|
||||
|
||||
val defaultUserAgent by lazy {
|
||||
preferences.defaultUserAgent().get()
|
||||
preferences.getString("default_user_agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0")!!
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@ import java.util.concurrent.TimeUnit.MINUTES
|
||||
private val DEFAULT_CACHE_CONTROL = CacheControl.Builder().maxAge(10, MINUTES).build()
|
||||
private val DEFAULT_HEADERS = Headers.Builder().build()
|
||||
private val DEFAULT_BODY: RequestBody = FormBody.Builder().build()
|
||||
internal val CACHE_CONTROL_NO_STORE = CacheControl.Builder().noStore().build()
|
||||
val CACHE_CONTROL_NO_STORE = CacheControl.Builder().noStore().build()
|
||||
|
||||
fun GET(
|
||||
url: String,
|
@ -5,7 +5,7 @@ import android.content.Context
|
||||
import android.webkit.WebView
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.ContextCompat
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.core.R
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import eu.kanade.tachiyomi.util.system.WebViewClientCompat
|
||||
import eu.kanade.tachiyomi.util.system.isOutdated
|
@ -5,7 +5,7 @@ import android.os.Build
|
||||
import android.webkit.WebSettings
|
||||
import android.webkit.WebView
|
||||
import android.widget.Toast
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.core.R
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import eu.kanade.tachiyomi.util.lang.launchUI
|
||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
@ -5,6 +5,7 @@ import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.CoroutineStart
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.InternalCoroutinesApi
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import rx.Emitter
|
||||
@ -20,6 +21,7 @@ import kotlin.coroutines.resumeWithException
|
||||
|
||||
suspend fun <T> Observable<T>.awaitSingle(): T = single().awaitOne()
|
||||
|
||||
@OptIn(InternalCoroutinesApi::class)
|
||||
private suspend fun <T> Observable<T>.awaitOne(): T = suspendCancellableCoroutine { cont ->
|
||||
cont.unsubscribeOnCancellation(
|
||||
subscribe(
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.util.system
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Build
|
||||
import com.google.android.material.color.DynamicColors
|
||||
import logcat.LogPriority
|
||||
|
||||
object DeviceUtil {
|
||||
@ -31,10 +30,6 @@ object DeviceUtil {
|
||||
Build.MANUFACTURER.equals("samsung", ignoreCase = true)
|
||||
}
|
||||
|
||||
val isDynamicColorAvailable by lazy {
|
||||
DynamicColors.isDynamicColorAvailable() || (isSamsung && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
|
||||
}
|
||||
|
||||
val invalidDefaultBrowsers = listOf("android", "com.huawei.android.internal.app")
|
||||
|
||||
@SuppressLint("PrivateApi")
|
@ -0,0 +1,28 @@
|
||||
package eu.kanade.tachiyomi.util.system
|
||||
|
||||
import android.content.Context
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.StringRes
|
||||
|
||||
/**
|
||||
* Display a toast in this context.
|
||||
*
|
||||
* @param resource the text resource.
|
||||
* @param duration the duration of the toast. Defaults to short.
|
||||
*/
|
||||
fun Context.toast(@StringRes resource: Int, duration: Int = Toast.LENGTH_SHORT, block: (Toast) -> Unit = {}): Toast {
|
||||
return toast(getString(resource), duration, block)
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a toast in this context.
|
||||
*
|
||||
* @param text the text to display.
|
||||
* @param duration the duration of the toast. Defaults to short.
|
||||
*/
|
||||
fun Context.toast(text: String?, duration: Int = Toast.LENGTH_SHORT, block: (Toast) -> Unit = {}): Toast {
|
||||
return Toast.makeText(applicationContext, text.orEmpty(), duration).also {
|
||||
block(it)
|
||||
it.show()
|
||||
}
|
||||
}
|
@ -3,8 +3,7 @@ package exh.log
|
||||
import android.content.Context
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.preference.PreferenceManager
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys
|
||||
import eu.kanade.tachiyomi.core.R
|
||||
|
||||
enum class EHLogLevel(@StringRes val nameRes: Int, @StringRes val description: Int) {
|
||||
MINIMAL(R.string.log_minimal, R.string.log_minimal_desc),
|
||||
@ -19,7 +18,7 @@ enum class EHLogLevel(@StringRes val nameRes: Int, @StringRes val description: I
|
||||
|
||||
fun init(context: Context) {
|
||||
curLogLevel = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
.getInt(PreferenceKeys.eh_logLevel, 0)
|
||||
.getInt("eh_log_level", 0) // todo
|
||||
}
|
||||
|
||||
fun shouldLog(requiredLogLevel: EHLogLevel): Boolean {
|
@ -1,5 +1,7 @@
|
||||
package exh.util
|
||||
|
||||
import java.util.Locale
|
||||
|
||||
fun Collection<String>.trimAll() = map { it.trim() }
|
||||
fun Collection<String>.dropBlank() = filter { it.isNotBlank() }
|
||||
fun Collection<String>.dropEmpty() = filter { it.isNotEmpty() }
|
||||
@ -13,3 +15,6 @@ fun String.removeArticles(): String {
|
||||
fun String.trimOrNull() = trim().nullIfBlank()
|
||||
|
||||
fun String.nullIfBlank(): String? = ifBlank { null }
|
||||
|
||||
fun String.capitalize(locale: Locale = Locale.getDefault()) =
|
||||
replaceFirstChar { if (it.isLowerCase()) it.titlecase(locale) else it.toString() }
|
@ -40,3 +40,5 @@ dependencyResolutionManagement {
|
||||
rootProject.name = "TachiyomiSY"
|
||||
include(":app")
|
||||
include(":i18n")
|
||||
include(":source-api")
|
||||
include(":core")
|
||||
|
1
source-api/.gitignore
vendored
Normal file
1
source-api/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/build
|
44
source-api/build.gradle.kts
Normal file
44
source-api/build.gradle.kts
Normal file
@ -0,0 +1,44 @@
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
kotlin("android")
|
||||
kotlin("plugin.serialization")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "eu.kanade.tachiyomi.source"
|
||||
compileSdk = AndroidConfig.compileSdk
|
||||
|
||||
defaultConfig {
|
||||
minSdk = AndroidConfig.minSdk
|
||||
targetSdk = AndroidConfig.targetSdk
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_1_8.toString()
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation(project(":core"))
|
||||
|
||||
api(kotlinx.serialization.json)
|
||||
|
||||
api(libs.rxjava)
|
||||
|
||||
api(libs.preferencektx)
|
||||
|
||||
api(libs.jsoup)
|
||||
|
||||
implementation(androidx.corektx)
|
||||
|
||||
// SY -->
|
||||
implementation(project(":i18n"))
|
||||
implementation(kotlinx.reflect)
|
||||
// SY <--
|
||||
}
|
2
source-api/src/main/AndroidManifest.xml
Normal file
2
source-api/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest />
|
@ -1,16 +1,10 @@
|
||||
package eu.kanade.tachiyomi.source
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
import eu.kanade.domain.source.model.SourceData
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||
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.util.lang.awaitSingle
|
||||
import rx.Observable
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
/**
|
||||
* A basic interface for creating a source. It could be an online source, a local source, etc...
|
||||
@ -88,53 +82,3 @@ interface Source {
|
||||
return fetchPageList(chapter).awaitSingle()
|
||||
}
|
||||
}
|
||||
|
||||
fun Source.icon(): Drawable? = Injekt.get<ExtensionManager>().getAppIconForSource(this)
|
||||
|
||||
fun Source.getPreferenceKey(): String = "source_$id"
|
||||
|
||||
fun Source.toSourceData(): SourceData = SourceData(id = id, lang = lang, name = name)
|
||||
|
||||
fun Source.getNameForMangaInfo(mergeSources: List<Source>?): String {
|
||||
val preferences = Injekt.get<PreferencesHelper>()
|
||||
val enabledLanguages = preferences.enabledLanguages().get()
|
||||
.filterNot { it in listOf("all", "other") }
|
||||
val hasOneActiveLanguages = enabledLanguages.size == 1
|
||||
val isInEnabledLanguages = lang in enabledLanguages
|
||||
return when {
|
||||
// SY -->
|
||||
!mergeSources.isNullOrEmpty() -> getMergedSourcesString(
|
||||
mergeSources,
|
||||
enabledLanguages,
|
||||
hasOneActiveLanguages,
|
||||
)
|
||||
// SY <--
|
||||
// For edge cases where user disables a source they got manga of in their library.
|
||||
hasOneActiveLanguages && !isInEnabledLanguages -> toString()
|
||||
// Hide the language tag when only one language is used.
|
||||
hasOneActiveLanguages && isInEnabledLanguages -> name
|
||||
else -> toString()
|
||||
}
|
||||
}
|
||||
|
||||
// SY -->
|
||||
private fun getMergedSourcesString(
|
||||
mergeSources: List<Source>,
|
||||
enabledLangs: List<String>,
|
||||
onlyName: Boolean,
|
||||
): String {
|
||||
return if (onlyName) {
|
||||
mergeSources.joinToString { source ->
|
||||
if (source.lang !in enabledLangs) {
|
||||
source.toString()
|
||||
} else {
|
||||
source.name
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mergeSources.joinToString()
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
|
||||
fun Source.isLocalOrStub(): Boolean = id == LocalSource.ID || this is SourceManager.StubSource
|
@ -1,6 +1,5 @@
|
||||
package eu.kanade.tachiyomi.source.model
|
||||
|
||||
import data.Chapters
|
||||
import java.io.Serializable
|
||||
|
||||
interface SChapter : Serializable {
|
||||
@ -23,14 +22,6 @@ interface SChapter : Serializable {
|
||||
scanlator = other.scanlator
|
||||
}
|
||||
|
||||
fun copyFrom(other: Chapters) {
|
||||
name = other.name
|
||||
url = other.url
|
||||
date_upload = other.date_upload
|
||||
chapter_number = other.chapter_number
|
||||
scanlator = other.scanlator
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun create(): SChapter {
|
||||
return SChapterImpl()
|
@ -1,11 +1,5 @@
|
||||
package eu.kanade.tachiyomi.source.model
|
||||
|
||||
import data.Mangas
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.Serializable
|
||||
|
||||
interface SManga : Serializable {
|
||||
@ -35,28 +29,17 @@ interface SManga : Serializable {
|
||||
|
||||
// SY -->
|
||||
val originalTitle: String
|
||||
get() = (this as? MangaImpl)?.ogTitle ?: title
|
||||
val originalAuthor: String?
|
||||
get() = (this as? MangaImpl)?.ogAuthor ?: author
|
||||
val originalArtist: String?
|
||||
get() = (this as? MangaImpl)?.ogArtist ?: artist
|
||||
val originalDescription: String?
|
||||
get() = (this as? MangaImpl)?.ogDesc ?: description
|
||||
val originalGenre: String?
|
||||
get() = (this as? MangaImpl)?.ogGenre ?: genre
|
||||
val originalStatus: Int
|
||||
get() = (this as? MangaImpl)?.ogStatus ?: status
|
||||
// SY <--
|
||||
|
||||
fun copyFrom(other: SManga) {
|
||||
// EXH -->
|
||||
if (other.title.isNotBlank() && originalTitle != other.title) {
|
||||
val oldTitle = originalTitle
|
||||
title = other.originalTitle
|
||||
val source = (this as? Manga)?.source
|
||||
if (source != null) {
|
||||
Injekt.get<DownloadManager>().renameMangaDir(oldTitle, other.originalTitle, source)
|
||||
}
|
||||
}
|
||||
// EXH <--
|
||||
|
||||
@ -87,45 +70,6 @@ interface SManga : Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
fun copyFrom(other: Mangas) {
|
||||
// EXH -->
|
||||
if (other.title.isNotBlank() && originalTitle != other.title) {
|
||||
val oldTitle = originalTitle
|
||||
title = other.title
|
||||
val source = (this as? Manga)?.source
|
||||
if (source != null) {
|
||||
Injekt.get<DownloadManager>().renameMangaDir(oldTitle, other.title, source)
|
||||
}
|
||||
}
|
||||
// EXH <--
|
||||
|
||||
if (other.author != null) {
|
||||
author = other.author
|
||||
}
|
||||
|
||||
if (other.artist != null) {
|
||||
artist = other.artist
|
||||
}
|
||||
|
||||
if (other.description != null) {
|
||||
description = other.description
|
||||
}
|
||||
|
||||
if (other.genre != null) {
|
||||
genre = other.genre.joinToString(separator = ", ")
|
||||
}
|
||||
|
||||
if (other.thumbnail_url != null) {
|
||||
thumbnail_url = other.thumbnail_url
|
||||
}
|
||||
|
||||
status = other.status.toInt()
|
||||
|
||||
if (!initialized) {
|
||||
initialized = other.initialized
|
||||
}
|
||||
}
|
||||
|
||||
fun copy() = create().also {
|
||||
it.url = url
|
||||
// SY -->
|
@ -21,4 +21,19 @@ class SMangaImpl : SManga {
|
||||
override var thumbnail_url: String? = null
|
||||
|
||||
override var initialized: Boolean = false
|
||||
|
||||
// SY -->
|
||||
override val originalTitle: String
|
||||
get() = title
|
||||
override val originalAuthor: String?
|
||||
get() = author
|
||||
override val originalArtist: String?
|
||||
get() = artist
|
||||
override val originalDescription: String?
|
||||
get() = description
|
||||
override val originalGenre: String?
|
||||
get() = genre
|
||||
override val originalStatus: Int
|
||||
get() = status
|
||||
// SY <--
|
||||
}
|
@ -1,10 +1,8 @@
|
||||
package eu.kanade.tachiyomi.source.online
|
||||
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import exh.md.utils.FollowStatus
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||
|
||||
interface FollowsSource : CatalogueSource {
|
||||
@ -16,14 +14,4 @@ interface FollowsSource : CatalogueSource {
|
||||
* @param SManga all smanga found for user
|
||||
*/
|
||||
suspend fun fetchAllFollows(): List<Pair<SManga, RaisedSearchMetadata>>
|
||||
|
||||
/**
|
||||
* updates the follow status for a manga
|
||||
*/
|
||||
suspend fun updateFollowStatus(mangaID: String, followStatus: FollowStatus): Boolean
|
||||
|
||||
/**
|
||||
* Get a MdList Track of the manga
|
||||
*/
|
||||
suspend fun fetchTrackingInfo(url: String): Track
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
package eu.kanade.tachiyomi.source.online
|
||||
|
||||
import android.app.Application
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.network.AndroidCookieJar
|
||||
import eu.kanade.tachiyomi.network.CACHE_CONTROL_NO_STORE
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
@ -15,7 +14,6 @@ import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import exh.log.maybeInjectEHLogger
|
||||
import exh.patch.injectPatches
|
||||
import exh.source.DelegatedHttpSource
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
@ -43,14 +41,14 @@ abstract class HttpSource : CatalogueSource {
|
||||
override val client: OkHttpClient
|
||||
get() = delegate?.networkHttpClient ?: network.client
|
||||
.newBuilder()
|
||||
.injectPatches { id }
|
||||
//.injectPatches { id } todo
|
||||
.maybeInjectEHLogger()
|
||||
.build()
|
||||
|
||||
override val cloudflareClient: OkHttpClient
|
||||
get() = delegate?.networkCloudflareClient ?: network.cloudflareClient
|
||||
.newBuilder()
|
||||
.injectPatches { id }
|
||||
//.injectPatches { id } todo
|
||||
.maybeInjectEHLogger()
|
||||
.build()
|
||||
|
||||
@ -411,7 +409,7 @@ abstract class HttpSource : CatalogueSource {
|
||||
|
||||
// EXH -->
|
||||
private var delegate: DelegatedHttpSource? = null
|
||||
get() = if (Injekt.get<PreferencesHelper>().delegateSources().get()) {
|
||||
get() = if (Injekt.get<NetworkHelper>().preferences.getBoolean("eh_delegate_sources", true)) { // todo
|
||||
field
|
||||
} else {
|
||||
null
|
@ -1,14 +1,10 @@
|
||||
package eu.kanade.tachiyomi.source.online
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import eu.kanade.domain.manga.interactor.GetFlatMetadataById
|
||||
import eu.kanade.domain.manga.interactor.GetManga
|
||||
import eu.kanade.domain.manga.interactor.InsertFlatMetadata
|
||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||
import eu.kanade.tachiyomi.util.lang.awaitSingle
|
||||
import eu.kanade.tachiyomi.util.lang.runAsObservable
|
||||
import exh.metadata.metadata.base.FlatMetadata
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||
import rx.Completable
|
||||
import rx.Single
|
||||
@ -20,7 +16,16 @@ import kotlin.reflect.KClass
|
||||
* LEWD!
|
||||
*/
|
||||
interface MetadataSource<M : RaisedSearchMetadata, I> : CatalogueSource {
|
||||
val getManga: GetManga get() = Injekt.get()
|
||||
interface GetMangaId {
|
||||
suspend fun awaitId(url: String, sourceId: Long): Long?
|
||||
}
|
||||
interface InsertFlatMetadata {
|
||||
suspend fun await(metadata: RaisedSearchMetadata)
|
||||
}
|
||||
interface GetFlatMetadataById {
|
||||
suspend fun await(id: Long): FlatMetadata?
|
||||
}
|
||||
val getMangaId: GetMangaId get() = Injekt.get()
|
||||
val insertFlatMetadata: InsertFlatMetadata get() = Injekt.get()
|
||||
val getFlatMetadataById: GetFlatMetadataById get() = Injekt.get()
|
||||
|
||||
@ -111,8 +116,5 @@ interface MetadataSource<M : RaisedSearchMetadata, I> : CatalogueSource {
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DescriptionComposable(state: MangaScreenState.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit)
|
||||
|
||||
suspend fun SManga.id() = getManga.await(url, id)?.id
|
||||
suspend fun SManga.id() = getMangaId.awaitId(url, id)
|
||||
}
|
@ -12,6 +12,7 @@ import org.jsoup.nodes.Element
|
||||
/**
|
||||
* A simple implementation for sources from a website using Jsoup, an HTML parser.
|
||||
*/
|
||||
@Suppress("unused")
|
||||
abstract class ParsedHttpSource : HttpSource() {
|
||||
|
||||
/**
|
@ -1,7 +1,7 @@
|
||||
package exh.md.utils
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.source.R
|
||||
|
||||
enum class MangaDexRelation(@StringRes val resId: Int, val mdString: String?) {
|
||||
SIMILAR(R.string.relation_similar, null),
|
60
source-api/src/main/java/exh/metadata/MetadataUtil.kt
Normal file
60
source-api/src/main/java/exh/metadata/MetadataUtil.kt
Normal file
@ -0,0 +1,60 @@
|
||||
package exh.metadata
|
||||
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import kotlin.math.ln
|
||||
import kotlin.math.pow
|
||||
|
||||
/**
|
||||
* Metadata utils
|
||||
*/
|
||||
object MetadataUtil {
|
||||
fun humanReadableByteCount(bytes: Long, si: Boolean): String {
|
||||
val unit = if (si) 1000 else 1024
|
||||
if (bytes < unit) return "$bytes B"
|
||||
val exp = (ln(bytes.toDouble()) / ln(unit.toDouble())).toInt()
|
||||
val pre = (if (si) "kMGTPE" else "KMGTPE")[exp - 1] + if (si) "" else "i"
|
||||
return String.format("%.1f %sB", bytes / unit.toDouble().pow(exp.toDouble()), pre)
|
||||
}
|
||||
|
||||
private const val KB_FACTOR: Long = 1000
|
||||
private const val KIB_FACTOR: Long = 1024
|
||||
private const val MB_FACTOR = 1000 * KB_FACTOR
|
||||
private const val MIB_FACTOR = 1024 * KIB_FACTOR
|
||||
private const val GB_FACTOR = 1000 * MB_FACTOR
|
||||
private const val GIB_FACTOR = 1024 * MIB_FACTOR
|
||||
|
||||
fun parseHumanReadableByteCount(bytes: String): Double? {
|
||||
val ret = bytes.substringBefore(' ').toDouble()
|
||||
return when (bytes.substringAfter(' ')) {
|
||||
"GB" -> ret * GB_FACTOR
|
||||
"GiB" -> ret * GIB_FACTOR
|
||||
"MB" -> ret * MB_FACTOR
|
||||
"MiB" -> ret * MIB_FACTOR
|
||||
"KB" -> ret * KB_FACTOR
|
||||
"KiB" -> ret * KIB_FACTOR
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
val ONGOING_SUFFIX = arrayOf(
|
||||
"[ongoing]",
|
||||
"(ongoing)",
|
||||
"{ongoing}",
|
||||
"<ongoing>",
|
||||
"ongoing",
|
||||
"[incomplete]",
|
||||
"(incomplete)",
|
||||
"{incomplete}",
|
||||
"<incomplete>",
|
||||
"incomplete",
|
||||
"[wip]",
|
||||
"(wip)",
|
||||
"{wip}",
|
||||
"<wip>",
|
||||
"wip",
|
||||
)
|
||||
|
||||
val EX_DATE_FORMAT = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US)
|
||||
}
|
||||
|
@ -2,8 +2,8 @@ package exh.metadata.metadata
|
||||
|
||||
import android.content.Context
|
||||
import androidx.core.net.toUri
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import eu.kanade.tachiyomi.source.R
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.model.copy
|
||||
import exh.metadata.MetadataUtil
|
||||
@ -53,7 +53,7 @@ class EHentaiSearchMetadata : RaisedSearchMetadata() {
|
||||
|
||||
// No title bug?
|
||||
val title = altTitle
|
||||
?.takeIf { Injekt.get<PreferencesHelper>().useJapaneseTitle().get() }
|
||||
?.takeIf { Injekt.get<NetworkHelper>().preferences.getBoolean("use_jp_title", false) } // todo
|
||||
?: title
|
||||
|
||||
// Set artist (if we can find one)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user