Update MangaPlus to handle the subscription changes (#18367)
* Update MangaPlus to handle the subscription changes. * Update the FAQ for MangaPlus. * Remove unused import.
This commit is contained in:
parent
477ef241b3
commit
42a3e238fe
|
@ -9,10 +9,10 @@ Table of Content
|
||||||
|
|
||||||
### Why chapters are missing in some titles?
|
### Why chapters are missing in some titles?
|
||||||
|
|
||||||
MANGA Plus does not host all chapters due to their licensing politics. The website
|
MANGA Plus does not host all chapters for free due to their licensing politics. The website
|
||||||
is designed to let the users read the weekly/monthly official simulreleases. If you want
|
is designed to let the users read the weekly/monthly official simulreleases. If you want
|
||||||
to read old chapters of a series that does not have the complete list, you need to find
|
to read old chapters of a series that does not have the complete list, you need subscribe
|
||||||
another sources.
|
to one of their paid plans and read directly in their app instead.
|
||||||
|
|
||||||
### Why disabling split pages setting does not work?
|
### Why disabling split pages setting does not work?
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,20 @@ image_quality_high=High
|
||||||
image_quality_low=Low
|
image_quality_low=Low
|
||||||
image_quality_medium=Medium
|
image_quality_medium=Medium
|
||||||
not_available=Title not available in this language.
|
not_available=Title not available in this language.
|
||||||
|
rating=Rating: %s
|
||||||
|
rating_all_ages=All ages
|
||||||
|
rating_mature=Mature
|
||||||
|
rating_teen=Teen
|
||||||
|
rating_teen_plus=Teen Plus
|
||||||
|
schedule=Schedule: %s
|
||||||
|
schedule_bimonthly=Bimonthly
|
||||||
|
schedule_biweekly=Biweekly
|
||||||
|
schedule_everyday=Everyday
|
||||||
|
schedule_monthly=Monthly
|
||||||
|
schedule_other=Other
|
||||||
|
schedule_trimonthly=Trimonthly
|
||||||
|
schedule_weekly=Weekly
|
||||||
|
serialization=Serialization: %s
|
||||||
split_double_pages=Split double pages
|
split_double_pages=Split double pages
|
||||||
split_double_pages_summary=Only a few titles supports disabling this setting.
|
split_double_pages_summary=Only a few titles supports disabling this setting.
|
||||||
title_removed=This title was removed from the MANGA Plus catalogue.
|
title_removed=This title was removed from the MANGA Plus catalogue.
|
||||||
|
|
|
@ -4,6 +4,20 @@ image_quality_high=Alta
|
||||||
image_quality_low=Baixa
|
image_quality_low=Baixa
|
||||||
image_quality_medium=Média
|
image_quality_medium=Média
|
||||||
not_available=Título não disponível neste idioma.
|
not_available=Título não disponível neste idioma.
|
||||||
|
rating=Classificação: %s
|
||||||
|
rating_all_ages=Todas as idades
|
||||||
|
rating_mature=+18
|
||||||
|
rating_teen=+10
|
||||||
|
rating_teen_plus=+16
|
||||||
|
schedule=Periodicidade: %s
|
||||||
|
schedule_bimonthly=Bimestral
|
||||||
|
schedule_biweekly=Bisemanal
|
||||||
|
schedule_everyday=Diário
|
||||||
|
schedule_monthly=Mensal
|
||||||
|
schedule_other=Outros
|
||||||
|
schedule_trimonthly=Trimestral
|
||||||
|
schedule_weekly=Semanal
|
||||||
|
serialization=Serialização: %s
|
||||||
split_double_pages=Dividir as páginas duplas
|
split_double_pages=Dividir as páginas duplas
|
||||||
split_double_pages_summary=Somente poucos títulos suportam a desativação desta configuração.
|
split_double_pages_summary=Somente poucos títulos suportam a desativação desta configuração.
|
||||||
title_removed=Este título foi removido do catálogo do MANGA Plus.
|
title_removed=Este título foi removido do catálogo do MANGA Plus.
|
||||||
|
|
|
@ -6,7 +6,7 @@ ext {
|
||||||
extName = 'MANGA Plus by SHUEISHA'
|
extName = 'MANGA Plus by SHUEISHA'
|
||||||
pkgNameSuffix = 'all.mangaplus'
|
pkgNameSuffix = 'all.mangaplus'
|
||||||
extClass = '.MangaPlusFactory'
|
extClass = '.MangaPlusFactory'
|
||||||
extVersionCode = 44
|
extVersionCode = 45
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
|
@ -186,7 +186,7 @@ class MangaPlus(
|
||||||
|
|
||||||
titleResult.success.titleDetailView!!
|
titleResult.success.titleDetailView!!
|
||||||
.takeIf { it.title.language == langCode }
|
.takeIf { it.title.language == langCode }
|
||||||
?.toSManga()
|
?.toSManga(intl)
|
||||||
}
|
}
|
||||||
|
|
||||||
return MangasPage(listOfNotNull(title), hasNextPage = false)
|
return MangasPage(listOfNotNull(title), hasNextPage = false)
|
||||||
|
@ -220,7 +220,7 @@ class MangaPlus(
|
||||||
.set("Referer", "$baseUrl/titles/$titleId")
|
.set("Referer", "$baseUrl/titles/$titleId")
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
return GET("$API_URL/title_detail?title_id=$titleId&format=json", newHeaders)
|
return GET("$API_URL/title_detailV3?title_id=$titleId&format=json", newHeaders)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun mangaDetailsParse(response: Response): SManga {
|
override fun mangaDetailsParse(response: Response): SManga {
|
||||||
|
@ -240,7 +240,7 @@ class MangaPlus(
|
||||||
.takeIf { it.title.language == langCode }
|
.takeIf { it.title.language == langCode }
|
||||||
?: throw Exception(intl["not_available"])
|
?: throw Exception(intl["not_available"])
|
||||||
|
|
||||||
return titleDetails.toSManga()
|
return titleDetails.toSManga(intl)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun chapterListRequest(manga: SManga): Request = mangaDetailsRequest(manga.url)
|
override fun chapterListRequest(manga: SManga): Request = mangaDetailsRequest(manga.url)
|
||||||
|
@ -260,11 +260,10 @@ class MangaPlus(
|
||||||
|
|
||||||
val titleDetailView = result.success.titleDetailView!!
|
val titleDetailView = result.success.titleDetailView!!
|
||||||
|
|
||||||
val chapters = titleDetailView.firstChapterList + titleDetailView.lastChapterList
|
return titleDetailView.chapterList
|
||||||
|
|
||||||
return chapters.reversed()
|
|
||||||
.filterNot(Chapter::isExpired)
|
.filterNot(Chapter::isExpired)
|
||||||
.map(Chapter::toSChapter)
|
.map(Chapter::toSChapter)
|
||||||
|
.reversed()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the '#' and map to the new url format used in website.
|
// Remove the '#' and map to the new url format used in website.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package eu.kanade.tachiyomi.extension.all.mangaplus
|
package eu.kanade.tachiyomi.extension.all.mangaplus
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.lib.i18n.Intl
|
||||||
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
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
|
@ -57,51 +58,83 @@ data class TitleDetailView(
|
||||||
val title: Title,
|
val title: Title,
|
||||||
val titleImageUrl: String,
|
val titleImageUrl: String,
|
||||||
val overview: String? = null,
|
val overview: String? = null,
|
||||||
val backgroundImageUrl: String,
|
|
||||||
val nextTimeStamp: Int = 0,
|
val nextTimeStamp: Int = 0,
|
||||||
val viewingPeriodDescription: String = "",
|
val viewingPeriodDescription: String = "",
|
||||||
val nonAppearanceInfo: String = "",
|
val nonAppearanceInfo: String = "",
|
||||||
val firstChapterList: List<Chapter> = emptyList(),
|
val chapterListGroup: List<ChapterListGroup> = emptyList(),
|
||||||
val lastChapterList: List<Chapter> = emptyList(),
|
|
||||||
val isSimulReleased: Boolean = false,
|
val isSimulReleased: Boolean = false,
|
||||||
|
val rating: Rating = Rating.ALL_AGES,
|
||||||
val chaptersDescending: Boolean = true,
|
val chaptersDescending: Boolean = true,
|
||||||
|
val titleLabels: TitleLabels,
|
||||||
|
val label: Label? = Label(LabelCode.WEEKLY_SHOUNEN_JUMP),
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
val chapterList: List<Chapter> by lazy {
|
||||||
|
chapterListGroup.flatMap { it.firstChapterList + it.lastChapterList }
|
||||||
|
}
|
||||||
|
|
||||||
private val isWebtoon: Boolean
|
private val isWebtoon: Boolean
|
||||||
get() = firstChapterList.all(Chapter::isVerticalOnly) &&
|
get() = chapterList.isNotEmpty() && chapterList.all(Chapter::isVerticalOnly)
|
||||||
lastChapterList.all(Chapter::isVerticalOnly)
|
|
||||||
|
|
||||||
private val isOneShot: Boolean
|
private val isOneShot: Boolean
|
||||||
get() = chapterCount == 1 && firstChapterList.firstOrNull()
|
get() = chapterList.size == 1 && chapterList.firstOrNull()
|
||||||
?.name?.equals("one-shot", true) == true
|
?.name?.equals("one-shot", true) == true
|
||||||
|
|
||||||
private val chapterCount: Int
|
|
||||||
get() = firstChapterList.size + lastChapterList.size
|
|
||||||
|
|
||||||
private val isReEdition: Boolean
|
private val isReEdition: Boolean
|
||||||
get() = viewingPeriodDescription.contains(REEDITION_REGEX)
|
get() = viewingPeriodDescription.contains(REEDITION_REGEX)
|
||||||
|
|
||||||
private val isCompleted: Boolean
|
private val isCompleted: Boolean
|
||||||
get() = nonAppearanceInfo.contains(COMPLETED_REGEX) || isOneShot
|
get() = nonAppearanceInfo.contains(COMPLETED_REGEX) || isOneShot ||
|
||||||
|
titleLabels.releaseSchedule == ReleaseSchedule.COMPLETED ||
|
||||||
|
titleLabels.releaseSchedule == ReleaseSchedule.DISABLED
|
||||||
|
|
||||||
|
private val isSimulpub: Boolean
|
||||||
|
get() = isSimulReleased || titleLabels.isSimulpub
|
||||||
|
|
||||||
private val isOnHiatus: Boolean
|
private val isOnHiatus: Boolean
|
||||||
get() = nonAppearanceInfo.contains(HIATUS_REGEX)
|
get() = nonAppearanceInfo.contains(HIATUS_REGEX)
|
||||||
|
|
||||||
private val genres: List<String>
|
private fun createGenres(intl: Intl): List<String> = buildList {
|
||||||
get() = listOfNotNull(
|
if (isSimulpub && !isReEdition && !isOneShot && !isCompleted) {
|
||||||
"Simulrelease".takeIf { isSimulReleased && !isReEdition && !isOneShot },
|
add("Simulrelease")
|
||||||
"One-shot".takeIf { isOneShot },
|
}
|
||||||
"Re-edition".takeIf { isReEdition },
|
|
||||||
"Webtoon".takeIf { isWebtoon },
|
|
||||||
)
|
|
||||||
|
|
||||||
fun toSManga(): SManga = title.toSManga().apply {
|
if (isOneShot) {
|
||||||
description = (overview.orEmpty() + "\n\n" + viewingPeriodDescription).trim()
|
add("One-shot")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isReEdition) {
|
||||||
|
add("Re-edition")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isWebtoon) {
|
||||||
|
add("Webtoon")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (label?.magazine != null) {
|
||||||
|
add(intl.format("serialization", label.magazine))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isCompleted) {
|
||||||
|
val scheduleLabel = intl["schedule_" + titleLabels.releaseSchedule.toString().lowercase()]
|
||||||
|
add(intl.format("schedule", scheduleLabel))
|
||||||
|
}
|
||||||
|
|
||||||
|
val ratingLabel = intl["rating_" + rating.toString().lowercase()]
|
||||||
|
add(intl.format("rating", ratingLabel))
|
||||||
|
}
|
||||||
|
|
||||||
|
private val viewingInformation: String?
|
||||||
|
get() = viewingPeriodDescription.takeIf { !isCompleted }
|
||||||
|
|
||||||
|
fun toSManga(intl: Intl): SManga = title.toSManga().apply {
|
||||||
|
description = "${overview.orEmpty()}\n\n${viewingInformation.orEmpty()}".trim()
|
||||||
status = when {
|
status = when {
|
||||||
isCompleted -> SManga.COMPLETED
|
isCompleted -> SManga.COMPLETED
|
||||||
isOnHiatus -> SManga.ON_HIATUS
|
isOnHiatus -> SManga.ON_HIATUS
|
||||||
else -> SManga.ONGOING
|
else -> SManga.ONGOING
|
||||||
}
|
}
|
||||||
genre = genres.joinToString()
|
genre = createGenres(intl).joinToString()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -111,6 +144,82 @@ data class TitleDetailView(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class TitleLabels(
|
||||||
|
val releaseSchedule: ReleaseSchedule = ReleaseSchedule.DISABLED,
|
||||||
|
val isSimulpub: Boolean = false,
|
||||||
|
)
|
||||||
|
|
||||||
|
enum class ReleaseSchedule {
|
||||||
|
DISABLED,
|
||||||
|
EVERYDAY,
|
||||||
|
WEEKLY,
|
||||||
|
BIWEEKLY,
|
||||||
|
MONTHLY,
|
||||||
|
BIMONTHLY,
|
||||||
|
TRIMONTHLY,
|
||||||
|
OTHER,
|
||||||
|
COMPLETED,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class Rating {
|
||||||
|
@SerialName("ALLAGE")
|
||||||
|
ALL_AGES,
|
||||||
|
TEEN,
|
||||||
|
|
||||||
|
@SerialName("TEENPLUS")
|
||||||
|
TEEN_PLUS,
|
||||||
|
MATURE,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class Label(val label: LabelCode? = LabelCode.WEEKLY_SHOUNEN_JUMP) {
|
||||||
|
val magazine: String?
|
||||||
|
get() = when (label) {
|
||||||
|
LabelCode.WEEKLY_SHOUNEN_JUMP -> "Weekly Shounen Jump"
|
||||||
|
LabelCode.JUMP_SQUARE -> "Jump SQ."
|
||||||
|
LabelCode.V_JUMP -> "V Jump"
|
||||||
|
LabelCode.WEEKLY_YOUNG_JUMP -> "Weekly Young Jump"
|
||||||
|
LabelCode.TONARI_NO_YOUNG_JUMP -> "Tonari no Young Jump"
|
||||||
|
LabelCode.SHOUNEN_JUMP_PLUS -> "Shounen Jump+"
|
||||||
|
LabelCode.REVIVAL -> "Revival"
|
||||||
|
LabelCode.MANGA_PLUS_CREATORS -> "MANGA Plus Creators"
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class LabelCode {
|
||||||
|
@SerialName("WJ")
|
||||||
|
WEEKLY_SHOUNEN_JUMP,
|
||||||
|
|
||||||
|
@SerialName("SQ")
|
||||||
|
JUMP_SQUARE,
|
||||||
|
|
||||||
|
@SerialName("VJ")
|
||||||
|
V_JUMP,
|
||||||
|
|
||||||
|
@SerialName("YJ")
|
||||||
|
WEEKLY_YOUNG_JUMP,
|
||||||
|
|
||||||
|
@SerialName("TYJ")
|
||||||
|
TONARI_NO_YOUNG_JUMP,
|
||||||
|
|
||||||
|
@SerialName("J_PLUS")
|
||||||
|
SHOUNEN_JUMP_PLUS,
|
||||||
|
REVIVAL,
|
||||||
|
|
||||||
|
@SerialName("CREATORS")
|
||||||
|
MANGA_PLUS_CREATORS,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ChapterListGroup(
|
||||||
|
val firstChapterList: List<Chapter> = emptyList(),
|
||||||
|
val lastChapterList: List<Chapter> = emptyList(),
|
||||||
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class MangaViewer(
|
data class MangaViewer(
|
||||||
val pages: List<MangaPlusPage> = emptyList(),
|
val pages: List<MangaPlusPage> = emptyList(),
|
||||||
|
@ -124,7 +233,6 @@ data class Title(
|
||||||
val name: String,
|
val name: String,
|
||||||
val author: String? = null,
|
val author: String? = null,
|
||||||
val portraitImageUrl: String,
|
val portraitImageUrl: String,
|
||||||
val landscapeImageUrl: String,
|
|
||||||
val viewCount: Int = 0,
|
val viewCount: Int = 0,
|
||||||
val language: Language? = Language.ENGLISH,
|
val language: Language? = Language.ENGLISH,
|
||||||
) {
|
) {
|
||||||
|
|
Loading…
Reference in New Issue