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
					
				
							
								
								
									
										2
									
								
								.github/workflows/issue_moderator.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/issue_moderator.yml
									
									
									
									
										vendored
									
									
								
							@ -43,7 +43,7 @@ jobs:
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                "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,
 | 
			
		||||
                "labels": ["invalid"],
 | 
			
		||||
                "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
 | 
			
		||||
- Comikey https://github.com/tachiyomiorg/tachiyomi-extensions/pull/11971
 | 
			
		||||
- 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
 | 
			
		||||
- Hitomi.la https://github.com/tachiyomiorg/tachiyomi-extensions/pull/11613
 | 
			
		||||
- 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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user