AnimeSama: add filtering by genre (#10059)
* Update AnimeSama Fix description & genre by updating html tag id * Update build.gradle Increasing the code version number * Adding latest items for AnimeSama only the items available on the main page * Fix URL on latest items * AnimeSama: adding genre filter Using almost the same code as FuzzyDoodle, I added the only filter available on animesama: genre * Update AnimeSama.kt remove lint errors * Including code review optimization Co-authored-by: stevenyomi <95685115+stevenyomi@users.noreply.github.com> * Fix build error --------- Co-authored-by: stevenyomi <95685115+stevenyomi@users.noreply.github.com>
This commit is contained in:
parent
c2317eeeed
commit
8c7c46e0e2
@ -1,7 +1,7 @@
|
|||||||
ext {
|
ext {
|
||||||
extName = 'AnimeSama'
|
extName = 'AnimeSama'
|
||||||
extClass = '.AnimeSama'
|
extClass = '.AnimeSama'
|
||||||
extVersionCode = 6
|
extVersionCode = 7
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
package eu.kanade.tachiyomi.extension.fr.animesama
|
package eu.kanade.tachiyomi.extension.fr.animesama
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
import eu.kanade.tachiyomi.network.await
|
||||||
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
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 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 kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||||
@ -33,13 +38,55 @@ class AnimeSama : ParsedHttpSource() {
|
|||||||
override fun headersBuilder(): Headers.Builder = super.headersBuilder()
|
override fun headersBuilder(): Headers.Builder = super.headersBuilder()
|
||||||
.add("Accept-Language", "fr-FR")
|
.add("Accept-Language", "fr-FR")
|
||||||
|
|
||||||
|
// filters
|
||||||
|
private var genreList = listOf<Pair<String, String>>()
|
||||||
|
private var fetchFilterAttempts = 0
|
||||||
|
|
||||||
|
private suspend fun fetchFilters() {
|
||||||
|
if (fetchFilterAttempts < 3 && (genreList.isEmpty())) {
|
||||||
|
try {
|
||||||
|
val response = client.newCall(filtersRequest()).await().asJsoup()
|
||||||
|
parseFilters(response)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("$name: Filters", e.stackTraceToString())
|
||||||
|
}
|
||||||
|
fetchFilterAttempts++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun filtersRequest() = GET("$baseUrl/catalogue", headers)
|
||||||
|
|
||||||
|
private fun parseFilters(document: Document) {
|
||||||
|
genreList = document.select("#list_genres label").mapNotNull { labelElement ->
|
||||||
|
val input = labelElement.selectFirst("input[name=genre[]]") ?: return@mapNotNull null
|
||||||
|
val labelText = labelElement.ownText()
|
||||||
|
val value = input.attr("value")
|
||||||
|
labelText to value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getFilterList(): FilterList {
|
||||||
|
val filters = mutableListOf<Filter<*>>()
|
||||||
|
launchIO { fetchFilters() }
|
||||||
|
|
||||||
|
if (genreList.isNotEmpty()) {
|
||||||
|
filters.add(GenreFilter(genreList))
|
||||||
|
}
|
||||||
|
if (filters.size < 1) {
|
||||||
|
filters.add(0, Filter.Header("Press 'reset' to load more filters"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return FilterList(filters)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun launchIO(block: suspend () -> Unit) = GlobalScope.launch { block() }
|
||||||
|
|
||||||
// Popular
|
// Popular
|
||||||
override fun popularMangaRequest(page: Int): Request {
|
override fun popularMangaRequest(page: Int): Request {
|
||||||
val url = "$baseUrl/catalogue".toHttpUrl().newBuilder()
|
val url = "$baseUrl/catalogue".toHttpUrl().newBuilder()
|
||||||
.addQueryParameter("type[0]", "Scans")
|
.addQueryParameter("type[0]", "Scans")
|
||||||
.addQueryParameter("page", page.toString())
|
.addQueryParameter("page", page.toString())
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
return GET(url, headers)
|
return GET(url, headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,6 +125,11 @@ class AnimeSama : ParsedHttpSource() {
|
|||||||
.addQueryParameter("type[0]", "Scans")
|
.addQueryParameter("type[0]", "Scans")
|
||||||
.addQueryParameter("search", query)
|
.addQueryParameter("search", query)
|
||||||
.addQueryParameter("page", page.toString())
|
.addQueryParameter("page", page.toString())
|
||||||
|
.apply {
|
||||||
|
filters.filterIsInstance<UrlPartFilter>().forEach {
|
||||||
|
it.addUrlParameter(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
return GET(url, headers)
|
return GET(url, headers)
|
||||||
@ -100,14 +152,14 @@ class AnimeSama : ParsedHttpSource() {
|
|||||||
|
|
||||||
override fun chapterFromElement(element: Element): SChapter = throw UnsupportedOperationException()
|
override fun chapterFromElement(element: Element): SChapter = throw UnsupportedOperationException()
|
||||||
|
|
||||||
fun String.containsMultipleTimes(search: String): Boolean {
|
private fun String.containsMultipleTimes(search: String): Boolean {
|
||||||
val regex = Regex(search)
|
val regex = Regex(search)
|
||||||
val matches = regex.findAll(this)
|
val matches = regex.findAll(this)
|
||||||
val count = matches.count()
|
val count = matches.count()
|
||||||
return count > 1
|
return count > 1
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseChapterFromResponse(response: Response, translation_name: String): List<SChapter> {
|
private fun parseChapterFromResponse(response: Response, translationName: String): List<SChapter> {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
|
|
||||||
val chapterUrl = document.baseUri().toHttpUrl()
|
val chapterUrl = document.baseUri().toHttpUrl()
|
||||||
@ -146,7 +198,7 @@ class AnimeSama : ParsedHttpSource() {
|
|||||||
SChapter.create().apply {
|
SChapter.create().apply {
|
||||||
name = "Chapitre $i"
|
name = "Chapitre $i"
|
||||||
setUrlWithoutDomain(chapterUrl.newBuilder().addQueryParameter("id", (parsedChapterList.size + 1).toString()).build().toString())
|
setUrlWithoutDomain(chapterUrl.newBuilder().addQueryParameter("id", (parsedChapterList.size + 1).toString()).build().toString())
|
||||||
scanlator = translation_name
|
scanlator = translationName
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -157,7 +209,7 @@ class AnimeSama : ParsedHttpSource() {
|
|||||||
SChapter.create().apply {
|
SChapter.create().apply {
|
||||||
name = "Chapitre $title"
|
name = "Chapitre $title"
|
||||||
setUrlWithoutDomain(chapterUrl.newBuilder().addQueryParameter("id", (parsedChapterList.size + 1).toString()).build().toString())
|
setUrlWithoutDomain(chapterUrl.newBuilder().addQueryParameter("id", (parsedChapterList.size + 1).toString()).build().toString())
|
||||||
scanlator = translation_name
|
scanlator = translationName
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
chapterDelay++
|
chapterDelay++
|
||||||
@ -166,12 +218,12 @@ class AnimeSama : ParsedHttpSource() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (index in parsedChapterList.size..parsedJavascriptFileToJson.size - 1) {
|
for (index in parsedChapterList.size until parsedJavascriptFileToJson.size) {
|
||||||
parsedChapterList.add(
|
parsedChapterList.add(
|
||||||
SChapter.create().apply {
|
SChapter.create().apply {
|
||||||
name = "Chapitre " + (parsedChapterList.size + 1 - chapterDelay)
|
name = "Chapitre " + (parsedChapterList.size + 1 - chapterDelay)
|
||||||
setUrlWithoutDomain(chapterUrl.newBuilder().addQueryParameter("id", (parsedChapterList.size + 1).toString()).build().toString())
|
setUrlWithoutDomain(chapterUrl.newBuilder().addQueryParameter("id", (parsedChapterList.size + 1).toString()).build().toString())
|
||||||
scanlator = translation_name
|
scanlator = translationName
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -222,7 +274,7 @@ class AnimeSama : ParsedHttpSource() {
|
|||||||
|
|
||||||
val documentString = document.body().toString()
|
val documentString = document.body().toString()
|
||||||
|
|
||||||
val allChapters: Map<Int, Int> = Regex("""eps(\d+)\s*(?:=\s*\[(.*?)\]|\.length\s*=\s*(\d+))""")
|
val allChapters: Map<Int, Int> = Regex("""eps(\d+)\s*(?:=\s*\[(.*?)]|\.length\s*=\s*(\d+))""")
|
||||||
.findAll(documentString)
|
.findAll(documentString)
|
||||||
.associate { match ->
|
.associate { match ->
|
||||||
val episode = match.groupValues[1].toInt()
|
val episode = match.groupValues[1].toInt()
|
||||||
@ -238,16 +290,16 @@ class AnimeSama : ParsedHttpSource() {
|
|||||||
episode to length
|
episode to length
|
||||||
}
|
}
|
||||||
|
|
||||||
val chapterSize = allChapters.get(chapter?.toInt()) ?: 1
|
val chapterSize = allChapters[chapter?.toInt()] ?: 1
|
||||||
|
|
||||||
val image_list = mutableListOf<Page>()
|
val imageList = mutableListOf<Page>()
|
||||||
for (index in 1 until chapterSize + 1) {
|
for (index in 1 until chapterSize + 1) {
|
||||||
image_list.add(
|
imageList.add(
|
||||||
Page(index, imageUrl = "$cdn$title/$chapter/$index.jpg"),
|
Page(index, imageUrl = "$cdn$title/$chapter/$index.jpg"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return image_list
|
return imageList
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException()
|
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException()
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
package eu.kanade.tachiyomi.extension.fr.animesama
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
|
import okhttp3.HttpUrl
|
||||||
|
|
||||||
|
interface UrlPartFilter {
|
||||||
|
fun addUrlParameter(url: HttpUrl.Builder)
|
||||||
|
}
|
||||||
|
|
||||||
|
class CheckBoxFilter(name: String, val value: String) : Filter.CheckBox(name)
|
||||||
|
|
||||||
|
abstract class CheckBoxGroup(
|
||||||
|
name: String,
|
||||||
|
options: List<Pair<String, String>>,
|
||||||
|
private val urlParameter: String,
|
||||||
|
) : UrlPartFilter, Filter.Group<CheckBoxFilter>(
|
||||||
|
name,
|
||||||
|
options.map { CheckBoxFilter(it.first, it.second) },
|
||||||
|
) {
|
||||||
|
override fun addUrlParameter(url: HttpUrl.Builder) {
|
||||||
|
state.filter { it.state }.forEach {
|
||||||
|
url.addQueryParameter(urlParameter, it.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GenreFilter(
|
||||||
|
options: List<Pair<String, String>>,
|
||||||
|
) : CheckBoxGroup(
|
||||||
|
"Genres",
|
||||||
|
options,
|
||||||
|
"genre[0]",
|
||||||
|
)
|
Loading…
x
Reference in New Issue
Block a user