Mangadex api v2 for manga info
(cherry picked from commit 38ec991a15d2eebc7ebd0522f8615c2d8dd7003b) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/source/online/handlers/ApiMangaParser.kt # app/src/main/java/eu/kanade/tachiyomi/source/online/handlers/serializers/CoversSerializer.kt # app/src/main/java/exh/md/handlers/MangaHandler.kt # app/src/main/java/exh/md/handlers/SearchHandler.kt # app/src/main/java/exh/md/handlers/serializers/ApiMangaSerializer.kt # app/src/main/res/drawable/manga_info_more_gradient.xml
This commit is contained in:
parent
68c12d79ee
commit
f1a65edd3a
@ -165,7 +165,7 @@ class MangaDex(delegate: HttpSource, val context: Context) :
|
||||
}
|
||||
|
||||
override fun parseIntoMetadata(metadata: MangaDexSearchMetadata, input: Response) {
|
||||
ApiMangaParser(listOf(mdLang)).parseIntoMetadata(metadata, input, preferences.mangaDexForceLatestCovers().get())
|
||||
ApiMangaParser(listOf(mdLang)).parseIntoMetadata(metadata, input, emptyList())
|
||||
}
|
||||
|
||||
override suspend fun fetchFollows(): MangasPage {
|
||||
|
@ -47,7 +47,7 @@ class ApiMangaParser(private val langs: List<String>) {
|
||||
*
|
||||
* Will also save the metadata to the DB if possible
|
||||
*/
|
||||
fun parseToManga(manga: SManga, input: Response, forceLatestCover: Boolean): Completable {
|
||||
fun parseToManga(manga: SManga, input: Response, coverUrls: List<String>): Completable {
|
||||
val mangaId = (manga as? Manga)?.id
|
||||
val metaObservable = if (mangaId != null) {
|
||||
// We have to use fromCallable because StorIO messes up the thread scheduling if we use their rx functions
|
||||
@ -61,7 +61,7 @@ class ApiMangaParser(private val langs: List<String>) {
|
||||
}
|
||||
|
||||
return metaObservable.map {
|
||||
parseIntoMetadata(it, input, forceLatestCover)
|
||||
parseIntoMetadata(it, input, coverUrls)
|
||||
it.copyTo(manga)
|
||||
it
|
||||
}.flatMapCompletable {
|
||||
@ -72,14 +72,14 @@ class ApiMangaParser(private val langs: List<String>) {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun parseToManga(manga: MangaInfo, input: Response, forceLatestCover: Boolean, sourceId: Long): MangaInfo {
|
||||
suspend fun parseToManga(manga: MangaInfo, input: Response, coverUrls: List<String>, sourceId: Long): MangaInfo {
|
||||
val mangaId = db.getManga(manga.key, sourceId).await()?.id
|
||||
val metadata = if (mangaId != null) {
|
||||
val flatMetadata = db.getFlatMetadataForManga(mangaId).await()
|
||||
flatMetadata?.raise(metaClass) ?: newMetaInstance()
|
||||
} else newMetaInstance()
|
||||
|
||||
parseInfoIntoMetadata(metadata, input, forceLatestCover)
|
||||
parseInfoIntoMetadata(metadata, input, coverUrls)
|
||||
if (mangaId != null) {
|
||||
metadata.mangaId = mangaId
|
||||
db.insertFlatMetadata(metadata.flatten()).await()
|
||||
@ -88,28 +88,26 @@ class ApiMangaParser(private val langs: List<String>) {
|
||||
return metadata.createMangaInfo(manga)
|
||||
}
|
||||
|
||||
fun parseInfoIntoMetadata(metadata: MangaDexSearchMetadata, input: Response, forceLatestCover: Boolean) = parseIntoMetadata(metadata, input, forceLatestCover)
|
||||
fun parseInfoIntoMetadata(metadata: MangaDexSearchMetadata, input: Response, coverUrls: List<String>) = parseIntoMetadata(metadata, input, coverUrls)
|
||||
|
||||
fun parseIntoMetadata(metadata: MangaDexSearchMetadata, input: Response, forceLatestCover: Boolean) {
|
||||
fun parseIntoMetadata(metadata: MangaDexSearchMetadata, input: Response, coverUrls: List<String>) {
|
||||
with(metadata) {
|
||||
try {
|
||||
val networkApiManga = MdUtil.jsonParser.decodeFromString<ApiMangaSerializer>(input.body!!.string())
|
||||
val networkManga = networkApiManga.manga
|
||||
val networkManga = networkApiManga.data.manga
|
||||
mdId = MdUtil.getMangaId(input.request.url.toString())
|
||||
mdUrl = input.request.url.toString()
|
||||
title = MdUtil.cleanString(networkManga.title)
|
||||
val coverList = networkManga.covers
|
||||
thumbnail_url = MdUtil.cdnUrl +
|
||||
if (forceLatestCover && coverList.isNotEmpty()) {
|
||||
coverList.last()
|
||||
} else {
|
||||
MdUtil.removeTimeParamUrl(networkManga.cover_url)
|
||||
}
|
||||
thumbnail_url = if (coverUrls.isNotEmpty()) {
|
||||
coverUrls.last()
|
||||
} else {
|
||||
networkManga.mainCover
|
||||
}
|
||||
description = MdUtil.cleanDescription(networkManga.description)
|
||||
author = MdUtil.cleanString(networkManga.author)
|
||||
artist = MdUtil.cleanString(networkManga.artist)
|
||||
lang_flag = networkManga.lang_flag
|
||||
last_chapter_number = networkManga.last_chapter?.toFloatOrNull()?.floor()
|
||||
author = MdUtil.cleanString(networkManga.author.joinToString())
|
||||
artist = MdUtil.cleanString(networkManga.artist.joinToString())
|
||||
lang_flag = networkManga.publication?.language
|
||||
last_chapter_number = networkManga.lastChapter?.toFloatOrNull()?.floor()
|
||||
|
||||
networkManga.rating?.let {
|
||||
rating = it.bayesian ?: it.mean
|
||||
@ -124,7 +122,7 @@ class ApiMangaParser(private val langs: List<String>) {
|
||||
}
|
||||
val filteredChapters = filterChapterForChecking(networkApiManga)
|
||||
|
||||
val tempStatus = parseStatus(networkManga.status)
|
||||
val tempStatus = parseStatus(networkManga.publication!!.status)
|
||||
val publishedOrCancelled =
|
||||
tempStatus == SManga.PUBLICATION_COMPLETE || tempStatus == SManga.CANCELLED
|
||||
if (publishedOrCancelled && isMangaCompleted(networkApiManga, filteredChapters)) {
|
||||
@ -134,17 +132,19 @@ class ApiMangaParser(private val langs: List<String>) {
|
||||
status = tempStatus
|
||||
}
|
||||
|
||||
val demographic = FilterHandler.demographics().filter { it.id == networkManga.demographic }.firstOrNull()
|
||||
|
||||
val genres =
|
||||
networkManga.genres.mapNotNull { FilterHandler.allTypes[it.toString()] }
|
||||
networkManga.tags.mapNotNull { FilterHandler.allTypes[it.toString()] }
|
||||
.toMutableList()
|
||||
|
||||
if (demographic != null) {
|
||||
genres.add(0, demographic.name)
|
||||
networkManga.publication.demographic?.let { demographicInt ->
|
||||
val demographic = FilterHandler.demographics().firstOrNull { it.id.toInt() == demographicInt }
|
||||
|
||||
if (demographic != null) {
|
||||
genres.add(0, demographic.name)
|
||||
}
|
||||
}
|
||||
|
||||
if (networkManga.hentai == 1) {
|
||||
if (networkManga.isHentai) {
|
||||
genres.add("Hentai")
|
||||
}
|
||||
|
||||
@ -163,41 +163,39 @@ class ApiMangaParser(private val langs: List<String>) {
|
||||
*/
|
||||
private fun isMangaCompleted(
|
||||
serializer: ApiMangaSerializer,
|
||||
filteredChapters: List<Map.Entry<String, ChapterSerializer>>
|
||||
filteredChapters: List<ChapterSerializer>
|
||||
): Boolean {
|
||||
if (filteredChapters.isEmpty() || serializer.manga.last_chapter.isNullOrEmpty()) {
|
||||
val finalChapterNumber = serializer.data.manga.lastChapter
|
||||
if (filteredChapters.isEmpty() || finalChapterNumber.isNullOrEmpty()) {
|
||||
return false
|
||||
}
|
||||
// just to fix the stupid lint
|
||||
val lastMangaChapter: String? = serializer.manga.last_chapter
|
||||
val finalChapterNumber = lastMangaChapter!!
|
||||
if (MdUtil.validOneShotFinalChapters.contains(finalChapterNumber)) {
|
||||
filteredChapters.firstOrNull()?.let {
|
||||
if (isOneShot(it.value, finalChapterNumber)) {
|
||||
if (isOneShot(it, finalChapterNumber)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
val removeOneshots = filteredChapters.asSequence()
|
||||
.map { it.value.chapter?.toDoubleOrNull()?.floor()?.nullIfZero() }
|
||||
.map { it.chapter?.toDoubleOrNull()?.floor()?.nullIfZero() }
|
||||
.filterNotNull()
|
||||
.toList().distinctBy { it }
|
||||
return removeOneshots.toList().size == finalChapterNumber.toDouble().floor()
|
||||
}
|
||||
|
||||
private fun filterChapterForChecking(serializer: ApiMangaSerializer): List<Map.Entry<String, ChapterSerializer>> {
|
||||
serializer.chapter ?: return emptyList()
|
||||
return serializer.chapter.entries
|
||||
.filter { langs.contains(it.value.lang_code) }
|
||||
private fun filterChapterForChecking(serializer: ApiMangaSerializer): List<ChapterSerializer> {
|
||||
return serializer.data.chapters.asSequence()
|
||||
.filter { langs.contains(it.language) }
|
||||
.filter {
|
||||
it.value.chapter?.let { chapterNumber ->
|
||||
it.chapter?.let { chapterNumber ->
|
||||
if (chapterNumber.toDoubleOrNull() == null) {
|
||||
return@filter false
|
||||
}
|
||||
return@filter true
|
||||
}
|
||||
return@filter false
|
||||
}.distinctBy { it.value.chapter }
|
||||
}.toList()
|
||||
}
|
||||
|
||||
private fun isOneShot(chapter: ChapterSerializer, finalChapterNumber: String): Boolean {
|
||||
@ -230,24 +228,20 @@ class ApiMangaParser(private val langs: List<String>) {
|
||||
fun chapterListParse(jsonData: String): List<SChapter> {
|
||||
val now = System.currentTimeMillis()
|
||||
val networkApiManga = MdUtil.jsonParser.decodeFromString<ApiMangaSerializer>(jsonData)
|
||||
val networkManga = networkApiManga.manga
|
||||
val networkChapters = networkApiManga.chapter
|
||||
if (networkChapters.isNullOrEmpty()) {
|
||||
return listOf()
|
||||
}
|
||||
val status = networkManga.status
|
||||
val networkManga = networkApiManga.data.manga
|
||||
val networkChapters = networkApiManga.data.chapters
|
||||
val groups = networkApiManga.data.groups
|
||||
|
||||
val finalChapterNumber = networkManga.last_chapter!!
|
||||
val status = networkManga.publication!!.status
|
||||
|
||||
val chapters = mutableListOf<SChapter>()
|
||||
val finalChapterNumber = networkManga.lastChapter
|
||||
|
||||
// Skip chapters that don't match the desired language, or are future releases
|
||||
|
||||
val chapLangs = MdLang.values().filter { langs.contains(it.dexLang) }
|
||||
networkChapters.filter { langs.contains(it.value.lang_code) && (it.value.timestamp * 1000) <= now }
|
||||
.mapTo(chapters) { mapChapter(it.key, it.value, finalChapterNumber, status, chapLangs, networkChapters.size) }
|
||||
|
||||
return chapters
|
||||
return networkChapters.asSequence()
|
||||
.filter { langs.contains(it.language) && (it.timestamp * 1000) <= now }
|
||||
.map { mapChapter(it, finalChapterNumber, status, chapLangs, networkChapters.size, groups) }.toList()
|
||||
}
|
||||
|
||||
fun chapterParseForMangaId(response: Response): Int {
|
||||
@ -267,15 +261,15 @@ class ApiMangaParser(private val langs: List<String>) {
|
||||
}
|
||||
|
||||
private fun mapChapter(
|
||||
chapterId: String,
|
||||
networkChapter: ChapterSerializer,
|
||||
finalChapterNumber: String,
|
||||
finalChapterNumber: String?,
|
||||
status: Int,
|
||||
chapLangs: List<MdLang>,
|
||||
totalChapterCount: Int
|
||||
totalChapterCount: Int,
|
||||
groups: Map<Long, String>
|
||||
): SChapter {
|
||||
val chapter = SChapter.create()
|
||||
chapter.url = MdUtil.apiChapter + chapterId
|
||||
chapter.url = MdUtil.apiChapter + networkChapter.id
|
||||
val chapterName = mutableListOf<String>()
|
||||
// Build chapter name
|
||||
|
||||
@ -305,10 +299,12 @@ class ApiMangaParser(private val langs: List<String>) {
|
||||
chapterName.add("Oneshot")
|
||||
}
|
||||
if ((status == 2 || status == 3)) {
|
||||
if ((isOneShot(networkChapter, finalChapterNumber) && totalChapterCount == 1) ||
|
||||
networkChapter.chapter == finalChapterNumber && finalChapterNumber.toIntOrNull() != 0
|
||||
) {
|
||||
chapterName.add("[END]")
|
||||
if (finalChapterNumber != null) {
|
||||
if ((isOneShot(networkChapter, finalChapterNumber) && totalChapterCount == 1) ||
|
||||
networkChapter.chapter == finalChapterNumber && finalChapterNumber.toIntOrNull() != 0
|
||||
) {
|
||||
chapterName.add("[END]")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -317,21 +313,13 @@ class ApiMangaParser(private val langs: List<String>) {
|
||||
chapter.date_upload = networkChapter.timestamp * 1000
|
||||
val scanlatorName = mutableSetOf<String>()
|
||||
|
||||
networkChapter.group_name?.let {
|
||||
scanlatorName.add(it)
|
||||
}
|
||||
networkChapter.group_name_2?.let {
|
||||
scanlatorName.add(it)
|
||||
}
|
||||
networkChapter.group_name_3?.let {
|
||||
scanlatorName.add(it)
|
||||
}
|
||||
networkChapter.groups.mapNotNull { groups[it] }.forEach { scanlatorName.add(it) }
|
||||
|
||||
chapter.scanlator = MdUtil.cleanString(MdUtil.getScanlatorString(scanlatorName))
|
||||
|
||||
// chapter.mangadex_chapter_id = MdUtil.getChapterId(chapter.url)
|
||||
|
||||
// chapter.language = chapLangs.firstOrNull { it.dexLang == networkChapter.lang_code }?.name
|
||||
// chapter.language = chapLangs.firstOrNull { it.dexLang == networkChapter.language }?.name
|
||||
|
||||
return chapter
|
||||
}
|
||||
|
@ -4,9 +4,13 @@ import com.elvishew.xlog.XLog
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.network.await
|
||||
import eu.kanade.tachiyomi.network.parseAs
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.model.toMangaInfo
|
||||
import eu.kanade.tachiyomi.source.model.toSManga
|
||||
import eu.kanade.tachiyomi.util.lang.runAsObservable
|
||||
import exh.md.handlers.serializers.ApiCovers
|
||||
import exh.md.utils.MdUtil
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
@ -20,9 +24,10 @@ import tachiyomi.source.model.MangaInfo
|
||||
class MangaHandler(val client: OkHttpClient, val headers: Headers, val langs: List<String>, val forceLatestCovers: Boolean = false) {
|
||||
|
||||
// TODO make use of this
|
||||
suspend fun fetchMangaAndChapterDetails(manga: SManga): Pair<SManga, List<SChapter>> {
|
||||
suspend fun fetchMangaAndChapterDetails(manga: MangaInfo, sourceId: Long): Pair<MangaInfo, List<SChapter>> {
|
||||
return withContext(Dispatchers.IO) {
|
||||
val response = client.newCall(apiRequest(manga)).await()
|
||||
val response = client.newCall(apiRequest(manga.toSManga())).await()
|
||||
val covers = getCovers(manga, forceLatestCovers)
|
||||
val parser = ApiMangaParser(langs)
|
||||
|
||||
val jsonData = withContext(Dispatchers.IO) { response.body!!.string() }
|
||||
@ -31,7 +36,7 @@ class MangaHandler(val client: OkHttpClient, val headers: Headers, val langs: Li
|
||||
throw Exception("Error from MangaDex Response code ${response.code} ")
|
||||
}
|
||||
|
||||
parser.parseToManga(manga, response, forceLatestCovers).await()
|
||||
parser.parseToManga(manga, response, covers, sourceId)
|
||||
val chapterList = parser.chapterListParse(jsonData)
|
||||
Pair(
|
||||
manga,
|
||||
@ -40,6 +45,15 @@ class MangaHandler(val client: OkHttpClient, val headers: Headers, val langs: Li
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getCovers(manga: MangaInfo, forceLatestCovers: Boolean): List<String> {
|
||||
return if (forceLatestCovers) {
|
||||
val covers = client.newCall(coverRequest(manga.toSManga())).await().parseAs<ApiCovers>()
|
||||
covers.data.map { it.url }
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getMangaIdFromChapterId(urlChapterId: String): Int {
|
||||
return withContext(Dispatchers.IO) {
|
||||
val request = GET(MdUtil.baseUrl + MdUtil.apiChapter + urlChapterId + MdUtil.apiChapterSuffix, headers, CacheControl.FORCE_NETWORK)
|
||||
@ -48,28 +62,26 @@ class MangaHandler(val client: OkHttpClient, val headers: Headers, val langs: Li
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun fetchMangaDetails(manga: SManga): SManga {
|
||||
return withContext(Dispatchers.IO) {
|
||||
val response = client.newCall(apiRequest(manga)).await()
|
||||
ApiMangaParser(langs).parseToManga(manga, response, forceLatestCovers).await()
|
||||
manga.apply {
|
||||
initialized = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getMangaDetails(manga: MangaInfo, sourceId: Long): MangaInfo {
|
||||
return withContext(Dispatchers.IO) {
|
||||
val response = client.newCall(apiRequest(manga.toSManga())).await()
|
||||
ApiMangaParser(langs).parseToManga(manga, response, forceLatestCovers, sourceId)
|
||||
val covers = getCovers(manga, forceLatestCovers)
|
||||
ApiMangaParser(langs).parseToManga(manga, response, covers, sourceId)
|
||||
}
|
||||
}
|
||||
|
||||
fun fetchMangaDetailsObservable(manga: SManga): Observable<SManga> {
|
||||
return client.newCall(apiRequest(manga))
|
||||
.asObservableSuccess()
|
||||
.flatMap { response ->
|
||||
runAsObservable({
|
||||
getCovers(manga.toMangaInfo(), forceLatestCovers)
|
||||
}).map {
|
||||
response to it
|
||||
}
|
||||
}
|
||||
.flatMap {
|
||||
ApiMangaParser(langs).parseToManga(manga, it, forceLatestCovers).andThen(
|
||||
ApiMangaParser(langs).parseToManga(manga, it.first, it.second).andThen(
|
||||
Observable.just(
|
||||
manga.apply {
|
||||
initialized = true
|
||||
@ -114,6 +126,10 @@ class MangaHandler(val client: OkHttpClient, val headers: Headers, val langs: Li
|
||||
}
|
||||
|
||||
private fun apiRequest(manga: SManga): Request {
|
||||
return GET(MdUtil.baseUrl + MdUtil.apiManga + MdUtil.getMangaId(manga.url), headers, CacheControl.FORCE_NETWORK)
|
||||
return GET(MdUtil.baseUrl + MdUtil.apiManga + MdUtil.getMangaId(manga.url) + MdUtil.includeChapters, headers, CacheControl.FORCE_NETWORK)
|
||||
}
|
||||
|
||||
private fun coverRequest(manga: SManga): Request {
|
||||
return GET(MdUtil.baseUrl + MdUtil.apiManga + MdUtil.getMangaId(manga.url) + MdUtil.apiCovers, headers, CacheControl.FORCE_NETWORK)
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package exh.md.handlers
|
||||
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
@ -17,13 +16,10 @@ import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Element
|
||||
import rx.Observable
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
// Unused, kept for reference todo
|
||||
class SearchHandler(val client: OkHttpClient, private val headers: Headers, val langs: List<String>, private val useLowQualityCovers: Boolean) {
|
||||
|
||||
private val preferences: PreferencesHelper by injectLazy()
|
||||
|
||||
fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
||||
return when {
|
||||
query.startsWith(PREFIX_ID_SEARCH) -> {
|
||||
@ -33,7 +29,7 @@ class SearchHandler(val client: OkHttpClient, private val headers: Headers, val
|
||||
.map { response ->
|
||||
val details = SManga.create()
|
||||
details.url = "/manga/$realQuery/"
|
||||
ApiMangaParser(langs).parseToManga(details, response, preferences.mangaDexForceLatestCovers().get()).await()
|
||||
ApiMangaParser(langs).parseToManga(details, response, emptyList()).await()
|
||||
MangasPage(listOf(details), false)
|
||||
}
|
||||
}
|
||||
|
@ -4,53 +4,39 @@ import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ApiMangaSerializer(
|
||||
val chapter: Map<String, ChapterSerializer>? = null,
|
||||
val manga: MangaSerializer,
|
||||
val data: DataSerializer,
|
||||
val status: String
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class MangaSerializer(
|
||||
val artist: String,
|
||||
val author: String,
|
||||
val cover_url: String,
|
||||
val description: String,
|
||||
val demographic: String,
|
||||
val genres: List<Int>,
|
||||
val covers: List<String>,
|
||||
val hentai: Int,
|
||||
val lang_flag: String,
|
||||
val lang_name: String,
|
||||
val last_chapter: String? = null,
|
||||
val links: LinksSerializer? = null,
|
||||
val rating: RatingSerializer? = null,
|
||||
val status: Int,
|
||||
val title: String
|
||||
data class DataSerializer(
|
||||
val manga: MangaSerializer,
|
||||
val chapters: List<ChapterSerializer>,
|
||||
val groups: Map<Long, String>,
|
||||
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class MangaSerializerTwo(
|
||||
data class MangaSerializer(
|
||||
val artist: List<String>,
|
||||
val author: List<String>,
|
||||
val mainCover: String,
|
||||
val description: String,
|
||||
val publication: Publication,
|
||||
val tags: List<Int>,
|
||||
// val covers: List<String>,
|
||||
val isHentai: Boolean,
|
||||
// val lang_flag: String,
|
||||
// val lang_name: String,
|
||||
val lastChapter: String? = null,
|
||||
val publication: PublicationSerializer? = null,
|
||||
val links: LinksSerializer? = null,
|
||||
val rating: RatingSerializerTwo? = null,
|
||||
val rating: RatingSerializer? = null,
|
||||
val title: String
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Publication(
|
||||
val language: String,
|
||||
data class PublicationSerializer(
|
||||
val language: String? = null,
|
||||
val status: Int,
|
||||
val demographic: Int
|
||||
val demographic: Int?
|
||||
|
||||
)
|
||||
|
||||
@Serializable
|
||||
@ -72,53 +58,13 @@ data class RatingSerializer(
|
||||
val users: String? = null
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class RatingSerializerTwo(
|
||||
val bayesian: Float? = null,
|
||||
val mean: Float? = null,
|
||||
val users: Int? = null
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ChapterSerializer(
|
||||
val volume: String? = null,
|
||||
val chapter: String? = null,
|
||||
val title: String? = null,
|
||||
val lang_code: String,
|
||||
val group_id: Int? = null,
|
||||
val group_name: String? = null,
|
||||
val group_id_2: Int? = null,
|
||||
val group_name_2: String? = null,
|
||||
val group_id_3: Int? = null,
|
||||
val group_name_3: String? = null,
|
||||
val timestamp: Long
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ChapterSerializerTwo(
|
||||
val id: Long,
|
||||
val volume: String? = null,
|
||||
val chapter: String? = null,
|
||||
val title: String? = null,
|
||||
val language: String,
|
||||
val groups: List<GroupSerializer> = emptyList(),
|
||||
val groups: List<Long>,
|
||||
val timestamp: Long
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class GroupSerializer(
|
||||
val id: Int,
|
||||
val name: String? = null
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class CoversResult(
|
||||
val covers: List<String> = emptyList(),
|
||||
val status: String
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ImageReportResult(
|
||||
val url: String,
|
||||
val success: Boolean,
|
||||
val bytes: Int?
|
||||
)
|
||||
|
@ -0,0 +1,14 @@
|
||||
package exh.md.handlers.serializers
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ApiCovers(
|
||||
val data: List<CoversResult>,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class CoversResult(
|
||||
val volume: String,
|
||||
val url: String
|
||||
)
|
@ -23,13 +23,14 @@ class MdUtil {
|
||||
const val cdnUrl = "https://mangadex.org" // "https://s0.mangadex.org"
|
||||
const val baseUrl = "https://mangadex.org"
|
||||
const val randMangaPage = "/manga/"
|
||||
const val apiManga = "/api/manga/"
|
||||
const val apiManga = "/api/v2/manga/"
|
||||
const val includeChapters = "?include=chapters"
|
||||
const val apiChapter = "/api/chapter/"
|
||||
const val apiChapterSuffix = "?mark_read=0"
|
||||
const val groupSearchUrl = "$baseUrl/groups/0/1/"
|
||||
const val followsAllApi = "/api/?type=manga_follows"
|
||||
const val followsMangaApi = "/api/?type=manga_follows&manga_id="
|
||||
const val coversApi = "/api/index.php?type=covers&id="
|
||||
const val apiCovers = "/covers"
|
||||
const val reportUrl = "https://api.mangadex.network/report"
|
||||
const val imageUrl = "$baseUrl/data"
|
||||
|
||||
|
@ -4,10 +4,8 @@
|
||||
|
||||
<gradient
|
||||
android:angle="180"
|
||||
android:startColor="#ff000000"
|
||||
android:centerColor="#ff000000"
|
||||
android:endColor="#00000000"
|
||||
android:startColor="#ff000000" />
|
||||
|
||||
android:endColor="#00000000" />
|
||||
<corners android:radius="0dp" />
|
||||
|
||||
</shape>
|
||||
</shape>
|
Loading…
x
Reference in New Issue
Block a user