AllAnime -> AllManga: update domain & small refactor (#4576)
* AllAnime -> AllManga: update domain & small refactor * preserve id * potential issue with img quality and cache?
This commit is contained in:
parent
2f4249e842
commit
a7b59aecd4
|
@ -2,7 +2,7 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<application>
|
||||
<activity
|
||||
android:name=".en.allanime.AllAnimeUrlActivity"
|
||||
android:name=".en.allanime.AllMangaUrlActivity"
|
||||
android:excludeFromRecents="true"
|
||||
android:exported="true"
|
||||
android:theme="@android:style/Theme.NoDisplay">
|
||||
|
@ -12,7 +12,7 @@
|
|||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data android:host="allanime.ai"/>
|
||||
<data android:host="allmanga.to"/>
|
||||
<data android:scheme="https"/>
|
||||
<data android:pathPattern="/manga/..*"/>
|
||||
<data android:pathPattern="/read/..*"/>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
ext {
|
||||
extName = 'AllAnime'
|
||||
extClass = '.AllAnime'
|
||||
extVersionCode = 6
|
||||
extName = 'AllManga'
|
||||
extClass = '.AllManga'
|
||||
extVersionCode = 7
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.en.allanime
|
||||
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.Headers
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import okhttp3.Response
|
||||
import org.jsoup.Jsoup
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
object AllAnimeHelper {
|
||||
|
||||
val json: Json = Json {
|
||||
ignoreUnknownKeys = true
|
||||
explicitNulls = false
|
||||
encodeDefaults = true
|
||||
coerceInputValues = true
|
||||
}
|
||||
|
||||
fun String.parseThumbnailUrl(): String {
|
||||
return if (this.matches(AllAnime.urlRegex)) {
|
||||
this
|
||||
} else {
|
||||
"$thumbnail_cdn$this?w=250"
|
||||
}
|
||||
}
|
||||
|
||||
fun String?.parseStatus(): Int {
|
||||
if (this == null) {
|
||||
return SManga.UNKNOWN
|
||||
}
|
||||
|
||||
return when {
|
||||
this.contains("releasing", true) -> SManga.ONGOING
|
||||
this.contains("finished", true) -> SManga.COMPLETED
|
||||
else -> SManga.UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
fun String.titleToSlug() = this.trim()
|
||||
.lowercase(Locale.US)
|
||||
.replace(titleSpecialCharactersRegex, "-")
|
||||
|
||||
fun String.parseDescription(): String {
|
||||
return Jsoup.parse(
|
||||
this.replace("<br>", "br2n"),
|
||||
).text().replace("br2n", "\n")
|
||||
}
|
||||
|
||||
fun String?.parseDate(): Long {
|
||||
return runCatching {
|
||||
dateFormat.parse(this!!)!!.time
|
||||
}.getOrDefault(0L)
|
||||
}
|
||||
|
||||
inline fun <reified T> Response.parseAs(): T = json.decodeFromString(body.string())
|
||||
|
||||
inline fun <reified T> List<*>.firstInstanceOrNull(): T? =
|
||||
filterIsInstance<T>().firstOrNull()
|
||||
|
||||
inline fun <reified T : Any> T.toJsonRequestBody(): RequestBody =
|
||||
json.encodeToString(this)
|
||||
.toRequestBody(JSON_MEDIA_TYPE)
|
||||
|
||||
fun Headers.Builder.buildApiHeaders(requestBody: RequestBody) = this
|
||||
.add("Content-Length", requestBody.contentLength().toString())
|
||||
.add("Content-Type", requestBody.contentType().toString())
|
||||
.build()
|
||||
|
||||
private const val thumbnail_cdn = "https://wp.youtube-anime.com/aln.youtube-anime.com/"
|
||||
private val titleSpecialCharactersRegex by lazy { Regex("[^a-z\\d]+") }
|
||||
private val dateFormat by lazy {
|
||||
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH)
|
||||
}
|
||||
val JSON_MEDIA_TYPE = "application/json; charset=utf-8".toMediaTypeOrNull()
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.en.allanime
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class GraphQL<T>(
|
||||
val variables: T,
|
||||
val query: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class PopularVariables(
|
||||
val type: String,
|
||||
val size: Int,
|
||||
val dateRange: Int,
|
||||
val page: Int,
|
||||
val allowAdult: Boolean,
|
||||
val allowUnknown: Boolean,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class SearchVariables(
|
||||
val search: SearchPayload,
|
||||
@SerialName("limit") val size: Int,
|
||||
val page: Int,
|
||||
val translationType: String,
|
||||
val countryOrigin: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class SearchPayload(
|
||||
val query: String?,
|
||||
val sortBy: String?,
|
||||
val genres: List<String>?,
|
||||
val excludeGenres: List<String>?,
|
||||
val isManga: Boolean,
|
||||
val allowAdult: Boolean,
|
||||
val allowUnknown: Boolean,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class IDVariables(
|
||||
val id: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ChapterListVariables(
|
||||
val id: String,
|
||||
val chapterNumStart: Float,
|
||||
val chapterNumEnd: Float,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class PageListVariables(
|
||||
val id: String,
|
||||
val chapterNum: String,
|
||||
val translationType: String,
|
||||
)
|
|
@ -5,10 +5,7 @@ import android.content.SharedPreferences
|
|||
import androidx.preference.ListPreference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import androidx.preference.SwitchPreferenceCompat
|
||||
import eu.kanade.tachiyomi.extension.en.allanime.AllAnimeHelper.buildApiHeaders
|
||||
import eu.kanade.tachiyomi.extension.en.allanime.AllAnimeHelper.firstInstanceOrNull
|
||||
import eu.kanade.tachiyomi.extension.en.allanime.AllAnimeHelper.parseAs
|
||||
import eu.kanade.tachiyomi.extension.en.allanime.AllAnimeHelper.toJsonRequestBody
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
|
@ -26,16 +23,18 @@ import rx.Observable
|
|||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class AllAnime : ConfigurableSource, HttpSource() {
|
||||
class AllManga : ConfigurableSource, HttpSource() {
|
||||
|
||||
override val name = "AllAnime"
|
||||
override val name = "AllManga"
|
||||
|
||||
override val baseUrl = "https://allanime.ai"
|
||||
override val baseUrl = "https://allmanga.to"
|
||||
|
||||
private val apiUrl = "https://api.allanime.day/api"
|
||||
|
||||
override val lang = "en"
|
||||
|
||||
override val id = 4709139914729853090
|
||||
|
||||
override val supportsLatest = true
|
||||
|
||||
private val preferences by lazy {
|
||||
|
@ -43,24 +42,6 @@ class AllAnime : ConfigurableSource, HttpSource() {
|
|||
}
|
||||
|
||||
override val client = network.cloudflareClient.newBuilder()
|
||||
.addInterceptor { chain ->
|
||||
val request = chain.request()
|
||||
val frag = request.url.fragment
|
||||
val quality = preferences.imageQuality
|
||||
|
||||
if (frag.isNullOrEmpty() || quality == IMAGE_QUALITY_PREF_DEFAULT) {
|
||||
return@addInterceptor chain.proceed(request)
|
||||
}
|
||||
|
||||
val oldUrl = request.url.toString()
|
||||
val newUrl = oldUrl.replace(imageQualityRegex, "$image_cdn/$1?w=$quality")
|
||||
|
||||
return@addInterceptor chain.proceed(
|
||||
request.newBuilder()
|
||||
.url(newUrl)
|
||||
.build(),
|
||||
)
|
||||
}
|
||||
.rateLimit(1)
|
||||
.build()
|
||||
|
||||
|
@ -72,7 +53,7 @@ class AllAnime : ConfigurableSource, HttpSource() {
|
|||
val payload = GraphQL(
|
||||
PopularVariables(
|
||||
type = "manga",
|
||||
size = limit,
|
||||
size = LIMIT,
|
||||
dateRange = 0,
|
||||
page = page,
|
||||
allowAdult = preferences.allowAdult,
|
||||
|
@ -83,9 +64,7 @@ class AllAnime : ConfigurableSource, HttpSource() {
|
|||
|
||||
val requestBody = payload.toJsonRequestBody()
|
||||
|
||||
val apiHeaders = headersBuilder().buildApiHeaders(requestBody)
|
||||
|
||||
return POST(apiUrl, apiHeaders, requestBody)
|
||||
return POST(apiUrl, headers, requestBody)
|
||||
}
|
||||
|
||||
override fun popularMangaParse(response: Response): MangasPage {
|
||||
|
@ -94,7 +73,7 @@ class AllAnime : ConfigurableSource, HttpSource() {
|
|||
val mangaList = result.data.popular.mangas
|
||||
.mapNotNull { it.manga?.toSManga() }
|
||||
|
||||
val hasNextPage = result.data.popular.mangas.size == limit
|
||||
val hasNextPage = result.data.popular.mangas.size == LIMIT
|
||||
|
||||
return MangasPage(mangaList, hasNextPage)
|
||||
}
|
||||
|
@ -128,7 +107,7 @@ class AllAnime : ConfigurableSource, HttpSource() {
|
|||
allowAdult = preferences.allowAdult,
|
||||
allowUnknown = false,
|
||||
),
|
||||
size = limit,
|
||||
size = LIMIT,
|
||||
page = page,
|
||||
translationType = "sub",
|
||||
countryOrigin = filters.firstInstanceOrNull<CountryFilter>()?.getValue() ?: "ALL",
|
||||
|
@ -138,9 +117,7 @@ class AllAnime : ConfigurableSource, HttpSource() {
|
|||
|
||||
val requestBody = payload.toJsonRequestBody()
|
||||
|
||||
val apiHeaders = headersBuilder().buildApiHeaders(requestBody)
|
||||
|
||||
return POST(apiUrl, apiHeaders, requestBody)
|
||||
return POST(apiUrl, headers, requestBody)
|
||||
}
|
||||
|
||||
override fun searchMangaParse(response: Response): MangasPage {
|
||||
|
@ -149,7 +126,7 @@ class AllAnime : ConfigurableSource, HttpSource() {
|
|||
val mangaList = result.data.mangas.edges
|
||||
.map(SearchManga::toSManga)
|
||||
|
||||
val hasNextPage = result.data.mangas.edges.size == limit
|
||||
val hasNextPage = result.data.mangas.edges.size == LIMIT
|
||||
|
||||
return MangasPage(mangaList, hasNextPage)
|
||||
}
|
||||
|
@ -167,9 +144,7 @@ class AllAnime : ConfigurableSource, HttpSource() {
|
|||
|
||||
val requestBody = payload.toJsonRequestBody()
|
||||
|
||||
val apiHeaders = headersBuilder().buildApiHeaders(requestBody)
|
||||
|
||||
return POST(apiUrl, apiHeaders, requestBody)
|
||||
return POST(apiUrl, headers, requestBody)
|
||||
}
|
||||
|
||||
override fun mangaDetailsParse(response: Response): SManga {
|
||||
|
@ -205,9 +180,7 @@ class AllAnime : ConfigurableSource, HttpSource() {
|
|||
|
||||
val requestBody = payload.toJsonRequestBody()
|
||||
|
||||
val apiHeaders = headersBuilder().buildApiHeaders(requestBody)
|
||||
|
||||
return POST(apiUrl, apiHeaders, requestBody)
|
||||
return POST(apiUrl, headers, requestBody)
|
||||
}
|
||||
|
||||
private fun chapterListParse(response: Response, manga: SManga): List<SChapter> {
|
||||
|
@ -246,9 +219,7 @@ class AllAnime : ConfigurableSource, HttpSource() {
|
|||
|
||||
val requestBody = payload.toJsonRequestBody()
|
||||
|
||||
val apiHeaders = headersBuilder().buildApiHeaders(requestBody)
|
||||
|
||||
return POST(apiUrl, apiHeaders, requestBody)
|
||||
return POST(apiUrl, headers, requestBody)
|
||||
}
|
||||
|
||||
override fun pageListParse(response: Response): List<Page> {
|
||||
|
@ -266,11 +237,24 @@ class AllAnime : ConfigurableSource, HttpSource() {
|
|||
return pages.pictureUrls?.mapIndexed { index, image ->
|
||||
Page(
|
||||
index = index,
|
||||
imageUrl = "$imageDomain${image.url}#page",
|
||||
imageUrl = "$imageDomain${image.url}",
|
||||
)
|
||||
} ?: emptyList()
|
||||
}
|
||||
|
||||
override fun imageRequest(page: Page): Request {
|
||||
val quality = preferences.imageQuality
|
||||
|
||||
if (quality == IMAGE_QUALITY_PREF_DEFAULT) {
|
||||
return super.imageRequest(page)
|
||||
}
|
||||
|
||||
val oldUrl = imageQualityRegex.find(page.imageUrl!!)!!.groupValues[1]
|
||||
val newUrl = "$IMAGE_CDN/$oldUrl?w=$quality"
|
||||
|
||||
return GET(newUrl, headers)
|
||||
}
|
||||
|
||||
override fun imageUrlParse(response: Response): String {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
@ -299,11 +283,11 @@ class AllAnime : ConfigurableSource, HttpSource() {
|
|||
get() = getString(IMAGE_QUALITY_PREF, IMAGE_QUALITY_PREF_DEFAULT)!!
|
||||
|
||||
companion object {
|
||||
private const val limit = 20
|
||||
private const val LIMIT = 20
|
||||
const val SEARCH_PREFIX = "id:"
|
||||
val urlRegex = Regex("^https?://.*")
|
||||
private const val image_cdn = "https://wp.youtube-anime.com"
|
||||
private val imageQualityRegex = Regex("^https?://(.*)#.*")
|
||||
private const val IMAGE_CDN = "https://wp.youtube-anime.com"
|
||||
private val imageQualityRegex = Regex("^https?://([^#]+)")
|
||||
|
||||
private const val SHOW_ADULT_PREF = "pref_adult"
|
||||
private const val SHOW_ADULT_PREF_DEFAULT = false
|
|
@ -7,7 +7,7 @@ import android.os.Bundle
|
|||
import android.util.Log
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
class AllAnimeUrlActivity : Activity() {
|
||||
class AllMangaUrlActivity : Activity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val pathSegments = intent?.data?.pathSegments
|
||||
|
@ -15,17 +15,17 @@ class AllAnimeUrlActivity : Activity() {
|
|||
val id = pathSegments[1]
|
||||
val mainIntent = Intent().apply {
|
||||
action = "eu.kanade.tachiyomi.SEARCH"
|
||||
putExtra("query", "${AllAnime.SEARCH_PREFIX}$id")
|
||||
putExtra("query", "${AllManga.SEARCH_PREFIX}$id")
|
||||
putExtra("filter", packageName)
|
||||
}
|
||||
|
||||
try {
|
||||
startActivity(mainIntent)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
Log.e("AllAnimeUrlActivity", e.toString())
|
||||
Log.e("AllMangaUrlActivity", e.toString())
|
||||
}
|
||||
} else {
|
||||
Log.e("AllAnimeUrlActivity", "could not parse uri from intent $intent")
|
||||
Log.e("AllMangaUrlActivity", "could not parse uri from intent $intent")
|
||||
}
|
||||
|
||||
finish()
|
|
@ -1,10 +1,5 @@
|
|||
package eu.kanade.tachiyomi.extension.en.allanime
|
||||
|
||||
import eu.kanade.tachiyomi.extension.en.allanime.AllAnimeHelper.parseDate
|
||||
import eu.kanade.tachiyomi.extension.en.allanime.AllAnimeHelper.parseDescription
|
||||
import eu.kanade.tachiyomi.extension.en.allanime.AllAnimeHelper.parseStatus
|
||||
import eu.kanade.tachiyomi.extension.en.allanime.AllAnimeHelper.parseThumbnailUrl
|
||||
import eu.kanade.tachiyomi.extension.en.allanime.AllAnimeHelper.titleToSlug
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import kotlinx.serialization.SerialName
|
||||
|
@ -22,39 +17,39 @@ typealias ApiChapterListResponse = Data<ChapterListData>
|
|||
typealias ApiPageListResponse = Data<PageListData>
|
||||
|
||||
@Serializable
|
||||
data class Data<T>(val data: T)
|
||||
class Data<T>(val data: T)
|
||||
|
||||
@Serializable
|
||||
data class Edges<T>(val edges: List<T>)
|
||||
class Edges<T>(val edges: List<T>)
|
||||
|
||||
// Popular
|
||||
@Serializable
|
||||
data class PopularData(
|
||||
class PopularData(
|
||||
@SerialName("queryPopular") val popular: PopularMangas,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class PopularMangas(
|
||||
class PopularMangas(
|
||||
@SerialName("recommendations") val mangas: List<PopularManga>,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class PopularManga(
|
||||
class PopularManga(
|
||||
@SerialName("anyCard") val manga: SearchManga? = null,
|
||||
)
|
||||
|
||||
// Search
|
||||
@Serializable
|
||||
data class SearchData(
|
||||
class SearchData(
|
||||
val mangas: Edges<SearchManga>,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class SearchManga(
|
||||
class SearchManga(
|
||||
@SerialName("_id") val id: String,
|
||||
val name: String,
|
||||
val thumbnail: String? = null,
|
||||
val englishName: String? = null,
|
||||
private val name: String,
|
||||
private val thumbnail: String? = null,
|
||||
private val englishName: String? = null,
|
||||
) {
|
||||
fun toSManga() = SManga.create().apply {
|
||||
title = englishName ?: name
|
||||
|
@ -65,22 +60,22 @@ data class SearchManga(
|
|||
|
||||
// Details
|
||||
@Serializable
|
||||
data class MangaDetailsData(
|
||||
class MangaDetailsData(
|
||||
val manga: Manga,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Manga(
|
||||
class Manga(
|
||||
@SerialName("_id") val id: String,
|
||||
val name: String,
|
||||
val thumbnail: String? = null,
|
||||
val description: String? = null,
|
||||
val authors: List<String>? = emptyList(),
|
||||
val genres: List<String>? = emptyList(),
|
||||
val tags: List<String>? = emptyList(),
|
||||
val status: String? = null,
|
||||
val altNames: List<String>? = emptyList(),
|
||||
val englishName: String? = null,
|
||||
private val name: String,
|
||||
private val thumbnail: String? = null,
|
||||
private val description: String? = null,
|
||||
private val authors: List<String>? = emptyList(),
|
||||
private val genres: List<String>? = emptyList(),
|
||||
private val tags: List<String>? = emptyList(),
|
||||
private val status: String? = null,
|
||||
private val altNames: List<String>? = emptyList(),
|
||||
private val englishName: String? = null,
|
||||
) {
|
||||
fun toSManga() = SManga.create().apply {
|
||||
title = englishName ?: name
|
||||
|
@ -108,15 +103,15 @@ data class Manga(
|
|||
|
||||
// chapters details
|
||||
@Serializable
|
||||
data class ChapterListData(
|
||||
class ChapterListData(
|
||||
@SerialName("episodeInfos") val chapterList: List<ChapterData>? = emptyList(),
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ChapterData(
|
||||
class ChapterData(
|
||||
@SerialName("episodeIdNum") val chapterNum: JsonPrimitive,
|
||||
@SerialName("notes") val title: String? = null,
|
||||
val uploadDates: DateDto? = null,
|
||||
private val uploadDates: DateDto? = null,
|
||||
) {
|
||||
fun toSChapter(mangaUrl: String) = SChapter.create().apply {
|
||||
name = "Chapter $chapterNum"
|
||||
|
@ -133,23 +128,23 @@ data class ChapterData(
|
|||
}
|
||||
|
||||
@Serializable
|
||||
data class DateDto(
|
||||
class DateDto(
|
||||
val sub: String? = null,
|
||||
)
|
||||
|
||||
// page lsit
|
||||
// page list
|
||||
@Serializable
|
||||
data class PageListData(
|
||||
class PageListData(
|
||||
@SerialName("chapterPages") val pageList: Edges<Servers>?,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Servers(
|
||||
class Servers(
|
||||
@SerialName("pictureUrlHead") val serverUrl: String? = null,
|
||||
val pictureUrls: List<PageUrl>?,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class PageUrl(
|
||||
class PageUrl(
|
||||
val url: String,
|
||||
)
|
|
@ -0,0 +1,58 @@
|
|||
package eu.kanade.tachiyomi.extension.en.allanime
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
class GraphQL<T>(
|
||||
private val variables: T,
|
||||
private val query: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class PopularVariables(
|
||||
private val type: String,
|
||||
private val size: Int,
|
||||
private val dateRange: Int,
|
||||
private val page: Int,
|
||||
private val allowAdult: Boolean,
|
||||
private val allowUnknown: Boolean,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class SearchVariables(
|
||||
private val search: SearchPayload,
|
||||
private val size: Int,
|
||||
private val page: Int,
|
||||
private val translationType: String,
|
||||
private val countryOrigin: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class SearchPayload(
|
||||
private val query: String?,
|
||||
private val sortBy: String?,
|
||||
private val genres: List<String>?,
|
||||
private val excludeGenres: List<String>?,
|
||||
private val isManga: Boolean,
|
||||
private val allowAdult: Boolean,
|
||||
private val allowUnknown: Boolean,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class IDVariables(
|
||||
private val id: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class ChapterListVariables(
|
||||
private val id: String,
|
||||
private val chapterNumStart: Float,
|
||||
private val chapterNumEnd: Float,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class PageListVariables(
|
||||
private val id: String,
|
||||
private val chapterNum: String,
|
||||
private val translationType: String,
|
||||
)
|
|
@ -41,14 +41,14 @@ val SEARCH_QUERY: String = buildQuery {
|
|||
"""
|
||||
query (
|
||||
%search: SearchInput
|
||||
%limit: Int
|
||||
%size: Int
|
||||
%page: Int
|
||||
%translationType: VaildTranslationTypeMangaEnumType
|
||||
%countryOrigin: VaildCountryOriginEnumType
|
||||
) {
|
||||
mangas(
|
||||
search: %search
|
||||
limit: %limit
|
||||
limit: %size
|
||||
page: %page
|
||||
translationType: %translationType
|
||||
countryOrigin: %countryOrigin
|
|
@ -0,0 +1,72 @@
|
|||
package eu.kanade.tachiyomi.extension.en.allanime
|
||||
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import okhttp3.Response
|
||||
import org.jsoup.Jsoup
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
val json: Json = Json {
|
||||
ignoreUnknownKeys = true
|
||||
explicitNulls = false
|
||||
encodeDefaults = true
|
||||
coerceInputValues = true
|
||||
}
|
||||
|
||||
fun String.parseThumbnailUrl(): String {
|
||||
return if (this.matches(AllManga.urlRegex)) {
|
||||
this
|
||||
} else {
|
||||
"$thumbnail_cdn$this?w=250"
|
||||
}
|
||||
}
|
||||
|
||||
fun String?.parseStatus(): Int {
|
||||
if (this == null) {
|
||||
return SManga.UNKNOWN
|
||||
}
|
||||
|
||||
return when {
|
||||
this.contains("releasing", true) -> SManga.ONGOING
|
||||
this.contains("finished", true) -> SManga.COMPLETED
|
||||
else -> SManga.UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
fun String.titleToSlug() = this.trim()
|
||||
.lowercase(Locale.US)
|
||||
.replace(titleSpecialCharactersRegex, "-")
|
||||
|
||||
fun String.parseDescription(): String {
|
||||
return Jsoup.parse(
|
||||
this.replace("<br>", "br2n"),
|
||||
).text().replace("br2n", "\n")
|
||||
}
|
||||
|
||||
fun String?.parseDate(): Long {
|
||||
return runCatching {
|
||||
dateFormat.parse(this!!)!!.time
|
||||
}.getOrDefault(0L)
|
||||
}
|
||||
|
||||
inline fun <reified T> Response.parseAs(): T = json.decodeFromString(body.string())
|
||||
|
||||
inline fun <reified T> List<*>.firstInstanceOrNull(): T? =
|
||||
filterIsInstance<T>().firstOrNull()
|
||||
|
||||
inline fun <reified T : Any> T.toJsonRequestBody(): RequestBody =
|
||||
json.encodeToString(this)
|
||||
.toRequestBody(JSON_MEDIA_TYPE)
|
||||
|
||||
private const val thumbnail_cdn = "https://wp.youtube-anime.com/aln.youtube-anime.com/"
|
||||
private val titleSpecialCharactersRegex = Regex("[^a-z\\d]+")
|
||||
private val dateFormat by lazy {
|
||||
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH)
|
||||
}
|
||||
val JSON_MEDIA_TYPE = "application/json; charset=utf-8".toMediaTypeOrNull()
|
Loading…
Reference in New Issue