mangadex beta WIP (#427)
* This update does a few things fixes #384 updates to support new api for mangadex being released soon switches genre to tristate adds filter by source language updates icon * added icons back * updated build.gradle
|
@ -5,8 +5,8 @@ ext {
|
||||||
appName = 'Tachiyomi: MangaDex'
|
appName = 'Tachiyomi: MangaDex'
|
||||||
pkgNameSuffix = 'all.mangadex'
|
pkgNameSuffix = 'all.mangadex'
|
||||||
extClass = '.MangadexFactory'
|
extClass = '.MangadexFactory'
|
||||||
extVersionCode = 32
|
extVersionCode = 33
|
||||||
extVersionSuffix = 32
|
extVersionSuffix = 33
|
||||||
libVersion = '1.2'
|
libVersion = '1.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 7.9 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 24 KiB |
|
@ -53,7 +53,6 @@ open class Mangadex(override val lang: String, private val internalLang: String,
|
||||||
.request()
|
.request()
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.addHeader("Cookie", cookiesHeader(r18Toggle, langCode))
|
.addHeader("Cookie", cookiesHeader(r18Toggle, langCode))
|
||||||
.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64)")
|
|
||||||
.build()
|
.build()
|
||||||
chain.proceed(newReq)
|
chain.proceed(newReq)
|
||||||
}.build()!!
|
}.build()!!
|
||||||
|
@ -154,17 +153,21 @@ open class Mangadex(override val lang: String, private val internalLang: String,
|
||||||
|
|
||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||||
val byGenre = filters.find { it is GenreList }
|
val byGenre = filters.find { it is GenreList }
|
||||||
val genres = mutableListOf<String>()
|
val genresToInclude = mutableListOf<String>()
|
||||||
|
val genresToExclude = mutableListOf<String>()
|
||||||
|
|
||||||
if (byGenre != null) {
|
if (byGenre != null) {
|
||||||
byGenre as GenreList
|
byGenre as GenreList
|
||||||
byGenre.state.forEach { genre ->
|
byGenre.state.forEach { genre ->
|
||||||
when (genre.state) {
|
if (genre.isExcluded()) {
|
||||||
true -> genres.add(genre.id)
|
genresToExclude.add(genre.id)
|
||||||
|
} else if (genre.isIncluded()) {
|
||||||
|
genresToInclude.add(genre.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//do traditional search
|
//do traditional search
|
||||||
val url = HttpUrl.parse("$baseUrl/?page=search")!!.newBuilder().addQueryParameter("p", page.toString()).addQueryParameter("title", query.replace(whitespaceRegex, " "))
|
val url = HttpUrl.parse("$baseUrl/?page=search")!!.newBuilder().addQueryParameter("s", "0").addQueryParameter("p", page.toString()).addQueryParameter("title", query.replace(whitespaceRegex, " "))
|
||||||
filters.forEach { filter ->
|
filters.forEach { filter ->
|
||||||
when (filter) {
|
when (filter) {
|
||||||
is TextField -> url.addQueryParameter(filter.key, filter.state)
|
is TextField -> url.addQueryParameter(filter.key, filter.state)
|
||||||
|
@ -173,11 +176,20 @@ open class Mangadex(override val lang: String, private val internalLang: String,
|
||||||
url.addQueryParameter("demo", filter.state.toString())
|
url.addQueryParameter("demo", filter.state.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
is OriginalLanguage -> {
|
||||||
|
if (filter.state != 0) {
|
||||||
|
val number: String = SOURCE_LANG_LIST.first { it -> it.first == filter.values[filter.state] }?.second
|
||||||
|
url.addQueryParameter("source_lang", number)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (genres.isNotEmpty()) {
|
if (genresToInclude.isNotEmpty()) {
|
||||||
url.addQueryParameter("genres", genres.joinToString(","))
|
url.addQueryParameter("genres_inc", genresToInclude.joinToString(","))
|
||||||
|
}
|
||||||
|
if (genresToExclude.isNotEmpty()) {
|
||||||
|
url.addQueryParameter("genres_exc", genresToExclude.joinToString(","))
|
||||||
}
|
}
|
||||||
return GET(url.toString(), headers)
|
return GET(url.toString(), headers)
|
||||||
|
|
||||||
|
@ -208,7 +220,7 @@ open class Mangadex(override val lang: String, private val internalLang: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun apiRequest(manga: SManga): Request {
|
private fun apiRequest(manga: SManga): Request {
|
||||||
return GET(baseUrl + URL + getMangaId(manga.url), headers)
|
return GET(baseUrl + API_MANGA + getMangaId(manga.url), headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getMangaId(url: String): String {
|
private fun getMangaId(url: String): String {
|
||||||
|
@ -244,7 +256,7 @@ open class Mangadex(override val lang: String, private val internalLang: String,
|
||||||
var genres = mutableListOf<String>()
|
var genres = mutableListOf<String>()
|
||||||
|
|
||||||
mangaJson.get("genres").asJsonArray.forEach { id ->
|
mangaJson.get("genres").asJsonArray.forEach { id ->
|
||||||
getGenreList().find { it -> it.id == id.string }?.let { genre ->
|
GENRE_LIST.find { it -> it.id == id.string }?.let { genre ->
|
||||||
genres.add(genre.name)
|
genres.add(genre.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -287,7 +299,7 @@ open class Mangadex(override val lang: String, private val internalLang: String,
|
||||||
|
|
||||||
override fun chapterListParse(response: Response): List<SChapter> {
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
val now = Date().time
|
val now = Date().time
|
||||||
var jsonData = response.body()!!.string()
|
val jsonData = response.body()!!.string()
|
||||||
val json = JsonParser().parse(jsonData).asJsonObject
|
val json = JsonParser().parse(jsonData).asJsonObject
|
||||||
val mangaJson = json.getAsJsonObject("manga")
|
val mangaJson = json.getAsJsonObject("manga")
|
||||||
val status = mangaJson.get("status").int
|
val status = mangaJson.get("status").int
|
||||||
|
@ -310,8 +322,8 @@ open class Mangadex(override val lang: String, private val internalLang: String,
|
||||||
|
|
||||||
private fun chapterFromJson(chapterId: String, chapterJson: JsonObject, finalChapterNumber: String, status: Int): SChapter {
|
private fun chapterFromJson(chapterId: String, chapterJson: JsonObject, finalChapterNumber: String, status: Int): SChapter {
|
||||||
val chapter = SChapter.create()
|
val chapter = SChapter.create()
|
||||||
chapter.url = BASE_CHAPTER + chapterId
|
chapter.url = API_CHAPTER + chapterId
|
||||||
var chapterName = mutableListOf<String>()
|
val chapterName = mutableListOf<String>()
|
||||||
//build chapter name
|
//build chapter name
|
||||||
if (chapterJson.get("volume").string.isNotBlank()) {
|
if (chapterJson.get("volume").string.isNotBlank()) {
|
||||||
chapterName.add("Vol." + chapterJson.get("volume").string)
|
chapterName.add("Vol." + chapterJson.get("volume").string)
|
||||||
|
@ -342,7 +354,7 @@ open class Mangadex(override val lang: String, private val internalLang: String,
|
||||||
if (!chapterJson.get("group_name_3").nullString.isNullOrBlank()) {
|
if (!chapterJson.get("group_name_3").nullString.isNullOrBlank()) {
|
||||||
scanlatorName.add(chapterJson.get("group_name_3").string)
|
scanlatorName.add(chapterJson.get("group_name_3").string)
|
||||||
}
|
}
|
||||||
chapter.scanlator = scanlatorName.joinToString(" & ")
|
chapter.scanlator = cleanString(scanlatorName.joinToString(" & "))
|
||||||
|
|
||||||
|
|
||||||
return chapter
|
return chapter
|
||||||
|
@ -350,15 +362,20 @@ open class Mangadex(override val lang: String, private val internalLang: String,
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element) = throw Exception("Not used")
|
override fun chapterFromElement(element: Element) = throw Exception("Not used")
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
override fun pageListParse(document: Document) = throw Exception("Not used")
|
||||||
val pages = mutableListOf<Page>()
|
|
||||||
val dataUrl = document.select("script").last().html().substringAfter("dataurl = '").substringBefore("';")
|
|
||||||
val imageUrl = document.select("script").last().html().substringAfter("page_array = [").substringBefore("];")
|
|
||||||
val listImageUrls = imageUrl.replace("'", "").split(",")
|
|
||||||
val server = document.select("script").last().html().substringAfter("server = '").substringBefore("';")
|
|
||||||
|
|
||||||
listImageUrls.filter { it.isNotBlank() }.forEach {
|
override fun pageListParse(response: Response): List<Page> {
|
||||||
val url = "$server$dataUrl/$it"
|
var jsonData = response.body()!!.string()
|
||||||
|
val json = JsonParser().parse(jsonData).asJsonObject
|
||||||
|
|
||||||
|
val pages = mutableListOf<Page>()
|
||||||
|
|
||||||
|
val hash = json.get("hash").string
|
||||||
|
val pageArray = json.getAsJsonArray("page_array")
|
||||||
|
val server = json.get("server").string
|
||||||
|
|
||||||
|
pageArray.forEach {
|
||||||
|
val url = "$server$hash/$it"
|
||||||
pages.add(Page(pages.size, "", getImageUrl(url)))
|
pages.add(Page(pages.size, "", getImageUrl(url)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,64 +420,23 @@ open class Mangadex(override val lang: String, private val internalLang: String,
|
||||||
|
|
||||||
|
|
||||||
private class TextField(name: String, val key: String) : Filter.Text(name)
|
private class TextField(name: String, val key: String) : Filter.Text(name)
|
||||||
private class Genre(val id: String, name: String) : Filter.CheckBox(name)
|
private class Genre(val id: String, name: String) : Filter.TriState(name)
|
||||||
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres)
|
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres)
|
||||||
private class R18 : Filter.Select<String>("R18+", arrayOf("Show all", "Show only", "Show none"))
|
private class R18 : Filter.Select<String>("R18+", arrayOf("Show all", "Show only", "Show none"))
|
||||||
private class Demographic : Filter.Select<String>("Demographic", arrayOf("All", "Shounen", "Shoujo", "Seinen", "Josei"))
|
private class Demographic : Filter.Select<String>("Demographic", arrayOf("All", "Shounen", "Shoujo", "Seinen", "Josei"))
|
||||||
|
private class OriginalLanguage : Filter.Select<String>("Original Language", SOURCE_LANG_LIST.map { it -> it.first }.toTypedArray())
|
||||||
|
|
||||||
|
|
||||||
override fun getFilterList() = FilterList(
|
override fun getFilterList() = FilterList(
|
||||||
TextField("Author", "author"),
|
TextField("Author", "author"),
|
||||||
TextField("Artist", "artist"),
|
TextField("Artist", "artist"),
|
||||||
R18(),
|
R18(),
|
||||||
Demographic(),
|
Demographic(),
|
||||||
GenreList(getGenreList())
|
OriginalLanguage(),
|
||||||
|
GenreList(GENRE_LIST)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
private fun getGenreList() = listOf(
|
|
||||||
Genre("1", "4-koma"),
|
|
||||||
Genre("2", "Action"),
|
|
||||||
Genre("3", "Adventure"),
|
|
||||||
Genre("4", "Award Winning"),
|
|
||||||
Genre("5", "Comedy"),
|
|
||||||
Genre("6", "Cooking"),
|
|
||||||
Genre("7", "Doujinshi"),
|
|
||||||
Genre("8", "Drama"),
|
|
||||||
Genre("9", "Ecchi"),
|
|
||||||
Genre("10", "Fantasy"),
|
|
||||||
Genre("11", "Gender Bender"),
|
|
||||||
Genre("12", "Harem"),
|
|
||||||
Genre("13", "Historical"),
|
|
||||||
Genre("14", "Horror"),
|
|
||||||
Genre("15", "Josei"),
|
|
||||||
Genre("16", "Martial Arts"),
|
|
||||||
Genre("17", "Mecha"),
|
|
||||||
Genre("18", "Medical"),
|
|
||||||
Genre("19", "Music"),
|
|
||||||
Genre("20", "Mystery"),
|
|
||||||
Genre("21", "Oneshot"),
|
|
||||||
Genre("22", "Psychological"),
|
|
||||||
Genre("23", "Romance"),
|
|
||||||
Genre("24", "School Life"),
|
|
||||||
Genre("25", "Sci-Fi"),
|
|
||||||
Genre("26", "Seinen"),
|
|
||||||
Genre("27", "Shoujo"),
|
|
||||||
Genre("28", "Shoujo Ai"),
|
|
||||||
Genre("29", "Shounen"),
|
|
||||||
Genre("30", "Shounen Ai"),
|
|
||||||
Genre("31", "Slice of Life"),
|
|
||||||
Genre("32", "Smut"),
|
|
||||||
Genre("33", "Sports"),
|
|
||||||
Genre("34", "Supernatural"),
|
|
||||||
Genre("35", "Tragedy"),
|
|
||||||
Genre("36", "Webtoon"),
|
|
||||||
Genre("37", "Yaoi"),
|
|
||||||
Genre("38", "Yuri"),
|
|
||||||
Genre("39", "[no chapters]"),
|
|
||||||
Genre("40", "Game"),
|
|
||||||
Genre("41", "Isekai")
|
|
||||||
)
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
//this number matches to the cookie
|
//this number matches to the cookie
|
||||||
private const val NO_R18 = 0
|
private const val NO_R18 = 0
|
||||||
|
@ -468,8 +444,65 @@ open class Mangadex(override val lang: String, private val internalLang: String,
|
||||||
private const val ONLY_R18 = 2
|
private const val ONLY_R18 = 2
|
||||||
private const val SHOW_R18_PREF_Title = "Default R18 Setting"
|
private const val SHOW_R18_PREF_Title = "Default R18 Setting"
|
||||||
private const val SHOW_R18_PREF = "showR18Default"
|
private const val SHOW_R18_PREF = "showR18Default"
|
||||||
private const val URL = "/api/3640f3fb/"
|
private const val API_MANGA = "/api/manga/"
|
||||||
private const val BASE_CHAPTER = "/chapter/"
|
private const val API_CHAPTER = "/api/chapter/"
|
||||||
|
private val SOURCE_LANG_LIST = listOf(
|
||||||
|
Pair("All", "0"),
|
||||||
|
Pair("Japanese", "2"),
|
||||||
|
Pair("English", "1"),
|
||||||
|
Pair("Polish", "3"),
|
||||||
|
Pair("German", "8"),
|
||||||
|
Pair("French", "10"),
|
||||||
|
Pair("Vietnamese", "12"),
|
||||||
|
Pair("Chinese", "21"),
|
||||||
|
Pair("Indonesian", "27"),
|
||||||
|
Pair("Korean", "28"),
|
||||||
|
Pair("Spanish (LATAM)", "29"),
|
||||||
|
Pair("Thai", "32"),
|
||||||
|
Pair("Filipino", "34")
|
||||||
|
)
|
||||||
|
private val GENRE_LIST = listOf(
|
||||||
|
Genre("1", "4-koma"),
|
||||||
|
Genre("2", "Action"),
|
||||||
|
Genre("3", "Adventure"),
|
||||||
|
Genre("4", "Award Winning"),
|
||||||
|
Genre("5", "Comedy"),
|
||||||
|
Genre("6", "Cooking"),
|
||||||
|
Genre("7", "Doujinshi"),
|
||||||
|
Genre("8", "Drama"),
|
||||||
|
Genre("9", "Ecchi"),
|
||||||
|
Genre("10", "Fantasy"),
|
||||||
|
Genre("11", "Gender Bender"),
|
||||||
|
Genre("12", "Harem"),
|
||||||
|
Genre("13", "Historical"),
|
||||||
|
Genre("14", "Horror"),
|
||||||
|
Genre("15", "Josei"),
|
||||||
|
Genre("16", "Martial Arts"),
|
||||||
|
Genre("17", "Mecha"),
|
||||||
|
Genre("18", "Medical"),
|
||||||
|
Genre("19", "Music"),
|
||||||
|
Genre("20", "Mystery"),
|
||||||
|
Genre("21", "Oneshot"),
|
||||||
|
Genre("22", "Psychological"),
|
||||||
|
Genre("23", "Romance"),
|
||||||
|
Genre("24", "School Life"),
|
||||||
|
Genre("25", "Sci-Fi"),
|
||||||
|
Genre("26", "Seinen"),
|
||||||
|
Genre("27", "Shoujo"),
|
||||||
|
Genre("28", "Shoujo Ai"),
|
||||||
|
Genre("29", "Shounen"),
|
||||||
|
Genre("30", "Shounen Ai"),
|
||||||
|
Genre("31", "Slice of Life"),
|
||||||
|
Genre("32", "Smut"),
|
||||||
|
Genre("33", "Sports"),
|
||||||
|
Genre("34", "Supernatural"),
|
||||||
|
Genre("35", "Tragedy"),
|
||||||
|
Genre("36", "Webtoon"),
|
||||||
|
Genre("37", "Yaoi"),
|
||||||
|
Genre("38", "Yuri"),
|
||||||
|
Genre("39", "[no chapters]"),
|
||||||
|
Genre("40", "Game"),
|
||||||
|
Genre("41", "Isekai"))
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|