优化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(
version = 47,
version = 48,
exportSchema = true,
entities = [Book::class, BookGroup::class, BookSource::class, BookChapter::class,
ReplaceRule::class, SearchBook::class, SearchKeyword::class, Cookie::class,
@ -31,7 +31,8 @@ val appDb by lazy {
AutoMigration(from = 43, to = 44),
AutoMigration(from = 44, to = 45),
AutoMigration(from = 45, to = 46),
AutoMigration(from = 46, to = 47)
AutoMigration(from = 46, to = 47),
AutoMigration(from = 47, to = 48)
]
)
abstract class AppDatabase : RoomDatabase() {

@ -1,5 +1,6 @@
package io.legado.app.data.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.jayway.jsonpath.DocumentContext
@ -18,11 +19,14 @@ data class HttpTTS(
var name: String = "",
var url: String = "",
var contentType: String? = null,
@ColumnInfo(defaultValue = "0")
override var concurrentRate: String? = "0",
override var loginUrl: String? = null,
override var loginUi: String? = null,
override var header: String? = null,
var loginCheckJs: String? = null,
@ColumnInfo(defaultValue = "0")
var lastUpdateTime: Long = System.currentTimeMillis()
) : BaseSource {
override fun getTag(): String {
@ -36,7 +40,7 @@ data class HttpTTS(
@Suppress("MemberVisibilityCanBePrivate")
companion object {
fun fromJsonDoc(doc: DocumentContext): HttpTTS? {
fun fromJsonDoc(doc: DocumentContext): Result<HttpTTS> {
return kotlin.runCatching {
val loginUi = doc.read<Any>("$.loginUi")
HttpTTS(
@ -50,23 +54,25 @@ data class HttpTTS(
header = doc.readString("$.header"),
loginCheckJs = doc.readString("$.loginCheckJs")
)
}.getOrNull()
}
}
fun fromJson(json: String): HttpTTS? {
fun fromJson(json: String): Result<HttpTTS> {
return fromJsonDoc(jsonPath.parse(json))
}
fun fromJsonArray(jsonArray: String): ArrayList<HttpTTS> {
val sources = arrayListOf<HttpTTS>()
val doc = jsonPath.parse(jsonArray).read<List<*>>("$")
doc.forEach {
val jsonItem = jsonPath.parse(it)
fromJsonDoc(jsonItem)?.let { source ->
sources.add(source)
fun fromJsonArray(jsonArray: String): Result<ArrayList<HttpTTS>> {
return kotlin.runCatching {
val sources = arrayListOf<HttpTTS>()
val doc = jsonPath.parse(jsonArray).read<List<*>>("$")
doc.forEach {
val jsonItem = jsonPath.parse(it)
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")
.readBytes()
)
HttpTTS.fromJsonArray(json)
HttpTTS.fromJsonArray(json).getOrElse {
emptyList()
}
}
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) {
execute {
if (json.isJsonArray()) {
HttpTTS.fromJsonArray(json).let {
HttpTTS.fromJsonArray(json).getOrThrow().let {
appDb.httpTTSDao.insert(*it.toTypedArray())
return@execute it.size
}
} else {
HttpTTS.fromJson(json)?.let {
HttpTTS.fromJson(json).getOrThrow().let {
appDb.httpTTSDao.insert(it)
return@execute 1
} ?: throw NoStackTraceException("格式不对")
}
}
}.onSuccess {
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 {
when {
text1.isJsonObject() -> {
HttpTTS.fromJson(text1)
HttpTTS.fromJson(text1).getOrThrow()
}
text1.isJsonArray() -> {
HttpTTS.fromJsonArray(text1).firstOrNull()
HttpTTS.fromJsonArray(text1).getOrThrow().first()
}
else -> {
throw NoStackTraceException("格式不对")
}
}
}.onSuccess {
it?.let { httpTts ->
onSuccess.invoke(httpTts)
} ?: context.toastOnUi("格式不对")
onSuccess.invoke(it)
}.onError {
context.toastOnUi(it.localizedMessage)
}

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

Loading…
Cancel
Save