Remove Cứu Truyện (#16654)
* Remove Cứu Truyện * Add to REMOVED_SOURCES.md * extra regex
This commit is contained in:
parent
6aa5ac0f17
commit
7ddf4ac5c7
|
@ -43,7 +43,7 @@ jobs:
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "both",
|
"type": "both",
|
||||||
"regex": ".*(hq\\s*dragon|manga\\s*host|supermangas|superhentais|union\\s*mangas|yes\\s*mangas|manhuascan|manhwahot|leitor\\.?net|manga\\s*livre|tsuki\\s*mangas|manga\\s*yabu|mangas\\.in|mangas\\.pw|hentaikai|toptoon\\+?|colamanhua|mangadig|hitomi\\.la|copymanga|neox|1manga\\.co|mangafox\\.fun|mangahere\\.onl|mangakakalot\\.fun|manganel(?!o)|mangaonline\\.fun|mangatoday|manga\\.town|onemanga\\.info|koushoku|ksk\\.moe|comikey|leercapitulo).*",
|
"regex": ".*(hq\\s*dragon|manga\\s*host|supermangas|superhentais|union\\s*mangas|yes\\s*mangas|manhuascan|manhwahot|leitor\\.?net|manga\\s*livre|tsuki\\s*mangas|manga\\s*yabu|mangas\\.in|mangas\\.pw|hentaikai|toptoon\\+?|colamanhua|mangadig|hitomi\\.la|copymanga|neox|1manga\\.co|mangafox\\.fun|mangahere\\.onl|mangakakalot\\.fun|manganel(?!o)|mangaonline\\.fun|mangatoday|manga\\.town|onemanga\\.info|koushoku|ksk\\.moe|comikey|leercapitulo|c[uứ]u\\s*truy[eệ]n).*",
|
||||||
"ignoreCase": true,
|
"ignoreCase": true,
|
||||||
"labels": ["invalid"],
|
"labels": ["invalid"],
|
||||||
"message": "{match} will not be added back as it is too difficult to maintain. Read #3475 for more information."
|
"message": "{match} will not be added back as it is too difficult to maintain. Read #3475 for more information."
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
- ColaManhua (COLA漫画) https://github.com/tachiyomiorg/tachiyomi-extensions/pull/11445
|
- ColaManhua (COLA漫画) https://github.com/tachiyomiorg/tachiyomi-extensions/pull/11445
|
||||||
- Comikey https://github.com/tachiyomiorg/tachiyomi-extensions/pull/11971
|
- Comikey https://github.com/tachiyomiorg/tachiyomi-extensions/pull/11971
|
||||||
- CopyManga (拷贝漫画) https://github.com/tachiyomiorg/tachiyomi-extensions/pull/12376
|
- CopyManga (拷贝漫画) https://github.com/tachiyomiorg/tachiyomi-extensions/pull/12376
|
||||||
|
- Cứu Truyện https://github.com/tachiyomiorg/tachiyomi-extensions/pull/16654
|
||||||
- Hentai Kai https://github.com/tachiyomiorg/tachiyomi-extensions/issues/9999
|
- Hentai Kai https://github.com/tachiyomiorg/tachiyomi-extensions/issues/9999
|
||||||
- Hitomi.la https://github.com/tachiyomiorg/tachiyomi-extensions/pull/11613
|
- Hitomi.la https://github.com/tachiyomiorg/tachiyomi-extensions/pull/11613
|
||||||
- HQ Dragon https://github.com/tachiyomiorg/tachiyomi-extensions/pull/7065
|
- HQ Dragon https://github.com/tachiyomiorg/tachiyomi-extensions/pull/7065
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
package="eu.kanade.tachiyomi.extension">
|
|
||||||
|
|
||||||
<application>
|
|
||||||
<activity
|
|
||||||
android:name="eu.kanade.tachiyomi.extension.vi.cuutruyen.CuuTruyenUrlActivity"
|
|
||||||
android:excludeFromRecents="true"
|
|
||||||
android:exported="true"
|
|
||||||
android:theme="@android:style/Theme.NoDisplay">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.VIEW" />
|
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
|
||||||
|
|
||||||
<data
|
|
||||||
android:host="cuutruyen.net"
|
|
||||||
android:pathPattern="/mangas/..*"
|
|
||||||
android:scheme="https" />
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
</application>
|
|
||||||
</manifest>
|
|
|
@ -1,13 +0,0 @@
|
||||||
apply plugin: 'com.android.application'
|
|
||||||
apply plugin: 'kotlin-android'
|
|
||||||
apply plugin: 'kotlinx-serialization'
|
|
||||||
|
|
||||||
ext {
|
|
||||||
extName = 'Cứu Truyện'
|
|
||||||
pkgNameSuffix = 'vi.cuutruyen'
|
|
||||||
extClass = '.CuuTruyen'
|
|
||||||
extVersionCode = 5
|
|
||||||
isNsfw = true
|
|
||||||
}
|
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
|
Binary file not shown.
Before Width: | Height: | Size: 2.5 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 3.6 KiB |
Binary file not shown.
Before Width: | Height: | Size: 6.9 KiB |
Binary file not shown.
Before Width: | Height: | Size: 11 KiB |
Binary file not shown.
Before Width: | Height: | Size: 63 KiB |
|
@ -1,195 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.vi.cuutruyen
|
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import android.content.SharedPreferences
|
|
||||||
import androidx.preference.ListPreference
|
|
||||||
import androidx.preference.PreferenceScreen
|
|
||||||
import eu.kanade.tachiyomi.extension.vi.cuutruyen.dto.ChapterDto
|
|
||||||
import eu.kanade.tachiyomi.extension.vi.cuutruyen.dto.MangaDto
|
|
||||||
import eu.kanade.tachiyomi.extension.vi.cuutruyen.dto.ResponseDto
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
|
||||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
|
||||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
|
||||||
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 okhttp3.CacheControl
|
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
|
||||||
import okhttp3.Request
|
|
||||||
import okhttp3.Response
|
|
||||||
import rx.Observable
|
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
|
|
||||||
class CuuTruyen : HttpSource(), ConfigurableSource {
|
|
||||||
|
|
||||||
override val name = "Cứu Truyện"
|
|
||||||
|
|
||||||
override val lang = "vi"
|
|
||||||
|
|
||||||
override val baseUrl = "https://cuutruyen.net"
|
|
||||||
private val apiUrl = "https://kakarot.cuutruyen.net/api/v2"
|
|
||||||
|
|
||||||
override val supportsLatest = true
|
|
||||||
|
|
||||||
private val preferences: SharedPreferences by lazy {
|
|
||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val json: Json by injectLazy()
|
|
||||||
|
|
||||||
override fun headersBuilder() = super.headersBuilder().add("Referer", "$baseUrl/")
|
|
||||||
|
|
||||||
override val client = network.client.newBuilder()
|
|
||||||
.rateLimit(3)
|
|
||||||
.addInterceptor(CuuTruyenImageInterceptor())
|
|
||||||
.build()
|
|
||||||
|
|
||||||
override fun popularMangaRequest(page: Int): Request {
|
|
||||||
val url = apiUrl.toHttpUrl().newBuilder().apply {
|
|
||||||
addPathSegments("mangas/top")
|
|
||||||
addQueryParameter("duration", "all")
|
|
||||||
addQueryParameter("page", page.toString())
|
|
||||||
addQueryParameter("per_page", "24")
|
|
||||||
}.build().toString()
|
|
||||||
return GET(url, headers = headers, cache = CacheControl.FORCE_NETWORK)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun popularMangaParse(response: Response): MangasPage {
|
|
||||||
if (response.code == 500) {
|
|
||||||
return MangasPage(emptyList(), false)
|
|
||||||
}
|
|
||||||
|
|
||||||
val responseDto = response.parseAs<ResponseDto<List<MangaDto>>>()
|
|
||||||
val hasMoreResults = responseDto.metadata!!.currentPage < responseDto.metadata.totalPages
|
|
||||||
|
|
||||||
val coverKey = preferences.coverQuality
|
|
||||||
return MangasPage(
|
|
||||||
responseDto.data.map { it.toSManga(coverKey) },
|
|
||||||
hasMoreResults,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int): Request {
|
|
||||||
val url = apiUrl.toHttpUrl().newBuilder().apply {
|
|
||||||
addPathSegments("mangas/recently_updated")
|
|
||||||
addQueryParameter("page", page.toString())
|
|
||||||
addQueryParameter("per_page", "24")
|
|
||||||
}.build().toString()
|
|
||||||
return GET(url, headers = headers, cache = CacheControl.FORCE_NETWORK)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun latestUpdatesParse(response: Response): MangasPage = popularMangaParse(response)
|
|
||||||
|
|
||||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
|
||||||
return when {
|
|
||||||
query.startsWith(PREFIX_ID_SEARCH) -> {
|
|
||||||
val id = query.removePrefix(PREFIX_ID_SEARCH).trim()
|
|
||||||
if (id.toIntOrNull() == null) {
|
|
||||||
throw Exception("ID tìm kiếm không hợp lệ (phải là một số).")
|
|
||||||
}
|
|
||||||
val url = "/mangas/$id"
|
|
||||||
fetchMangaDetails(
|
|
||||||
SManga.create().apply {
|
|
||||||
this.url = url
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.map {
|
|
||||||
it.url = url
|
|
||||||
MangasPage(listOf(it), false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> super.fetchSearchManga(page, query, filters)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
|
||||||
val url = apiUrl.toHttpUrl().newBuilder().apply {
|
|
||||||
addPathSegments("mangas/search")
|
|
||||||
addQueryParameter("q", query)
|
|
||||||
addQueryParameter("page", page.toString())
|
|
||||||
addQueryParameter("per_page", "24")
|
|
||||||
}.build().toString()
|
|
||||||
return GET(url, headers = headers, cache = CacheControl.FORCE_NETWORK)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun searchMangaParse(response: Response) = popularMangaParse(response)
|
|
||||||
|
|
||||||
override fun fetchMangaDetails(manga: SManga): Observable<SManga> =
|
|
||||||
client.newCall(GET("$apiUrl${manga.url}", headers = headers, cache = CacheControl.FORCE_NETWORK))
|
|
||||||
.asObservableSuccess()
|
|
||||||
.map { mangaDetailsParse(it) }
|
|
||||||
|
|
||||||
override fun mangaDetailsRequest(manga: SManga): Request = GET("$baseUrl${manga.url}")
|
|
||||||
|
|
||||||
override fun mangaDetailsParse(response: Response): SManga {
|
|
||||||
val responseDto = response.parseAs<ResponseDto<MangaDto>>()
|
|
||||||
return responseDto.data.toSManga(preferences.coverQuality)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterListRequest(manga: SManga): Request =
|
|
||||||
GET("$apiUrl${manga.url}/chapters", headers = headers, cache = CacheControl.FORCE_NETWORK)
|
|
||||||
|
|
||||||
override fun chapterListParse(response: Response): List<SChapter> {
|
|
||||||
val segments = response.request.url.pathSegments
|
|
||||||
val lastIndex = segments.lastIndex
|
|
||||||
val mangaUrl = "/${segments[lastIndex - 2]}/${segments[lastIndex - 1]}"
|
|
||||||
return response.parseAs<ResponseDto<List<ChapterDto>>>().data.map { it.toSChapter(mangaUrl) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun pageListRequest(chapter: SChapter): Request {
|
|
||||||
val url = apiUrl.toHttpUrl().newBuilder().apply {
|
|
||||||
val chapterId = chapter.url.split("/").last()
|
|
||||||
addPathSegment("chapters")
|
|
||||||
addPathSegment(chapterId)
|
|
||||||
}.build().toString()
|
|
||||||
return GET(url, headers = headers, cache = CacheControl.FORCE_NETWORK)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun pageListParse(response: Response): List<Page> {
|
|
||||||
val chapterDto = response.parseAs<ResponseDto<ChapterDto>>()
|
|
||||||
return chapterDto.data.pages!!.map { it.toPage() }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException("Not used")
|
|
||||||
|
|
||||||
private inline fun <reified T> Response.parseAs(): T = use {
|
|
||||||
json.decodeFromString(body.string())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
|
||||||
val coverQualityPref = ListPreference(screen.context).apply {
|
|
||||||
key = "coverQuality"
|
|
||||||
title = "Chất lượng ảnh bìa"
|
|
||||||
entries = arrayOf("Chất lượng cao", "Di động")
|
|
||||||
entryValues = arrayOf("cover_url", "cover_mobile_url")
|
|
||||||
setDefaultValue("cover_url")
|
|
||||||
|
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
|
||||||
val selected = newValue as String
|
|
||||||
val index = findIndexOfValue(selected)
|
|
||||||
val entry = entryValues[index] as String
|
|
||||||
|
|
||||||
preferences.edit()
|
|
||||||
.putString("coverQuality", entry)
|
|
||||||
.commit()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
screen.addPreference(coverQualityPref)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val SharedPreferences.coverQuality
|
|
||||||
get() = getString("coverQuality", "")
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val PREFIX_ID_SEARCH = "id:"
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because one or more lines are too long
|
@ -1,37 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.vi.cuutruyen
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.ActivityNotFoundException
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.util.Log
|
|
||||||
import kotlin.system.exitProcess
|
|
||||||
|
|
||||||
/*
|
|
||||||
Springboard that accepts https://cuutruyen.net/mangas/xxxx intents
|
|
||||||
*/
|
|
||||||
class CuuTruyenUrlActivity : Activity() {
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
val pathSegments = intent?.data?.pathSegments
|
|
||||||
if (pathSegments != null && pathSegments.size > 1) {
|
|
||||||
val id = pathSegments[1]
|
|
||||||
try {
|
|
||||||
startActivity(
|
|
||||||
Intent().apply {
|
|
||||||
action = "eu.kanade.tachiyomi.SEARCH"
|
|
||||||
putExtra("query", "${CuuTruyen.PREFIX_ID_SEARCH}$id")
|
|
||||||
putExtra("filter", packageName)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
} catch (e: ActivityNotFoundException) {
|
|
||||||
Log.e("CuuTruyenUrlActivity", e.toString())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.e("CuuTruyenUrlActivity", "Could not parse URI from intent $intent")
|
|
||||||
}
|
|
||||||
|
|
||||||
finish()
|
|
||||||
exitProcess(0)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.vi.cuutruyen.dto
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.extension.vi.cuutruyen.CuuTruyenImageInterceptor
|
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
|
||||||
import eu.kanade.tachiyomi.source.model.SChapter
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.Locale
|
|
||||||
import java.util.TimeZone
|
|
||||||
|
|
||||||
val DATE_FORMATTER = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US).apply {
|
|
||||||
timeZone = TimeZone.getTimeZone("Asia/Ho_Chi_Minh")
|
|
||||||
}
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class ChapterDto(
|
|
||||||
val id: Int,
|
|
||||||
val order: Int,
|
|
||||||
val number: String,
|
|
||||||
@SerialName("updated_at") val updatedAt: String,
|
|
||||||
val name: String? = null,
|
|
||||||
val pages: List<PageDto>? = null,
|
|
||||||
) {
|
|
||||||
fun toSChapter(mangaUrl: String) = SChapter.create().apply {
|
|
||||||
val dto = this@ChapterDto
|
|
||||||
url = "$mangaUrl/chapters/$id"
|
|
||||||
name = "Chapter ${dto.number}"
|
|
||||||
if (dto.name != null && dto.name.isNotBlank()) {
|
|
||||||
name += ": ${dto.name}"
|
|
||||||
}
|
|
||||||
|
|
||||||
date_upload = runCatching {
|
|
||||||
DATE_FORMATTER.parse(dto.updatedAt.replace("+07:00", "Z"))?.time
|
|
||||||
}.getOrNull() ?: 0L
|
|
||||||
|
|
||||||
chapter_number = dto.number.toFloatOrNull() ?: -1f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class PageDto(
|
|
||||||
val id: Int,
|
|
||||||
val order: Int,
|
|
||||||
val width: Int?,
|
|
||||||
val height: Int?,
|
|
||||||
val status: String,
|
|
||||||
@SerialName("image_url") val imageUrl: String,
|
|
||||||
@SerialName("image_url_size") val imageUrlSize: Int,
|
|
||||||
@SerialName("drm_data") val drmData: String,
|
|
||||||
) {
|
|
||||||
fun toPage(): Page {
|
|
||||||
val dto = this@PageDto
|
|
||||||
val url = imageUrl.toHttpUrl().newBuilder()
|
|
||||||
.fragment("${CuuTruyenImageInterceptor.KEY}=$drmData")
|
|
||||||
.build()
|
|
||||||
.toString()
|
|
||||||
return Page(dto.order, imageUrl = url)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.vi.cuutruyen.dto
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class AuthorDto(
|
|
||||||
val name: String,
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class TeamDto(
|
|
||||||
val id: Int,
|
|
||||||
val name: String,
|
|
||||||
val description: String,
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class MangaDto(
|
|
||||||
val id: Int,
|
|
||||||
val name: String,
|
|
||||||
@SerialName("cover_url") val coverUrl: String? = null,
|
|
||||||
@SerialName("cover_mobile_url") val coverMobileUrl: String? = null,
|
|
||||||
|
|
||||||
val author: AuthorDto? = null,
|
|
||||||
@SerialName("author_name") val authorName: String? = null,
|
|
||||||
|
|
||||||
val description: String? = null,
|
|
||||||
val team: TeamDto? = null,
|
|
||||||
) {
|
|
||||||
fun toSManga(coverQuality: String? = null): SManga = SManga.create().apply {
|
|
||||||
val dto = this@MangaDto
|
|
||||||
url = "/mangas/${dto.id}"
|
|
||||||
title = dto.name
|
|
||||||
author = dto.author?.name ?: dto.authorName
|
|
||||||
|
|
||||||
description = ""
|
|
||||||
if (dto.team != null) {
|
|
||||||
description += "Nhóm dịch: ${dto.team.name}\n\n"
|
|
||||||
}
|
|
||||||
description += dto.description ?: ""
|
|
||||||
|
|
||||||
thumbnail_url = dto.coverUrl
|
|
||||||
if (coverQuality == "cover_url") {
|
|
||||||
thumbnail_url = dto.coverUrl
|
|
||||||
} else if (coverQuality == "cover_mobile_url") {
|
|
||||||
thumbnail_url = dto.coverMobileUrl
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.vi.cuutruyen.dto
|
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class ResponseDto<T>(
|
|
||||||
val data: T,
|
|
||||||
@SerialName("_metadata") val metadata: PaginationMetadataDto? = null,
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class PaginationMetadataDto(
|
|
||||||
@SerialName("total_count") val totalCount: Int,
|
|
||||||
@SerialName("total_pages") val totalPages: Int,
|
|
||||||
@SerialName("current_page") val currentPage: Int,
|
|
||||||
@SerialName("per_page") val perPage: Int,
|
|
||||||
)
|
|
Loading…
Reference in New Issue