pull/1673/head
kunfei 3 years ago
parent 5c27c2c868
commit 6a0d6636f6
  1. 3
      app/src/main/java/io/legado/app/api/controller/BookController.kt
  2. 4
      app/src/main/java/io/legado/app/api/controller/BookSourceController.kt
  3. 16
      app/src/main/java/io/legado/app/data/entities/BaseSource.kt
  4. 6
      app/src/main/java/io/legado/app/data/entities/Book.kt
  5. 4
      app/src/main/java/io/legado/app/data/entities/BookChapter.kt
  6. 32
      app/src/main/java/io/legado/app/data/entities/BookSource.kt
  7. 4
      app/src/main/java/io/legado/app/data/entities/RssArticle.kt
  8. 2
      app/src/main/java/io/legado/app/data/entities/RssStar.kt
  9. 4
      app/src/main/java/io/legado/app/data/entities/SearchBook.kt
  10. 19
      app/src/main/java/io/legado/app/help/DefaultData.kt
  11. 2
      app/src/main/java/io/legado/app/help/JsExtensions.kt
  12. 16
      app/src/main/java/io/legado/app/help/ReadBookConfig.kt
  13. 40
      app/src/main/java/io/legado/app/help/SourceAnalyzer.kt
  14. 11
      app/src/main/java/io/legado/app/help/ThemeConfig.kt
  15. 4
      app/src/main/java/io/legado/app/help/storage/AppWebDav.kt
  16. 2
      app/src/main/java/io/legado/app/help/storage/BackupRestore.kt
  17. 7
      app/src/main/java/io/legado/app/help/storage/OldReplace.kt
  18. 7
      app/src/main/java/io/legado/app/help/storage/Restore.kt
  19. 15
      app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt
  20. 51
      app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt
  21. 4
      app/src/main/java/io/legado/app/model/localBook/LocalBook.kt
  22. 2
      app/src/main/java/io/legado/app/service/TTSReadAloudService.kt
  23. 8
      app/src/main/java/io/legado/app/ui/association/BaseAssociationViewModel.kt
  24. 2
      app/src/main/java/io/legado/app/ui/association/ImportReplaceRuleDialog.kt
  25. 7
      app/src/main/java/io/legado/app/ui/book/local/rule/TxtTocRuleActivity.kt
  26. 4
      app/src/main/java/io/legado/app/ui/book/local/rule/TxtTocRuleViewModel.kt
  27. 2
      app/src/main/java/io/legado/app/ui/book/read/config/ReadAloudConfigDialog.kt
  28. 7
      app/src/main/java/io/legado/app/ui/book/read/config/SpeakEngineDialog.kt
  29. 5
      app/src/main/java/io/legado/app/ui/book/read/config/TocRegexDialog.kt
  30. 4
      app/src/main/java/io/legado/app/ui/book/read/config/TocRegexViewModel.kt
  31. 4
      app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt
  32. 41
      app/src/main/java/io/legado/app/utils/DataExtensions.kt
  33. 15
      app/src/main/java/io/legado/app/utils/GsonExtensions.kt
  34. 4
      app/src/main/java/io/legado/app/utils/IntentExtensions.kt
  35. 3
      app/src/main/java/io/legado/app/web/socket/BookSourceDebugWebSocket.kt
  36. 3
      app/src/main/java/io/legado/app/web/socket/RssSourceDebugWebSocket.kt

@ -166,9 +166,8 @@ object BookController {
* 保存书籍 * 保存书籍
*/ */
fun saveBook(postData: String?): ReturnData { fun saveBook(postData: String?): ReturnData {
val book = GSON.fromJsonObject<Book>(postData)
val returnData = ReturnData() val returnData = ReturnData()
if (book != null) { GSON.fromJsonObject<Book>(postData).getOrNull()?.let { book ->
book.save() book.save()
AppWebDav.uploadBookProgress(book) AppWebDav.uploadBookProgress(book)
if (ReadBook.book?.bookUrl == book.bookUrl) { if (ReadBook.book?.bookUrl == book.bookUrl) {

@ -73,11 +73,13 @@ object BookSourceController {
fun deleteSources(postData: String?): ReturnData { fun deleteSources(postData: String?): ReturnData {
kotlin.runCatching { kotlin.runCatching {
GSON.fromJsonArray<BookSource>(postData)?.let { GSON.fromJsonArray<BookSource>(postData).getOrThrow()?.let {
it.forEach { source -> it.forEach { source ->
appDb.bookSourceDao.delete(source) appDb.bookSourceDao.delete(source)
} }
} }
}.onFailure {
return ReturnData().setErrorMsg(it.localizedMessage ?: "数据格式错误")
} }
return ReturnData().setData("已执行"/*okSources*/) return ReturnData().setData("已执行"/*okSources*/)
} }

@ -8,10 +8,7 @@ import io.legado.app.help.AppConfig
import io.legado.app.help.CacheManager import io.legado.app.help.CacheManager
import io.legado.app.help.JsExtensions import io.legado.app.help.JsExtensions
import io.legado.app.help.http.CookieStore import io.legado.app.help.http.CookieStore
import io.legado.app.utils.EncoderUtils import io.legado.app.utils.*
import io.legado.app.utils.GSON
import io.legado.app.utils.fromJsonArray
import io.legado.app.utils.fromJsonObject
import javax.script.SimpleBindings import javax.script.SimpleBindings
/** /**
@ -30,7 +27,10 @@ interface BaseSource : JsExtensions {
fun getKey(): String fun getKey(): String
fun loginUi(): List<RowUi>? { fun loginUi(): List<RowUi>? {
return GSON.fromJsonArray(loginUi) return GSON.fromJsonArray<RowUi>(loginUi)
.onFailure {
it.printOnDebug()
}.getOrNull()
} }
fun getLoginJs(): String? { fun getLoginJs(): String? {
@ -64,7 +64,7 @@ interface BaseSource : JsExtensions {
evalJS(it.substring(4, it.lastIndexOf("<"))).toString() evalJS(it.substring(4, it.lastIndexOf("<"))).toString()
else -> it else -> it
} }
)?.let { map -> ).getOrNull()?.let { map ->
putAll(map) putAll(map)
} }
} }
@ -84,7 +84,7 @@ interface BaseSource : JsExtensions {
fun getLoginHeaderMap(): Map<String, String>? { fun getLoginHeaderMap(): Map<String, String>? {
val cache = getLoginHeader() ?: return null val cache = getLoginHeader() ?: return null
return GSON.fromJsonObject(cache) return GSON.fromJsonObject<Map<String, String>>(cache).getOrNull()
} }
/** /**
@ -117,7 +117,7 @@ interface BaseSource : JsExtensions {
} }
fun getLoginInfoMap(): Map<String, String>? { fun getLoginInfoMap(): Map<String, String>? {
return GSON.fromJsonObject(getLoginInfo()) return GSON.fromJsonObject<Map<String, String>>(getLoginInfo()).getOrNull()
} }
/** /**

@ -92,8 +92,8 @@ data class Book(
@delegate:Transient @delegate:Transient
@delegate:Ignore @delegate:Ignore
@IgnoredOnParcel @IgnoredOnParcel
override val variableMap by lazy { override val variableMap: HashMap<String, String> by lazy {
GSON.fromJsonObject<HashMap<String, String>>(variable) ?: HashMap() GSON.fromJsonObject<HashMap<String, String>>(variable).getOrNull() ?: hashMapOf()
} }
override fun putVariable(key: String, value: String?) { override fun putVariable(key: String, value: String?) {
@ -307,6 +307,6 @@ data class Book(
fun readConfigToString(config: ReadConfig?): String = GSON.toJson(config) fun readConfigToString(config: ReadConfig?): String = GSON.toJson(config)
@TypeConverter @TypeConverter
fun stringToReadConfig(json: String?) = GSON.fromJsonObject<ReadConfig>(json) fun stringToReadConfig(json: String?) = GSON.fromJsonObject<ReadConfig>(json).getOrNull()
} }
} }

@ -50,8 +50,8 @@ data class BookChapter(
@delegate:Transient @delegate:Transient
@delegate:Ignore @delegate:Ignore
@IgnoredOnParcel @IgnoredOnParcel
override val variableMap by lazy { override val variableMap: HashMap<String, String> by lazy {
GSON.fromJsonObject<HashMap<String, String>>(variable) ?: HashMap() GSON.fromJsonObject<HashMap<String, String>>(variable).getOrNull() ?: hashMapOf()
} }
override fun putVariable(key: String, value: String?) { override fun putVariable(key: String, value: String?) {

@ -108,7 +108,7 @@ data class BookSource(
} }
} }
if (ruleStr.isJsonArray()) { if (ruleStr.isJsonArray()) {
GSON.fromJsonArray<ExploreKind>(ruleStr)?.let { GSON.fromJsonArray<ExploreKind>(ruleStr).getOrThrow()?.let {
kinds.addAll(it) kinds.addAll(it)
} }
} else { } else {
@ -219,34 +219,44 @@ data class BookSource(
class Converters { class Converters {
@TypeConverter @TypeConverter
fun exploreRuleToString(exploreRule: ExploreRule?): String = GSON.toJson(exploreRule) fun exploreRuleToString(exploreRule: ExploreRule?): String =
GSON.toJson(exploreRule)
@TypeConverter @TypeConverter
fun stringToExploreRule(json: String?) = GSON.fromJsonObject<ExploreRule>(json) fun stringToExploreRule(json: String?) =
GSON.fromJsonObject<ExploreRule>(json).getOrNull()
@TypeConverter @TypeConverter
fun searchRuleToString(searchRule: SearchRule?): String = GSON.toJson(searchRule) fun searchRuleToString(searchRule: SearchRule?): String =
GSON.toJson(searchRule)
@TypeConverter @TypeConverter
fun stringToSearchRule(json: String?) = GSON.fromJsonObject<SearchRule>(json) fun stringToSearchRule(json: String?) =
GSON.fromJsonObject<SearchRule>(json).getOrNull()
@TypeConverter @TypeConverter
fun bookInfoRuleToString(bookInfoRule: BookInfoRule?): String = GSON.toJson(bookInfoRule) fun bookInfoRuleToString(bookInfoRule: BookInfoRule?): String =
GSON.toJson(bookInfoRule)
@TypeConverter @TypeConverter
fun stringToBookInfoRule(json: String?) = GSON.fromJsonObject<BookInfoRule>(json) fun stringToBookInfoRule(json: String?) =
GSON.fromJsonObject<BookInfoRule>(json).getOrNull()
@TypeConverter @TypeConverter
fun tocRuleToString(tocRule: TocRule?): String = GSON.toJson(tocRule) fun tocRuleToString(tocRule: TocRule?): String =
GSON.toJson(tocRule)
@TypeConverter @TypeConverter
fun stringToTocRule(json: String?) = GSON.fromJsonObject<TocRule>(json) fun stringToTocRule(json: String?) =
GSON.fromJsonObject<TocRule>(json).getOrNull()
@TypeConverter @TypeConverter
fun contentRuleToString(contentRule: ContentRule?): String = GSON.toJson(contentRule) fun contentRuleToString(contentRule: ContentRule?): String =
GSON.toJson(contentRule)
@TypeConverter @TypeConverter
fun stringToContentRule(json: String?) = GSON.fromJsonObject<ContentRule>(json) fun stringToContentRule(json: String?) =
GSON.fromJsonObject<ContentRule>(json).getOrNull()
} }
} }

@ -36,8 +36,8 @@ data class RssArticle(
@delegate:Transient @delegate:Transient
@delegate:Ignore @delegate:Ignore
@IgnoredOnParcel @IgnoredOnParcel
override val variableMap by lazy { override val variableMap: HashMap<String, String> by lazy {
GSON.fromJsonObject<HashMap<String, String>>(variable) ?: HashMap() GSON.fromJsonObject<HashMap<String, String>>(variable).getOrNull() ?: hashMapOf()
} }
override fun putVariable(key: String, value: String?) { override fun putVariable(key: String, value: String?) {

@ -29,7 +29,7 @@ data class RssStar(
@delegate:Ignore @delegate:Ignore
@IgnoredOnParcel @IgnoredOnParcel
override val variableMap by lazy { override val variableMap by lazy {
GSON.fromJsonObject<HashMap<String, String>>(variable) ?: HashMap() GSON.fromJsonObject<HashMap<String, String>>(variable).getOrNull() ?: hashMapOf()
} }
override fun putVariable(key: String, value: String?) { override fun putVariable(key: String, value: String?) {

@ -59,8 +59,8 @@ data class SearchBook(
@delegate:Transient @delegate:Transient
@delegate:Ignore @delegate:Ignore
@IgnoredOnParcel @IgnoredOnParcel
override val variableMap by lazy { override val variableMap: HashMap<String, String> by lazy {
GSON.fromJsonObject<HashMap<String, String>>(variable) ?: HashMap() GSON.fromJsonObject<HashMap<String, String>>(variable).getOrNull() ?: HashMap()
} }
override fun putVariable(key: String, value: String?) { override fun putVariable(key: String, value: String?) {

@ -28,7 +28,8 @@ object DefaultData {
appCtx.assets.open("defaultData${File.separator}${ReadBookConfig.configFileName}") appCtx.assets.open("defaultData${File.separator}${ReadBookConfig.configFileName}")
.readBytes() .readBytes()
) )
GSON.fromJsonArray(json)!! GSON.fromJsonArray<ReadBookConfig.Config>(json).getOrNull()
?: emptyList()
} }
val txtTocRules: List<TxtTocRule> by lazy { val txtTocRules: List<TxtTocRule> by lazy {
@ -36,7 +37,7 @@ object DefaultData {
appCtx.assets.open("defaultData${File.separator}$txtTocRuleFileName") appCtx.assets.open("defaultData${File.separator}$txtTocRuleFileName")
.readBytes() .readBytes()
) )
GSON.fromJsonArray(json)!! GSON.fromJsonArray<TxtTocRule>(json).getOrNull() ?: emptyList()
} }
val themeConfigs: List<ThemeConfig.Config> by lazy { val themeConfigs: List<ThemeConfig.Config> by lazy {
@ -44,15 +45,17 @@ object DefaultData {
appCtx.assets.open("defaultData${File.separator}${ThemeConfig.configFileName}") appCtx.assets.open("defaultData${File.separator}${ThemeConfig.configFileName}")
.readBytes() .readBytes()
) )
GSON.fromJsonArray(json)!! GSON.fromJsonArray<ThemeConfig.Config>(json).getOrNull() ?: emptyList()
} }
val rssSources: List<RssSource> by lazy { val rssSources: List<RssSource> by lazy {
val json = String( kotlin.runCatching {
appCtx.assets.open("defaultData${File.separator}rssSources.json") val json = String(
.readBytes() appCtx.assets.open("defaultData${File.separator}rssSources.json")
) .readBytes()
RssSource.fromJsonArray(json) )
RssSource.fromJsonArray(json)
}.getOrDefault(emptyList())
} }
fun importDefaultHttpTTS() { fun importDefaultHttpTTS() {

@ -97,7 +97,7 @@ interface JsExtensions {
fun connect(urlStr: String, header: String?): StrResponse { fun connect(urlStr: String, header: String?): StrResponse {
return runBlocking { return runBlocking {
val headerMap = GSON.fromJsonObject<Map<String, String>>(header) val headerMap = GSON.fromJsonObject<Map<String, String>>(header).getOrNull()
val analyzeUrl = AnalyzeUrl(urlStr, headerMapF = headerMap, source = getSource()) val analyzeUrl = AnalyzeUrl(urlStr, headerMapF = headerMap, source = getSource())
kotlin.runCatching { kotlin.runCatching {
analyzeUrl.getStrResponseAwait() analyzeUrl.getStrResponseAwait()

@ -6,15 +6,17 @@ import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import androidx.annotation.Keep import androidx.annotation.Keep
import io.legado.app.R import io.legado.app.R
import io.legado.app.constant.AppLog
import io.legado.app.constant.PreferKey import io.legado.app.constant.PreferKey
import io.legado.app.help.coroutine.Coroutine import io.legado.app.help.coroutine.Coroutine
import io.legado.app.model.NoStackTraceException
import io.legado.app.ui.book.read.page.provider.ChapterProvider import io.legado.app.ui.book.read.page.provider.ChapterProvider
import io.legado.app.utils.* import io.legado.app.utils.*
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import splitties.init.appCtx import splitties.init.appCtx
import java.io.File import java.io.File
import java.io.IOException
/** /**
* 阅读界面配置 * 阅读界面配置
@ -60,9 +62,9 @@ object ReadBookConfig {
if (configFile.exists()) { if (configFile.exists()) {
try { try {
val json = configFile.readText() val json = configFile.readText()
configs = GSON.fromJsonArray(json) configs = GSON.fromJsonArray<Config>(json).getOrThrow()
} catch (e: Exception) { } catch (e: Exception) {
e.printOnDebug() AppLog.put("读取排版配置文件出错", e)
} }
} }
(configs ?: DefaultData.readConfigs).let { (configs ?: DefaultData.readConfigs).let {
@ -77,7 +79,7 @@ object ReadBookConfig {
if (configFile.exists()) { if (configFile.exists()) {
try { try {
val json = configFile.readText() val json = configFile.readText()
c = GSON.fromJsonObject(json) c = GSON.fromJsonObject<Config>(json).getOrThrow()
} catch (e: Exception) { } catch (e: Exception) {
e.printOnDebug() e.printOnDebug()
} }
@ -325,7 +327,7 @@ object ReadBookConfig {
} }
fun getExportConfig(): Config { fun getExportConfig(): Config {
val exportConfig = GSON.fromJsonObject<Config>(GSON.toJson(durConfig))!! val exportConfig = durConfig.deepCopy()
if (shareLayout) { if (shareLayout) {
exportConfig.textFont = shareConfig.textFont exportConfig.textFont = shareConfig.textFont
exportConfig.textBold = shareConfig.textBold exportConfig.textBold = shareConfig.textBold
@ -364,6 +366,7 @@ object ReadBookConfig {
return exportConfig return exportConfig
} }
@Throws(IOException::class)
suspend fun import(byteArray: ByteArray): Config { suspend fun import(byteArray: ByteArray): Config {
return withContext(IO) { return withContext(IO) {
val configZipPath = FileUtils.getPath(appCtx.externalCache, "readConfig.zip") val configZipPath = FileUtils.getPath(appCtx.externalCache, "readConfig.zip")
@ -376,7 +379,8 @@ object ReadBookConfig {
ZipUtils.unzipFile(zipFile, FileUtils.createFolderIfNotExist(configDirPath)) ZipUtils.unzipFile(zipFile, FileUtils.createFolderIfNotExist(configDirPath))
val configDir = FileUtils.createFolderIfNotExist(configDirPath) val configDir = FileUtils.createFolderIfNotExist(configDirPath)
val configFile = configDir.getFile(configFileName) val configFile = configDir.getFile(configFileName)
val config: Config = GSON.fromJsonObject(configFile.readText())!! val config: Config = GSON.fromJsonObject<Config>(configFile.readText()).getOrThrow()
?: throw NoStackTraceException("排版配置格式错误")
if (config.textFont.isNotEmpty()) { if (config.textFont.isNotEmpty()) {
val fontName = FileUtils.getName(config.textFont) val fontName = FileUtils.getName(config.textFont)
val fontPath = val fontPath =

@ -3,6 +3,7 @@ package io.legado.app.help
import androidx.annotation.Keep import androidx.annotation.Keep
import com.jayway.jsonpath.JsonPath import com.jayway.jsonpath.JsonPath
import io.legado.app.constant.AppConst import io.legado.app.constant.AppConst
import io.legado.app.constant.AppLog
import io.legado.app.constant.BookType import io.legado.app.constant.BookType
import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.BookSource
import io.legado.app.data.entities.rule.* import io.legado.app.data.entities.rule.*
@ -31,11 +32,10 @@ object SourceAnalyzer {
fun jsonToBookSource(json: String): BookSource? { fun jsonToBookSource(json: String): BookSource? {
val source = BookSource() val source = BookSource()
val sourceAny = try { val sourceAny = GSON.fromJsonObject<BookSourceAny>(json.trim())
GSON.fromJsonObject<BookSourceAny>(json.trim()) .onFailure {
} catch (e: Exception) { AppLog.put("转化书源出错", it)
null }.getOrNull()
}
try { try {
if (sourceAny?.ruleToc == null) { if (sourceAny?.ruleToc == null) {
source.apply { source.apply {
@ -132,30 +132,40 @@ object SourceAnalyzer {
source.weight = sourceAny.weight source.weight = sourceAny.weight
source.exploreUrl = sourceAny.exploreUrl source.exploreUrl = sourceAny.exploreUrl
source.ruleExplore = if (sourceAny.ruleExplore is String) { source.ruleExplore = if (sourceAny.ruleExplore is String) {
GSON.fromJsonObject(sourceAny.ruleExplore.toString()) GSON.fromJsonObject<ExploreRule>(sourceAny.ruleExplore.toString())
.getOrNull()
} else { } else {
GSON.fromJsonObject(GSON.toJson(sourceAny.ruleExplore)) GSON.fromJsonObject<ExploreRule>(GSON.toJson(sourceAny.ruleExplore))
.getOrNull()
} }
source.searchUrl = sourceAny.searchUrl source.searchUrl = sourceAny.searchUrl
source.ruleSearch = if (sourceAny.ruleSearch is String) { source.ruleSearch = if (sourceAny.ruleSearch is String) {
GSON.fromJsonObject(sourceAny.ruleSearch.toString()) GSON.fromJsonObject<SearchRule>(sourceAny.ruleSearch.toString())
.getOrNull()
} else { } else {
GSON.fromJsonObject(GSON.toJson(sourceAny.ruleSearch)) GSON.fromJsonObject<SearchRule>(GSON.toJson(sourceAny.ruleSearch))
.getOrNull()
} }
source.ruleBookInfo = if (sourceAny.ruleBookInfo is String) { source.ruleBookInfo = if (sourceAny.ruleBookInfo is String) {
GSON.fromJsonObject(sourceAny.ruleBookInfo.toString()) GSON.fromJsonObject<BookInfoRule>(sourceAny.ruleBookInfo.toString())
.getOrNull()
} else { } else {
GSON.fromJsonObject(GSON.toJson(sourceAny.ruleBookInfo)) GSON.fromJsonObject<BookInfoRule>(GSON.toJson(sourceAny.ruleBookInfo))
.getOrNull()
} }
source.ruleToc = if (sourceAny.ruleToc is String) { source.ruleToc = if (sourceAny.ruleToc is String) {
GSON.fromJsonObject(sourceAny.ruleToc.toString()) GSON.fromJsonObject<TocRule>(sourceAny.ruleToc.toString())
.getOrNull()
} else { } else {
GSON.fromJsonObject(GSON.toJson(sourceAny.ruleToc)) GSON.fromJsonObject<TocRule>(GSON.toJson(sourceAny.ruleToc))
.getOrNull()
} }
source.ruleContent = if (sourceAny.ruleContent is String) { source.ruleContent = if (sourceAny.ruleContent is String) {
GSON.fromJsonObject(sourceAny.ruleContent.toString()) GSON.fromJsonObject<ContentRule>(sourceAny.ruleContent.toString())
.getOrNull()
} else { } else {
GSON.fromJsonObject(GSON.toJson(sourceAny.ruleContent)) GSON.fromJsonObject<ContentRule>(GSON.toJson(sourceAny.ruleContent))
.getOrNull()
} }
} }
} catch (e: Exception) { } catch (e: Exception) {

@ -83,10 +83,11 @@ object ThemeConfig {
} }
fun addConfig(json: String): Boolean { fun addConfig(json: String): Boolean {
GSON.fromJsonObject<Config>(json.trim { it < ' ' })?.let { GSON.fromJsonObject<Config>(json.trim { it < ' ' }).getOrNull()
addConfig(it) ?.let {
return true addConfig(it)
} return true
}
return false return false
} }
@ -106,7 +107,7 @@ object ThemeConfig {
if (configFile.exists()) { if (configFile.exists()) {
kotlin.runCatching { kotlin.runCatching {
val json = configFile.readText() val json = configFile.readText()
return GSON.fromJsonArray(json) return GSON.fromJsonArray<Config>(json).getOrThrow()
}.onFailure { }.onFailure {
it.printOnDebug() it.printOnDebug()
} }

@ -172,9 +172,7 @@ object AppWebDav {
WebDav(url).download()?.let { byteArray -> WebDav(url).download()?.let { byteArray ->
val json = String(byteArray) val json = String(byteArray)
if (json.isJson()) { if (json.isJson()) {
GSON.fromJsonObject<BookProgress>(json)?.let { return GSON.fromJsonObject<BookProgress>(json).getOrNull()
return it
}
} }
} }
} }

@ -13,7 +13,7 @@ abstract class BackupRestore {
val ignoreConfig: HashMap<String, Boolean> by lazy { val ignoreConfig: HashMap<String, Boolean> by lazy {
val file = FileUtils.createFileIfNotExist(ignoreConfigPath) val file = FileUtils.createFileIfNotExist(ignoreConfigPath)
val json = file.readText() val json = file.readText()
GSON.fromJsonObject<HashMap<String, Boolean>>(json) ?: hashMapOf() GSON.fromJsonObject<HashMap<String, Boolean>>(json).getOrNull() ?: hashMapOf()
} }
//忽略key //忽略key

@ -20,12 +20,9 @@ object OldReplace {
} }
private fun jsonToReplaceRule(json: String): ReplaceRule? { private fun jsonToReplaceRule(json: String): ReplaceRule? {
var replaceRule: ReplaceRule? = null val replaceRule: ReplaceRule? = GSON.fromJsonObject<ReplaceRule>(json.trim()).getOrNull()
runCatching { runCatching {
replaceRule = GSON.fromJsonObject<ReplaceRule>(json.trim()) if (replaceRule == null || replaceRule.pattern.isBlank()) {
}
runCatching {
if (replaceRule == null || replaceRule?.pattern.isNullOrBlank()) {
val jsonItem = jsonPath.parse(json.trim()) val jsonItem = jsonPath.parse(json.trim())
val rule = ReplaceRule() val rule = ReplaceRule()
rule.id = jsonItem.readLong("$.id") ?: System.currentTimeMillis() rule.id = jsonItem.readLong("$.id") ?: System.currentTimeMillis()

@ -6,6 +6,7 @@ import androidx.documentfile.provider.DocumentFile
import io.legado.app.BuildConfig import io.legado.app.BuildConfig
import io.legado.app.R import io.legado.app.R
import io.legado.app.constant.AppConst.androidId import io.legado.app.constant.AppConst.androidId
import io.legado.app.constant.AppLog
import io.legado.app.constant.EventBus import io.legado.app.constant.EventBus
import io.legado.app.constant.PreferKey import io.legado.app.constant.PreferKey
import io.legado.app.data.appDb import io.legado.app.data.appDb
@ -20,7 +21,6 @@ import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import splitties.init.appCtx import splitties.init.appCtx
import java.io.File import java.io.File
@ -193,9 +193,10 @@ object Restore : BackupRestore() {
try { try {
val file = FileUtils.createFileIfNotExist(path + File.separator + fileName) val file = FileUtils.createFileIfNotExist(path + File.separator + fileName)
val json = file.readText() val json = file.readText()
return GSON.fromJsonArray(json) return GSON.fromJsonArray<T>(json).getOrThrow()
} catch (e: Exception) { } catch (e: Exception) {
e.printOnDebug() AppLog.put("读取文件出错\n${e.localizedMessage}", e)
appCtx.toastOnUi("读取文件出错\n${e.localizedMessage}")
} }
return null return null
} }

@ -341,8 +341,11 @@ class AnalyzeRule(
val putMatcher = putPattern.matcher(vRuleStr) val putMatcher = putPattern.matcher(vRuleStr)
while (putMatcher.find()) { while (putMatcher.find()) {
vRuleStr = vRuleStr.replace(putMatcher.group(), "") vRuleStr = vRuleStr.replace(putMatcher.group(), "")
val map = GSON.fromJsonObject<Map<String, String>>(putMatcher.group(1)) GSON.fromJsonObject<Map<String, String>>(putMatcher.group(1))
map?.let { putMap.putAll(map) } .getOrNull()
?.let {
putMap.putAll(it)
}
} }
return vRuleStr return vRuleStr
} }
@ -379,7 +382,7 @@ class AnalyzeRule(
* 分解规则生成规则列表 * 分解规则生成规则列表
*/ */
fun splitSourceRule(ruleStr: String?, allInOne: Boolean = false): List<SourceRule> { fun splitSourceRule(ruleStr: String?, allInOne: Boolean = false): List<SourceRule> {
if (ruleStr.isNullOrEmpty()) return ArrayList<SourceRule>() if (ruleStr.isNullOrEmpty()) return emptyList()
val ruleList = ArrayList<SourceRule>() val ruleList = ArrayList<SourceRule>()
var mMode: Mode = Mode.Default var mMode: Mode = Mode.Default
var start = 0 var start = 0
@ -597,9 +600,9 @@ class AnalyzeRule(
private fun isRule(ruleStr: String): Boolean { private fun isRule(ruleStr: String): Boolean {
return ruleStr.startsWith('@') //js首个字符不可能是@,除非是装饰器,所以@开头规定为规则 return ruleStr.startsWith('@') //js首个字符不可能是@,除非是装饰器,所以@开头规定为规则
|| ruleStr.startsWith("$.") || ruleStr.startsWith("$.")
|| ruleStr.startsWith("$[") || ruleStr.startsWith("$[")
|| ruleStr.startsWith("//") || ruleStr.startsWith("//")
} }
} }

@ -167,34 +167,35 @@ class AnalyzeUrl(
baseUrl = it baseUrl = it
} }
if (urlNoOption.length != ruleUrl.length) { if (urlNoOption.length != ruleUrl.length) {
GSON.fromJsonObject<UrlOption>(ruleUrl.substring(urlMatcher.end()))?.let { option -> GSON.fromJsonObject<UrlOption>(ruleUrl.substring(urlMatcher.end())).getOrNull()
option.method?.let { ?.let { option ->
if (it.equals("POST", true)) method = RequestMethod.POST option.method?.let {
} if (it.equals("POST", true)) method = RequestMethod.POST
option.headers?.let { headers -> }
if (headers is Map<*, *>) { option.headers?.let { headers ->
headers.forEach { entry -> if (headers is Map<*, *>) {
headerMap[entry.key.toString()] = entry.value.toString() headers.forEach { entry ->
headerMap[entry.key.toString()] = entry.value.toString()
}
} else if (headers is String) {
GSON.fromJsonObject<Map<String, String>>(headers).getOrNull()
?.let { headerMap.putAll(it) }
} }
} else if (headers is String) {
GSON.fromJsonObject<Map<String, String>>(headers)
?.let { headerMap.putAll(it) }
} }
} option.body?.let {
option.body?.let { body = if (it is String) it else GSON.toJson(it)
body = if (it is String) it else GSON.toJson(it) }
} type = option.type
type = option.type charset = option.charset
charset = option.charset retry = option.retry
retry = option.retry useWebView = option.webView?.toString()?.isNotBlank() == true
useWebView = option.webView?.toString()?.isNotBlank() == true webJs = option.webJs
webJs = option.webJs option.js?.let { jsStr ->
option.js?.let { jsStr -> evalJS(jsStr, url)?.toString()?.let {
evalJS(jsStr, url)?.toString()?.let { url = it
url = it }
} }
} }
}
} }
headerMap[UA_NAME] ?: let { headerMap[UA_NAME] ?: let {
headerMap[UA_NAME] = AppConfig.userAgent headerMap[UA_NAME] = AppConfig.userAgent
@ -510,7 +511,7 @@ class AnalyzeUrl(
suspend fun upload(fileName: String, file: Any, contentType: String): StrResponse { suspend fun upload(fileName: String, file: Any, contentType: String): StrResponse {
return getProxyClient(proxy).newCallStrResponse(retry) { return getProxyClient(proxy).newCallStrResponse(retry) {
url(urlNoQuery) url(urlNoQuery)
val bodyMap = GSON.fromJsonObject<HashMap<String, Any>>(body)!! val bodyMap = GSON.fromJsonObject<HashMap<String, Any>>(body).getOrNull()!!
bodyMap.forEach { entry -> bodyMap.forEach { entry ->
if (entry.value.toString() == "fileRequest") { if (entry.value.toString() == "fileRequest") {
bodyMap[entry.key] = mapOf( bodyMap[entry.key] = mapOf(

@ -141,8 +141,8 @@ object LocalBook {
//将文件名注入到脚步的src变量中 //将文件名注入到脚步的src变量中
SimpleBindings().also { it["src"] = tempFileName } SimpleBindings().also { it["src"] = tempFileName }
).toString() ).toString()
val bookMess = val bookMess = GSON.fromJsonObject<HashMap<String, String>>(jsonStr)
GSON.fromJsonObject<HashMap<String, String>>(jsonStr) ?: HashMap() .getOrThrow() ?: HashMap()
name = bookMess["name"] ?: tempFileName name = bookMess["name"] ?: tempFileName
author = bookMess["author"]?.takeIf { it.length != tempFileName.length } ?: "" author = bookMess["author"]?.takeIf { it.length != tempFileName.length } ?: ""
} catch (e: Exception) { } catch (e: Exception) {

@ -37,7 +37,7 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener
@Synchronized @Synchronized
private fun initTts() { private fun initTts() {
ttsInitFinish = false ttsInitFinish = false
val engine = GSON.fromJsonObject<SelectItem<String>>(ReadAloud.ttsEngine)?.value val engine = GSON.fromJsonObject<SelectItem<String>>(ReadAloud.ttsEngine).getOrNull()?.value
textToSpeech = if (engine.isNullOrBlank()) { textToSpeech = if (engine.isNullOrBlank()) {
TextToSpeech(this, this) TextToSpeech(this, this)
} else { } else {

@ -19,11 +19,11 @@ abstract class BaseAssociationViewModel(application: Application) : BaseViewMode
fun importTextTocRule(json: String, finally: (title: String, msg: String) -> Unit) { fun importTextTocRule(json: String, finally: (title: String, msg: String) -> Unit) {
execute { execute {
if (json.isJsonArray()) { if (json.isJsonArray()) {
GSON.fromJsonArray<TxtTocRule>(json)?.let { GSON.fromJsonArray<TxtTocRule>(json).getOrThrow()?.let {
appDb.txtTocRuleDao.insert(*it.toTypedArray()) appDb.txtTocRuleDao.insert(*it.toTypedArray())
} ?: throw NoStackTraceException("格式不对") } ?: throw NoStackTraceException("格式不对")
} else { } else {
GSON.fromJsonObject<TxtTocRule>(json)?.let { GSON.fromJsonObject<TxtTocRule>(json).getOrThrow()?.let {
appDb.txtTocRuleDao.insert(it) appDb.txtTocRuleDao.insert(it)
} ?: throw NoStackTraceException("格式不对") } ?: throw NoStackTraceException("格式不对")
} }
@ -63,11 +63,11 @@ abstract class BaseAssociationViewModel(application: Application) : BaseViewMode
fun importTheme(json: String, finally: (title: String, msg: String) -> Unit) { fun importTheme(json: String, finally: (title: String, msg: String) -> Unit) {
execute { execute {
if (json.isJsonArray()) { if (json.isJsonArray()) {
GSON.fromJsonArray<ThemeConfig.Config>(json)?.forEach { GSON.fromJsonArray<ThemeConfig.Config>(json).getOrThrow()?.forEach {
ThemeConfig.addConfig(it) ThemeConfig.addConfig(it)
} ?: throw NoStackTraceException("格式不对") } ?: throw NoStackTraceException("格式不对")
} else { } else {
GSON.fromJsonObject<ThemeConfig.Config>(json)?.let { GSON.fromJsonObject<ThemeConfig.Config>(json).getOrThrow()?.let {
ThemeConfig.addConfig(it) ThemeConfig.addConfig(it)
} ?: throw NoStackTraceException("格式不对") } ?: throw NoStackTraceException("格式不对")
} }

@ -181,7 +181,7 @@ class ImportReplaceRuleDialog() : BaseDialogFragment(R.layout.dialog_recycler_vi
override fun onCodeSave(code: String, requestId: String?) { override fun onCodeSave(code: String, requestId: String?) {
requestId?.toInt()?.let { requestId?.toInt()?.let {
GSON.fromJsonObject<ReplaceRule>(code)?.let { rule -> GSON.fromJsonObject<ReplaceRule>(code).getOrNull()?.let { rule ->
viewModel.allRules[it] = rule viewModel.allRules[it] = rule
adapter.setItem(it, rule) adapter.setItem(it, rule)
} }

@ -6,7 +6,6 @@ import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper
import com.google.android.material.snackbar.Snackbar
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.VMBaseActivity import io.legado.app.base.VMBaseActivity
import io.legado.app.data.appDb import io.legado.app.data.appDb
@ -22,8 +21,8 @@ import io.legado.app.ui.widget.recycler.ItemTouchCallback
import io.legado.app.ui.widget.recycler.VerticalDivider import io.legado.app.ui.widget.recycler.VerticalDivider
import io.legado.app.utils.ACache import io.legado.app.utils.ACache
import io.legado.app.utils.setEdgeEffectColor import io.legado.app.utils.setEdgeEffectColor
import io.legado.app.utils.snackbar
import io.legado.app.utils.splitNotBlank import io.legado.app.utils.splitNotBlank
import io.legado.app.utils.toastOnUi
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -184,10 +183,8 @@ class TxtTocRuleActivity : VMBaseActivity<ActivityTxtTocRuleBinding, TxtTocRuleV
cacheUrls.add(0, it) cacheUrls.add(0, it)
aCache.put(importTocRuleKey, cacheUrls.joinToString(",")) aCache.put(importTocRuleKey, cacheUrls.joinToString(","))
} }
Snackbar.make(binding.root, R.string.importing, Snackbar.LENGTH_INDEFINITE)
.show()
viewModel.importOnLine(it) { msg -> viewModel.importOnLine(it) { msg ->
binding.root.snackbar(msg) toastOnUi(msg)
} }
} }
} }

@ -42,14 +42,14 @@ class TxtTocRuleViewModel(app: Application) : BaseViewModel(app) {
okHttpClient.newCallResponseBody { okHttpClient.newCallResponseBody {
url(url) url(url)
}.text("utf-8").let { json -> }.text("utf-8").let { json ->
GSON.fromJsonArray<TxtTocRule>(json)?.let { GSON.fromJsonArray<TxtTocRule>(json).getOrThrow()?.let {
appDb.txtTocRuleDao.insert(*it.toTypedArray()) appDb.txtTocRuleDao.insert(*it.toTypedArray())
} }
} }
}.onSuccess { }.onSuccess {
finally("导入成功") finally("导入成功")
}.onError { }.onError {
finally("导入失败") finally("导入失败\n${it.localizedMessage}")
} }
} }

@ -65,7 +65,7 @@ class ReadAloudConfigDialog : DialogFragment() {
return appDb.httpTTSDao.getName(ttsEngine.toLong()) return appDb.httpTTSDao.getName(ttsEngine.toLong())
?: getString(R.string.system_tts) ?: getString(R.string.system_tts)
} }
return GSON.fromJsonObject<SelectItem<String>>(ttsEngine)?.title return GSON.fromJsonObject<SelectItem<String>>(ttsEngine).getOrNull()?.title
?: getString(R.string.system_tts) ?: getString(R.string.system_tts)
} }

@ -95,8 +95,8 @@ class SpeakEngineDialog(val callBack: CallBack) : BaseDialogFragment(R.layout.di
labelSys.visible() labelSys.visible()
cbName.text = engine.label cbName.text = engine.label
cbName.tag = engine.name cbName.tag = engine.name
cbName.isChecked = cbName.isChecked = GSON.fromJsonObject<SelectItem<String>>(ttsEngine)
GSON.fromJsonObject<SelectItem<String>>(ttsEngine)?.value == cbName.tag .getOrNull()?.value == cbName.tag
cbName.setOnClickListener { cbName.setOnClickListener {
upTts(GSON.toJson(SelectItem(engine.label, engine.name))) upTts(GSON.toJson(SelectItem(engine.label, engine.name)))
} }
@ -192,7 +192,8 @@ class SpeakEngineDialog(val callBack: CallBack) : BaseDialogFragment(R.layout.di
private fun upTts(tts: String) { private fun upTts(tts: String) {
ttsEngine = tts ttsEngine = tts
sysTtsViews.forEach { sysTtsViews.forEach {
it.isChecked = GSON.fromJsonObject<SelectItem<String>>(ttsEngine)?.value == it.tag it.isChecked = GSON.fromJsonObject<SelectItem<String>>(ttsEngine)
.getOrNull()?.value == it.tag
} }
adapter.notifyItemRangeChanged(adapter.getHeaderCount(), adapter.itemCount) adapter.notifyItemRangeChanged(adapter.getHeaderCount(), adapter.itemCount)
} }

@ -10,7 +10,6 @@ import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.snackbar.Snackbar
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.BaseDialogFragment import io.legado.app.base.BaseDialogFragment
import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.ItemViewHolder
@ -154,10 +153,8 @@ class TocRegexDialog() : BaseDialogFragment(R.layout.dialog_toc_regex),
cacheUrls.add(0, it) cacheUrls.add(0, it)
aCache.put(importTocRuleKey, cacheUrls.joinToString(",")) aCache.put(importTocRuleKey, cacheUrls.joinToString(","))
} }
Snackbar.make(binding.toolBar, R.string.importing, Snackbar.LENGTH_INDEFINITE)
.show()
viewModel.importOnLine(it) { msg -> viewModel.importOnLine(it) { msg ->
binding.toolBar.snackbar(msg) toastOnUi(msg)
} }
} }
} }

@ -33,14 +33,14 @@ class TocRegexViewModel(application: Application) : BaseViewModel(application) {
okHttpClient.newCallResponseBody { okHttpClient.newCallResponseBody {
url(url) url(url)
}.text("utf-8").let { json -> }.text("utf-8").let { json ->
GSON.fromJsonArray<TxtTocRule>(json)?.let { GSON.fromJsonArray<TxtTocRule>(json).getOrThrow()?.let {
appDb.txtTocRuleDao.insert(*it.toTypedArray()) appDb.txtTocRuleDao.insert(*it.toTypedArray())
} }
} }
}.onSuccess { }.onSuccess {
finally("导入成功") finally("导入成功")
}.onError { }.onError {
finally("导入失败") finally("导入失败\n${it.localizedMessage}")
} }
} }

@ -126,7 +126,7 @@ class BookshelfViewModel(application: Application) : BaseViewModel(application)
private fun importBookshelfByJson(json: String, groupId: Long) { private fun importBookshelfByJson(json: String, groupId: Long) {
execute { execute {
val bookSources = appDb.bookSourceDao.allEnabled val bookSources = appDb.bookSourceDao.allEnabled
GSON.fromJsonArray<Map<String, String?>>(json)?.forEach { bookInfo -> GSON.fromJsonArray<Map<String, String?>>(json).getOrThrow()?.forEach { bookInfo ->
if (!isActive) return@execute if (!isActive) return@execute
val name = bookInfo["name"] ?: "" val name = bookInfo["name"] ?: ""
val author = bookInfo["author"] ?: "" val author = bookInfo["author"] ?: ""
@ -143,6 +143,8 @@ class BookshelfViewModel(application: Application) : BaseViewModel(application)
} }
} }
} }
}.onError {
it.printOnDebug()
}.onFinally { }.onFinally {
context.toastOnUi(R.string.success) context.toastOnUi(R.string.success)
} }

@ -0,0 +1,41 @@
package io.legado.app.utils
import kotlin.reflect.KClass
import kotlin.reflect.full.memberProperties
import kotlin.reflect.full.primaryConstructor
@Suppress("UNCHECKED_CAST")
fun <T : Any> T.deepCopy(): T {
//如果不是数据类,直接返回
if (!this::class.isData) {
return this
}
//拿到构造函数
return this::class.primaryConstructor!!.let { primaryConstructor ->
//转换类型
//memberProperties 返回非扩展属性中的第一个并将构造函数赋值给其
//最终value=第一个参数类型的对象
//如果当前类(这里的当前类指的是参数对应的类型,比如说这里如果非基本类型时)是数据类
//最终返回一个新的映射map,即返回一个属性值重新组合的map,并调用callBy返回指定的对象
primaryConstructor.parameters.associate { parameter ->
//转换类型
//memberProperties 返回非扩展属性中的第一个并将构造函数赋值给其
//最终value=第一个参数类型的对象
val value = (this::class as KClass<T>).memberProperties.first {
it.name == parameter.name
}.get(this)
//如果当前类(这里的当前类指的是参数对应的类型,比如说这里如果非基本类型时)是数据类
if ((parameter.type.classifier as? KClass<*>)?.isData == true) {
parameter to value?.deepCopy()
} else {
parameter to value
}
//最终返回一个新的映射map,即返回一个属性值重新组合的map,并调用callBy返回指定的对象
}.let(primaryConstructor::callBy)
}
}

@ -4,7 +4,6 @@ import com.google.gson.*
import com.google.gson.internal.LinkedTreeMap import com.google.gson.internal.LinkedTreeMap
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonWriter import com.google.gson.stream.JsonWriter
import java.io.OutputStream import java.io.OutputStream
import java.io.OutputStreamWriter import java.io.OutputStreamWriter
import java.lang.reflect.ParameterizedType import java.lang.reflect.ParameterizedType
@ -26,22 +25,16 @@ val GSON: Gson by lazy {
inline fun <reified T> genericType(): Type = object : TypeToken<T>() {}.type inline fun <reified T> genericType(): Type = object : TypeToken<T>() {}.type
inline fun <reified T> Gson.fromJsonObject(json: String?): T? {//可转成任意类型 inline fun <reified T> Gson.fromJsonObject(json: String?): Result<T?> {
json ?: return null
return kotlin.runCatching { return kotlin.runCatching {
fromJson(json, genericType<T>()) as? T fromJson(json, genericType<T>()) as? T
}.onFailure { }
DebugLog.e("GSON解析出错", json, it)
}.getOrNull()
} }
inline fun <reified T> Gson.fromJsonArray(json: String?): List<T>? { inline fun <reified T> Gson.fromJsonArray(json: String?): Result<List<T>?> {
json ?: return null
return kotlin.runCatching { return kotlin.runCatching {
fromJson(json, ParameterizedTypeImpl(T::class.java)) as? List<T> fromJson(json, ParameterizedTypeImpl(T::class.java)) as? List<T>
}.onFailure { }
DebugLog.e("GSON解析出错", json, it)
}.getOrNull()
} }
fun Gson.writeToOutputStream(out: OutputStream, any: Any) { fun Gson.writeToOutputStream(out: OutputStream, any: Any) {

@ -12,10 +12,10 @@ fun Intent.putJson(key: String, any: Any?) {
inline fun <reified T> Intent.getJsonObject(key: String): T? { inline fun <reified T> Intent.getJsonObject(key: String): T? {
val value = getStringExtra(key) val value = getStringExtra(key)
return GSON.fromJsonObject<T>(value) return GSON.fromJsonObject<T>(value).getOrNull()
} }
inline fun <reified T> Intent.getJsonArray(key: String): List<T>? { inline fun <reified T> Intent.getJsonArray(key: String): List<T>? {
val value = getStringExtra(key) val value = getStringExtra(key)
return GSON.fromJsonArray(value) return GSON.fromJsonArray<T>(value).getOrNull()
} }

@ -49,7 +49,8 @@ class BookSourceDebugWebSocket(handshakeRequest: NanoHTTPD.IHTTPSession) :
close(NanoWSD.WebSocketFrame.CloseCode.NormalClosure, "调试结束", false) close(NanoWSD.WebSocketFrame.CloseCode.NormalClosure, "调试结束", false)
return@launch return@launch
} }
val debugBean = GSON.fromJsonObject<Map<String, String>>(message.textPayload) val debugBean =
GSON.fromJsonObject<Map<String, String>>(message.textPayload).getOrNull()
if (debugBean != null) { if (debugBean != null) {
val tag = debugBean["tag"] val tag = debugBean["tag"]
val key = debugBean["key"] val key = debugBean["key"]

@ -49,7 +49,8 @@ class RssSourceDebugWebSocket(handshakeRequest: NanoHTTPD.IHTTPSession) :
close(NanoWSD.WebSocketFrame.CloseCode.NormalClosure, "调试结束", false) close(NanoWSD.WebSocketFrame.CloseCode.NormalClosure, "调试结束", false)
return@launch return@launch
} }
val debugBean = GSON.fromJsonObject<Map<String, String>>(message.textPayload) val debugBean =
GSON.fromJsonObject<Map<String, String>>(message.textPayload).getOrNull()
if (debugBean != null) { if (debugBean != null) {
val tag = debugBean["tag"] val tag = debugBean["tag"]
if (tag.isNullOrBlank()) { if (tag.isNullOrBlank()) {

Loading…
Cancel
Save