优化tts导入

pull/1861/head
kunfei 3 years ago
parent 8cdd938fdb
commit 3aadc4cd77
  1. 1633
      app/schemas/io.legado.app.data.AppDatabase/48.json
  2. 5
      app/src/main/java/io/legado/app/data/AppDatabase.kt
  3. 28
      app/src/main/java/io/legado/app/data/entities/HttpTTS.kt
  4. 4
      app/src/main/java/io/legado/app/help/DefaultData.kt
  5. 6
      app/src/main/java/io/legado/app/ui/association/BaseAssociationViewModel.kt
  6. 124
      app/src/main/java/io/legado/app/ui/association/ImportHttpTtsDialog.kt
  7. 116
      app/src/main/java/io/legado/app/ui/association/ImportHttpTtsViewModel.kt
  8. 8
      app/src/main/java/io/legado/app/ui/book/read/config/HttpTtsEditViewModel.kt
  9. 6
      app/src/main/java/io/legado/app/ui/book/read/config/SpeakEngineViewModel.kt

File diff suppressed because it is too large Load Diff

@ -20,7 +20,7 @@ val appDb by lazy {
} }
@Database( @Database(
version = 47, version = 48,
exportSchema = true, exportSchema = true,
entities = [Book::class, BookGroup::class, BookSource::class, BookChapter::class, entities = [Book::class, BookGroup::class, BookSource::class, BookChapter::class,
ReplaceRule::class, SearchBook::class, SearchKeyword::class, Cookie::class, ReplaceRule::class, SearchBook::class, SearchKeyword::class, Cookie::class,
@ -31,7 +31,8 @@ val appDb by lazy {
AutoMigration(from = 43, to = 44), AutoMigration(from = 43, to = 44),
AutoMigration(from = 44, to = 45), AutoMigration(from = 44, to = 45),
AutoMigration(from = 45, to = 46), AutoMigration(from = 45, to = 46),
AutoMigration(from = 46, to = 47) AutoMigration(from = 46, to = 47),
AutoMigration(from = 47, to = 48)
] ]
) )
abstract class AppDatabase : RoomDatabase() { abstract class AppDatabase : RoomDatabase() {

@ -1,5 +1,6 @@
package io.legado.app.data.entities package io.legado.app.data.entities
import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import com.jayway.jsonpath.DocumentContext import com.jayway.jsonpath.DocumentContext
@ -18,11 +19,14 @@ data class HttpTTS(
var name: String = "", var name: String = "",
var url: String = "", var url: String = "",
var contentType: String? = null, var contentType: String? = null,
@ColumnInfo(defaultValue = "0")
override var concurrentRate: String? = "0", override var concurrentRate: String? = "0",
override var loginUrl: String? = null, override var loginUrl: String? = null,
override var loginUi: String? = null, override var loginUi: String? = null,
override var header: String? = null, override var header: String? = null,
var loginCheckJs: String? = null, var loginCheckJs: String? = null,
@ColumnInfo(defaultValue = "0")
var lastUpdateTime: Long = System.currentTimeMillis()
) : BaseSource { ) : BaseSource {
override fun getTag(): String { override fun getTag(): String {
@ -36,7 +40,7 @@ data class HttpTTS(
@Suppress("MemberVisibilityCanBePrivate") @Suppress("MemberVisibilityCanBePrivate")
companion object { companion object {
fun fromJsonDoc(doc: DocumentContext): HttpTTS? { fun fromJsonDoc(doc: DocumentContext): Result<HttpTTS> {
return kotlin.runCatching { return kotlin.runCatching {
val loginUi = doc.read<Any>("$.loginUi") val loginUi = doc.read<Any>("$.loginUi")
HttpTTS( HttpTTS(
@ -50,23 +54,25 @@ data class HttpTTS(
header = doc.readString("$.header"), header = doc.readString("$.header"),
loginCheckJs = doc.readString("$.loginCheckJs") loginCheckJs = doc.readString("$.loginCheckJs")
) )
}.getOrNull() }
} }
fun fromJson(json: String): HttpTTS? { fun fromJson(json: String): Result<HttpTTS> {
return fromJsonDoc(jsonPath.parse(json)) return fromJsonDoc(jsonPath.parse(json))
} }
fun fromJsonArray(jsonArray: String): ArrayList<HttpTTS> { fun fromJsonArray(jsonArray: String): Result<ArrayList<HttpTTS>> {
val sources = arrayListOf<HttpTTS>() return kotlin.runCatching {
val doc = jsonPath.parse(jsonArray).read<List<*>>("$") val sources = arrayListOf<HttpTTS>()
doc.forEach { val doc = jsonPath.parse(jsonArray).read<List<*>>("$")
val jsonItem = jsonPath.parse(it) doc.forEach {
fromJsonDoc(jsonItem)?.let { source -> val jsonItem = jsonPath.parse(it)
sources.add(source) fromJsonDoc(jsonItem).getOrThrow().let { source ->
sources.add(source)
}
} }
return@runCatching sources
} }
return sources
} }
} }

@ -22,7 +22,9 @@ object DefaultData {
appCtx.assets.open("defaultData${File.separator}httpTTS.json") appCtx.assets.open("defaultData${File.separator}httpTTS.json")
.readBytes() .readBytes()
) )
HttpTTS.fromJsonArray(json) HttpTTS.fromJsonArray(json).getOrElse {
emptyList()
}
} }
val readConfigs: List<ReadBookConfig.Config> by lazy { val readConfigs: List<ReadBookConfig.Config> by lazy {

@ -40,15 +40,15 @@ abstract class BaseAssociationViewModel(application: Application) : BaseViewMode
fun importHttpTTS(json: String, finally: (title: String, msg: String) -> Unit) { fun importHttpTTS(json: String, finally: (title: String, msg: String) -> Unit) {
execute { execute {
if (json.isJsonArray()) { if (json.isJsonArray()) {
HttpTTS.fromJsonArray(json).let { HttpTTS.fromJsonArray(json).getOrThrow().let {
appDb.httpTTSDao.insert(*it.toTypedArray()) appDb.httpTTSDao.insert(*it.toTypedArray())
return@execute it.size return@execute it.size
} }
} else { } else {
HttpTTS.fromJson(json)?.let { HttpTTS.fromJson(json).getOrThrow().let {
appDb.httpTTSDao.insert(it) appDb.httpTTSDao.insert(it)
return@execute 1 return@execute 1
} ?: throw NoStackTraceException("格式不对") }
} }
}.onSuccess { }.onSuccess {
finally.invoke(context.getString(R.string.success), "导入${it}朗读引擎") finally.invoke(context.getString(R.string.success), "导入${it}朗读引擎")

@ -0,0 +1,124 @@
package io.legado.app.ui.association
import android.annotation.SuppressLint
import android.content.Context
import android.content.DialogInterface
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.viewModels
import io.legado.app.R
import io.legado.app.base.BaseDialogFragment
import io.legado.app.base.adapter.ItemViewHolder
import io.legado.app.base.adapter.RecyclerAdapter
import io.legado.app.data.entities.HttpTTS
import io.legado.app.databinding.DialogRecyclerViewBinding
import io.legado.app.databinding.ItemSourceImportBinding
import io.legado.app.lib.theme.primaryColor
import io.legado.app.ui.widget.dialog.CodeDialog
import io.legado.app.utils.GSON
import io.legado.app.utils.setLayout
import io.legado.app.utils.showDialogFragment
import io.legado.app.utils.viewbindingdelegate.viewBinding
import splitties.views.onClick
class ImportHttpTtsDialog() : BaseDialogFragment(R.layout.dialog_recycler_view) {
constructor(source: String, finishOnDismiss: Boolean = false) : this() {
arguments = Bundle().apply {
putString("source", source)
putBoolean("finishOnDismiss", finishOnDismiss)
}
}
private val binding by viewBinding(DialogRecyclerViewBinding::bind)
private val viewModel by viewModels<ImportHttpTtsViewModel>()
override fun onStart() {
super.onStart()
setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
}
override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
if (arguments?.getBoolean("finishOnDismiss") == true) {
activity?.finish()
}
}
@SuppressLint("NotifyDataSetChanged")
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
binding.toolBar.setBackgroundColor(primaryColor)
binding.toolBar.setTitle(R.string.import_book_source)
binding.rotateLoading.show()
}
private fun upSelectText() {
if (viewModel.isSelectAll) {
binding.tvFooterLeft.text = getString(
R.string.select_cancel_count,
viewModel.selectCount,
viewModel.allSources.size
)
} else {
binding.tvFooterLeft.text = getString(
R.string.select_all_count,
viewModel.selectCount,
viewModel.allSources.size
)
}
}
inner class SourcesAdapter(context: Context) :
RecyclerAdapter<HttpTTS, ItemSourceImportBinding>(context) {
override fun getViewBinding(parent: ViewGroup): ItemSourceImportBinding {
return ItemSourceImportBinding.inflate(inflater, parent, false)
}
override fun convert(
holder: ItemViewHolder,
binding: ItemSourceImportBinding,
item: HttpTTS,
payloads: MutableList<Any>
) {
binding.apply {
cbSourceName.isChecked = viewModel.selectStatus[holder.layoutPosition]
cbSourceName.text = item.name
val localSource = viewModel.checkSources[holder.layoutPosition]
tvSourceState.text = when {
localSource == null -> "新增"
item.lastUpdateTime > localSource.lastUpdateTime -> "更新"
else -> "已有"
}
}
}
override fun registerListener(holder: ItemViewHolder, binding: ItemSourceImportBinding) {
binding.apply {
cbSourceName.setOnCheckedChangeListener { buttonView, isChecked ->
if (buttonView.isPressed) {
viewModel.selectStatus[holder.layoutPosition] = isChecked
upSelectText()
}
}
root.onClick {
cbSourceName.isChecked = !cbSourceName.isChecked
viewModel.selectStatus[holder.layoutPosition] = cbSourceName.isChecked
upSelectText()
}
tvOpen.setOnClickListener {
val source = viewModel.allSources[holder.layoutPosition]
showDialogFragment(
CodeDialog(
GSON.toJson(source),
disableEdit = false,
requestId = holder.layoutPosition.toString()
)
)
}
}
}
}
}

@ -0,0 +1,116 @@
package io.legado.app.ui.association
import android.app.Application
import androidx.lifecycle.MutableLiveData
import com.jayway.jsonpath.JsonPath
import io.legado.app.R
import io.legado.app.base.BaseViewModel
import io.legado.app.data.appDb
import io.legado.app.data.entities.BookSource
import io.legado.app.data.entities.HttpTTS
import io.legado.app.exception.NoStackTraceException
import io.legado.app.help.ContentProcessor
import io.legado.app.help.SourceHelp
import io.legado.app.help.config.AppConfig
import io.legado.app.help.http.newCallResponseBody
import io.legado.app.help.http.okHttpClient
import io.legado.app.help.http.text
import io.legado.app.utils.isAbsUrl
import io.legado.app.utils.isJsonArray
import io.legado.app.utils.isJsonObject
import io.legado.app.utils.printOnDebug
class ImportHttpTtsViewModel(app: Application) : BaseViewModel(app) {
val errorLiveData = MutableLiveData<String>()
val successLiveData = MutableLiveData<Int>()
val allSources = arrayListOf<HttpTTS>()
val checkSources = arrayListOf<HttpTTS?>()
val selectStatus = arrayListOf<Boolean>()
val isSelectAll: Boolean
get() {
selectStatus.forEach {
if (!it) {
return false
}
}
return true
}
val selectCount: Int
get() {
var count = 0
selectStatus.forEach {
if (it) {
count++
}
}
return count
}
fun importSelect(finally: () -> Unit) {
execute {
val keepName = AppConfig.importKeepName
val selectSource = arrayListOf<BookSource>()
SourceHelp.insertBookSource(*selectSource.toTypedArray())
ContentProcessor.upReplaceRules()
}.onFinally {
finally.invoke()
}
}
fun importSource(text: String) {
execute {
val mText = text.trim()
when {
mText.isJsonObject() -> {
val json = JsonPath.parse(mText)
val urls = json.read<List<String>>("$.sourceUrls")
if (!urls.isNullOrEmpty()) {
urls.forEach {
importSourceUrl(it)
}
} else {
HttpTTS.fromJson(mText).getOrThrow().let {
allSources.add(it)
}
}
}
mText.isJsonArray() -> HttpTTS.fromJsonArray(mText).getOrThrow().let { items ->
allSources.addAll(items)
}
mText.isAbsUrl() -> {
importSourceUrl(mText)
}
else -> throw NoStackTraceException(context.getString(R.string.wrong_format))
}
}.onError {
it.printOnDebug()
errorLiveData.postValue(it.localizedMessage ?: "")
}.onSuccess {
comparisonSource()
}
}
private suspend fun importSourceUrl(url: String) {
okHttpClient.newCallResponseBody {
url(url)
}.text().let {
allSources.addAll(HttpTTS.fromJsonArray(it).getOrThrow())
}
}
private fun comparisonSource() {
execute {
allSources.forEach {
val source = appDb.httpTTSDao.get(it.id)
checkSources.add(source)
selectStatus.add(source == null || source.lastUpdateTime < it.lastUpdateTime)
}
successLiveData.postValue(allSources.size)
}
}
}

@ -57,19 +57,17 @@ class HttpTtsEditViewModel(app: Application) : BaseViewModel(app) {
execute { execute {
when { when {
text1.isJsonObject() -> { text1.isJsonObject() -> {
HttpTTS.fromJson(text1) HttpTTS.fromJson(text1).getOrThrow()
} }
text1.isJsonArray() -> { text1.isJsonArray() -> {
HttpTTS.fromJsonArray(text1).firstOrNull() HttpTTS.fromJsonArray(text1).getOrThrow().first()
} }
else -> { else -> {
throw NoStackTraceException("格式不对") throw NoStackTraceException("格式不对")
} }
} }
}.onSuccess { }.onSuccess {
it?.let { httpTts -> onSuccess.invoke(it)
onSuccess.invoke(httpTts)
} ?: context.toastOnUi("格式不对")
}.onError { }.onError {
context.toastOnUi(it.localizedMessage) context.toastOnUi(it.localizedMessage)
} }

@ -18,7 +18,7 @@ import io.legado.app.utils.toastOnUi
class SpeakEngineViewModel(application: Application) : BaseViewModel(application) { class SpeakEngineViewModel(application: Application) : BaseViewModel(application) {
val sysEngines = TextToSpeech(context, null).engines val sysEngines: List<TextToSpeech.EngineInfo> = TextToSpeech(context, null).engines
fun importDefault() { fun importDefault() {
execute { execute {
@ -53,12 +53,12 @@ class SpeakEngineViewModel(application: Application) : BaseViewModel(application
fun import(text: String) { fun import(text: String) {
when { when {
text.isJsonArray() -> { text.isJsonArray() -> {
HttpTTS.fromJsonArray(text).let { HttpTTS.fromJsonArray(text).getOrThrow().let {
appDb.httpTTSDao.insert(*it.toTypedArray()) appDb.httpTTSDao.insert(*it.toTypedArray())
} }
} }
text.isJsonObject() -> { text.isJsonObject() -> {
HttpTTS.fromJson(text)?.let { HttpTTS.fromJson(text).getOrThrow().let {
appDb.httpTTSDao.insert(it) appDb.httpTTSDao.insert(it)
} }
} }

Loading…
Cancel
Save