diff --git a/app/build.gradle b/app/build.gradle index b3427a75..58d968b5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -14,8 +14,8 @@ android { applicationId "com.lagradost.quicknovel" minSdkVersion 22 targetSdkVersion 33 - versionCode 52 - versionName "3.1.2" + versionCode 53 + versionName "3.1.3" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/java/com/lagradost/quicknovel/ReadActivity2.kt b/app/src/main/java/com/lagradost/quicknovel/ReadActivity2.kt index 74ed4754..67dd4708 100644 --- a/app/src/main/java/com/lagradost/quicknovel/ReadActivity2.kt +++ b/app/src/main/java/com/lagradost/quicknovel/ReadActivity2.kt @@ -524,11 +524,11 @@ class ReadActivity2 : AppCompatActivity(), ColorPickerDialogListener { val topScroll = top.top - getTopY() lockTop = currentScroll + topScroll val bottomScroll = - bottom.bottom - getBottomY() + if (binding.readOverlay.isVisible) binding.readOverlay.height else 0 + bottom.bottom - getBottomY() lockBottom = currentScroll + bottomScroll // binding.tmpTtsStart.fixLine(top.top) - // binding.tmpTtsEnd.fixLine(bottom.bottom) + //binding.tmpTtsEnd.fixLine(bottom.bottom) // we have reached the end, scroll to the top if (bottomScroll > 0) { @@ -953,12 +953,12 @@ class ReadActivity2 : AppCompatActivity(), ColorPickerDialogListener { if (event.historySize <= 1) return@setOnTouchListener false val start = event.getHistoricalY(0, event.historySize - 1) val end = event.getY(0) - val dy = (end - start).div(Resources.getSystem().displayMetrics.density).coerceIn(-1.0f,1.0f) + val dy = (end - start).div(Resources.getSystem().displayMetrics.density).coerceIn(-2.0f,2.0f) // if cant scroll in the direction then translate Y with the dy val translated = !canScrollVertically(-1) || !canScrollVertically(1) if (translated) { // * (maxScrollOver - currentOverScroll.absoluteValue)) - currentOverScroll += dy * 0.3f + currentOverScroll += dy * 0.4f } // if we can scroll down then we cant translate down @@ -1026,7 +1026,7 @@ class ReadActivity2 : AppCompatActivity(), ColorPickerDialogListener { currentScroll += dy val delta = rdy - dy if (delta != 0 && canScrollVertically(delta)) { - updateFromCode = true + //updateFromCode = true scrollBy(0, delta) } } else { diff --git a/app/src/main/java/com/lagradost/quicknovel/providers/AllNovelProvider.kt b/app/src/main/java/com/lagradost/quicknovel/providers/AllNovelProvider.kt index cd0a6ab2..98a96bf8 100644 --- a/app/src/main/java/com/lagradost/quicknovel/providers/AllNovelProvider.kt +++ b/app/src/main/java/com/lagradost/quicknovel/providers/AllNovelProvider.kt @@ -4,7 +4,7 @@ import com.lagradost.quicknovel.* import com.lagradost.quicknovel.MainActivity.Companion.app import org.jsoup.Jsoup -class AllNovelProvider : MainAPI() { +open class AllNovelProvider : MainAPI() { override val name = "AllNovel" override val mainUrl = "https://allnovel.org" override val hasMainPage = true @@ -64,55 +64,75 @@ class AllNovelProvider : MainAPI() { Pair("invayne", "invayne"), Pair("LitRPG", "LitRPG"), Pair("LGBT", "LGBT"), - Pair( - "Comedy Drama Romance Shounen Ai Supernatural", - "Comedy Drama Romance Shounen Ai Supernatural" - ), + "Comedy" to "Comedy", + "Drama" to "Drama", + "Shounen+Ai" to "Shounen+Ai", + "Supernatural" to "Supernatural", Pair("Shoujo Ai", "Shoujo Ai"), Pair("Supernatura", "Supernatura"), Pair("Canopy", "Canopy") ) + override val orderBys = listOf( + "Genre" to "", + "Latest Release" to "latest-release-novel", + "Hot Novel" to "hot-novel", + "Completed Novel" to "completed-novel", + "Most Popular" to "most-popular", + ) + + override suspend fun loadMainPage( page: Int, mainCategory: String?, orderBy: String?, tag: String? ): HeadMainPageResponse { - val firstresponse = app.get(mainUrl) - val firstdocument = Jsoup.parse(firstresponse.text) - fun getId(tagvalue: String?): String? { - return firstdocument.select("#hot-genre-select>option") - .firstOrNull { it.text() == tagvalue }?.attr("value") - } - - // I cant fix this because idk how it works - val url = "$mainUrl/ajax-search?type=hot&genre=${getId(tag)}" - val response = app.get(url) - val document = Jsoup.parse(response.text) - val headers = document.select("div.item") - if (headers.size <= 0) return HeadMainPageResponse(url, ArrayList()) - val returnValue: ArrayList = ArrayList() - for (h in headers) { - val h3 = h?.selectFirst("a") - val cUrl = mainUrl + h3?.attr("href") - val name = h3?.attr("title") ?: throw ErrorLoadingException("Invalid name") + val url = + if (orderBy == "" && tag != "All") "$mainUrl/genre/$tag?page=$page" else "$mainUrl/${if (orderBy.isNullOrBlank()) "hot-novel" else orderBy}?page=$page" + val document = app.get(url).document - val posterUrl = - mainUrl + h.selectFirst("img")?.attr("src") - - returnValue.add( + return HeadMainPageResponse( + url, + list = document.select("div.list>div.row").mapNotNull { element -> + val a = + element.selectFirst("div > div > h3.truyen-title > a") ?: return@mapNotNull null SearchResponse( - name, - cUrl, - fixUrlNull(posterUrl), + name = a.text(), + url = fixUrlNull(a.attr("href")) ?: return@mapNotNull null, + fixUrlNull(element.selectFirst("div > div > img")?.attr("src")), null, null, this.name ) - ) - } - return HeadMainPageResponse(url, returnValue) + }) + + /*val url = "$mainUrl/ajax-search?type=hot&genre=${getId(tag)}" + val response = app.get(url) + val document = Jsoup.parse(response.text) + val headers = document.select("div.item") + if (headers.size <= 0) return HeadMainPageResponse(url, ArrayList()) + val returnValue: ArrayList = ArrayList() + for (h in headers) { + val h3 = h?.selectFirst("a") + val cUrl = mainUrl + h3?.attr("href") + val name = h3?.attr("title") ?: throw ErrorLoadingException("Invalid name") + + val posterUrl = + mainUrl + h.selectFirst("img")?.attr("src") + + returnValue.add( + SearchResponse( + name, + cUrl, + fixUrlNull(posterUrl), + null, + null, + this.name + ) + ) + } + return HeadMainPageResponse(url, returnValue)*/ } override suspend fun loadHtml(url: String): String? { diff --git a/app/src/main/java/com/lagradost/quicknovel/providers/MtlNovelsProvider.kt b/app/src/main/java/com/lagradost/quicknovel/providers/MtlNovelsProvider.kt index 51fdbc6b..e37f4ee0 100644 --- a/app/src/main/java/com/lagradost/quicknovel/providers/MtlNovelsProvider.kt +++ b/app/src/main/java/com/lagradost/quicknovel/providers/MtlNovelsProvider.kt @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.module.kotlin.readValue import com.lagradost.quicknovel.* import com.lagradost.quicknovel.MainActivity.Companion.app +import com.lagradost.quicknovel.network.CloudflareKiller import org.jsoup.Jsoup class MtlNovelProvider : MainAPI() { @@ -17,47 +18,48 @@ class MtlNovelProvider : MainAPI() { override val tags = listOf( Pair("All", ""), - Pair("Adult","adult"), - Pair("Adventure","adventure"), - Pair("Comedy","comedy"), - Pair("Drama","drama"), - Pair("Ecchi","ecchi"), - Pair("Erciyuan","erciyuan"), - Pair("Fan-Fiction","fan-fiction"), - Pair("Fantasy","fantasy"), - Pair("Game","game"), - Pair("Gender Bender","Gender-Bender"), - Pair("Harem","harem"), - Pair("Historical","historical"), - Pair("Horror","horror"), - Pair("Josei","josei"), - Pair("Martial Arts","martial-arts"), - Pair("Mature","mature"), - Pair("Mecha","mecha"), - Pair("Military","military"), - Pair("Mystery","mystery"), - Pair("Psychological","psychological"), - Pair("Romance","romance"), - Pair("School Life","school-life"), - Pair("Sci-fi","sci-fi"), - Pair("Seinen","seinen"), - Pair("Shoujo","shoujo"), - Pair("Shoujo Ai","shoujo-ai"), - Pair("Shounen","shounen"), - Pair("Shounen Ai","shounen-ai"), - Pair("Slice of Life","slice-of-life"), - Pair("Smut","smut"), - Pair("Sports","sports"), - Pair("Supernatural","supernatural"), - Pair("Tragedy","tragedy"), - Pair("Two-dimensional","two-dimensional"), - Pair("Urban Life","urban-life"), - Pair("Wuxia","wuxia"), - Pair("Xianxia","xianxia"), - Pair("Xuanhuan","xuanhuan"), - Pair("Yaoi","yaoi"), - Pair("Yuri","yuri"), + Pair("Adult", "adult"), + Pair("Adventure", "adventure"), + Pair("Comedy", "comedy"), + Pair("Drama", "drama"), + Pair("Ecchi", "ecchi"), + Pair("Erciyuan", "erciyuan"), + Pair("Fan-Fiction", "fan-fiction"), + Pair("Fantasy", "fantasy"), + Pair("Game", "game"), + Pair("Gender Bender", "Gender-Bender"), + Pair("Harem", "harem"), + Pair("Historical", "historical"), + Pair("Horror", "horror"), + Pair("Josei", "josei"), + Pair("Martial Arts", "martial-arts"), + Pair("Mature", "mature"), + Pair("Mecha", "mecha"), + Pair("Military", "military"), + Pair("Mystery", "mystery"), + Pair("Psychological", "psychological"), + Pair("Romance", "romance"), + Pair("School Life", "school-life"), + Pair("Sci-fi", "sci-fi"), + Pair("Seinen", "seinen"), + Pair("Shoujo", "shoujo"), + Pair("Shoujo Ai", "shoujo-ai"), + Pair("Shounen", "shounen"), + Pair("Shounen Ai", "shounen-ai"), + Pair("Slice of Life", "slice-of-life"), + Pair("Smut", "smut"), + Pair("Sports", "sports"), + Pair("Supernatural", "supernatural"), + Pair("Tragedy", "tragedy"), + Pair("Two-dimensional", "two-dimensional"), + Pair("Urban Life", "urban-life"), + Pair("Wuxia", "wuxia"), + Pair("Xianxia", "xianxia"), + Pair("Xuanhuan", "xuanhuan"), + Pair("Yaoi", "yaoi"), + Pair("Yuri", "yuri"), ) + val interceptor = CloudflareKiller() override suspend fun loadMainPage( page: Int, @@ -69,13 +71,14 @@ class MtlNovelProvider : MainAPI() { if (tag.isNullOrBlank()) "$mainUrl/alltime-rank/page/$page" else "$mainUrl/genre/$tag/page/$page" - val document = app.get(url).document + val document = app.get(url, interceptor = interceptor).document - val headers = document.select("div.box") + val headers = document.select("div.box") if (headers.size <= 0) return HeadMainPageResponse(url, ArrayList()) val returnValue: ArrayList = ArrayList() for (h in headers) { - val name = h?.selectFirst("a")?.attr("aria-label")?.substringBeforeLast("Cover") ?: continue + val name = + h?.selectFirst("a")?.attr("aria-label")?.substringBeforeLast("Cover") ?: continue val cUrl = h.selectFirst("a")?.attr("href") ?: throw ErrorLoadingException() val posterUrl = h.selectFirst("amp-img amp-img")?.attr("src") returnValue.add( @@ -93,14 +96,29 @@ class MtlNovelProvider : MainAPI() { } override suspend fun loadHtml(url: String): String? { - return app.get(url).document.selectFirst("div.par")?.html() + return app.get(url, interceptor = interceptor).document.selectFirst("div.par")?.html() } override suspend fun search(query: String): List { val response = - SearchResults.fromJson(app.get("https://www.mtlnovel.com/wp-admin/admin-ajax.php?action=autosuggest&q=$query").text) - return response?.items?.first()?.results?.map { SearchResponse(Jsoup.parse(it.title).text(), it.permalink!!, it.thumbnail, null, null, name) }!! } + SearchResults.fromJson( + app.get( + "$mainUrl/wp-admin/admin-ajax.php?action=autosuggest&q=$query", + interceptor = interceptor + ).text + ) + return response.items?.first()?.results?.mapNotNull { + SearchResponse( + name = Jsoup.parse(it.title ?: return@mapNotNull null).text(), + url = it.permalink ?: return@mapNotNull null, + it.thumbnail, + null, + null, + name + ) + }!! + } override suspend fun load(url: String): LoadResponse? { @@ -119,7 +137,10 @@ class MtlNovelProvider : MainAPI() { val synopsis = document.selectFirst("div.desc")?.text() val data: ArrayList = ArrayList() - val chapters = app.get(url+"/chapter-list/").document.select("div.ch-list a").reversed() + val chapters = app.get( + "$url/chapter-list/", + interceptor = interceptor + ).document.select("div.ch-list a").reversed() for (c in chapters) { val href = c?.attr("href") ?: continue val cName = c.text() @@ -127,8 +148,12 @@ class MtlNovelProvider : MainAPI() { } - val rating = document.selectFirst("span.rating-info")?.selectFirst("strong")?.text()?.toFloat()?.times(200)?.toInt() - val peopleVoted = "\\((.+) re".toRegex().find(document.selectFirst("span.rating-info")?.text().toString())?.groupValues?.last()?.toInt() + val rating = + document.selectFirst("span.rating-info")?.selectFirst("strong")?.text()?.toFloat() + ?.times(200)?.toInt() + val peopleVoted = "\\((.+) re".toRegex() + .find(document.selectFirst("span.rating-info")?.text().toString())?.groupValues?.last() + ?.toInt() return StreamResponse( @@ -148,19 +173,20 @@ class MtlNovelProvider : MainAPI() { } -private data class SearchResults ( +private data class SearchResults( @get:JsonProperty("items") val items: List? = null ) { companion object { fun fromJson(json: String) = mapper.readValue(json) } } -private data class Item ( + +private data class Item( @get:JsonProperty("query") val query: String? = null, @get:JsonProperty("results") val results: List? = null ) -private data class Result ( +private data class Result( @get:JsonProperty("title") val title: String? = null, @get:JsonProperty("permalink") val permalink: String? = null, @get:JsonProperty("thumbnail") val thumbnail: String? = null, diff --git a/app/src/main/java/com/lagradost/quicknovel/providers/NovelFullProvider.kt b/app/src/main/java/com/lagradost/quicknovel/providers/NovelFullProvider.kt index afab9bb8..5a1a545a 100644 --- a/app/src/main/java/com/lagradost/quicknovel/providers/NovelFullProvider.kt +++ b/app/src/main/java/com/lagradost/quicknovel/providers/NovelFullProvider.kt @@ -1,11 +1,18 @@ package com.lagradost.quicknovel.providers -import com.lagradost.quicknovel.* -import com.lagradost.quicknovel.MainActivity.Companion.app -import org.jsoup.Jsoup -import java.lang.Exception -import kotlin.collections.ArrayList +import com.lagradost.quicknovel.R +class NovelFullProvider : AllNovelProvider() { + override val name = "NovelFull" + override val mainUrl = "https://novelfull.com" + override val hasMainPage = true + + override val iconId = R.drawable.icon_novelfull + + override val iconBackgroundId = R.color.white +} + +/* class NovelFullProvider : MainAPI() { override val name = "NovelFull" override val mainUrl = "https://novelfull.com" @@ -236,3 +243,4 @@ class NovelFullProvider : MainAPI() { ) } } +*/ \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/quicknovel/util/Apis.kt b/app/src/main/java/com/lagradost/quicknovel/util/Apis.kt index ea249611..778e95b3 100644 --- a/app/src/main/java/com/lagradost/quicknovel/util/Apis.kt +++ b/app/src/main/java/com/lagradost/quicknovel/util/Apis.kt @@ -23,10 +23,10 @@ class Apis { // WuxiaWorldOnlineProvider(), // Site does not work RoyalRoadProvider(), FreewebnovelProvider(), - AzynovelProvider(), + //AzynovelProvider(), // dont exist anymore ReadfromnetProvider(), AllNovelProvider(), - RanobesProvider(), + //RanobesProvider(), // custom capcha NovelFullProvider(), //MNovelFreeProvider(), // same as NovelFullVipProvider EngNovelProvider(),