From ed23874353c85c6147f09073254fdea41a3eca0c Mon Sep 17 00:00:00 2001 From: Horis <821938089@qq.com> Date: Tue, 13 Jun 2023 22:10:07 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/service/BaseReadAloudService.kt | 32 ++++++----- .../legado/app/service/TTSReadAloudService.kt | 54 +++++++++++-------- .../ui/book/read/config/SpeakEngineDialog.kt | 16 ++++++ 3 files changed, 65 insertions(+), 37 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt index 425577d5d..a42a0945b 100644 --- a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt @@ -29,6 +29,8 @@ import io.legado.app.ui.book.read.ReadBookActivity import io.legado.app.ui.book.read.page.entities.TextChapter import io.legado.app.utils.* import kotlinx.coroutines.* +import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.Dispatchers.Main import splitties.init.appCtx import splitties.systemservices.audioManager import splitties.systemservices.powerManager @@ -71,7 +73,7 @@ abstract class BaseReadAloudService : BaseService(), private val mediaSessionCompat: MediaSessionCompat by lazy { MediaSessionCompat(this, "readAloud") } - internal val contentList = arrayListOf() + internal var contentList = emptyList() internal var nowSpeak: Int = 0 internal var readAloudNumber: Int = 0 internal var textChapter: TextChapter? = null @@ -132,6 +134,7 @@ abstract class BaseReadAloudService : BaseService(), intent.getIntExtra("pageIndex", ReadBook.durPageIndex), intent.getIntExtra("startPos", 0) ) + IntentAction.pause -> pauseReadAloud() IntentAction.resume -> resumeReadAloud() IntentAction.upTtsSpeechRate -> upSpeechRate(true) @@ -144,20 +147,17 @@ abstract class BaseReadAloudService : BaseService(), return super.onStartCommand(intent, flags, startId) } - private fun newReadAloud(play: Boolean, pageIndex: Int, startPos: Int) { - this.pageIndex = pageIndex + private fun newReadAloud(play: Boolean, pageIndex: Int, startPos: Int) = launch(IO) { + this@BaseReadAloudService.pageIndex = pageIndex textChapter = ReadBook.curTextChapter - textChapter?.let { textChapter -> - nowSpeak = 0 - readAloudNumber = textChapter.getReadLength(pageIndex) + startPos - contentList.clear() - val readAloudByPage = getPrefBoolean(PreferKey.readAloudByPage) - textChapter.getNeedReadAloud(pageIndex, readAloudByPage, startPos) - .split("\n").forEach { text -> - if (text.isNotEmpty()) { - contentList.add(text) - } - } + val textChapter = textChapter ?: return@launch + nowSpeak = 0 + readAloudNumber = textChapter.getReadLength(pageIndex) + startPos + val readAloudByPage = getPrefBoolean(PreferKey.readAloudByPage) + contentList = textChapter.getNeedReadAloud(pageIndex, readAloudByPage, startPos) + .split("\n") + .filter { it.isNotEmpty() } + launch(Main) { if (play) play() else pageChanged = true } } @@ -335,10 +335,12 @@ abstract class BaseReadAloudService : BaseService(), AppLog.put("音频焦点获得") } } + AudioManager.AUDIOFOCUS_LOSS -> { AppLog.put("音频焦点丢失,暂停朗读") pauseReadAloud() } + AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { AppLog.put("音频焦点暂时丢失并会很快再次获得,暂停朗读") if (!pause) { @@ -346,6 +348,7 @@ abstract class BaseReadAloudService : BaseService(), pauseReadAloud(false) } } + AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> { // 短暂丢失焦点,这种情况是被其他应用申请了短暂的焦点希望其他声音能压低音量(或者关闭声音)凸显这个声音(比如短信提示音), AppLog.put("音频焦点短暂丢失,不做处理") @@ -364,6 +367,7 @@ abstract class BaseReadAloudService : BaseService(), R.string.read_aloud_timer, timeMinute ) + else -> getString(R.string.read_aloud_t) } nTitle += ": ${ReadBook.book?.name}" diff --git a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt index 3b6cdb7b8..78b6ad2c6 100644 --- a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt @@ -11,10 +11,12 @@ import io.legado.app.constant.EventBus import io.legado.app.exception.NoStackTraceException import io.legado.app.help.MediaHelp import io.legado.app.help.config.AppConfig +import io.legado.app.help.coroutine.Coroutine import io.legado.app.lib.dialogs.SelectItem import io.legado.app.model.ReadAloud import io.legado.app.model.ReadBook import io.legado.app.utils.* +import kotlinx.coroutines.ensureActive /** * 本地朗读 @@ -24,6 +26,7 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener private var textToSpeech: TextToSpeech? = null private var ttsInitFinish = false private val ttsUtteranceListener = TTSUtteranceListener() + private var speakJob: Coroutine<*>? = null override fun onCreate() { super.onCreate() @@ -74,30 +77,34 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener if (contentList.isEmpty()) { AppLog.putDebug("朗读列表为空") ReadBook.readAloud() - } else { - super.play() - kotlin.runCatching { - MediaHelp.playSilentSound(this@TTSReadAloudService) - val tts = textToSpeech ?: throw NoStackTraceException("tts is null") - var result = tts.speak("", TextToSpeech.QUEUE_FLUSH, null, null) - if (result == TextToSpeech.ERROR) { - clearTTS() - initTts() - return - } - for (i in nowSpeak until contentList.size) { - val text = contentList[i] - if (!text.matches(AppPattern.notReadAloudRegex)) { - result = tts.speak(text, TextToSpeech.QUEUE_ADD, null, AppConst.APP_TAG + i) - if (result == TextToSpeech.ERROR) { - AppLog.put("tts朗读出错:$text") - } - } - } - }.onFailure { - AppLog.put("tts朗读出错", it) - toastOnUi(it.localizedMessage) + return + } + super.play() + MediaHelp.playSilentSound(this@TTSReadAloudService) + speakJob?.cancel() + speakJob = execute { + val tts = textToSpeech ?: throw NoStackTraceException("tts is null") + var result = tts.speak("", TextToSpeech.QUEUE_FLUSH, null, null) + if (result == TextToSpeech.ERROR) { + clearTTS() + initTts() + return@execute } + val contentList = contentList + for (i in nowSpeak until contentList.size) { + ensureActive() + val text = contentList[i] + if (text.matches(AppPattern.notReadAloudRegex)) { + continue + } + result = tts.speak(text, TextToSpeech.QUEUE_ADD, null, AppConst.APP_TAG + i) + if (result == TextToSpeech.ERROR) { + AppLog.put("tts朗读出错:$text") + } + } + }.onError { + AppLog.put("tts朗读出错", it) + toastOnUi(it.localizedMessage) } } @@ -125,6 +132,7 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener */ override fun pauseReadAloud(abandonFocus: Boolean) { super.pauseReadAloud(abandonFocus) + speakJob?.cancel() textToSpeech?.stop() } diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/SpeakEngineDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/SpeakEngineDialog.kt index 0bf632d8d..6085bf262 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/SpeakEngineDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/SpeakEngineDialog.kt @@ -85,6 +85,21 @@ class SpeakEngineDialog(val callBack: CallBack) : BaseDialogFragment(R.layout.di recyclerView.setEdgeEffectColor(primaryColor) recyclerView.layoutManager = LinearLayoutManager(requireContext()) recyclerView.adapter = adapter + adapter.addHeaderView { + ItemHttpTtsBinding.inflate(layoutInflater, recyclerView, false).apply { + sysTtsViews.add(cbName) + ivEdit.gone() + ivMenuDelete.gone() + labelSys.visible() + cbName.text = "系统默认" + cbName.tag = "" + cbName.isChecked = GSON.fromJsonObject>(ttsEngine) + .getOrNull()?.value.isNullOrEmpty() + cbName.setOnClickListener { + upTts(GSON.toJson(SelectItem("系统默认", ""))) + } + } + } viewModel.sysEngines.forEach { engine -> adapter.addHeaderView { ItemHttpTtsBinding.inflate(layoutInflater, recyclerView, false).apply { @@ -147,6 +162,7 @@ class SpeakEngineDialog(val callBack: CallBack) : BaseDialogFragment(R.layout.di mode = HandleFileContract.FILE allowExtensions = arrayOf("txt", "json") } + R.id.menu_import_onLine -> importAlert() R.id.menu_export -> exportDirResult.launch { mode = HandleFileContract.EXPORT