ru/AComics: Fix NPEs (#941)
* fix: Fix manga details * fix: Fix chapter list * fix: Fix page selector * refactor: General refactoration * chore: Set isNsfw flag * chore: Bump version * refactor: Apply suggestion
This commit is contained in:
		
							parent
							
								
									246fe574e7
								
							
						
					
					
						commit
						8f7c88a723
					
				| @ -1,7 +1,8 @@ | |||||||
| ext { | ext { | ||||||
|     extName = 'AComics' |     extName = 'AComics' | ||||||
|     extClass = '.AComics' |     extClass = '.AComics' | ||||||
|     extVersionCode = 3 |     extVersionCode = 4 | ||||||
|  |     isNsfw = true | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| apply from: "$rootDir/common.gradle" | apply from: "$rootDir/common.gradle" | ||||||
|  | |||||||
| @ -8,11 +8,11 @@ import eu.kanade.tachiyomi.source.model.SChapter | |||||||
| import eu.kanade.tachiyomi.source.model.SManga | import eu.kanade.tachiyomi.source.model.SManga | ||||||
| import eu.kanade.tachiyomi.source.online.ParsedHttpSource | import eu.kanade.tachiyomi.source.online.ParsedHttpSource | ||||||
| import eu.kanade.tachiyomi.util.asJsoup | import eu.kanade.tachiyomi.util.asJsoup | ||||||
|  | import okhttp3.HttpUrl.Companion.toHttpUrl | ||||||
| import okhttp3.Request | import okhttp3.Request | ||||||
| import okhttp3.Response | import okhttp3.Response | ||||||
| import org.jsoup.nodes.Document | import org.jsoup.nodes.Document | ||||||
| import org.jsoup.nodes.Element | import org.jsoup.nodes.Element | ||||||
| import java.net.URLEncoder |  | ||||||
| 
 | 
 | ||||||
| class AComics : ParsedHttpSource() { | class AComics : ParsedHttpSource() { | ||||||
| 
 | 
 | ||||||
| @ -22,23 +22,12 @@ class AComics : ParsedHttpSource() { | |||||||
| 
 | 
 | ||||||
|     override val lang = "ru" |     override val lang = "ru" | ||||||
| 
 | 
 | ||||||
|     private val cookiesHeader by lazy { |  | ||||||
|         val cookies = mutableMapOf<String, String>() |  | ||||||
|         cookies["ageRestrict"] = "17" |  | ||||||
|         buildCookies(cookies) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private fun buildCookies(cookies: Map<String, String>) = |  | ||||||
|         cookies.entries.joinToString(separator = "; ", postfix = ";") { |  | ||||||
|             "${URLEncoder.encode(it.key, "UTF-8")}=${URLEncoder.encode(it.value, "UTF-8")}" |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|     override val client = network.client.newBuilder() |     override val client = network.client.newBuilder() | ||||||
|         .addNetworkInterceptor { chain -> |         .addNetworkInterceptor { chain -> | ||||||
|             val newReq = chain |             val newReq = chain | ||||||
|                 .request() |                 .request() | ||||||
|                 .newBuilder() |                 .newBuilder() | ||||||
|                 .addHeader("Cookie", cookiesHeader) |                 .addHeader("Cookie", "ageRestrict=17;") | ||||||
|                 .build() |                 .build() | ||||||
| 
 | 
 | ||||||
|             chain.proceed(newReq) |             chain.proceed(newReq) | ||||||
| @ -46,153 +35,159 @@ class AComics : ParsedHttpSource() { | |||||||
| 
 | 
 | ||||||
|     override val supportsLatest = true |     override val supportsLatest = true | ||||||
| 
 | 
 | ||||||
|  |     // ============================== Popular =============================== | ||||||
|     override fun popularMangaRequest(page: Int): Request = |     override fun popularMangaRequest(page: Int): Request = | ||||||
|         GET("$baseUrl/comics?categories=&ratings[]=1&ratings[]=2&ratings[]=3&ratings[]=4&ratings[]=5ratings[]=6&&type=0&updatable=0&subscribe=0&issue_count=2&sort=subscr_count&skip=${10 * (page - 1)}", headers) |         GET("$baseUrl/comics?$DEFAULT_COMIC_QUERIES&sort=subscr_count&skip=${10 * (page - 1)}", headers) | ||||||
| 
 | 
 | ||||||
|  |     override fun popularMangaSelector() = "table.list-loadable > tbody > tr" | ||||||
|  | 
 | ||||||
|  |     override fun popularMangaFromElement(element: Element) = SManga.create().apply { | ||||||
|  |         thumbnail_url = element.selectFirst("a > img")?.absUrl("src") | ||||||
|  |         element.selectFirst("div.title > a")!!.run { | ||||||
|  |             setUrlWithoutDomain(attr("href") + "/about") | ||||||
|  |             title = text() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun popularMangaNextPageSelector() = "span.button:not(:has(a)) + span.button > a" | ||||||
|  | 
 | ||||||
|  |     // =============================== Latest =============================== | ||||||
|     override fun latestUpdatesRequest(page: Int): Request = |     override fun latestUpdatesRequest(page: Int): Request = | ||||||
|         GET("$baseUrl/comics?categories=&ratings[]=1&ratings[]=2&ratings[]=3&ratings[]=4&ratings[]=5ratings[]=6&&type=0&updatable=0&subscribe=0&issue_count=2&sort=last_update&skip=${10 * (page - 1)}", headers) |         GET("$baseUrl/comics?$DEFAULT_COMIC_QUERIES&sort=last_update&skip=${10 * (page - 1)}", headers) | ||||||
| 
 | 
 | ||||||
|  |     override fun latestUpdatesSelector() = popularMangaSelector() | ||||||
|  | 
 | ||||||
|  |     override fun latestUpdatesFromElement(element: Element) = popularMangaFromElement(element) | ||||||
|  | 
 | ||||||
|  |     override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector() | ||||||
|  | 
 | ||||||
|  |     // =============================== Search =============================== | ||||||
|     override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { |     override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { | ||||||
|         val url: String = if (query.isNotEmpty()) { |         val url = if (query.isNotEmpty()) { | ||||||
|             "$baseUrl/search?keyword=$query" |             "$baseUrl/search?keyword=$query" | ||||||
|         } else { |         } else { | ||||||
|             val categories = mutableListOf<Int>() |             val urlBuilder = "$baseUrl/comics?type=0&subscribe=0&issue_count=2&sort=subscr_count" | ||||||
|             var status = "0" |                 .toHttpUrl() | ||||||
|             val rating = mutableListOf<Int>() |                 .newBuilder() | ||||||
|  |                 .addQueryParameter("skip", "${10 * (page - 1)}") | ||||||
|             for (filter in if (filters.isEmpty()) getFilterList() else filters) { |             for (filter in if (filters.isEmpty()) getFilterList() else filters) { | ||||||
|                 when (filter) { |                 when (filter) { | ||||||
|                     is GenreList -> { |                     is GenreList -> { | ||||||
|                         filter.state.forEach { |                         val categories = filter.state.filter { it.state }.joinToString(",") { it.id } | ||||||
|                             if (it.state) { |                         urlBuilder.addQueryParameter("categories", categories) | ||||||
|                                 categories.add(it.id) |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                     } |                     } | ||||||
|                     is Status -> { |                     is Status -> { | ||||||
|                         if (filter.state == 1) { |                         val status = when (filter.state) { | ||||||
|                             status = "no" |                             1 -> "no" | ||||||
|                         } |                             2 -> "yes" | ||||||
|                         if (filter.state == 2) { |                             else -> "0" | ||||||
|                             status = "yes" |  | ||||||
|                         } |                         } | ||||||
|  |                         urlBuilder.addQueryParameter("updatable", status) | ||||||
|                     } |                     } | ||||||
|                     is RatingList -> { |                     is RatingList -> { | ||||||
|                         filter.state.forEach { |                         filter.state.forEach { | ||||||
|                             if (it.state) { |                             if (it.state) { | ||||||
|                                 rating.add(it.id) |                                 urlBuilder.addQueryParameter("ratings[]", it.id) | ||||||
|                             } |                             } | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                     else -> {} |                     else -> {} | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             "$baseUrl/comics?categories=${categories.joinToString(",")}&${rating.joinToString { "ratings[]=$it" }}&type=0&updatable=$status&subscribe=0&issue_count=2&sort=subscr_count&skip=${10 * (page - 1)}" |             urlBuilder.build().toString() | ||||||
|         } |         } | ||||||
|         return GET(url, headers) |         return GET(url, headers) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun popularMangaSelector() = "table.list-loadable > tbody > tr" |  | ||||||
| 
 |  | ||||||
|     override fun latestUpdatesSelector() = popularMangaSelector() |  | ||||||
| 
 |  | ||||||
|     override fun searchMangaSelector() = popularMangaSelector() |     override fun searchMangaSelector() = popularMangaSelector() | ||||||
| 
 | 
 | ||||||
|     override fun popularMangaFromElement(element: Element): SManga { |     override fun searchMangaFromElement(element: Element) = popularMangaFromElement(element) | ||||||
|         val manga = SManga.create() |  | ||||||
|         manga.thumbnail_url = baseUrl + element.select("a > img").first()!!.attr("src") |  | ||||||
|         element.select("div.title > a").first()!!.let { |  | ||||||
|             manga.setUrlWithoutDomain(it.attr("href") + "/about") |  | ||||||
|             manga.title = it.text() |  | ||||||
|         } |  | ||||||
|         return manga |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     override fun latestUpdatesFromElement(element: Element): SManga = |  | ||||||
|         popularMangaFromElement(element) |  | ||||||
| 
 |  | ||||||
|     override fun searchMangaFromElement(element: Element): SManga = |  | ||||||
|         popularMangaFromElement(element) |  | ||||||
| 
 |  | ||||||
|     override fun popularMangaNextPageSelector() = "span.button:not(:has(a)) + span.button > a" |  | ||||||
| 
 |  | ||||||
|     override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector() |  | ||||||
| 
 | 
 | ||||||
|     override fun searchMangaNextPageSelector() = popularMangaNextPageSelector() |     override fun searchMangaNextPageSelector() = popularMangaNextPageSelector() | ||||||
| 
 | 
 | ||||||
|     override fun mangaDetailsParse(document: Document): SManga { |     // =========================== Manga Details ============================ | ||||||
|         val infoElement = document.select(".about-summary").first()!! |     override fun mangaDetailsParse(document: Document) = SManga.create().apply { | ||||||
|         val manga = SManga.create() |         val article = document.selectFirst("article.common-article")!! | ||||||
|         manga.author = infoElement.select(".about-summary > p:contains(Автор)").text().split(":")[1] |         with(article) { | ||||||
|         manga.genre = infoElement.select("a.button").joinToString { it.text() } |             title = selectFirst(".page-header-with-menu h1")!!.text() | ||||||
|         manga.description = infoElement.ownText() |             genre = select("p.serial-about-badges a.category").joinToString { it.text() } | ||||||
|         return manga |             author = select("p.serial-about-authors a, p:contains(Автор оригинала)").joinToString { it.ownText() } | ||||||
|  |             description = selectFirst("section.serial-about-text")?.text() | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     // ============================== Chapters ============================== | ||||||
|     override fun chapterListParse(response: Response): List<SChapter> { |     override fun chapterListParse(response: Response): List<SChapter> { | ||||||
|         val res = mutableListOf<SChapter>() |         val doc = response.asJsoup() | ||||||
|         val count = response.asJsoup() |         val count = doc | ||||||
|             .select(".about-summary > p:contains(Количество выпусков:)") |             .selectFirst("p:has(b:contains(Количество выпусков:))")!! | ||||||
|             .text() |             .ownText() | ||||||
|             .split("Количество выпусков: ")[1].toInt() |             .toInt() | ||||||
| 
 | 
 | ||||||
|         for (index in count downTo 1) { |         val comicPath = doc.location().substringBefore("/about") | ||||||
|             val chapter = SChapter.create() | 
 | ||||||
|             chapter.chapter_number = index.toFloat() |         return (count downTo 1).map { | ||||||
|             chapter.name = index.toString() |             SChapter.create().apply { | ||||||
|             val url = response.request.url.toString().split("/about")[0].split(baseUrl)[1] |                 chapter_number = it.toFloat() | ||||||
|             chapter.url = "$url/$index" |                 name = it.toString() | ||||||
|             res.add(chapter) |                 setUrlWithoutDomain("$comicPath/$it") | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         return res |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun chapterListSelector(): Nothing = throw UnsupportedOperationException() |     override fun chapterListSelector(): Nothing = throw UnsupportedOperationException() | ||||||
| 
 | 
 | ||||||
|     override fun chapterFromElement(element: Element): SChapter = throw UnsupportedOperationException() |     override fun chapterFromElement(element: Element): SChapter = throw UnsupportedOperationException() | ||||||
| 
 | 
 | ||||||
|  |     // =============================== Pages ================================ | ||||||
|     override fun pageListParse(document: Document): List<Page> { |     override fun pageListParse(document: Document): List<Page> { | ||||||
|         val imageElement = document.select("img#mainImage").first()!! |         val imageElement = document.selectFirst("img.issue")!! | ||||||
|         return listOf(Page(0, imageUrl = baseUrl + imageElement.attr("src"))) |         return listOf(Page(0, imageUrl = imageElement.absUrl("src"))) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun imageUrlParse(document: Document) = "" |     override fun imageUrlParse(document: Document) = throw UnsupportedOperationException() | ||||||
| 
 | 
 | ||||||
|     private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Категории", genres) |     // ============================== Filters =============================== | ||||||
|     private class Genre(name: String, val id: Int) : Filter.CheckBox(name) |     private class Genre(name: String, val id: String) : Filter.CheckBox(name) | ||||||
|     private class Rating(name: String, val id: Int) : Filter.CheckBox(name, state = true) |     private class Rating(name: String, val id: String) : Filter.CheckBox(name, state = true) | ||||||
|     private class Status : Filter.Select<String>("Статус", arrayOf("Все", "Завершенный", "Продолжающийся")) |     private class Status : Filter.Select<String>("Статус", arrayOf("Все", "Завершенный", "Продолжающийся")) | ||||||
| 
 | 
 | ||||||
|  |     private class GenreList : Filter.Group<Genre>( | ||||||
|  |         "Категории", | ||||||
|  |         listOf( | ||||||
|  |             Genre("Животные", "1"), | ||||||
|  |             Genre("Драма", "2"), | ||||||
|  |             Genre("Фэнтези", "3"), | ||||||
|  |             Genre("Игры", "4"), | ||||||
|  |             Genre("Юмор", "5"), | ||||||
|  |             Genre("Журнал", "6"), | ||||||
|  |             Genre("Паранормальное", "7"), | ||||||
|  |             Genre("Конец света", "8"), | ||||||
|  |             Genre("Романтика", "9"), | ||||||
|  |             Genre("Фантастика", "10"), | ||||||
|  |             Genre("Бытовое", "11"), | ||||||
|  |             Genre("Стимпанк", "12"), | ||||||
|  |             Genre("Супергерои", "13"), | ||||||
|  |         ), | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|     private class RatingList : Filter.Group<Rating>( |     private class RatingList : Filter.Group<Rating>( | ||||||
|         "Возрастная категория", |         "Возрастная категория", | ||||||
|         listOf( |         listOf( | ||||||
|             Rating("???", 1), |             Rating("???", "1"), | ||||||
|             Rating("0+", 2), |             Rating("0+", "2"), | ||||||
|             Rating("6+", 3), |             Rating("6+", "3"), | ||||||
|             Rating("12+", 4), |             Rating("12+", "4"), | ||||||
|             Rating("16+", 5), |             Rating("16+", "5"), | ||||||
|             Rating("18+", 6), |             Rating("18+", "6"), | ||||||
|         ), |         ), | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     override fun getFilterList() = FilterList( |     override fun getFilterList() = FilterList( | ||||||
|         Status(), |         Status(), | ||||||
|         RatingList(), |         RatingList(), | ||||||
|         GenreList(getGenreList()), |         GenreList(), | ||||||
|     ) |  | ||||||
| 
 |  | ||||||
|     private fun getGenreList() = listOf( |  | ||||||
|         Genre("Животные", 1), |  | ||||||
|         Genre("Драма", 2), |  | ||||||
|         Genre("Фэнтези", 3), |  | ||||||
|         Genre("Игры", 4), |  | ||||||
|         Genre("Юмор", 5), |  | ||||||
|         Genre("Журнал", 6), |  | ||||||
|         Genre("Паранормальное", 7), |  | ||||||
|         Genre("Конец света", 8), |  | ||||||
|         Genre("Романтика", 9), |  | ||||||
|         Genre("Фантастика", 10), |  | ||||||
|         Genre("Бытовое", 11), |  | ||||||
|         Genre("Стимпанк", 12), |  | ||||||
|         Genre("Супергерои", 13), |  | ||||||
|     ) |     ) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | private const val DEFAULT_COMIC_QUERIES = "categories=&ratings[]=1&ratings[]=2&ratings[]=3&ratings[]=4&ratings[]=5&ratings[]=6&type=0&updatable=0&issue_count=2" | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Claudemirovsky
						Claudemirovsky