diff --git a/src/all/comickfun/AndroidManifest.xml b/src/all/comickfun/AndroidManifest.xml index 305c286df..8d9f69c07 100644 --- a/src/all/comickfun/AndroidManifest.xml +++ b/src/all/comickfun/AndroidManifest.xml @@ -3,7 +3,7 @@ @@ -14,6 +14,7 @@ + diff --git a/src/all/comickfun/build.gradle b/src/all/comickfun/build.gradle index 4aa96d636..a84d54e9f 100644 --- a/src/all/comickfun/build.gradle +++ b/src/all/comickfun/build.gradle @@ -1,7 +1,7 @@ ext { extName = 'Comick' - extClass = '.ComickFunFactory' - extVersionCode = 41 + extClass = '.ComickFactory' + extVersionCode = 42 isNsfw = true } diff --git a/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFun.kt b/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/Comick.kt similarity index 86% rename from src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFun.kt rename to src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/Comick.kt index d2f065e86..b4099d431 100644 --- a/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFun.kt +++ b/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/Comick.kt @@ -26,19 +26,16 @@ import okhttp3.Response import rx.Observable import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get -import java.text.SimpleDateFormat -import java.util.Locale -import java.util.TimeZone import kotlin.math.min -abstract class ComickFun( +abstract class Comick( override val lang: String, - private val comickFunLang: String, + private val comickLang: String, ) : ConfigurableSource, HttpSource() { override val name = "Comick" - override val baseUrl = "https://comick.cc" + override val baseUrl = "https://comick.io" private val apiUrl = "https://api.comick.fun" @@ -62,8 +59,9 @@ abstract class ComickFun( ) } - private val preferences: SharedPreferences by lazy { + private val preferences by lazy { Injekt.get().getSharedPreferences("source_$id", 0x0000) + .newLineIgnoredGroups() } override fun setupPreferenceScreen(screen: PreferenceScreen) { @@ -151,23 +149,18 @@ abstract class ComickFun( private val SharedPreferences.scorePosition: String get() = getString(SCORE_POSITION_PREF, SCORE_POSITION_DEFAULT) ?: SCORE_POSITION_DEFAULT - init { - preferences.newLineIgnoredGroups() - } - override fun headersBuilder() = Headers.Builder().apply { add("Referer", "$baseUrl/") add("User-Agent", "Tachiyomi ${System.getProperty("http.agent")}") } override val client = network.client.newBuilder() - .addInterceptor(::thumbnailIntercept) .rateLimit(3, 1) .build() /** Popular Manga **/ override fun popularMangaRequest(page: Int): Request { - val url = "$apiUrl/v1.0/search?sort=follow&limit=$limit&page=$page&tachiyomi=true" + val url = "$apiUrl/v1.0/search?sort=follow&limit=$LIMIT&page=$page&tachiyomi=true" return GET(url, headers) } @@ -175,13 +168,13 @@ abstract class ComickFun( val result = response.parseAs>() return MangasPage( result.map(SearchManga::toSManga), - hasNextPage = result.size >= limit, + hasNextPage = result.size >= LIMIT, ) } /** Latest Manga **/ override fun latestUpdatesRequest(page: Int): Request { - val url = "$apiUrl/v1.0/search?sort=uploaded&limit=$limit&page=$page&tachiyomi=true" + val url = "$apiUrl/v1.0/search?sort=uploaded&limit=$LIMIT&page=$page&tachiyomi=true" return GET(url, headers) } @@ -233,8 +226,8 @@ abstract class ComickFun( } private fun paginatedSearchPage(page: Int): MangasPage { - val end = min(page * limit, searchResponse.size) - val entries = searchResponse.subList((page - 1) * limit, end) + val end = min(page * LIMIT, searchResponse.size) + val entries = searchResponse.subList((page - 1) * LIMIT, end) .map(SearchManga::toSManga) return MangasPage(entries, end < searchResponse.size) } @@ -317,7 +310,7 @@ abstract class ComickFun( } } addQueryParameter("tachiyomi", "true") - addQueryParameter("limit", "$limit") + addQueryParameter("limit", "$LIMIT") addQueryParameter("page", "$page") }.build() @@ -367,7 +360,7 @@ abstract class ComickFun( val coversUrl = "$apiUrl/comic/${mangaData.comic.slug ?: mangaData.comic.hid}/covers?tachiyomi=true" val covers = client.newCall(GET(coversUrl)).execute() - .parseAs().md_covers.reversed() + .parseAs().mdCovers.reversed() return mangaData.toSManga( includeMuTags = preferences.includeMuTags, covers = if (covers.any { it.vol == "1" }) covers.filter { it.vol == "1" } else covers, @@ -387,19 +380,15 @@ abstract class ComickFun( throw Exception("Migrate from Comick to Comick") } - return paginatedChapterListRequest(manga.url.removeSuffix("#"), 1) - } + val mangaUrl = manga.url.removeSuffix("#") + val url = "$apiUrl$mangaUrl".toHttpUrl().newBuilder().apply { + addPathSegment("chapters") + if (comickLang != "all") addQueryParameter("lang", comickLang) + addQueryParameter("tachiyomi", "true") + addQueryParameter("limit", "$CHAPTERS_LIMIT") + }.build() - private fun paginatedChapterListRequest(mangaUrl: String, page: Int): Request { - return GET( - "$apiUrl$mangaUrl".toHttpUrl().newBuilder().apply { - addPathSegment("chapters") - if (comickFunLang != "all") addQueryParameter("lang", comickFunLang) - addQueryParameter("tachiyomi", "true") - addQueryParameter("page", "$page") - }.build(), - headers, - ) + return GET(url, headers) } override fun chapterListParse(response: Response): List { @@ -409,20 +398,6 @@ abstract class ComickFun( .substringBefore("/chapters") .substringAfter(apiUrl) - var resultSize = chapterListResponse.chapters.size - var page = 2 - - while (chapterListResponse.total > resultSize) { - val newRequest = paginatedChapterListRequest(mangaUrl, page) - val newResponse = client.newCall(newRequest).execute() - val newChapterListResponse = newResponse.parseAs() - - chapterListResponse.chapters += newChapterListResponse.chapters - - resultSize += newChapterListResponse.chapters.size - page += 1 - } - return chapterListResponse.chapters .filter { it.groups.map { g -> g.lowercase() }.intersect(preferences.ignoredGroups).isEmpty() @@ -457,8 +432,8 @@ abstract class ComickFun( override fun getFilterList() = getFilters() - private fun SharedPreferences.newLineIgnoredGroups() { - if (getBoolean(MIGRATED_IGNORED_GROUPS, false)) return + private fun SharedPreferences.newLineIgnoredGroups(): SharedPreferences { + if (getBoolean(MIGRATED_IGNORED_GROUPS, false)) return this val ignoredGroups = getString(IGNORED_GROUPS_PREF, "").orEmpty() edit() @@ -472,6 +447,8 @@ abstract class ComickFun( ) .putBoolean(MIGRATED_IGNORED_GROUPS, true) .apply() + + return this } companion object { @@ -484,14 +461,7 @@ abstract class ComickFun( private const val FIRST_COVER_DEFAULT = true private const val SCORE_POSITION_PREF = "ScorePosition" private const val SCORE_POSITION_DEFAULT = "top" - private const val limit = 20 - val dateFormat by lazy { - SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH).apply { - timeZone = TimeZone.getTimeZone("UTC") - } - } - val markdownLinksRegex = "\\[([^]]+)]\\(([^)]+)\\)".toRegex() - val markdownItalicBoldRegex = "\\*+\\s*([^*]*)\\s*\\*+".toRegex() - val markdownItalicRegex = "_+\\s*([^_]*)\\s*_+".toRegex() + private const val LIMIT = 20 + private const val CHAPTERS_LIMIT = 99999 } } diff --git a/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFunFactory.kt b/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFactory.kt similarity index 95% rename from src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFunFactory.kt rename to src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFactory.kt index ef9cf7c3f..79aae75d6 100644 --- a/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFunFactory.kt +++ b/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFactory.kt @@ -10,7 +10,7 @@ val legacyLanguageMappings = mapOf( "zh" to "zh-Hans", // Simplified Chinese ).withDefault { it } // country code matches language code -class ComickFunFactory : SourceFactory { +class ComickFactory : SourceFactory { private val idMap = listOf( "all" to 982606170401027267, "en" to 2971557565147974499, @@ -55,7 +55,7 @@ class ComickFunFactory : SourceFactory { "da" to 7137437402245830147, ).toMap() override fun createSources(): List = idMap.keys.map { - object : ComickFun(legacyLanguageMappings.getValue(it), it) { + object : Comick(legacyLanguageMappings.getValue(it), it) { override val id: Long = idMap[it]!! } } diff --git a/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFunUrlActivity.kt b/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickUrlActivity.kt similarity index 89% rename from src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFunUrlActivity.kt rename to src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickUrlActivity.kt index 4bd07c9fc..fc7d912c0 100644 --- a/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFunUrlActivity.kt +++ b/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickUrlActivity.kt @@ -7,7 +7,7 @@ import android.os.Bundle import android.util.Log import kotlin.system.exitProcess -class ComickFunUrlActivity : Activity() { +class ComickUrlActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val pathSegments = intent?.data?.pathSegments @@ -15,7 +15,7 @@ class ComickFunUrlActivity : Activity() { val slug = pathSegments[1] val mainIntent = Intent().apply { action = "eu.kanade.tachiyomi.SEARCH" - putExtra("query", "${ComickFun.SLUG_SEARCH_PREFIX}$slug") + putExtra("query", "${Comick.SLUG_SEARCH_PREFIX}$slug") putExtra("filter", packageName) } diff --git a/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFunDto.kt b/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/Dto.kt similarity index 86% rename from src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFunDto.kt rename to src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/Dto.kt index 405a6e37e..7f229f663 100644 --- a/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFunDto.kt +++ b/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/Dto.kt @@ -8,9 +8,9 @@ import java.math.BigDecimal import java.math.RoundingMode @Serializable -data class SearchManga( - val hid: String, - val title: String, +class SearchManga( + private val hid: String, + private val title: String, @SerialName("md_covers") val mdCovers: List = emptyList(), @SerialName("cover_url") val cover: String? = null, ) { @@ -23,12 +23,12 @@ data class SearchManga( } @Serializable -data class Manga( +class Manga( val comic: Comic, - val artists: List = emptyList(), - val authors: List = emptyList(), - val genres: List = emptyList(), - val demographic: String? = null, + private val artists: List = emptyList(), + private val authors: List = emptyList(), + private val genres: List = emptyList(), + private val demographic: String? = null, ) { fun toSManga( includeMuTags: Boolean = false, @@ -90,10 +90,10 @@ data class Manga( } @Serializable -data class Comic( +class Comic( val hid: String, val title: String, - val country: String? = null, + private val country: String? = null, val slug: String? = null, @SerialName("md_titles") val altTitles: List = emptyList(), val desc: String? = null, @@ -125,55 +125,54 @@ data class Comic( } @Serializable -data class MdGenres( +class MdGenres( @SerialName("md_genres") val name: Name? = null, ) @Serializable -data class MuComicCategories( +class MuComicCategories( @SerialName("mu_comic_categories") val categories: List<MuCategories?> = emptyList(), ) @Serializable -data class MuCategories( +class MuCategories( @SerialName("mu_categories") val category: Title? = null, ) @Serializable -data class Covers( - val md_covers: List<MDcovers> = emptyList(), +class Covers( + @SerialName("md_covers") val mdCovers: List<MDcovers> = emptyList(), ) @Serializable -data class MDcovers( +class MDcovers( val b2key: String?, val vol: String? = null, ) @Serializable -data class Title( +class Title( val title: String?, ) @Serializable -data class Name( +class Name( val name: String, ) @Serializable -data class ChapterList( - val chapters: MutableList<Chapter>, - val total: Int, +class ChapterList( + val chapters: List<Chapter>, ) @Serializable -data class Chapter( - val hid: String, - val lang: String = "", - val title: String = "", +class Chapter( + private val hid: String, + private val lang: String = "", + private val title: String = "", @SerialName("created_at") val createdAt: String = "", - val chap: String = "", - val vol: String = "", + private val chap: String = "", + private val vol: String = "", @SerialName("group_name") val groups: List<String> = emptyList(), ) { fun toSChapter(mangaUrl: String) = SChapter.create().apply { @@ -185,16 +184,16 @@ data class Chapter( } @Serializable -data class PageList( +class PageList( val chapter: ChapterPageData, ) @Serializable -data class ChapterPageData( +class ChapterPageData( val images: List<Page>, ) @Serializable -data class Page( +class Page( val url: String? = null, ) diff --git a/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFunFilters.kt b/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/Filters.kt similarity index 100% rename from src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFunFilters.kt rename to src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/Filters.kt diff --git a/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFunHelper.kt b/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/Helpers.kt similarity index 63% rename from src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFunHelper.kt rename to src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/Helpers.kt index 1d9f365a4..50bc71049 100644 --- a/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFunHelper.kt +++ b/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/Helpers.kt @@ -1,13 +1,19 @@ package eu.kanade.tachiyomi.extension.all.comickfun -import eu.kanade.tachiyomi.extension.all.comickfun.ComickFun.Companion.dateFormat -import eu.kanade.tachiyomi.extension.all.comickfun.ComickFun.Companion.markdownItalicBoldRegex -import eu.kanade.tachiyomi.extension.all.comickfun.ComickFun.Companion.markdownItalicRegex -import eu.kanade.tachiyomi.extension.all.comickfun.ComickFun.Companion.markdownLinksRegex import eu.kanade.tachiyomi.source.model.SManga -import okhttp3.Interceptor -import okhttp3.Response import org.jsoup.parser.Parser +import java.text.SimpleDateFormat +import java.util.Locale +import java.util.TimeZone + +private val dateFormat by lazy { + SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH).apply { + timeZone = TimeZone.getTimeZone("UTC") + } +} +private val markdownLinksRegex = "\\[([^]]+)]\\(([^)]+)\\)".toRegex() +private val markdownItalicBoldRegex = "\\*+\\s*([^*]*)\\s*\\*+".toRegex() +private val markdownItalicRegex = "_+\\s*([^_]*)\\s*_+".toRegex() internal fun String.beautifyDescription(): String { return Parser.unescapeEntities(this, false) @@ -42,25 +48,6 @@ internal fun parseCover(thumbnailUrl: String?, mdCovers: List<MDcovers>): String return thumbnailUrl?.replaceAfterLast("/", "$b2key#$vol") } -internal fun thumbnailIntercept(chain: Interceptor.Chain): Response { - val request = chain.request() - val frag = request.url.fragment - if (frag.isNullOrEmpty()) return chain.proceed(request) - val response = chain.proceed(request) - if (!response.isSuccessful && response.code == 404) { - response.close() - val url = request.url.toString() - .replaceAfterLast("/", frag) - - return chain.proceed( - request.newBuilder() - .url(url) - .build(), - ) - } - return response -} - internal fun beautifyChapterName(vol: String, chap: String, title: String): String { return buildString { if (vol.isNotEmpty()) {