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