Show Mangadex relations in Mangadex similar
This commit is contained in:
parent
87d9512b1f
commit
77f5acf2dd
@ -9,6 +9,7 @@ import eu.kanade.tachiyomi.data.track.TrackManager
|
|||||||
import eu.kanade.tachiyomi.data.track.mdlist.MdList
|
import eu.kanade.tachiyomi.data.track.mdlist.MdList
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
|
import eu.kanade.tachiyomi.source.model.MetadataMangasPage
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
import eu.kanade.tachiyomi.source.model.SChapter
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
@ -284,10 +285,14 @@ class MangaDex(delegate: HttpSource, val context: Context) :
|
|||||||
return mangaHandler.fetchRandomMangaId()
|
return mangaHandler.fetchRandomMangaId()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getMangaSimilar(manga: MangaInfo): MangasPage {
|
suspend fun getMangaSimilar(manga: MangaInfo): MetadataMangasPage {
|
||||||
return similarHandler.getSimilar(manga)
|
return similarHandler.getSimilar(manga)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun getMangaRelated(manga: MangaInfo): MetadataMangasPage {
|
||||||
|
return similarHandler.getRelated(manga)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val dataSaverPref = "dataSaverV5"
|
private const val dataSaverPref = "dataSaverV5"
|
||||||
|
|
||||||
|
@ -61,6 +61,10 @@ class SourceComfortableGridHolder(private val view: View, private val adapter: F
|
|||||||
binding.badges.localText.text = itemView.context.resources.getStringArray(R.array.md_follows_options).asList()[it]
|
binding.badges.localText.text = itemView.context.resources.getStringArray(R.array.md_follows_options).asList()[it]
|
||||||
binding.badges.localText.isVisible = true
|
binding.badges.localText.isVisible = true
|
||||||
}
|
}
|
||||||
|
metadata.relation?.let {
|
||||||
|
binding.badges.localText.setText(it.resId)
|
||||||
|
binding.badges.localText.isVisible = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// SY <--
|
// SY <--
|
||||||
|
@ -58,6 +58,10 @@ open class SourceCompactGridHolder(private val view: View, private val adapter:
|
|||||||
binding.badges.localText.text = itemView.context.resources.getStringArray(R.array.md_follows_options).asList()[it]
|
binding.badges.localText.text = itemView.context.resources.getStringArray(R.array.md_follows_options).asList()[it]
|
||||||
binding.badges.localText.isVisible = true
|
binding.badges.localText.isVisible = true
|
||||||
}
|
}
|
||||||
|
metadata.relation?.let {
|
||||||
|
binding.badges.localText.setText(it.resId)
|
||||||
|
binding.badges.localText.isVisible = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// SY <--
|
// SY <--
|
||||||
|
@ -58,6 +58,10 @@ class SourceListHolder(private val view: View, adapter: FlexibleAdapter<*>) :
|
|||||||
binding.localText.text = itemView.context.resources.getStringArray(R.array.md_follows_options).asList()[it]
|
binding.localText.text = itemView.context.resources.getStringArray(R.array.md_follows_options).asList()[it]
|
||||||
binding.localText.isVisible = true
|
binding.localText.isVisible = true
|
||||||
}
|
}
|
||||||
|
metadata.relation?.let {
|
||||||
|
binding.localText.setText(it.resId)
|
||||||
|
binding.localText.isVisible = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// SY <--
|
// SY <--
|
||||||
|
@ -18,3 +18,25 @@ data class SimilarMangaMatchListDto(
|
|||||||
val contentRating: String,
|
val contentRating: String,
|
||||||
val score: Double,
|
val score: Double,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class RelationListDto(
|
||||||
|
val response: String,
|
||||||
|
val data: List<RelationDto>,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class RelationDto(
|
||||||
|
val attributes: RelationAttributesDto,
|
||||||
|
val relationships: List<RelationMangaDto>,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class RelationMangaDto(
|
||||||
|
val id: String
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class RelationAttributesDto(
|
||||||
|
val relation: String,
|
||||||
|
)
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
package exh.md.handlers
|
package exh.md.handlers
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
import eu.kanade.tachiyomi.source.model.MetadataMangasPage
|
||||||
import eu.kanade.tachiyomi.source.model.toSManga
|
import eu.kanade.tachiyomi.source.model.toSManga
|
||||||
|
import eu.kanade.tachiyomi.util.lang.withIOContext
|
||||||
|
import exh.md.dto.RelationListDto
|
||||||
import exh.md.dto.SimilarMangaDto
|
import exh.md.dto.SimilarMangaDto
|
||||||
import exh.md.service.MangaDexService
|
import exh.md.service.MangaDexService
|
||||||
import exh.md.service.SimilarService
|
import exh.md.service.SimilarService
|
||||||
|
import exh.md.utils.MangaDexRelation
|
||||||
import exh.md.utils.MdUtil
|
import exh.md.utils.MdUtil
|
||||||
|
import exh.metadata.metadata.MangaDexSearchMetadata
|
||||||
import tachiyomi.source.model.MangaInfo
|
import tachiyomi.source.model.MangaInfo
|
||||||
|
|
||||||
class SimilarHandler(
|
class SimilarHandler(
|
||||||
@ -14,14 +18,14 @@ class SimilarHandler(
|
|||||||
private val similarService: SimilarService
|
private val similarService: SimilarService
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend fun getSimilar(manga: MangaInfo): MangasPage {
|
suspend fun getSimilar(manga: MangaInfo): MetadataMangasPage {
|
||||||
val similarDto = similarService.getSimilarManga(MdUtil.getMangaId(manga.key))
|
val similarDto = withIOContext { similarService.getSimilarManga(MdUtil.getMangaId(manga.key)) }
|
||||||
return similarDtoToMangaListPage(similarDto)
|
return similarDtoToMangaListPage(similarDto)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun similarDtoToMangaListPage(
|
private suspend fun similarDtoToMangaListPage(
|
||||||
similarMangaDto: SimilarMangaDto,
|
similarMangaDto: SimilarMangaDto,
|
||||||
): MangasPage {
|
): MetadataMangasPage {
|
||||||
val ids = similarMangaDto.matches.map {
|
val ids = similarMangaDto.matches.map {
|
||||||
it.id
|
it.id
|
||||||
}
|
}
|
||||||
@ -30,6 +34,34 @@ class SimilarHandler(
|
|||||||
MdUtil.createMangaEntry(it, lang).toSManga()
|
MdUtil.createMangaEntry(it, lang).toSManga()
|
||||||
}
|
}
|
||||||
|
|
||||||
return MangasPage(mangaList, false)
|
return MetadataMangasPage(mangaList, false, List(mangaList.size) { MangaDexSearchMetadata().also { it.relation = MangaDexRelation.SIMILAR } })
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getRelated(manga: MangaInfo): MetadataMangasPage {
|
||||||
|
val relatedListDto = withIOContext { service.relatedManga(MdUtil.getMangaId(manga.key)) }
|
||||||
|
return relatedDtoToMangaListPage(relatedListDto)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun relatedDtoToMangaListPage(
|
||||||
|
relatedListDto: RelationListDto,
|
||||||
|
): MetadataMangasPage {
|
||||||
|
val ids = relatedListDto.data
|
||||||
|
.mapNotNull { it.relationships.firstOrNull() }
|
||||||
|
.map { it.id }
|
||||||
|
|
||||||
|
val mangaList = service.viewMangas(ids).data.map {
|
||||||
|
MdUtil.createMangaEntry(it, lang).toSManga()
|
||||||
|
}
|
||||||
|
|
||||||
|
return MetadataMangasPage(
|
||||||
|
mangas = mangaList,
|
||||||
|
hasNextPage = false,
|
||||||
|
mangasMetadata = mangaList.map { manga ->
|
||||||
|
MangaDexSearchMetadata().also {
|
||||||
|
it.relation = relatedListDto.data.firstOrNull { it.relationships.any { it.id == MdUtil.getMangaId(manga.url) } }
|
||||||
|
?.attributes?.relation?.let(MangaDexRelation::fromDex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import exh.md.dto.ChapterDto
|
|||||||
import exh.md.dto.ChapterListDto
|
import exh.md.dto.ChapterListDto
|
||||||
import exh.md.dto.MangaDto
|
import exh.md.dto.MangaDto
|
||||||
import exh.md.dto.MangaListDto
|
import exh.md.dto.MangaListDto
|
||||||
|
import exh.md.dto.RelationListDto
|
||||||
import exh.md.dto.ResultDto
|
import exh.md.dto.ResultDto
|
||||||
import exh.md.utils.MdApi
|
import exh.md.utils.MdApi
|
||||||
import exh.md.utils.MdConstants
|
import exh.md.utils.MdConstants
|
||||||
@ -145,6 +146,21 @@ class MangaDexService(
|
|||||||
): AtHomeDto {
|
): AtHomeDto {
|
||||||
return client.newCall(GET(atHomeRequestUrl, headers, CacheControl.FORCE_NETWORK))
|
return client.newCall(GET(atHomeRequestUrl, headers, CacheControl.FORCE_NETWORK))
|
||||||
.await()
|
.await()
|
||||||
.parseAs()
|
.parseAs(MdUtil.jsonParser)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun relatedManga(id: String): RelationListDto {
|
||||||
|
return client.newCall(
|
||||||
|
GET(
|
||||||
|
MdApi.manga.toHttpUrl().newBuilder()
|
||||||
|
.apply {
|
||||||
|
addPathSegment(id)
|
||||||
|
addPathSegment("relation")
|
||||||
|
}
|
||||||
|
.build()
|
||||||
|
.toString(),
|
||||||
|
cache = CacheControl.FORCE_NETWORK
|
||||||
|
)
|
||||||
|
).await().parseAs(MdUtil.jsonParser)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,12 @@ package exh.md.similar
|
|||||||
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.database.models.toMangaInfo
|
import eu.kanade.tachiyomi.data.database.models.toMangaInfo
|
||||||
|
import eu.kanade.tachiyomi.source.model.MetadataMangasPage
|
||||||
import eu.kanade.tachiyomi.source.online.all.MangaDex
|
import eu.kanade.tachiyomi.source.online.all.MangaDex
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.NoResultsException
|
import eu.kanade.tachiyomi.ui.browse.source.browse.NoResultsException
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.Pager
|
import eu.kanade.tachiyomi.ui.browse.source.browse.Pager
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import kotlinx.coroutines.coroutineScope
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MangaDexSimilarPager inherited from the general Pager.
|
* MangaDexSimilarPager inherited from the general Pager.
|
||||||
@ -12,7 +15,18 @@ import eu.kanade.tachiyomi.ui.browse.source.browse.Pager
|
|||||||
class MangaDexSimilarPager(val manga: Manga, val source: MangaDex) : Pager() {
|
class MangaDexSimilarPager(val manga: Manga, val source: MangaDex) : Pager() {
|
||||||
|
|
||||||
override suspend fun requestNextPage() {
|
override suspend fun requestNextPage() {
|
||||||
val mangasPage = source.getMangaSimilar(manga.toMangaInfo())
|
val mangasPage = coroutineScope {
|
||||||
|
val similarPageDef = async { source.getMangaSimilar(manga.toMangaInfo()) }
|
||||||
|
val relatedPageDef = async { source.getMangaRelated(manga.toMangaInfo()) }
|
||||||
|
val similarPage = similarPageDef.await()
|
||||||
|
val relatedPage = relatedPageDef.await()
|
||||||
|
|
||||||
|
MetadataMangasPage(
|
||||||
|
relatedPage.mangas + similarPage.mangas,
|
||||||
|
false,
|
||||||
|
relatedPage.mangasMetadata + similarPage.mangasMetadata
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if (mangasPage.mangas.isNotEmpty()) {
|
if (mangasPage.mangas.isNotEmpty()) {
|
||||||
onPageReceived(mangasPage)
|
onPageReceived(mangasPage)
|
||||||
|
27
app/src/main/java/exh/md/utils/MangaDexRelation.kt
Normal file
27
app/src/main/java/exh/md/utils/MangaDexRelation.kt
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package exh.md.utils
|
||||||
|
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
|
||||||
|
enum class MangaDexRelation(@StringRes val resId: Int, val mdString: String?) {
|
||||||
|
SIMILAR(R.string.relation_similar, null),
|
||||||
|
MONOCHROME(R.string.relation_monochrome, "monochrome"),
|
||||||
|
MAIN_STORY(R.string.relation_main_story, "main_story"),
|
||||||
|
ADAPTED_FROM(R.string.relation_adapted_from, "adapted_from"),
|
||||||
|
BASED_ON(R.string.relation_based_on, "based_on"),
|
||||||
|
PREQUEL(R.string.relation_prequel, "prequel"),
|
||||||
|
SIDE_STORY(R.string.relation_side_story, "side_story"),
|
||||||
|
DOUJINSHI(R.string.relation_doujinshi, "doujinshi"),
|
||||||
|
SAME_FRANCHISE(R.string.relation_same_franchise, "same_franchise"),
|
||||||
|
SHARED_UNIVERSE(R.string.relation_shared_universe, "shared_universe"),
|
||||||
|
SEQUEL(R.string.relation_sequel, "sequel"),
|
||||||
|
SPIN_OFF(R.string.relation_spin_off, "spin_off"),
|
||||||
|
ALTERNATE_STORY(R.string.relation_alternate_story, "alternate_story"),
|
||||||
|
PRESERIALIZATION(R.string.relation_preserialization, "preserialization"),
|
||||||
|
COLORED(R.string.relation_colored, "colored"),
|
||||||
|
SERIALIZATION(R.string.relation_serialization, "serialization");
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun fromDex(mdString: String) = values().find { it.mdString == mdString }
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ package exh.metadata.metadata
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
import exh.md.utils.MangaDexRelation
|
||||||
import exh.md.utils.MdUtil
|
import exh.md.utils.MdUtil
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@ -40,6 +41,7 @@ class MangaDexSearchMetadata : RaisedSearchMetadata() {
|
|||||||
// var missing_chapters: String? = null
|
// var missing_chapters: String? = null
|
||||||
|
|
||||||
var followStatus: Int? = null
|
var followStatus: Int? = null
|
||||||
|
var relation: MangaDexRelation? = null
|
||||||
|
|
||||||
// var maxChapterNumber: Int? = null
|
// var maxChapterNumber: Int? = null
|
||||||
|
|
||||||
|
@ -669,6 +669,24 @@
|
|||||||
<!-- Similar -->
|
<!-- Similar -->
|
||||||
<string name="similar">Similar to %1$s</string>
|
<string name="similar">Similar to %1$s</string>
|
||||||
<string name="similar_no_results">No Similar Manga found</string>
|
<string name="similar_no_results">No Similar Manga found</string>
|
||||||
|
|
||||||
|
<!-- Mangadex relations-->
|
||||||
|
<string name="relation_similar">Similar</string>
|
||||||
|
<string name="relation_monochrome">Monochrome</string>
|
||||||
|
<string name="relation_main_story">Main story</string>
|
||||||
|
<string name="relation_adapted_from">Adapted from</string>
|
||||||
|
<string name="relation_based_on">Based on</string>
|
||||||
|
<string name="relation_prequel">Prequel</string>
|
||||||
|
<string name="relation_side_story">Side story</string>
|
||||||
|
<string name="relation_doujinshi">Doujinshi</string>
|
||||||
|
<string name="relation_same_franchise">Same franchise</string>
|
||||||
|
<string name="relation_shared_universe">Shared universe</string>
|
||||||
|
<string name="relation_sequel">Sequel</string>
|
||||||
|
<string name="relation_spin_off">Spin-off</string>
|
||||||
|
<string name="relation_alternate_story">Alternate story</string>
|
||||||
|
<string name="relation_preserialization">Pre-serialization</string>
|
||||||
|
<string name="relation_colored">Colored</string>
|
||||||
|
<string name="relation_serialization">Serialization</string>
|
||||||
|
|
||||||
<!-- Humanize time -->
|
<!-- Humanize time -->
|
||||||
<plurals name="humanize_year">
|
<plurals name="humanize_year">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user