This commit is contained in:
Horis
2025-12-16 23:14:06 +08:00
parent baba6159d2
commit 2d4fabf0ac
16 changed files with 93 additions and 69 deletions
+1 -1
View File
@@ -49,7 +49,7 @@ android {
defaultConfig { defaultConfig {
applicationId "io.legado.app" applicationId "io.legado.app"
minSdk 21 minSdk 21
targetSdk 35 targetSdk 36
versionCode 10000 + gitCommits versionCode 10000 + gitCommits
versionName version versionName version
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -18,6 +18,7 @@
> `{"example":"https://www.example.com/js/example.js", ...}` 自动复用已经下载的js文件 > `{"example":"https://www.example.com/js/example.js", ...}` 自动复用已经下载的js文件
> 注意此处定义的函数可能会被多个线程同时调用,在函数里的全局变量内容将会共享使用,对其进行修改可能会出现竞争问题 > 注意此处定义的函数可能会被多个线程同时调用,在函数里的全局变量内容将会共享使用,对其进行修改可能会出现竞争问题
> 函数内不可声明全局变量,函数外的全局变量不可再赋值,否则会抛出 `无法修改密封对象的属性` 异常
* 并发率 * 并发率
> 并发限制,单位ms,可填写两种格式 > 并发限制,单位ms,可填写两种格式
@@ -46,9 +46,7 @@ suspend fun OkHttpClient.newCallResponseBody(
retry: Int = 0, retry: Int = 0,
builder: Request.Builder.() -> Unit builder: Request.Builder.() -> Unit
): ResponseBody { ): ResponseBody {
return newCallResponse(retry, builder).let { return newCallResponse(retry, builder).body
it.body ?: throw IOException(it.message)
}
} }
suspend fun OkHttpClient.newCallStrResponse( suspend fun OkHttpClient.newCallStrResponse(
@@ -56,7 +54,7 @@ suspend fun OkHttpClient.newCallStrResponse(
builder: Request.Builder.() -> Unit builder: Request.Builder.() -> Unit
): StrResponse { ): StrResponse {
return newCallResponse(retry, builder).let { return newCallResponse(retry, builder).let {
StrResponse(it, it.body?.text() ?: it.message) StrResponse(it, it.body.text())
} }
} }
@@ -142,6 +140,7 @@ fun Request.Builder.postForm(encodedForm: String) {
post(encodedForm.toRequestBody(formContentType)) post(encodedForm.toRequestBody(formContentType))
} }
@Suppress("unused")
fun Request.Builder.postForm(form: Map<String, String>, encoded: Boolean = false) { fun Request.Builder.postForm(form: Map<String, String>, encoded: Boolean = false) {
val formBody = FormBody.Builder() val formBody = FormBody.Builder()
form.forEach { form.forEach {
@@ -36,8 +36,8 @@ object AppUpdateGitHub : AppUpdate.AppUpdateInterface {
if (!res.isSuccessful) { if (!res.isSuccessful) {
throw NoStackTraceException("获取新版本出错(${res.code})") throw NoStackTraceException("获取新版本出错(${res.code})")
} }
val body = res.body?.text() val body = res.body.text()
if (body.isNullOrBlank()) { if (body.isBlank()) {
throw NoStackTraceException("获取新版本出错") throw NoStackTraceException("获取新版本出错")
} }
return GSON.fromJsonObject<GithubRelease>(body) return GSON.fromJsonObject<GithubRelease>(body)
@@ -16,6 +16,7 @@ import io.legado.app.utils.findNSPrefix
import io.legado.app.utils.printOnDebug import io.legado.app.utils.printOnDebug
import io.legado.app.utils.toRequestBody import io.legado.app.utils.toRequestBody
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.currentCoroutineContext
import kotlinx.coroutines.ensureActive import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl
@@ -36,7 +37,6 @@ import java.time.LocalDateTime
import java.time.ZoneOffset import java.time.ZoneOffset
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.coroutines.coroutineContext
@Suppress("unused", "MemberVisibilityCanBePrivate") @Suppress("unused", "MemberVisibilityCanBePrivate")
open class WebDav( open class WebDav(
@@ -169,7 +169,7 @@ open class WebDav(
method("PROPFIND", requestBody) method("PROPFIND", requestBody)
}.apply { }.apply {
checkResult(this) checkResult(this)
}.body?.text() }.body.text()
} }
/** /**
@@ -252,7 +252,7 @@ open class WebDav(
method("PROPFIND", requestBody) method("PROPFIND", requestBody)
}.use { it.isSuccessful } }.use { it.isSuccessful }
}.onFailure { }.onFailure {
coroutineContext.ensureActive() currentCoroutineContext().ensureActive()
}.getOrDefault(false) }.getOrDefault(false)
} }
@@ -268,7 +268,7 @@ open class WebDav(
method("PROPFIND", requestBody) method("PROPFIND", requestBody)
}.use { it.code != 401 } }.use { it.code != 401 }
}.onFailure { }.onFailure {
coroutineContext.ensureActive() currentCoroutineContext().ensureActive()
}.getOrDefault(true) }.getOrDefault(true)
} }
@@ -289,7 +289,7 @@ open class WebDav(
} }
} }
}.onFailure { }.onFailure {
coroutineContext.ensureActive() currentCoroutineContext().ensureActive()
AppLog.put("WebDav创建目录失败\n${it.localizedMessage}", it) AppLog.put("WebDav创建目录失败\n${it.localizedMessage}", it)
}.isSuccess }.isSuccess
} }
@@ -346,7 +346,7 @@ open class WebDav(
} }
} }
}.onFailure { }.onFailure {
coroutineContext.ensureActive() currentCoroutineContext().ensureActive()
AppLog.put("WebDav上传失败\n${it.localizedMessage}", it) AppLog.put("WebDav上传失败\n${it.localizedMessage}", it)
throw WebDavException("WebDav上传失败\n${it.localizedMessage}") throw WebDavException("WebDav上传失败\n${it.localizedMessage}")
} }
@@ -367,7 +367,7 @@ open class WebDav(
} }
} }
}.onFailure { }.onFailure {
coroutineContext.ensureActive() currentCoroutineContext().ensureActive()
AppLog.put("WebDav上传失败\n${it.localizedMessage}", it) AppLog.put("WebDav上传失败\n${it.localizedMessage}", it)
throw WebDavException("WebDav上传失败\n${it.localizedMessage}") throw WebDavException("WebDav上传失败\n${it.localizedMessage}")
} }
@@ -388,7 +388,7 @@ open class WebDav(
} }
} }
}.onFailure { }.onFailure {
coroutineContext.ensureActive() currentCoroutineContext().ensureActive()
AppLog.put("WebDav上传失败\n${it.localizedMessage}", it) AppLog.put("WebDav上传失败\n${it.localizedMessage}", it)
throw WebDavException("WebDav上传失败\n${it.localizedMessage}") throw WebDavException("WebDav上传失败\n${it.localizedMessage}")
} }
@@ -401,8 +401,8 @@ open class WebDav(
url(url) url(url)
}.apply { }.apply {
checkResult(this) checkResult(this)
}.body?.byteStream() }.body.byteStream()
return byteStream ?: throw WebDavException("WebDav下载出错\nNull Exception") return byteStream
} }
/** /**
@@ -419,7 +419,7 @@ open class WebDav(
checkResult(it) checkResult(it)
} }
}.onFailure { }.onFailure {
coroutineContext.ensureActive() currentCoroutineContext().ensureActive()
AppLog.put("WebDav删除失败\n${it.localizedMessage}", it) AppLog.put("WebDav删除失败\n${it.localizedMessage}", it)
}.isSuccess }.isSuccess
} }
@@ -429,7 +429,7 @@ open class WebDav(
*/ */
private fun checkResult(response: Response) { private fun checkResult(response: Response) {
if (!response.isSuccessful) { if (!response.isSuccessful) {
val body = response.body?.string() val body = response.body.string()
if (response.code == 401) { if (response.code == 401) {
val headers = response.headers("WWW-Authenticate") val headers = response.headers("WWW-Authenticate")
val supportBasicAuth = headers.any { val supportBasicAuth = headers.any {
@@ -440,7 +440,7 @@ open class WebDav(
} }
} }
if (response.message.isNotBlank() || body.isNullOrBlank()) { if (response.message.isNotBlank() || body.isBlank()) {
throw WebDavException("${url}\n${response.code}:${response.message}") throw WebDavException("${url}\n${response.code}:${response.message}")
} }
val document = Jsoup.parse(body) val document = Jsoup.parse(body)
@@ -4,6 +4,7 @@ import android.graphics.Bitmap
import android.graphics.Color import android.graphics.Color
import android.graphics.pdf.PdfRenderer import android.graphics.pdf.PdfRenderer
import android.os.ParcelFileDescriptor import android.os.ParcelFileDescriptor
import androidx.core.graphics.createBitmap
import io.legado.app.constant.AppLog import io.legado.app.constant.AppLog
import io.legado.app.data.entities.Book import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookChapter
@@ -121,16 +122,14 @@ class PdfFile(var book: Book) {
if (index >= renderer.pageCount) { if (index >= renderer.pageCount) {
return null return null
} }
return renderer.openPage(index)?.use { page -> return renderer.openPage(index).use { page ->
Bitmap.createBitmap( createBitmap(
SystemUtils.screenWidthPx, SystemUtils.screenWidthPx,
(SystemUtils.screenWidthPx.toDouble() * page.height / page.width).toInt(), (SystemUtils.screenWidthPx.toDouble() * page.height / page.width).toInt()
Bitmap.Config.ARGB_8888 ).apply {
) this.eraseColor(Color.WHITE)
.apply { page.render(this, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY)
this.eraseColor(Color.WHITE) }
page.render(this, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY)
}
} }
} }
@@ -168,7 +167,7 @@ class PdfFile(var book: Book) {
null null
} }
} catch (e: Exception) { } catch (_: Exception) {
return null return null
} }
} }
@@ -53,7 +53,7 @@ class AutoReadDialog : BaseDialogFragment(R.layout.dialog_auto_read) {
val bottomDialog = (activity as ReadBookActivity).bottomDialog++ val bottomDialog = (activity as ReadBookActivity).bottomDialog++
if (bottomDialog > 0) { if (bottomDialog > 0) {
dismiss() dismiss()
return return@run
} }
val bg = requireContext().bottomBackground val bg = requireContext().bottomBackground
val isLight = ColorUtils.isColorLight(bg) val isLight = ColorUtils.isColorLight(bg)
@@ -10,8 +10,14 @@ import android.graphics.drawable.Drawable
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONObject import org.json.JSONObject
import splitties.init.appCtx import splitties.init.appCtx
import java.io.* import java.io.ByteArrayInputStream
import java.util.* import java.io.ByteArrayOutputStream
import java.io.File
import java.io.IOException
import java.io.ObjectInputStream
import java.io.ObjectOutputStream
import java.io.Serializable
import java.util.Collections
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.atomic.AtomicLong import java.util.concurrent.atomic.AtomicLong
import kotlin.math.min import kotlin.math.min
@@ -458,6 +464,7 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int)
*/ */
private object Utils { private object Utils {
@Suppress("ConstPropertyName")
private const val mSeparator = ' ' private const val mSeparator = ' '
/** /**
@@ -762,8 +769,8 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int)
var fileSize: Long = 0 var fileSize: Long = 0
if (mostLongUsedFile != null) { if (mostLongUsedFile != null) {
fileSize = calculateSize(mostLongUsedFile!!) fileSize = calculateSize(mostLongUsedFile)
if (mostLongUsedFile!!.delete()) { if (mostLongUsedFile.delete()) {
lastUsageDates.remove(mostLongUsedFile) lastUsageDates.remove(mostLongUsedFile)
} }
} }
@@ -2,11 +2,22 @@ package io.legado.app.utils.compress
import android.annotation.SuppressLint import android.annotation.SuppressLint
import io.legado.app.utils.DebugLog import io.legado.app.utils.DebugLog
import io.legado.app.utils.compress.ZipUtils.zipFile
import io.legado.app.utils.printOnDebug import io.legado.app.utils.printOnDebug
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.io.* import java.io.BufferedInputStream
import java.util.zip.* import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.util.zip.GZIPOutputStream
import java.util.zip.ZipEntry
import java.util.zip.ZipFile
import java.util.zip.ZipInputStream
import java.util.zip.ZipOutputStream
@SuppressLint("ObsoleteSdkInt") @SuppressLint("ObsoleteSdkInt")
@Suppress("unused", "MemberVisibilityCanBePrivate") @Suppress("unused", "MemberVisibilityCanBePrivate")
@@ -241,7 +252,7 @@ object ZipUtils {
if (!entryFile.canonicalPath.startsWith(dir.canonicalPath)) { if (!entryFile.canonicalPath.startsWith(dir.canonicalPath)) {
throw SecurityException("压缩文件只能解压到指定路径") throw SecurityException("压缩文件只能解压到指定路径")
} }
if (entry!!.isDirectory) { if (entry.isDirectory) {
if (!entryFile.exists()) { if (!entryFile.exists()) {
entryFile.mkdirs() entryFile.mkdirs()
} }
@@ -286,7 +297,7 @@ object ZipUtils {
if (entry!!.isDirectory) { if (entry!!.isDirectory) {
continue continue
} }
val fileName = entry!!.name val fileName = entry.name
if (filter != null && filter.invoke(fileName)) if (filter != null && filter.invoke(fileName))
fileNames.add(fileName) fileNames.add(fileName)
} }
+2 -2
View File
@@ -2,8 +2,8 @@
buildscript { buildscript {
ext{ ext{
compile_sdk_version = 35 compile_sdk_version = 36
build_tool_version = '34.0.0' // build_tool_version = '34.0.0'
// kotlin_version = '1.9.22' // kotlin_version = '1.9.22'
// ksp_version = "1.0.17" // ksp_version = "1.0.17"
// agp_version = '8.2.2' // agp_version = '8.2.2'
+1 -1
View File
@@ -21,7 +21,7 @@ android.useAndroidX=true
android.enableJetifier=false android.enableJetifier=false
# Kotlin code style for this project: "official" or "obsolete": # Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official kotlin.code.style=official
kotlin.incremental.useClasspathSnapshot=true # kotlin.incremental.useClasspathSnapshot=true
android.enableResourceOptimizations=true android.enableResourceOptimizations=true
# android.enableNewResourceShrinker' is deprecated. # android.enableNewResourceShrinker' is deprecated.
# It was removed in version 8.0 of the Android Gradle plugin. # It was removed in version 8.0 of the Android Gradle plugin.
+26 -19
View File
@@ -1,53 +1,60 @@
[versions] [versions]
kotlin = "2.2.0" kotlin = "2.3.0"
ksp = "2.2.0-2.0.2" ksp = "2.3.3"
agp = "8.10.1" agp = "8.13.2"
appcompat = "1.7.0" appcompat = "1.7.1"
colorpicker = "1.1.0" colorpicker = "1.1.0"
commonsText = "1.13.1" commonsText = "1.15.0"
constraintlayout = "2.2.1" constraintlayout = "2.2.1"
core = "1.16.0" core = "1.17.0"
#noinspection GradleDependency
firebaseBom = "33.2.0" firebaseBom = "33.2.0"
flexbox = "3.0.0" flexbox = "3.0.0"
fragment = "1.8.7" fragment = "1.8.9"
#不要更新版本 #不要更新版本
#noinspection GradleDependency
hutool = "5.8.22" hutool = "5.8.22"
libarchive = "1.1.6" libarchive = "1.1.6"
lifecycle = "2.9.0" #noinspection GradleDependency
glide = "4.16.0" lifecycle = "2.9.4"
gson = "2.13.1" glide = "5.0.5"
jsonPath = "2.9.0" gson = "2.13.2"
jsonPath = "2.10.0"
# issue #3811,不要更新版本,新版引入了一个破坏性变更(详见https://github.com/jhy/jsoup/pull/2017 # issue #3811,不要更新版本,新版引入了一个破坏性变更(详见https://github.com/jhy/jsoup/pull/2017
# 若要升级请确保相关代码不会受此变更影响(如AnalyzeByJSoup.kt、JsoupXpath库等) # 若要升级请确保相关代码不会受此变更影响(如AnalyzeByJSoup.kt、JsoupXpath库等)
#noinspection GradleDependency
jsoup = "1.16.2" jsoup = "1.16.2"
jsoupxpath = "2.5.3" jsoupxpath = "2.5.3"
coroutines = "1.10.2" coroutines = "1.10.2"
liveeventbus = "1.8.14" liveeventbus = "1.8.14"
markwon = "4.6.2" markwon = "4.6.2"
material = "1.12.0" material = "1.13.0"
media = "1.7.0" media = "1.7.1"
media3 = "1.6.1" media3 = "1.8.0"
nanoHttpd = "2.3.1" nanoHttpd = "2.3.1"
okhttp = "5.1.0" okhttp = "5.3.2"
preference = "1.2.1" preference = "1.2.1"
#noinspection GradleDependency
protobufJavalite = "4.26.1" protobufJavalite = "4.26.1"
quickChineseTransfer = "0.2.16" quickChineseTransfer = "0.2.16"
#noinspection GradleDependency
room = "2.7.1" room = "2.7.1"
splitties = "3.0.0" splitties = "3.0.0"
rhino = "1.8.0" rhino = "1.8.1"
desugar = "2.1.5" desugar = "2.1.5"
activity = "1.10.1" #noinspection GradleDependency
activity = "1.11.0"
#kotlinxSerialization = "1.8.0" #kotlinxSerialization = "1.8.0"
swiperefreshlayout = "1.1.0" swiperefreshlayout = "1.2.0"
#noinspection GradleDependency #noinspection GradleDependency
recyclerview = "1.2.0" recyclerview = "1.2.0"
#noinspection GradleDependency #noinspection GradleDependency
viewpager2 = "1.0.0" viewpager2 = "1.0.0"
webkit = "1.13.0" webkit = "1.14.0"
collection = "1.5.0" collection = "1.5.0"
zxingLite = "3.3.0" zxingLite = "3.3.0"
+1 -1
View File
@@ -1,6 +1,6 @@
#Tue Aug 27 18:19:17 CST 2024 #Tue Aug 27 18:19:17 CST 2024
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
+1 -1
View File
@@ -13,7 +13,7 @@ android {
} }
defaultConfig { defaultConfig {
minSdk 21 minSdk 21
targetSdk 35 targetSdk 36
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro" consumerProguardFiles "consumer-rules.pro"
+1 -1
View File
@@ -15,7 +15,7 @@ android {
} }
defaultConfig { defaultConfig {
minSdk 21 minSdk 21
targetSdk 35 targetSdk 36
consumerProguardFiles "consumer-rules.pro" consumerProguardFiles "consumer-rules.pro"
} }
@@ -206,7 +206,7 @@ object RhinoScriptEngine : AbstractScriptEngine(), Invocable, Compilable {
thiz1 = Context.toObject(thiz1, topLevel) thiz1 = Context.toObject(thiz1, topLevel)
} }
val engineScope = getRuntimeScope(context) val engineScope = getRuntimeScope(context)
val localScope = if (thiz1 != null) thiz1 as Scriptable else engineScope val localScope = thiz1 ?: engineScope
val obj = ScriptableObject.getProperty(localScope, name) as? Function val obj = ScriptableObject.getProperty(localScope, name) as? Function
?: throw NoSuchMethodException("no such method: $name") ?: throw NoSuchMethodException("no such method: $name")
var scope = obj.parentScope var scope = obj.parentScope
@@ -229,7 +229,7 @@ object RhinoScriptEngine : AbstractScriptEngine(), Invocable, Compilable {
override fun <T> getInterface(clazz: Class<T>): T? { override fun <T> getInterface(clazz: Class<T>): T? {
return try { return try {
implementor.getInterface(null, clazz) implementor.getInterface(null, clazz)
} catch (var3: ScriptException) { } catch (_: ScriptException) {
null null
} }
} }
@@ -240,7 +240,7 @@ object RhinoScriptEngine : AbstractScriptEngine(), Invocable, Compilable {
} else { } else {
try { try {
implementor.getInterface(obj, paramClass) implementor.getInterface(obj, paramClass)
} catch (var4: ScriptException) { } catch (_: ScriptException) {
null null
} }
} }
@@ -393,7 +393,7 @@ object RhinoScriptEngine : AbstractScriptEngine(), Invocable, Compilable {
if (System.getSecurityManager() != null) { if (System.getSecurityManager() != null) {
try { try {
AccessController.checkPermission(AllPermission()) AccessController.checkPermission(AllPermission())
} catch (var6: AccessControlException) { } catch (_: AccessControlException) {
accessContext = AccessController.getContext() accessContext = AccessController.getContext()
} }
} }
@@ -413,7 +413,7 @@ object RhinoScriptEngine : AbstractScriptEngine(), Invocable, Compilable {
obj1 = Context.toObject(obj1, topLevel) obj1 = Context.toObject(obj1, topLevel)
} }
val engineScope = getRuntimeScope(context) val engineScope = getRuntimeScope(context)
val localScope = if (obj1 != null) obj1 as Scriptable else engineScope val localScope = obj1 ?: engineScope
val methods = clazz.methods val methods = clazz.methods
val methodsSize = methods.size val methodsSize = methods.size
for (index in 0 until methodsSize) { for (index in 0 until methodsSize) {