FlixScans: api changes (#2229)
* FlixScans: api changes * review changes * move filter fetching to `getFilterList`
This commit is contained in:
		
							parent
							
								
									ea833d9401
								
							
						
					
					
						commit
						e8f8e9e8a9
					
				| @ -2,4 +2,4 @@ plugins { | |||||||
|     id("lib-multisrc") |     id("lib-multisrc") | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| baseVersionCode = 5 | baseVersionCode = 6 | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| package eu.kanade.tachiyomi.multisrc.flixscans | package eu.kanade.tachiyomi.multisrc.flixscans | ||||||
| 
 | 
 | ||||||
| import android.util.Log | import android.util.Log | ||||||
| import eu.kanade.tachiyomi.network.POST | import eu.kanade.tachiyomi.network.GET | ||||||
| import eu.kanade.tachiyomi.network.interceptor.rateLimit | import eu.kanade.tachiyomi.network.interceptor.rateLimit | ||||||
| import eu.kanade.tachiyomi.source.model.Filter | import eu.kanade.tachiyomi.source.model.Filter | ||||||
| import eu.kanade.tachiyomi.source.model.FilterList | import eu.kanade.tachiyomi.source.model.FilterList | ||||||
| @ -14,18 +14,17 @@ import kotlinx.serialization.decodeFromString | |||||||
| import kotlinx.serialization.json.Json | import kotlinx.serialization.json.Json | ||||||
| import okhttp3.Call | import okhttp3.Call | ||||||
| import okhttp3.Callback | import okhttp3.Callback | ||||||
| import okhttp3.MediaType.Companion.toMediaTypeOrNull | import okhttp3.HttpUrl.Companion.toHttpUrl | ||||||
| import okhttp3.Request | import okhttp3.Request | ||||||
| import okhttp3.RequestBody.Companion.toRequestBody |  | ||||||
| import okhttp3.Response | import okhttp3.Response | ||||||
| import rx.Observable |  | ||||||
| import uy.kohesive.injekt.injectLazy | import uy.kohesive.injekt.injectLazy | ||||||
|  | import java.io.IOException | ||||||
| 
 | 
 | ||||||
| abstract class FlixScans( | abstract class FlixScans( | ||||||
|     override val name: String, |     override val name: String, | ||||||
|     override val baseUrl: String, |     override val baseUrl: String, | ||||||
|     override val lang: String, |     override val lang: String, | ||||||
|     protected val apiUrl: String = "$baseUrl/api/__api_party/noxApi", |     protected val apiUrl: String = "$baseUrl/api/v1", | ||||||
|     protected val cdnUrl: String = baseUrl.replace("://", "://media.").plus("/"), |     protected val cdnUrl: String = baseUrl.replace("://", "://media.").plus("/"), | ||||||
| ) : HttpSource() { | ) : HttpSource() { | ||||||
| 
 | 
 | ||||||
| @ -38,22 +37,10 @@ abstract class FlixScans( | |||||||
|         .build() |         .build() | ||||||
| 
 | 
 | ||||||
|     override fun headersBuilder() = super.headersBuilder() |     override fun headersBuilder() = super.headersBuilder() | ||||||
|         .add("Referer", baseUrl) |         .add("Referer", "$baseUrl/") | ||||||
| 
 |  | ||||||
|     protected open fun postPath(path: String): Request { |  | ||||||
|         val payload = """{"path":"$path","headers":{}}""".toRequestBody(JSON_MEDIA_TYPE) |  | ||||||
| 
 |  | ||||||
|         return POST(apiUrl, headers, payload) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     override fun fetchPopularManga(page: Int): Observable<MangasPage> { |  | ||||||
|         runCatching { fetchGenre() } |  | ||||||
| 
 |  | ||||||
|         return super.fetchPopularManga(page) |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     override fun popularMangaRequest(page: Int): Request { |     override fun popularMangaRequest(page: Int): Request { | ||||||
|         return postPath("webtoon/pages/home/romance") |         return GET("$apiUrl/webtoon/pages/home/romance", headers) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun popularMangaParse(response: Response): MangasPage { |     override fun popularMangaParse(response: Response): MangasPage { | ||||||
| @ -66,21 +53,15 @@ abstract class FlixScans( | |||||||
|         return MangasPage(entries, false) |         return MangasPage(entries, false) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun fetchLatestUpdates(page: Int): Observable<MangasPage> { |  | ||||||
|         runCatching { fetchGenre() } |  | ||||||
| 
 |  | ||||||
|         return super.fetchLatestUpdates(page) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     override fun latestUpdatesRequest(page: Int): Request { |     override fun latestUpdatesRequest(page: Int): Request { | ||||||
|         return postPath("search/advance?page=$page&serie_type=webtoon") |         return GET("$apiUrl/search/advance?page=$page&serie_type=webtoon", headers) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun latestUpdatesParse(response: Response): MangasPage { |     override fun latestUpdatesParse(response: Response): MangasPage { | ||||||
|         val result = response.parseAs<ApiResponse<BrowseSeries>>() |         val result = response.parseAs<ApiResponse<BrowseSeries>>() | ||||||
| 
 | 
 | ||||||
|         val entries = result.data.map { it.toSManga(cdnUrl) } |         val entries = result.data.map { it.toSManga(cdnUrl) } | ||||||
|         val hasNextPage = result.meta.lastPage > result.meta.currentPage |         val hasNextPage = result.lastPage > result.currentPage | ||||||
| 
 | 
 | ||||||
|         return MangasPage(entries, hasNextPage) |         return MangasPage(entries, hasNextPage) | ||||||
|     } |     } | ||||||
| @ -100,7 +81,7 @@ abstract class FlixScans( | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private val fetchGenreCallback = object : Callback { |     private val fetchGenreCallback = object : Callback { | ||||||
|         override fun onFailure(call: Call, e: okio.IOException) { |         override fun onFailure(call: Call, e: IOException) { | ||||||
|             fetchGenreAttempt++ |             fetchGenreAttempt++ | ||||||
|             fetchGenreFailed = true |             fetchGenreFailed = true | ||||||
|             fetchGenreCallOngoing = false |             fetchGenreCallOngoing = false | ||||||
| @ -132,7 +113,7 @@ abstract class FlixScans( | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private fun fetchGenreRequest(): Request { |     private fun fetchGenreRequest(): Request { | ||||||
|         return postPath("search/genres") |         return GET("$apiUrl/search/genres", headers) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private fun fetchGenreParse(response: Response): List<GenreHolder> { |     private fun fetchGenreParse(response: Response): List<GenreHolder> { | ||||||
| @ -140,6 +121,8 @@ abstract class FlixScans( | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun getFilterList(): FilterList { |     override fun getFilterList(): FilterList { | ||||||
|  |         fetchGenre() | ||||||
|  | 
 | ||||||
|         val filters: MutableList<Filter<*>> = mutableListOf( |         val filters: MutableList<Filter<*>> = mutableListOf( | ||||||
|             Filter.Header("Ignored when using Text Search"), |             Filter.Header("Ignored when using Text Search"), | ||||||
|             MainGenreFilter(), |             MainGenreFilter(), | ||||||
| @ -161,60 +144,59 @@ abstract class FlixScans( | |||||||
|         return FilterList(filters) |         return FilterList(filters) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> { |  | ||||||
|         runCatching { fetchGenre() } |  | ||||||
| 
 |  | ||||||
|         return super.fetchSearchManga(page, query, filters) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { |     override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { | ||||||
|         if (query.isNotEmpty()) { |         if (query.isNotEmpty()) { | ||||||
|             return postPath("search/serie/${query.trim()}?page=$page") |             val url = "$apiUrl/search/serie".toHttpUrl().newBuilder() | ||||||
|  |                 .addPathSegment(query.trim()) | ||||||
|  |                 .addQueryParameter("page", page.toString()) | ||||||
|  |                 .build() | ||||||
|  | 
 | ||||||
|  |             return GET(url, headers) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         val advSearchBody = buildString { |         val advSearchUrl = apiUrl.toHttpUrl().newBuilder().apply { | ||||||
|             append("search/advance") |             addPathSegments("search/advance") | ||||||
|             append("?page=", page) |             addQueryParameter("page", page.toString()) | ||||||
|             append("&serie_type=webtoon") |             addQueryParameter("serie_type", "webtoon") | ||||||
| 
 | 
 | ||||||
|             filters.forEach { filter -> |             filters.forEach { filter -> | ||||||
|                 when (filter) { |                 when (filter) { | ||||||
|                     is GenreFilter -> { |                     is GenreFilter -> { | ||||||
|                         filter.checked.let { |                         filter.checked.let { | ||||||
|                             if (it.isNotEmpty()) { |                             if (it.isNotEmpty()) { | ||||||
|                                 append("&genres=", it.joinToString(",")) |                                 addQueryParameter("genres", it.joinToString(",")) | ||||||
|                             } |                             } | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                     is MainGenreFilter -> { |                     is MainGenreFilter -> { | ||||||
|                         if (filter.state > 0) { |                         if (filter.state > 0) { | ||||||
|                             append("&main_genres=", filter.selected) |                             addQueryParameter("main_genres", filter.selected) | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                     is TypeFilter -> { |                     is TypeFilter -> { | ||||||
|                         if (filter.state > 0) { |                         if (filter.state > 0) { | ||||||
|                             append("&type=", filter.selected) |                             addQueryParameter("type", filter.selected) | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                     is StatusFilter -> { |                     is StatusFilter -> { | ||||||
|                         if (filter.state > 0) { |                         if (filter.state > 0) { | ||||||
|                             append("&status=", filter.selected) |                             addQueryParameter("status", filter.selected) | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                     else -> {} |                     else -> {} | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         }.build() | ||||||
| 
 | 
 | ||||||
|         return postPath(advSearchBody) |         return GET(advSearchUrl, headers) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun searchMangaParse(response: Response) = latestUpdatesParse(response) |     override fun searchMangaParse(response: Response) = latestUpdatesParse(response) | ||||||
| 
 | 
 | ||||||
|     override fun mangaDetailsRequest(manga: SManga): Request { |     override fun mangaDetailsRequest(manga: SManga): Request { | ||||||
|         val id = manga.url.split("-")[1] |         val (prefix, id) = getPrefixIdFromUrl(manga.url) | ||||||
| 
 | 
 | ||||||
|         return postPath("webtoon/series/$id") |         return GET("$apiUrl/webtoon/series/$id/$prefix", headers) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun getMangaUrl(manga: SManga) = baseUrl + manga.url |     override fun getMangaUrl(manga: SManga) = baseUrl + manga.url | ||||||
| @ -226,23 +208,30 @@ abstract class FlixScans( | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun chapterListRequest(manga: SManga): Request { |     override fun chapterListRequest(manga: SManga): Request { | ||||||
|         val id = manga.url.split("-")[1] |         val (prefix, id) = getPrefixIdFromUrl(manga.url) | ||||||
| 
 | 
 | ||||||
|         return postPath("webtoon/chapters/$id-desc") |         return GET("$apiUrl/webtoon/chapters/$id-desc#$prefix", headers) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun chapterListParse(response: Response): List<SChapter> { |     override fun chapterListParse(response: Response): List<SChapter> { | ||||||
|         val chapters = response.parseAs<List<Chapter>>() |         val chapters = response.parseAs<List<Chapter>>() | ||||||
|  |         val prefix = response.request.url.fragment!! | ||||||
| 
 | 
 | ||||||
|         return chapters.map(Chapter::toSChapter) |         return chapters.map { it.toSChapter(prefix) } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun pageListRequest(chapter: SChapter): Request { |     override fun pageListRequest(chapter: SChapter): Request { | ||||||
|         val id = chapter.url |         val (prefix, id) = getPrefixIdFromUrl(chapter.url) | ||||||
|             .substringAfterLast("/") |  | ||||||
|             .substringBefore("-") |  | ||||||
| 
 | 
 | ||||||
|         return postPath("webtoon/chapters/chapter/$id") |         return GET("$apiUrl/webtoon/chapters/chapter/$id/$prefix", headers) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     protected fun getPrefixIdFromUrl(url: String): Pair<String, String> { | ||||||
|  |         return with(url.substringAfterLast("/")) { | ||||||
|  |             val split = split("-") | ||||||
|  | 
 | ||||||
|  |             split[0] to split[1] | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun getChapterUrl(chapter: SChapter) = baseUrl + chapter.url |     override fun getChapterUrl(chapter: SChapter) = baseUrl + chapter.url | ||||||
| @ -259,8 +248,4 @@ abstract class FlixScans( | |||||||
| 
 | 
 | ||||||
|     protected inline fun <reified T> Response.parseAs(): T = |     protected inline fun <reified T> Response.parseAs(): T = | ||||||
|         use { body.string() }.let(json::decodeFromString) |         use { body.string() }.let(json::decodeFromString) | ||||||
| 
 |  | ||||||
|     companion object { |  | ||||||
|         private val JSON_MEDIA_TYPE = "application/json".toMediaTypeOrNull() |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -11,13 +11,8 @@ import java.util.Locale | |||||||
| @Serializable | @Serializable | ||||||
| data class ApiResponse<T>( | data class ApiResponse<T>( | ||||||
|     val data: List<T>, |     val data: List<T>, | ||||||
|     val meta: PageInfo, |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| @Serializable |  | ||||||
| data class PageInfo( |  | ||||||
|     @SerialName("last_page") val lastPage: Int, |  | ||||||
|     @SerialName("current_page") val currentPage: Int, |     @SerialName("current_page") val currentPage: Int, | ||||||
|  |     @SerialName("last_page") val lastPage: Int, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @Serializable | @Serializable | ||||||
| @ -120,8 +115,8 @@ data class Chapter( | |||||||
|     val slug: String, |     val slug: String, | ||||||
|     val createdAt: String? = null, |     val createdAt: String? = null, | ||||||
| ) { | ) { | ||||||
|     fun toSChapter() = SChapter.create().apply { |     fun toSChapter(prefix: String) = SChapter.create().apply { | ||||||
|         url = "/read/webtoon/$id-$slug" |         url = "/read/webtoon/$prefix-$id-$slug" | ||||||
|         name = this@Chapter.name |         name = this@Chapter.name | ||||||
|         date_upload = runCatching { dateFormat.parse(createdAt!!)!!.time }.getOrDefault(0L) |         date_upload = runCatching { dateFormat.parse(createdAt!!)!!.time }.getOrDefault(0L) | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -2,6 +2,11 @@ package eu.kanade.tachiyomi.extension.ar.galaxymanga | |||||||
| 
 | 
 | ||||||
| import eu.kanade.tachiyomi.multisrc.flixscans.FlixScans | import eu.kanade.tachiyomi.multisrc.flixscans.FlixScans | ||||||
| 
 | 
 | ||||||
| class GalaxyManga : FlixScans("جالاكسي مانجا", "https://flixscans.com", "ar") { | class GalaxyManga : FlixScans( | ||||||
|  |     "جالاكسي مانجا", | ||||||
|  |     "https://flixscans.com", | ||||||
|  |     "ar", | ||||||
|  |     "https://ar.flixscans.site/api/v1", | ||||||
|  | ) { | ||||||
|     override val versionId = 2 |     override val versionId = 2 | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,4 +2,9 @@ package eu.kanade.tachiyomi.extension.en.flixscans | |||||||
| 
 | 
 | ||||||
| import eu.kanade.tachiyomi.multisrc.flixscans.FlixScans | import eu.kanade.tachiyomi.multisrc.flixscans.FlixScans | ||||||
| 
 | 
 | ||||||
| class FlixScansNet : FlixScans("Flix Scans", "https://flixscans.org", "en") | class FlixScansNet : FlixScans( | ||||||
|  |     "Flix Scans", | ||||||
|  |     "https://flixscans.org", | ||||||
|  |     "en", | ||||||
|  |     "https://flixscans.site/api/v1", | ||||||
|  | ) | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 AwkwardPeak7
						AwkwardPeak7