优化
This commit is contained in:
@@ -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) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
option.body?.let {
|
||||||
|
body = if (it is String) it else GSON.toJson(it)
|
||||||
|
}
|
||||||
|
type = option.type
|
||||||
|
charset = option.charset
|
||||||
|
retry = option.retry
|
||||||
|
useWebView = option.webView?.toString()?.isNotBlank() == true
|
||||||
|
webJs = option.webJs
|
||||||
|
option.js?.let { jsStr ->
|
||||||
|
evalJS(jsStr, url)?.toString()?.let {
|
||||||
|
url = it
|
||||||
}
|
}
|
||||||
} else if (headers is String) {
|
|
||||||
GSON.fromJsonObject<Map<String, String>>(headers)
|
|
||||||
?.let { headerMap.putAll(it) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
option.body?.let {
|
|
||||||
body = if (it is String) it else GSON.toJson(it)
|
|
||||||
}
|
|
||||||
type = option.type
|
|
||||||
charset = option.charset
|
|
||||||
retry = option.retry
|
|
||||||
useWebView = option.webView?.toString()?.isNotBlank() == true
|
|
||||||
webJs = option.webJs
|
|
||||||
option.js?.let { jsStr ->
|
|
||||||
evalJS(jsStr, url)?.toString()?.let {
|
|
||||||
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()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user