Some fixes for Manga Plus (#1146)
* Fix images not loading and duplicated content. * Remove Log import from debug. * Increase version. * Fix 'Open in Browser' action.
This commit is contained in:
parent
110190c239
commit
126a5ec612
|
@ -5,7 +5,7 @@ ext {
|
||||||
appName = 'Tachiyomi: Manga Plus by Shueisha'
|
appName = 'Tachiyomi: Manga Plus by Shueisha'
|
||||||
pkgNameSuffix = 'en.mangaplus'
|
pkgNameSuffix = 'en.mangaplus'
|
||||||
extClass = '.MangaPlus'
|
extClass = '.MangaPlus'
|
||||||
extVersionCode = 2
|
extVersionCode = 3
|
||||||
libVersion = '1.2'
|
libVersion = '1.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import okhttp3.*
|
import okhttp3.*
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import java.lang.Exception
|
import java.lang.Exception
|
||||||
import java.util.UUID.randomUUID
|
import java.util.UUID
|
||||||
|
|
||||||
class MangaPlus : HttpSource() {
|
class MangaPlus : HttpSource() {
|
||||||
override val name = "Manga Plus by Shueisha"
|
override val name = "Manga Plus by Shueisha"
|
||||||
|
@ -22,14 +22,17 @@ class MangaPlus : HttpSource() {
|
||||||
|
|
||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
|
|
||||||
private val catalogHeaders = Headers.Builder().apply {
|
private val catalogHeaders = Headers.Builder()
|
||||||
|
.apply {
|
||||||
add("Origin", WEB_URL)
|
add("Origin", WEB_URL)
|
||||||
add("Referer", WEB_URL)
|
add("Referer", WEB_URL)
|
||||||
add("User-Agent", USER_AGENT)
|
add("User-Agent", USER_AGENT)
|
||||||
add("SESSION-TOKEN", randomUUID().toString())
|
add("SESSION-TOKEN", UUID.randomUUID().toString())
|
||||||
}.build()
|
}
|
||||||
|
.build()
|
||||||
|
|
||||||
override val client = network.client.newBuilder().addInterceptor {
|
override val client = network.client.newBuilder()
|
||||||
|
.addInterceptor {
|
||||||
var request = it.request()
|
var request = it.request()
|
||||||
|
|
||||||
if (!request.url().queryParameterNames().contains("encryptionKey")) {
|
if (!request.url().queryParameterNames().contains("encryptionKey")) {
|
||||||
|
@ -48,7 +51,8 @@ class MangaPlus : HttpSource() {
|
||||||
|
|
||||||
val body = ResponseBody.create(MediaType.parse("image/jpeg"), image)
|
val body = ResponseBody.create(MediaType.parse("image/jpeg"), image)
|
||||||
response.newBuilder().body(body).build()
|
response.newBuilder().body(body).build()
|
||||||
}.build()
|
}
|
||||||
|
.build()
|
||||||
|
|
||||||
override fun popularMangaRequest(page: Int): Request {
|
override fun popularMangaRequest(page: Int): Request {
|
||||||
return GET("$baseUrl/title_list/ranking", catalogHeaders)
|
return GET("$baseUrl/title_list/ranking", catalogHeaders)
|
||||||
|
@ -60,7 +64,9 @@ class MangaPlus : HttpSource() {
|
||||||
if (result["success"] == null)
|
if (result["success"] == null)
|
||||||
return MangasPage(emptyList(), false)
|
return MangasPage(emptyList(), false)
|
||||||
|
|
||||||
val mangas = result["success"]["titleRankingView"]["titles"].array.map {
|
val mangas = result["success"]["titleRankingView"]["titles"].array
|
||||||
|
.filter { if (it.obj.has("language")) it["language"].int < 1 else true }
|
||||||
|
.map {
|
||||||
SManga.create().apply {
|
SManga.create().apply {
|
||||||
title = it["name"].string
|
title = it["name"].string
|
||||||
thumbnail_url = it["portraitImageUrl"].string
|
thumbnail_url = it["portraitImageUrl"].string
|
||||||
|
@ -84,21 +90,21 @@ class MangaPlus : HttpSource() {
|
||||||
val mangas = result["success"]["webHomeView"]["groups"].array
|
val mangas = result["success"]["webHomeView"]["groups"].array
|
||||||
.flatMap { it["titles"].array }
|
.flatMap { it["titles"].array }
|
||||||
.mapNotNull { it["title"].obj }
|
.mapNotNull { it["title"].obj }
|
||||||
|
.filter { if (it.obj.has("language")) it["language"].int < 1 else true }
|
||||||
.map {
|
.map {
|
||||||
SManga.create().apply {
|
SManga.create().apply {
|
||||||
title = it["name"].string
|
title = it["name"].string
|
||||||
thumbnail_url = it["portraitImageUrl"].string
|
thumbnail_url = removeDuration(it["portraitImageUrl"].string)
|
||||||
url = "#/titles/${it["titleId"].int}"
|
url = "#/titles/${it["titleId"].int}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.distinctBy { it.title }
|
||||||
|
|
||||||
return MangasPage(mangas, false)
|
return MangasPage(mangas, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
||||||
return client.newCall(searchMangaRequest(page, query, filters))
|
return super.fetchSearchManga(page, query, filters)
|
||||||
.asObservableSuccess()
|
|
||||||
.map { searchMangaParse(it) }
|
|
||||||
.map { MangasPage(it.mangas.filter { m -> m.title.contains(query, true) }, it.hasNextPage) }
|
.map { MangasPage(it.mangas.filter { m -> m.title.contains(query, true) }, it.hasNextPage) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,10 +118,12 @@ class MangaPlus : HttpSource() {
|
||||||
if (result["success"] == null)
|
if (result["success"] == null)
|
||||||
return MangasPage(emptyList(), false)
|
return MangasPage(emptyList(), false)
|
||||||
|
|
||||||
val mangas = result["success"]["allTitlesView"]["titles"].array.map {
|
val mangas = result["success"]["allTitlesView"]["titles"].array
|
||||||
|
.filter { if (it.obj.has("language")) it["language"].int < 1 else true }
|
||||||
|
.map {
|
||||||
SManga.create().apply {
|
SManga.create().apply {
|
||||||
title = it["name"].string
|
title = it["name"].string
|
||||||
thumbnail_url = it["portraitImageUrl"].string
|
thumbnail_url = removeDuration(it["portraitImageUrl"].string)
|
||||||
url = "#/titles/${it["titleId"].int}"
|
url = "#/titles/${it["titleId"].int}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,13 +136,23 @@ class MangaPlus : HttpSource() {
|
||||||
return GET("$baseUrl/title_detail?title_id=$mangaId", catalogHeaders)
|
return GET("$baseUrl/title_detail?title_id=$mangaId", catalogHeaders)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun mangaDetailsRequest(manga: SManga): Request = titleDetailsRequest(manga)
|
// Workaround to allow "Open in browser" use the real URL.
|
||||||
|
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
|
||||||
|
return client.newCall(titleDetailsRequest(manga))
|
||||||
|
.asObservableSuccess()
|
||||||
|
.map { response ->
|
||||||
|
mangaDetailsParse(response).apply { initialized = true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always returns the real URL for the "Open in browser".
|
||||||
|
override fun mangaDetailsRequest(manga: SManga): Request = GET(WEB_URL + manga.url, catalogHeaders)
|
||||||
|
|
||||||
override fun mangaDetailsParse(response: Response): SManga {
|
override fun mangaDetailsParse(response: Response): SManga {
|
||||||
val result = response.asProto()
|
val result = response.asProto()
|
||||||
|
|
||||||
if (result["success"] == null)
|
if (result["success"] == null)
|
||||||
throw Exception("Some error happened when trying to obtain the title details.")
|
throw Exception(result["error"]["englishPopup"]["body"].string)
|
||||||
|
|
||||||
val details = result["success"]["titleDetailView"].obj
|
val details = result["success"]["titleDetailView"].obj
|
||||||
val title = details["title"].obj
|
val title = details["title"].obj
|
||||||
|
@ -144,6 +162,7 @@ class MangaPlus : HttpSource() {
|
||||||
artist = title["author"].string
|
artist = title["author"].string
|
||||||
description = details["overview"].string + "\n\n" + details["viewingPeriodDescription"].string
|
description = details["overview"].string + "\n\n" + details["viewingPeriodDescription"].string
|
||||||
status = SManga.ONGOING
|
status = SManga.ONGOING
|
||||||
|
thumbnail_url = removeDuration(title["portraitImageUrl"].string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +172,7 @@ class MangaPlus : HttpSource() {
|
||||||
val result = response.asProto()
|
val result = response.asProto()
|
||||||
|
|
||||||
if (result["success"] == null)
|
if (result["success"] == null)
|
||||||
return emptyList()
|
throw Exception(result["error"]["englishPopup"]["body"].string)
|
||||||
|
|
||||||
val titleDetailView = result["success"]["titleDetailView"].obj
|
val titleDetailView = result["success"]["titleDetailView"].obj
|
||||||
|
|
||||||
|
@ -183,7 +202,7 @@ class MangaPlus : HttpSource() {
|
||||||
val result = response.asProto()
|
val result = response.asProto()
|
||||||
|
|
||||||
if (result["success"] == null)
|
if (result["success"] == null)
|
||||||
return emptyList()
|
throw Exception(result["error"]["englishPopup"]["body"].string)
|
||||||
|
|
||||||
return result["success"]["mangaViewer"]["pages"].array
|
return result["success"]["mangaViewer"]["pages"].array
|
||||||
.mapNotNull { it["page"].obj }
|
.mapNotNull { it["page"].obj }
|
||||||
|
@ -203,11 +222,14 @@ class MangaPlus : HttpSource() {
|
||||||
val newHeaders = Headers.Builder().apply {
|
val newHeaders = Headers.Builder().apply {
|
||||||
add("Referer", WEB_URL)
|
add("Referer", WEB_URL)
|
||||||
add("User-Agent", USER_AGENT)
|
add("User-Agent", USER_AGENT)
|
||||||
}.build()
|
|
||||||
|
|
||||||
return GET(page.imageUrl!!, newHeaders)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return GET(page.imageUrl!!, newHeaders.build())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maybe removing the duration parameter make the image accessible forever.
|
||||||
|
private fun removeDuration(url: String): String = url.substringBefore("&duration")
|
||||||
|
|
||||||
private fun decodeImage(encryptionKey: String, image: ByteArray): ByteArray {
|
private fun decodeImage(encryptionKey: String, image: ByteArray): ByteArray {
|
||||||
val variablesSrc = """
|
val variablesSrc = """
|
||||||
var ENCRYPTION_KEY = "$encryptionKey";
|
var ENCRYPTION_KEY = "$encryptionKey";
|
||||||
|
@ -293,6 +315,7 @@ class MangaPlus : HttpSource() {
|
||||||
var Root = protobuf.Root;
|
var Root = protobuf.Root;
|
||||||
var Type = protobuf.Type;
|
var Type = protobuf.Type;
|
||||||
var Field = protobuf.Field;
|
var Field = protobuf.Field;
|
||||||
|
var Enum = protobuf.Enum;
|
||||||
|
|
||||||
var Response = new Type("Response")
|
var Response = new Type("Response")
|
||||||
.add(new Field("success", 1, "SuccessResult"))
|
.add(new Field("success", 1, "SuccessResult"))
|
||||||
|
@ -303,6 +326,10 @@ class MangaPlus : HttpSource() {
|
||||||
.add(new Field("englishPopup", 2, "Popup"))
|
.add(new Field("englishPopup", 2, "Popup"))
|
||||||
.add(new Field("spanishPopup", 3, "Popup"));
|
.add(new Field("spanishPopup", 3, "Popup"));
|
||||||
|
|
||||||
|
var Popup = new Type("Popup")
|
||||||
|
.add(new Field("subject", 1, "string"))
|
||||||
|
.add(new Field("body", 2, "string"));
|
||||||
|
|
||||||
var SuccessResult = new Type("SuccessResult")
|
var SuccessResult = new Type("SuccessResult")
|
||||||
.add(new Field("allTitlesView", 5, "AllTitlesView"))
|
.add(new Field("allTitlesView", 5, "AllTitlesView"))
|
||||||
.add(new Field("titleRankingView", 6, "TitleRankingView"))
|
.add(new Field("titleRankingView", 6, "TitleRankingView"))
|
||||||
|
@ -325,6 +352,7 @@ class MangaPlus : HttpSource() {
|
||||||
.add(new Field("viewingPeriodDescription", 7, "string"))
|
.add(new Field("viewingPeriodDescription", 7, "string"))
|
||||||
.add(new Field("firstChapterList", 9, "Chapter", "repeated"))
|
.add(new Field("firstChapterList", 9, "Chapter", "repeated"))
|
||||||
.add(new Field("lastChapterList", 10, "Chapter", "repeated"))
|
.add(new Field("lastChapterList", 10, "Chapter", "repeated"))
|
||||||
|
.add(new Field("isSimulReleased", 14, "bool"))
|
||||||
.add(new Field("chaptersDescending", 17, "bool"));
|
.add(new Field("chaptersDescending", 17, "bool"));
|
||||||
|
|
||||||
var MangaViewer = new Type("MangaViewer")
|
var MangaViewer = new Type("MangaViewer")
|
||||||
|
@ -335,7 +363,11 @@ class MangaPlus : HttpSource() {
|
||||||
.add(new Field("name", 2, "string"))
|
.add(new Field("name", 2, "string"))
|
||||||
.add(new Field("author", 3, "string"))
|
.add(new Field("author", 3, "string"))
|
||||||
.add(new Field("portraitImageUrl", 4, "string"))
|
.add(new Field("portraitImageUrl", 4, "string"))
|
||||||
.add(new Field("language", 7, "int32"));
|
.add(new Field("landscapeImageUrl", 5, "string"))
|
||||||
|
.add(new Field("viewCount", 6, "uint32"))
|
||||||
|
.add(new Field("language", 7, "Language"));
|
||||||
|
|
||||||
|
var Language = new Enum("Language", {"english": 0, "spanish": 1});
|
||||||
|
|
||||||
var UpdatedTitleGroup = new Type("UpdatedTitleGroup")
|
var UpdatedTitleGroup = new Type("UpdatedTitleGroup")
|
||||||
.add(new Field("groupName", 1, "string"))
|
.add(new Field("groupName", 1, "string"))
|
||||||
|
@ -368,6 +400,7 @@ class MangaPlus : HttpSource() {
|
||||||
.define("mangaplus")
|
.define("mangaplus")
|
||||||
.add(Response)
|
.add(Response)
|
||||||
.add(ErrorResult)
|
.add(ErrorResult)
|
||||||
|
.add(Popup)
|
||||||
.add(SuccessResult)
|
.add(SuccessResult)
|
||||||
.add(TitleRankingView)
|
.add(TitleRankingView)
|
||||||
.add(AllTitlesView)
|
.add(AllTitlesView)
|
||||||
|
@ -375,6 +408,7 @@ class MangaPlus : HttpSource() {
|
||||||
.add(TitleDetailView)
|
.add(TitleDetailView)
|
||||||
.add(MangaViewer)
|
.add(MangaViewer)
|
||||||
.add(Title)
|
.add(Title)
|
||||||
|
.add(Language)
|
||||||
.add(UpdatedTitleGroup)
|
.add(UpdatedTitleGroup)
|
||||||
.add(UpdatedTitle)
|
.add(UpdatedTitle)
|
||||||
.add(Chapter)
|
.add(Chapter)
|
||||||
|
|
Loading…
Reference in New Issue