Tsumino is now supported by the new tag display, you may have to refresh your Tsumino manga for them to work properly. Also Set the groundwork for more special features
This commit is contained in:
parent
9e986bbeb6
commit
a8f2f03562
@ -4,6 +4,7 @@ import android.content.Context
|
||||
import android.net.Uri
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.source.online.LewdSource
|
||||
@ -14,6 +15,8 @@ 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.util.dropBlank
|
||||
import exh.util.trimAll
|
||||
import exh.util.urlImportFetchSearchManga
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
@ -28,13 +31,13 @@ class Tsumino(delegate: HttpSource, val context: Context) :
|
||||
override val lang = "en"
|
||||
|
||||
// Support direct URL importing
|
||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList) =
|
||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> =
|
||||
urlImportFetchSearchManga(context, query) {
|
||||
super.fetchSearchManga(page, query, filters)
|
||||
}
|
||||
|
||||
override fun mapUrlToMangaUrl(uri: Uri): String? {
|
||||
val lcFirstPathSegment = uri.pathSegments.firstOrNull()?.toLowerCase() ?: return null
|
||||
val lcFirstPathSegment = uri.pathSegments.firstOrNull()?.toLowerCase(Locale.ROOT) ?: return null
|
||||
if (lcFirstPathSegment != "read" && lcFirstPathSegment != "book" && lcFirstPathSegment != "entry") {
|
||||
return null
|
||||
}
|
||||
@ -58,9 +61,12 @@ class Tsumino(delegate: HttpSource, val context: Context) :
|
||||
title = it.trim()
|
||||
}
|
||||
|
||||
input.getElementById("Artist")?.children()?.first()?.text()?.trim()?.let {
|
||||
tags.add(RaisedTag("artist", it, TAG_TYPE_VIRTUAL))
|
||||
artist = it
|
||||
input.getElementById("Artist")?.children()?.first()?.text()?.trim()?.let { artistString ->
|
||||
artistString.split("|").trimAll().dropBlank().forEach {
|
||||
tags.add(RaisedTag("artist", it, TAG_TYPE_DEFAULT))
|
||||
}
|
||||
tags.add(RaisedTag("artist", artistString, TAG_TYPE_VIRTUAL))
|
||||
artist = artistString
|
||||
}
|
||||
|
||||
input.getElementById("Uploader")?.children()?.first()?.text()?.trim()?.let {
|
||||
@ -86,18 +92,19 @@ class Tsumino(delegate: HttpSource, val context: Context) :
|
||||
|
||||
input.getElementById("Collection")?.children()?.first()?.text()?.let {
|
||||
collection = it.trim()
|
||||
tags.add(RaisedTag("collection", it, TAG_TYPE_DEFAULT))
|
||||
}
|
||||
|
||||
input.getElementById("Group")?.children()?.first()?.text()?.let {
|
||||
group = it.trim()
|
||||
tags.add(RaisedTag("group", it, TAG_TYPE_VIRTUAL))
|
||||
tags.add(RaisedTag("group", it, TAG_TYPE_DEFAULT))
|
||||
}
|
||||
|
||||
val newParody = mutableListOf<String>()
|
||||
input.getElementById("Parody")?.children()?.forEach {
|
||||
val entry = it.text().trim()
|
||||
newParody.add(entry)
|
||||
tags.add(RaisedTag("parody", entry, TAG_TYPE_VIRTUAL))
|
||||
tags.add(RaisedTag("parody", entry, TAG_TYPE_DEFAULT))
|
||||
}
|
||||
parody = newParody
|
||||
|
||||
@ -105,14 +112,14 @@ class Tsumino(delegate: HttpSource, val context: Context) :
|
||||
input.getElementById("Character")?.children()?.forEach {
|
||||
val entry = it.text().trim()
|
||||
newCharacter.add(entry)
|
||||
tags.add(RaisedTag("character", entry, TAG_TYPE_VIRTUAL))
|
||||
tags.add(RaisedTag("character", entry, TAG_TYPE_DEFAULT))
|
||||
}
|
||||
character = newCharacter
|
||||
|
||||
input.getElementById("Tag")?.children()?.let {
|
||||
input.getElementById("Tag")?.children()?.let { tagElements ->
|
||||
tags.addAll(
|
||||
it.map {
|
||||
RaisedTag(null, it.text().trim(), TAG_TYPE_DEFAULT)
|
||||
tagElements.map {
|
||||
RaisedTag("tags", it.text().trim(), TAG_TYPE_DEFAULT)
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -126,6 +133,5 @@ class Tsumino(delegate: HttpSource, val context: Context) :
|
||||
|
||||
companion object {
|
||||
val TM_DATE_FORMAT = SimpleDateFormat("yyyy MMM dd", Locale.US)
|
||||
private val ASP_NET_COOKIE_NAME = "ASP.NET_SessionId"
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ import eu.kanade.tachiyomi.source.LocalSource
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.source.online.LewdSource
|
||||
import eu.kanade.tachiyomi.ui.base.controller.FabController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||
@ -69,6 +70,9 @@ import eu.kanade.tachiyomi.util.view.gone
|
||||
import eu.kanade.tachiyomi.util.view.shrinkOnScroll
|
||||
import eu.kanade.tachiyomi.util.view.snack
|
||||
import eu.kanade.tachiyomi.util.view.visible
|
||||
import exh.metadata.metadata.base.FlatMetadata
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||
import exh.source.EnhancedHttpSource
|
||||
import java.io.IOException
|
||||
import kotlinx.android.synthetic.main.main_activity.root_coordinator
|
||||
import kotlinx.coroutines.CancellationException
|
||||
@ -419,6 +423,16 @@ class MangaController :
|
||||
|
||||
// Manga info - start
|
||||
|
||||
// SY -->
|
||||
fun onNextMetaInfo(flatMetadata: FlatMetadata) {
|
||||
presenter.meta = if (presenter.source is LewdSource<*, *>) {
|
||||
flatMetadata.raise((presenter.source as LewdSource<*, *>).metaClass)
|
||||
} else if (presenter.source is EnhancedHttpSource && (presenter.source as EnhancedHttpSource).enhancedSource is LewdSource<*, *>) {
|
||||
flatMetadata.raise(((presenter.source as EnhancedHttpSource).enhancedSource as LewdSource<*, *>).metaClass)
|
||||
} else null
|
||||
}
|
||||
// SY <--
|
||||
|
||||
/**
|
||||
* Check if manga is initialized.
|
||||
* If true update header with manga information,
|
||||
@ -427,10 +441,10 @@ class MangaController :
|
||||
* @param manga manga object containing information about manga.
|
||||
* @param source the source of the manga.
|
||||
*/
|
||||
fun onNextMangaInfo(manga: Manga, source: Source) {
|
||||
fun onNextMangaInfo(manga: Manga, source: Source /* SY --> */, meta: RaisedSearchMetadata? /* SY <-- */) {
|
||||
if (manga.initialized) {
|
||||
// Update view.
|
||||
mangaInfoAdapter?.update(manga, source)
|
||||
mangaInfoAdapter?.update(manga, source /* SY --> */, meta /* SY <-- */)
|
||||
} else {
|
||||
// Initialize manga.
|
||||
fetchMangaInfoFromSource()
|
||||
|
@ -18,6 +18,7 @@ import eu.kanade.tachiyomi.data.library.CustomMangaManager
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.source.LocalSource
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.online.LewdSource
|
||||
import eu.kanade.tachiyomi.source.online.all.MergedSource
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
|
||||
@ -33,6 +34,10 @@ import exh.MERGED_SOURCE_ID
|
||||
import exh.debug.DebugToggles
|
||||
import exh.eh.EHentaiUpdateHelper
|
||||
import exh.isEhBasedSource
|
||||
import exh.metadata.metadata.base.FlatMetadata
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||
import exh.metadata.metadata.base.getFlatMetadataForManga
|
||||
import exh.source.EnhancedHttpSource
|
||||
import exh.util.await
|
||||
import exh.util.trimOrNull
|
||||
import java.util.Date
|
||||
@ -101,15 +106,23 @@ class MangaPresenter(
|
||||
private val redirectUserRelay = BehaviorRelay.create<EXHRedirect>()
|
||||
|
||||
data class EXHRedirect(val manga: Manga, val update: Boolean)
|
||||
|
||||
var meta: RaisedSearchMetadata? = null
|
||||
// EXH <--
|
||||
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
|
||||
// SY -->
|
||||
if (manga.initialized && (source is LewdSource<*, *> || (source is EnhancedHttpSource && source.enhancedSource is LewdSource<*, *>))) {
|
||||
getMangaMetaObservable().subscribeLatestCache({ view, flatMetadata -> if (flatMetadata != null) view.onNextMetaInfo(flatMetadata) else Timber.d("Invalid metadata") })
|
||||
}
|
||||
// SY <--
|
||||
|
||||
// Manga info - start
|
||||
|
||||
getMangaObservable()
|
||||
.subscribeLatestCache({ view, manga -> view.onNextMangaInfo(manga, source) })
|
||||
.subscribeLatestCache({ view, manga -> view.onNextMangaInfo(manga, source /* SY --> */, meta/* SY <-- */) })
|
||||
|
||||
// Prepare the relay.
|
||||
chaptersRelay.flatMap { applyChapterFilters(it) }
|
||||
@ -177,6 +190,16 @@ class MangaPresenter(
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
// SY -->
|
||||
private fun getMangaMetaObservable(): Observable<FlatMetadata?> {
|
||||
val mangaId = manga.id
|
||||
return if (mangaId != null) {
|
||||
db.getFlatMetadataForManga(mangaId).asRxObservable()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
} else Observable.just(null)
|
||||
}
|
||||
// SY <--
|
||||
|
||||
/**
|
||||
* Fetch manga information from source.
|
||||
*/
|
||||
@ -190,6 +213,13 @@ class MangaPresenter(
|
||||
db.insertManga(manga).executeAsBlocking()
|
||||
manga
|
||||
}
|
||||
// SY -->
|
||||
.doOnNext {
|
||||
if (source is LewdSource<*, *> || (source is EnhancedHttpSource && source.enhancedSource is LewdSource<*, *>)) {
|
||||
getMangaMetaObservable().subscribeLatestCache({ view, flatMetadata -> if (flatMetadata != null) view.onNextMetaInfo(flatMetadata) else Timber.d("Invalid metadata") })
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeFirst(
|
||||
@ -259,7 +289,7 @@ class MangaPresenter(
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeLatestCache(
|
||||
{ view, _ ->
|
||||
view.onNextMangaInfo(manga, source)
|
||||
view.onNextMangaInfo(manga, source /* SY --> */, meta/* SY <-- */)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -30,12 +30,9 @@ import eu.kanade.tachiyomi.util.view.gone
|
||||
import eu.kanade.tachiyomi.util.view.setTooltip
|
||||
import eu.kanade.tachiyomi.util.view.visible
|
||||
import eu.kanade.tachiyomi.util.view.visibleIf
|
||||
import exh.EH_SOURCE_ID
|
||||
import exh.EXH_SOURCE_ID
|
||||
import exh.HITOMI_SOURCE_ID
|
||||
import exh.MERGED_SOURCE_ID
|
||||
import exh.NHENTAI_SOURCE_ID
|
||||
import exh.PURURIN_SOURCE_ID
|
||||
import exh.isNamespaceSource
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||
import exh.util.SourceTagsUtil
|
||||
import exh.util.makeSearchChip
|
||||
import exh.util.setChipsExtended
|
||||
@ -57,6 +54,7 @@ class MangaInfoHeaderAdapter(
|
||||
|
||||
private var manga: Manga = controller.presenter.manga
|
||||
private var source: Source = controller.presenter.source
|
||||
private var meta: RaisedSearchMetadata? = controller.presenter.meta
|
||||
|
||||
private val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||
private lateinit var binding: MangaInfoHeaderBinding
|
||||
@ -83,9 +81,10 @@ class MangaInfoHeaderAdapter(
|
||||
* @param manga manga object containing information about manga.
|
||||
* @param source the source of the manga.
|
||||
*/
|
||||
fun update(manga: Manga, source: Source) {
|
||||
fun update(manga: Manga, source: Source, meta: RaisedSearchMetadata?) {
|
||||
this.manga = manga
|
||||
this.source = source
|
||||
this.meta = meta
|
||||
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
@ -336,7 +335,7 @@ class MangaInfoHeaderAdapter(
|
||||
// Update genres list
|
||||
if (!manga.genre.isNullOrBlank()) {
|
||||
// SY -->
|
||||
if (source != null && (source.id == EH_SOURCE_ID || source.id == EXH_SOURCE_ID || source.id == NHENTAI_SOURCE_ID || source.id == HITOMI_SOURCE_ID || source.id == PURURIN_SOURCE_ID)) {
|
||||
if (source != null && source.isNamespaceSource()) {
|
||||
val genre = manga.getGenres()
|
||||
if (!genre.isNullOrEmpty()) {
|
||||
val namespaceTags = genre.map { SourceTagsUtil().parseTag(it) }
|
||||
@ -414,7 +413,7 @@ class MangaInfoHeaderAdapter(
|
||||
|
||||
binding.mangaGenresTagsCompact.visibleIf { isExpanded }
|
||||
// SY -->
|
||||
if (source.id == EH_SOURCE_ID || source.id == EXH_SOURCE_ID || source.id == NHENTAI_SOURCE_ID || source.id == HITOMI_SOURCE_ID || source.id == PURURIN_SOURCE_ID) {
|
||||
if (source.isNamespaceSource()) {
|
||||
binding.mangaNamespaceTagsRecycler.visibleIf { !isExpanded }
|
||||
} else {
|
||||
binding.mangaGenresTagsFullChips.visibleIf { !isExpanded }
|
||||
|
@ -57,3 +57,5 @@ fun isLewdSource(source: Long) = source in 6900..6999 ||
|
||||
lewdDelegatedSourceIds.binarySearch(source) >= 0
|
||||
|
||||
fun Source.isEhBasedSource() = id == EH_SOURCE_ID || id == EXH_SOURCE_ID
|
||||
|
||||
fun Source.isNamespaceSource() = id == EH_SOURCE_ID || id == EXH_SOURCE_ID || id == NHENTAI_SOURCE_ID || id == HITOMI_SOURCE_ID || id == PURURIN_SOURCE_ID || id == TSUMINO_SOURCE_ID
|
||||
|
@ -5,6 +5,7 @@ import exh.EXH_SOURCE_ID
|
||||
import exh.HITOMI_SOURCE_ID
|
||||
import exh.NHENTAI_SOURCE_ID
|
||||
import exh.PURURIN_SOURCE_ID
|
||||
import exh.TSUMINO_SOURCE_ID
|
||||
|
||||
class SourceTagsUtil {
|
||||
fun getWrappedTag(sourceId: Long, namespace: String? = null, tag: String? = null, fullTag: String? = null): String? {
|
||||
@ -15,6 +16,7 @@ class SourceTagsUtil {
|
||||
HITOMI_SOURCE_ID -> wrapTagHitomi(parsed.first, parsed.second.substringBefore('|').trim())
|
||||
NHENTAI_SOURCE_ID -> wrapTagNHentai(parsed.first, parsed.second.substringBefore('|').trim())
|
||||
PURURIN_SOURCE_ID -> parsed.second.substringBefore('|').trim()
|
||||
TSUMINO_SOURCE_ID -> parsed.second.substringBefore('|').trim()
|
||||
else -> wrapTag(parsed.first, parsed.second.substringBefore('|').trim())
|
||||
}
|
||||
} else null
|
||||
|
Loading…
x
Reference in New Issue
Block a user