all/SimplyHentai: Fix http 404 (#1008)
* fix: Fix popular manga page * fix: Fix latest manga page * fix: Fix search manga page * chore: Minor changes to prevent future issues * refactor: Minor refactoration * chore: Bump version * chore: Follow suggestion - re-add cloudflareClient * refactor: Commit suggestion - remove unnecessary chapter_number Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com> --------- Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>
This commit is contained in:
parent
ac1575dd81
commit
00e4bed8ab
@ -1,7 +1,7 @@
|
||||
ext {
|
||||
extName = 'Simply Hentai'
|
||||
extClass = '.SimplyHentaiFactory'
|
||||
extVersionCode = 6
|
||||
extVersionCode = 7
|
||||
isNsfw = true
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,6 @@ import android.net.Uri
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
@ -13,15 +12,20 @@ import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.decodeFromStream
|
||||
import okhttp3.Response
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
open class SimplyHentai(override val lang: String) : ConfigurableSource, HttpSource() {
|
||||
open class SimplyHentai(
|
||||
override val lang: String,
|
||||
private val langName: String,
|
||||
) : ConfigurableSource, HttpSource() {
|
||||
|
||||
override val name = "Simply Hentai"
|
||||
|
||||
override val baseUrl = "https://www.simply-hentai.com"
|
||||
@ -34,47 +38,32 @@ open class SimplyHentai(override val lang: String) : ConfigurableSource, HttpSou
|
||||
|
||||
private val apiUrl = "https://api.simply-hentai.com/v3"
|
||||
|
||||
private val langName by lazy {
|
||||
Locale.forLanguageTag(lang).displayName
|
||||
}
|
||||
|
||||
private val json by lazy { Injekt.get<Json>() }
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
private val preferences by lazy {
|
||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)!!
|
||||
}
|
||||
|
||||
override fun popularMangaRequest(page: Int) =
|
||||
Uri.parse("$apiUrl/albums").buildUpon().run {
|
||||
appendQueryParameter("si", "0")
|
||||
appendQueryParameter("locale", lang)
|
||||
appendQueryParameter("language", langName)
|
||||
appendQueryParameter("sort", "spotlight")
|
||||
Uri.parse("$apiUrl/tag/$langName").buildUpon().run {
|
||||
appendQueryParameter("type", "language")
|
||||
appendQueryParameter("page", page.toString())
|
||||
GET(build().toString(), headers)
|
||||
}
|
||||
|
||||
override fun popularMangaParse(response: Response) =
|
||||
response.decode<SHList<SHObject>>().run {
|
||||
response.decode<SHList<SHDataAlbum>>().run {
|
||||
MangasPage(
|
||||
data.map {
|
||||
SManga.create().apply {
|
||||
url = it.path
|
||||
title = it.title
|
||||
thumbnail_url = it.preview.sizes.thumb
|
||||
}
|
||||
},
|
||||
data.albums.map(SHObject::toSManga),
|
||||
pagination.next != null,
|
||||
)
|
||||
}
|
||||
|
||||
override fun latestUpdatesRequest(page: Int) =
|
||||
Uri.parse("$apiUrl/albums").buildUpon().run {
|
||||
appendQueryParameter("si", "0")
|
||||
appendQueryParameter("locale", lang)
|
||||
appendQueryParameter("language", langName)
|
||||
appendQueryParameter("sort", "newest")
|
||||
Uri.parse("$apiUrl/tag/$langName").buildUpon().run {
|
||||
appendQueryParameter("type", "language")
|
||||
appendQueryParameter("page", page.toString())
|
||||
appendQueryParameter("sort", "newest")
|
||||
GET(build().toString(), headers)
|
||||
}
|
||||
|
||||
@ -83,18 +72,16 @@ open class SimplyHentai(override val lang: String) : ConfigurableSource, HttpSou
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList) =
|
||||
Uri.parse("$apiUrl/search/complex").buildUpon().run {
|
||||
appendQueryParameter("si", "0")
|
||||
appendQueryParameter("locale", lang)
|
||||
appendQueryParameter("query", query)
|
||||
appendQueryParameter("page", page.toString())
|
||||
appendQueryParameter("blacklist", blacklist)
|
||||
appendQueryParameter("filter[languages][0]", langName)
|
||||
appendQueryParameter("filter[language][0]", langName.replaceFirstChar(Char::uppercase))
|
||||
filters.forEach { filter ->
|
||||
when (filter) {
|
||||
is SortFilter -> {
|
||||
appendQueryParameter("sort", filter.orders[filter.state])
|
||||
}
|
||||
is SeriesFilter -> filter.value?.let {
|
||||
is SeriesFilter -> filter.value?.also {
|
||||
appendQueryParameter("filter[series_title][0]", it)
|
||||
}
|
||||
is TagsFilter -> filter.value?.forEachIndexed { idx, tag ->
|
||||
@ -116,25 +103,14 @@ open class SimplyHentai(override val lang: String) : ConfigurableSource, HttpSou
|
||||
}
|
||||
|
||||
override fun searchMangaParse(response: Response) =
|
||||
response.decode<SHList<SHWrapper>>().run {
|
||||
response.decode<SHList<List<SHWrapper>>>().run {
|
||||
MangasPage(
|
||||
data.map {
|
||||
SManga.create().apply {
|
||||
url = it.`object`.path
|
||||
title = it.`object`.title
|
||||
thumbnail_url = it.`object`.preview.sizes.thumb
|
||||
}
|
||||
},
|
||||
data.map { it.`object`.toSManga() },
|
||||
pagination.next != null,
|
||||
)
|
||||
}
|
||||
|
||||
override fun mangaDetailsRequest(manga: SManga) =
|
||||
GET(baseUrl + manga.url, headers)
|
||||
|
||||
override fun fetchMangaDetails(manga: SManga) =
|
||||
client.newCall(chapterListRequest(manga))
|
||||
.asObservableSuccess().map(::mangaDetailsParse)!!
|
||||
override fun mangaDetailsRequest(manga: SManga) = chapterListRequest(manga)
|
||||
|
||||
override fun mangaDetailsParse(response: Response) =
|
||||
SManga.create().apply {
|
||||
@ -143,9 +119,9 @@ open class SimplyHentai(override val lang: String) : ConfigurableSource, HttpSou
|
||||
title = album.title
|
||||
description = buildString {
|
||||
if (!album.description.isNullOrEmpty()) {
|
||||
append("${album.description}\n\n")
|
||||
append(album.description, "\n\n")
|
||||
}
|
||||
append("Series: ${album.series.title}\n")
|
||||
append("Series: ", album.series.title, "\n")
|
||||
album.characters.joinTo(this, prefix = "Characters: ") { it.title }
|
||||
}
|
||||
thumbnail_url = album.preview.sizes.thumb
|
||||
@ -156,10 +132,8 @@ open class SimplyHentai(override val lang: String) : ConfigurableSource, HttpSou
|
||||
}
|
||||
|
||||
override fun chapterListRequest(manga: SManga) =
|
||||
Uri.parse("$apiUrl/album").buildUpon().run {
|
||||
Uri.parse("$apiUrl/manga").buildUpon().run {
|
||||
appendEncodedPath(manga.url.split('/')[2])
|
||||
appendQueryParameter("si", "0")
|
||||
appendQueryParameter("locale", lang)
|
||||
GET(build().toString(), headers)
|
||||
}
|
||||
|
||||
@ -167,18 +141,15 @@ open class SimplyHentai(override val lang: String) : ConfigurableSource, HttpSou
|
||||
SChapter.create().apply {
|
||||
val album = response.decode<SHAlbum>().data
|
||||
name = "Chapter"
|
||||
chapter_number = -1f
|
||||
url = "${album.path}/all-pages"
|
||||
scanlator = album.translators.joinToString { it.title }
|
||||
date_upload = dateFormat.parse(album.created_at)?.time ?: 0L
|
||||
}.let(::listOf)
|
||||
|
||||
override fun pageListRequest(chapter: SChapter) =
|
||||
Uri.parse("$apiUrl/album").buildUpon().run {
|
||||
Uri.parse("$apiUrl/manga").buildUpon().run {
|
||||
appendEncodedPath(chapter.url.split('/')[2])
|
||||
appendEncodedPath("/pages")
|
||||
appendQueryParameter("si", "0")
|
||||
appendQueryParameter("locale", lang)
|
||||
appendEncodedPath("pages")
|
||||
GET(build().toString(), headers)
|
||||
}
|
||||
|
||||
@ -215,8 +186,8 @@ open class SimplyHentai(override val lang: String) : ConfigurableSource, HttpSou
|
||||
private inline val blacklist: String
|
||||
get() = preferences.getString("blacklist", "")!!
|
||||
|
||||
private inline fun <reified T> Response.decode() =
|
||||
json.decodeFromString<T>(body.string())
|
||||
private inline fun <reified T> Response.decode(): T =
|
||||
json.decodeFromStream(body.byteStream())
|
||||
|
||||
override fun imageUrlParse(response: Response) =
|
||||
throw UnsupportedOperationException()
|
||||
|
@ -1,9 +1,10 @@
|
||||
package eu.kanade.tachiyomi.extension.all.simplyhentai
|
||||
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class SHList<T>(val pagination: SHPagination, val data: List<T>)
|
||||
data class SHList<T>(val pagination: SHPagination, val data: T)
|
||||
|
||||
@Serializable
|
||||
data class SHPagination(val next: Int?)
|
||||
@ -11,6 +12,9 @@ data class SHPagination(val next: Int?)
|
||||
@Serializable
|
||||
data class SHWrapper(val `object`: SHObject)
|
||||
|
||||
@Serializable
|
||||
data class SHDataAlbum(val albums: List<SHObject>)
|
||||
|
||||
@Serializable
|
||||
data class SHObject(
|
||||
val preview: SHImage,
|
||||
@ -18,7 +22,11 @@ data class SHObject(
|
||||
val slug: String,
|
||||
val title: String,
|
||||
) {
|
||||
val path by lazy { "/${series.slug}/$slug" }
|
||||
fun toSManga() = SManga.create().apply {
|
||||
url = "/${series.slug}/$slug"
|
||||
title = this@SHObject.title
|
||||
thumbnail_url = preview.sizes.thumb
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
|
@ -4,20 +4,15 @@ import eu.kanade.tachiyomi.source.SourceFactory
|
||||
|
||||
class SimplyHentaiFactory : SourceFactory {
|
||||
override fun createSources() = listOf(
|
||||
SimplyHentai("en"),
|
||||
SimplyHentai("ja"),
|
||||
SimplyHentai("zh"),
|
||||
SimplyHentai("ko"),
|
||||
SimplyHentai("es"),
|
||||
SimplyHentai("ru"),
|
||||
SimplyHentai("fr"),
|
||||
SimplyHentai("de"),
|
||||
object : SimplyHentai("pt-BR") {
|
||||
// The site uses a Portugal flag for the language,
|
||||
// but the contents are in Brazilian Portuguese.
|
||||
override val id = 23032005200449651
|
||||
},
|
||||
SimplyHentai("it"),
|
||||
SimplyHentai("pl"),
|
||||
SimplyHentai("en", "english"),
|
||||
SimplyHentai("ja", "japanese"),
|
||||
SimplyHentai("zh", "chinese"),
|
||||
SimplyHentai("ko", "korean"),
|
||||
SimplyHentai("es", "spanish"),
|
||||
SimplyHentai("ru", "russian"),
|
||||
SimplyHentai("fr", "french"),
|
||||
SimplyHentai("de", "german"),
|
||||
SimplyHentai("it", "italian"),
|
||||
SimplyHentai("pl", "polish"),
|
||||
)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user