合并上游更改
感谢:@821938089、@zhongerxll、@youke2580c、@Leroy-X、@Dark-Tide、@lhjgege、@3harmony、@mgz0227
This commit is contained in:
87 files changed
+800
-365
No files matched your search
@@ -101,7 +101,7 @@ object DirectLinkUpload {
|
||||
|
||||
@Keep
|
||||
data class Rule(
|
||||
var uploadUrl: String, //上传url
|
||||
var uploadUrl: String, //创建分享链接
|
||||
var downloadUrlRule: String, //下载链接规则
|
||||
var summary: String, //注释
|
||||
var compress: Boolean = false, //是否压缩
|
||||
|
||||
@@ -988,6 +988,7 @@ interface JsExtensions : JsEncodeUtils {
|
||||
|
||||
// 新增 mimeType 参数,默认为 null(保持兼容性)
|
||||
fun openUrl(url: String, mimeType: String? = null) {
|
||||
require(url.length < 64 * 1024) { "openUrl parameter url too long" }
|
||||
rhinoContext.ensureActive()
|
||||
val source = getSource() ?: throw NoStackTraceException("openUrl source cannot be null")
|
||||
appCtx.startActivity<OpenUrlConfirmActivity> {
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.legato.kazusa.help.book
|
||||
import android.graphics.BitmapFactory
|
||||
import android.os.ParcelFileDescriptor
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import com.script.rhino.runScriptWithContext
|
||||
import io.legato.kazusa.constant.AppLog
|
||||
import io.legato.kazusa.constant.AppPattern
|
||||
import io.legato.kazusa.constant.EventBus
|
||||
@@ -28,7 +29,6 @@ import io.legato.kazusa.utils.getFile
|
||||
import io.legato.kazusa.utils.isContentScheme
|
||||
import io.legato.kazusa.utils.onEachParallel
|
||||
import io.legato.kazusa.utils.postEvent
|
||||
import com.script.rhino.runScriptWithContext
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.ensureActive
|
||||
@@ -157,7 +157,7 @@ object BookHelp {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun saveContent(
|
||||
fun saveContent(
|
||||
bookSource: BookSource,
|
||||
book: Book,
|
||||
bookChapter: BookChapter,
|
||||
@@ -404,7 +404,11 @@ object BookHelp {
|
||||
bookChapter.getFileName()
|
||||
)
|
||||
if (file.exists()) {
|
||||
return file.readText()
|
||||
val string = file.readText()
|
||||
if (string.isEmpty()) {
|
||||
return null
|
||||
}
|
||||
return string
|
||||
}
|
||||
if (book.isLocal) {
|
||||
val string = LocalBook.getContent(book, bookChapter)
|
||||
|
||||
@@ -570,6 +570,9 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
val mouseWheelPage
|
||||
get() = appCtx.getPrefBoolean(PreferKey.mouseWheelPage, true)
|
||||
|
||||
val paddingDisplayCutouts
|
||||
get() = appCtx.getPrefBoolean(PreferKey.paddingDisplayCutouts, false)
|
||||
|
||||
var searchScope: String
|
||||
get() = appCtx.getPrefString("searchScope") ?: ""
|
||||
set(value) {
|
||||
|
||||
@@ -5,8 +5,8 @@ import android.graphics.drawable.BitmapDrawable
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import androidx.annotation.Keep
|
||||
import androidx.core.graphics.toColorInt
|
||||
import com.google.android.material.color.MaterialColors
|
||||
import io.legato.kazusa.R
|
||||
import io.legato.kazusa.constant.AppLog
|
||||
import io.legato.kazusa.constant.PageAnim
|
||||
import io.legato.kazusa.constant.PreferKey
|
||||
@@ -30,8 +30,6 @@ import io.legato.kazusa.utils.printOnDebug
|
||||
import io.legato.kazusa.utils.putPrefBoolean
|
||||
import io.legato.kazusa.utils.putPrefInt
|
||||
import io.legato.kazusa.utils.resizeAndRecycle
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.withContext
|
||||
import splitties.init.appCtx
|
||||
import java.io.File
|
||||
|
||||
@@ -439,66 +437,55 @@ object ReadBookConfig {
|
||||
return exportConfig
|
||||
}
|
||||
|
||||
suspend fun import(byteArray: ByteArray): Result<Config> {
|
||||
return kotlin.runCatching {
|
||||
withContext(IO) {
|
||||
val configZipPath = FileUtils.getPath(appCtx.externalCache, "readConfig.zip")
|
||||
FileUtils.delete(configZipPath)
|
||||
val zipFile = FileUtils.createFileIfNotExist(configZipPath)
|
||||
zipFile.writeBytes(byteArray)
|
||||
val configDir = appCtx.externalCache.getFile("readConfig")
|
||||
configDir.createFolderReplace()
|
||||
ZipUtils.unZipToPath(zipFile, configDir)
|
||||
val configFile = configDir.getFile(configFileName)
|
||||
val config: Config = GSON.fromJsonObject<Config>(configFile.readText()).getOrThrow()
|
||||
if (config.textFont.isNotEmpty()) {
|
||||
val fontName = FileUtils.getName(config.textFont)
|
||||
val fontPath =
|
||||
FileUtils.getPath(appCtx.externalFiles, "font", fontName)
|
||||
if (!FileUtils.exist(fontPath)) {
|
||||
configDir.getFile(fontName).copyTo(File(fontPath))
|
||||
}
|
||||
config.textFont = fontPath
|
||||
}
|
||||
if (config.bgType == 2) {
|
||||
val bgName = FileUtils.getName(config.bgStr)
|
||||
config.bgStr = bgName
|
||||
val bgPath = FileUtils.getPath(appCtx.externalFiles, "bg", bgName)
|
||||
if (!FileUtils.exist(bgPath)) {
|
||||
val bgFile = configDir.getFile(bgName)
|
||||
if (bgFile.exists()) {
|
||||
bgFile.copyTo(File(bgPath))
|
||||
}
|
||||
}
|
||||
config.bgStr = bgPath
|
||||
}
|
||||
if (config.bgTypeNight == 2) {
|
||||
val bgName = FileUtils.getName(config.bgStrNight)
|
||||
config.bgStrNight = bgName
|
||||
val bgPath = FileUtils.getPath(appCtx.externalFiles, "bg", bgName)
|
||||
if (!FileUtils.exist(bgPath)) {
|
||||
val bgFile = configDir.getFile(bgName)
|
||||
if (bgFile.exists()) {
|
||||
bgFile.copyTo(File(bgPath))
|
||||
}
|
||||
}
|
||||
config.bgStrNight = bgPath
|
||||
}
|
||||
if (config.bgTypeEInk == 2) {
|
||||
val bgName = FileUtils.getName(config.bgStrEInk)
|
||||
config.bgStrEInk = bgName
|
||||
val bgPath = FileUtils.getPath(appCtx.externalFiles, "bg", bgName)
|
||||
if (!FileUtils.exist(bgPath)) {
|
||||
val bgFile = configDir.getFile(bgName)
|
||||
if (bgFile.exists()) {
|
||||
bgFile.copyTo(File(bgPath))
|
||||
}
|
||||
}
|
||||
config.bgStrEInk = bgPath
|
||||
}
|
||||
return@withContext config
|
||||
fun import(byteArray: ByteArray): Config {
|
||||
val configZipPath = FileUtils.getPath(appCtx.externalCache, "readConfig.zip")
|
||||
FileUtils.delete(configZipPath)
|
||||
val zipFile = FileUtils.createFileIfNotExist(configZipPath)
|
||||
zipFile.writeBytes(byteArray)
|
||||
val configDir = appCtx.externalCache.getFile("readConfig")
|
||||
configDir.createFolderReplace()
|
||||
ZipUtils.unZipToPath(zipFile, configDir)
|
||||
val configFile = configDir.getFile(configFileName)
|
||||
val config: Config = GSON.fromJsonObject<Config>(configFile.readText()).getOrThrow()
|
||||
if (config.textFont.isNotEmpty()) {
|
||||
val fontName = FileUtils.getName(config.textFont)
|
||||
val fontPath =
|
||||
FileUtils.getPath(appCtx.externalFiles, "font", fontName)
|
||||
if (!FileUtils.exist(fontPath)) {
|
||||
configDir.getFile(fontName).copyTo(File(fontPath))
|
||||
}
|
||||
config.textFont = fontPath
|
||||
}
|
||||
if (config.bgType == 2) {
|
||||
val bgName = FileUtils.getName(config.bgStr)
|
||||
config.bgStr = bgName
|
||||
val bgPath = FileUtils.getPath(appCtx.externalFiles, "bg", bgName)
|
||||
if (!FileUtils.exist(bgPath)) {
|
||||
val bgFile = configDir.getFile(bgName)
|
||||
if (bgFile.exists()) {
|
||||
bgFile.copyTo(File(bgPath))
|
||||
}
|
||||
}
|
||||
config.bgStrNight = bgPath
|
||||
} else if (config.bgTypeNight == 0) {
|
||||
config.bgStrNight.toColorInt()
|
||||
}
|
||||
if (config.bgTypeEInk == 2) {
|
||||
val bgName = FileUtils.getName(config.bgStrEInk)
|
||||
config.bgStrEInk = bgName
|
||||
val bgPath = FileUtils.getPath(appCtx.externalFiles, "bg", bgName)
|
||||
if (!FileUtils.exist(bgPath)) {
|
||||
val bgFile = configDir.getFile(bgName)
|
||||
if (bgFile.exists()) {
|
||||
bgFile.copyTo(File(bgPath))
|
||||
}
|
||||
}
|
||||
config.bgStrEInk = bgPath
|
||||
} else if (config.bgTypeEInk == 0) {
|
||||
config.bgStrEInk.toColorInt()
|
||||
}
|
||||
config.curTextColor()
|
||||
return config
|
||||
}
|
||||
|
||||
@Keep
|
||||
|
||||
@@ -2,19 +2,18 @@ package io.legato.kazusa.help.config
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Color
|
||||
import android.util.DisplayMetrics
|
||||
import androidx.annotation.Keep
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.graphics.toColorInt
|
||||
import io.legato.kazusa.R
|
||||
import io.legato.kazusa.constant.AppLog
|
||||
import io.legato.kazusa.constant.EventBus
|
||||
import io.legato.kazusa.constant.PreferKey
|
||||
import io.legato.kazusa.constant.Theme
|
||||
import io.legato.kazusa.help.DefaultData
|
||||
import io.legato.kazusa.lib.theme.ThemeStore
|
||||
import io.legato.kazusa.model.BookCover
|
||||
import io.legato.kazusa.utils.BitmapUtils
|
||||
import io.legato.kazusa.utils.ColorUtils
|
||||
import io.legato.kazusa.utils.FileUtils
|
||||
import io.legato.kazusa.utils.GSON
|
||||
import io.legato.kazusa.utils.fromJsonArray
|
||||
@@ -29,7 +28,6 @@ import io.legato.kazusa.utils.putPrefInt
|
||||
import io.legato.kazusa.utils.stackBlur
|
||||
import splitties.init.appCtx
|
||||
import java.io.File
|
||||
import androidx.core.graphics.toColorInt
|
||||
|
||||
@Keep
|
||||
object ThemeConfig {
|
||||
@@ -117,13 +115,18 @@ object ThemeConfig {
|
||||
fun addConfig(json: String): Boolean {
|
||||
GSON.fromJsonObject<Config>(json.trim { it < ' ' }).getOrNull()
|
||||
?.let {
|
||||
addConfig(it)
|
||||
return true
|
||||
if (validateConfig(it)) {
|
||||
addConfig(it)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun addConfig(newConfig: Config) {
|
||||
if (!validateConfig(newConfig)) {
|
||||
return
|
||||
}
|
||||
configList.forEachIndexed { index, config ->
|
||||
if (newConfig.themeName == config.themeName) {
|
||||
configList[index] = newConfig
|
||||
@@ -134,6 +137,18 @@ object ThemeConfig {
|
||||
save()
|
||||
}
|
||||
|
||||
private fun validateConfig(config: Config): Boolean {
|
||||
try {
|
||||
config.primaryColor.toColorInt()
|
||||
config.accentColor.toColorInt()
|
||||
config.backgroundColor.toColorInt()
|
||||
config.bottomBackground.toColorInt()
|
||||
return true
|
||||
} catch (_: Exception) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConfigs(): List<Config>? {
|
||||
val configFile = File(configFilePath)
|
||||
if (configFile.exists()) {
|
||||
@@ -148,23 +163,27 @@ object ThemeConfig {
|
||||
}
|
||||
|
||||
fun applyConfig(context: Context, config: Config) {
|
||||
val primary = config.primaryColor.toColorInt()
|
||||
val accent = config.accentColor.toColorInt()
|
||||
val background = config.backgroundColor.toColorInt()
|
||||
val bBackground = config.bottomBackground.toColorInt()
|
||||
if (config.isNightTheme) {
|
||||
context.putPrefInt(PreferKey.cNPrimary, primary)
|
||||
context.putPrefInt(PreferKey.cNAccent, accent)
|
||||
context.putPrefInt(PreferKey.cNBackground, background)
|
||||
context.putPrefInt(PreferKey.cNBBackground, bBackground)
|
||||
} else {
|
||||
context.putPrefInt(PreferKey.cPrimary, primary)
|
||||
context.putPrefInt(PreferKey.cAccent, accent)
|
||||
context.putPrefInt(PreferKey.cBackground, background)
|
||||
context.putPrefInt(PreferKey.cBBackground, bBackground)
|
||||
try {
|
||||
val primary = config.primaryColor.toColorInt()
|
||||
val accent = config.accentColor.toColorInt()
|
||||
val background = config.backgroundColor.toColorInt()
|
||||
val bBackground = config.bottomBackground.toColorInt()
|
||||
if (config.isNightTheme) {
|
||||
context.putPrefInt(PreferKey.cNPrimary, primary)
|
||||
context.putPrefInt(PreferKey.cNAccent, accent)
|
||||
context.putPrefInt(PreferKey.cNBackground, background)
|
||||
context.putPrefInt(PreferKey.cNBBackground, bBackground)
|
||||
} else {
|
||||
context.putPrefInt(PreferKey.cPrimary, primary)
|
||||
context.putPrefInt(PreferKey.cAccent, accent)
|
||||
context.putPrefInt(PreferKey.cBackground, background)
|
||||
context.putPrefInt(PreferKey.cBBackground, bBackground)
|
||||
}
|
||||
AppConfig.isNightTheme = config.isNightTheme
|
||||
applyDayNight(context)
|
||||
} catch (e: Exception) {
|
||||
AppLog.put("设置主题出错\n$e", e, true)
|
||||
}
|
||||
AppConfig.isNightTheme = config.isNightTheme
|
||||
applyDayNight(context)
|
||||
}
|
||||
|
||||
fun saveDayTheme(context: Context, name: String) {
|
||||
|
||||
@@ -12,7 +12,7 @@ import java.security.MessageDigest
|
||||
* @radius: 0..25
|
||||
*/
|
||||
class BlurTransformation(
|
||||
@IntRange(from = 0, to = 25) private val radius: Int
|
||||
@param:IntRange(from = 0, to = 25) private val radius: Int
|
||||
) : BitmapTransformation() {
|
||||
|
||||
override fun transform(
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.legato.kazusa.help.http
|
||||
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
import okhttp3.ResponseBody
|
||||
import okhttp3.ResponseBody.Companion.asResponseBody
|
||||
import okhttp3.internal.http.promisesBody
|
||||
import okio.buffer
|
||||
@@ -24,7 +25,7 @@ object DecompressInterceptor : Interceptor {
|
||||
val response = chain.proceed(requestBuilder.build())
|
||||
val body = response.body
|
||||
|
||||
if (!transparentDecompress || !response.promisesBody() || body == null) {
|
||||
if (!transparentDecompress || !response.promisesBody() || body == ResponseBody.EMPTY) {
|
||||
return response
|
||||
}
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ val okHttpClientManga by lazy {
|
||||
val response = chain.proceed(request)
|
||||
val url = request.url.toString()
|
||||
response.newBuilder()
|
||||
.body(ProgressResponseBody(url, LISTENER, response.body!!))
|
||||
.body(ProgressResponseBody(url, LISTENER, response.body))
|
||||
.build()
|
||||
}
|
||||
interceptors.add(1) { chain ->
|
||||
|
||||
@@ -18,8 +18,6 @@ import okhttp3.Protocol
|
||||
import okhttp3.Request
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.Response
|
||||
import okhttp3.internal.notifyAll
|
||||
import okhttp3.internal.wait
|
||||
import okio.Buffer
|
||||
import okio.BufferedSink
|
||||
import okio.Pipe
|
||||
@@ -186,7 +184,7 @@ class ObsoleteUrlFactory(private var client: OkHttpClient) : URLStreamHandlerFac
|
||||
return try {
|
||||
val response = getResponse(true)
|
||||
if (hasBody(response) && response.code >= HTTP_BAD_REQUEST) {
|
||||
response.body!!.byteStream()
|
||||
response.body.byteStream()
|
||||
} else null
|
||||
} catch (e: IOException) {
|
||||
null
|
||||
@@ -258,7 +256,7 @@ class ObsoleteUrlFactory(private var client: OkHttpClient) : URLStreamHandlerFac
|
||||
}
|
||||
val response = getResponse(false)
|
||||
if (response.code >= HTTP_BAD_REQUEST) throw FileNotFoundException(url.toString())
|
||||
return response.body!!.byteStream()
|
||||
return response.body.byteStream()
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
@@ -1174,6 +1172,14 @@ class ObsoleteUrlFactory(private var client: OkHttpClient) : URLStreamHandlerFac
|
||||
throw AssertionError()
|
||||
}
|
||||
|
||||
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "NOTHING_TO_INLINE")
|
||||
private inline fun Any.wait() = (this as Object).wait()
|
||||
|
||||
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "NOTHING_TO_INLINE")
|
||||
private inline fun Any.notify() = (this as Object).notify()
|
||||
|
||||
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "NOTHING_TO_INLINE")
|
||||
private inline fun Any.notifyAll() = (this as Object).notifyAll()
|
||||
@Throws(Exception::class)
|
||||
@JvmStatic
|
||||
fun main(args: Array<String>) {
|
||||
|
||||
@@ -29,6 +29,7 @@ object SourceVerificationHelp {
|
||||
* 获取书源验证结果
|
||||
* 图片验证码 防爬 滑动验证码 点击字符 等等
|
||||
*/
|
||||
@Synchronized
|
||||
fun getVerificationResult(
|
||||
source: BaseSource?,
|
||||
url: String,
|
||||
@@ -38,9 +39,8 @@ object SourceVerificationHelp {
|
||||
): String {
|
||||
source
|
||||
?: throw NoStackTraceException("getVerificationResult parameter source cannot be null")
|
||||
if (isMainThread) {
|
||||
error("getVerificationResult must be called on a background thread")
|
||||
}
|
||||
require(url.length < 64 * 1024) { "getVerificationResult parameter url too long" }
|
||||
check(!isMainThread) { "getVerificationResult must be called on a background thread" }
|
||||
|
||||
clearResult(source.getKey())
|
||||
|
||||
@@ -84,6 +84,7 @@ object SourceVerificationHelp {
|
||||
refetchAfterSuccess: Boolean? = true
|
||||
) {
|
||||
source ?: throw NoStackTraceException("startBrowser parameter source cannot be null")
|
||||
require(url.length < 64 * 1024) { "startBrowser parameter url too long" }
|
||||
appCtx.startActivity<WebViewActivity> {
|
||||
putExtra("title", title)
|
||||
putExtra("url", url)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.legato.kazusa.help.storage
|
||||
|
||||
import android.content.Context
|
||||
import android.database.sqlite.SQLiteConstraintException
|
||||
import android.net.Uri
|
||||
import androidx.core.content.edit
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
@@ -106,7 +107,6 @@ object Restore {
|
||||
.forEach { book ->
|
||||
book.coverUrl = LocalBook.getCoverPath(book)
|
||||
}
|
||||
val updateBooks = arrayListOf<Book>()
|
||||
val newBooks = arrayListOf<Book>()
|
||||
val ignoreLocalBook = BackupConfig.ignoreLocalBook
|
||||
it.forEach { book ->
|
||||
@@ -114,12 +114,15 @@ object Restore {
|
||||
return@forEach
|
||||
}
|
||||
if (appDb.bookDao.has(book.bookUrl)) {
|
||||
updateBooks.add(book)
|
||||
try {
|
||||
appDb.bookDao.update(book)
|
||||
} catch (_: SQLiteConstraintException) {
|
||||
appDb.bookDao.insert(book)
|
||||
}
|
||||
} else {
|
||||
newBooks.add(book)
|
||||
}
|
||||
}
|
||||
appDb.bookDao.update(*updateBooks.toTypedArray())
|
||||
appDb.bookDao.insert(*newBooks.toTypedArray())
|
||||
}
|
||||
fileToListT<Bookmark>(path, "bookmark.json")?.let {
|
||||
|
||||
Reference in new issue
Block a user