[优化] 优化听书相关代码
This commit is contained in:
@@ -69,6 +69,7 @@ object PreferKey {
|
||||
const val webDavAccount = "web_dav_account"
|
||||
const val webDavPassword = "web_dav_password"
|
||||
const val webDavDir = "webDavDir"
|
||||
const val webServiceAutoStart = "webServiceAutoStart"
|
||||
const val enableCustomExport = "enableCustomExport"
|
||||
const val exportToWebDav = "webDavCacheBackup"
|
||||
const val exportNoChapterName = "exportNoChapterName"
|
||||
@@ -243,4 +244,6 @@ object PreferKey {
|
||||
|
||||
const val showTip = "showTip"
|
||||
const val sliderVibrator = "sliderVibrator"
|
||||
const val audioCacheCleanTime = "audioCacheCleanTime"
|
||||
const val audioPreDownloadNum = "audioPreDownloadNum"
|
||||
}
|
||||
|
||||
@@ -20,9 +20,6 @@ import io.legado.app.utils.removePref
|
||||
import io.legado.app.utils.sysConfiguration
|
||||
import io.legado.app.utils.toastOnUi
|
||||
import splitties.init.appCtx
|
||||
// 【新增引用】为了支持文件清理操作
|
||||
import java.io.File
|
||||
import io.legado.app.utils.FileUtils
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate", "ConstPropertyName")
|
||||
object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
@@ -60,7 +57,7 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
var optimizeRender = CanvasRecorderFactory.isSupport
|
||||
&& appCtx.getPrefBoolean(PreferKey.optimizeRender, false)
|
||||
var recordLog = appCtx.getPrefBoolean(PreferKey.recordLog)
|
||||
|
||||
var webServiceAutoStart = appCtx.getPrefBoolean(PreferKey.webServiceAutoStart)
|
||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
|
||||
when (key) {
|
||||
|
||||
@@ -976,39 +973,16 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
appCtx.putPrefBoolean(PreferKey.sliderVibrator, value)
|
||||
}
|
||||
|
||||
// ================= 自定义功能区域 Start =================
|
||||
|
||||
// 1. 听书预加载数量
|
||||
// 逻辑:从设置里读取字符串,转成数字。如果读不到,默认返回 10。
|
||||
val audioPreDownloadNum: Int
|
||||
get() {
|
||||
// 注意:EditTextPreference 保存的是 String
|
||||
val str = appCtx.getPrefString("audioPreDownloadNum")
|
||||
return str?.toIntOrNull() ?: 10
|
||||
}
|
||||
get() = appCtx.getPrefInt(PreferKey.audioPreDownloadNum, 10)
|
||||
|
||||
val audioCacheCleanTimeOrgin: Int
|
||||
get() = appCtx.getPrefInt(PreferKey.audioCacheCleanTime, 10)
|
||||
|
||||
// 2. 音频缓存保留时间 (返回毫秒)
|
||||
// 逻辑:用户输入的是“分钟”,我们在这里把它乘以 60000 变成“毫秒”。
|
||||
val audioCacheCleanTime: Long
|
||||
get() {
|
||||
val str = appCtx.getPrefString("audioCacheCleanTime")
|
||||
val minutes = str?.toLongOrNull() ?: 10L // 默认 10 分钟
|
||||
return minutes * 60 * 1000L
|
||||
val str = appCtx.getPrefInt(PreferKey.audioCacheCleanTime, 10)
|
||||
return str * 60 * 1000L
|
||||
}
|
||||
|
||||
/**
|
||||
* 【新增】手动清理 TTS 缓存
|
||||
* 这个方法会自动寻找 externalCacheDir(外部存储),如果找不到再找内部。
|
||||
* 确保和 Service 里的逻辑保持一致。
|
||||
*/
|
||||
fun clearTtsCache() {
|
||||
val baseDir = appCtx.externalCacheDir ?: appCtx.cacheDir
|
||||
// 清理音频文件
|
||||
FileUtils.delete(baseDir.absolutePath + File.separator + "httpTTS")
|
||||
// 清理数据库索引 (可选,建议一起清,防止索引还在但文件没了)
|
||||
FileUtils.delete(baseDir.absolutePath + File.separator + "httpTTS_cache")
|
||||
}
|
||||
|
||||
// ================= 自定义功能区域 End =================
|
||||
|
||||
}
|
||||
|
||||
@@ -65,11 +65,9 @@ import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.net.ConnectException
|
||||
import java.net.SocketTimeoutException
|
||||
import kotlin.coroutines.coroutineContext
|
||||
|
||||
/**
|
||||
* 在线朗读
|
||||
* (完美匹配版:修复文件名MD5不一致 + 修复缓存不可见 + 修复0分钟不彻底清理)
|
||||
*/
|
||||
@SuppressLint("UnsafeOptInUsageError")
|
||||
class HttpReadAloudService : BaseReadAloudService(),
|
||||
@@ -78,7 +76,7 @@ class HttpReadAloudService : BaseReadAloudService(),
|
||||
ExoPlayer.Builder(this).build()
|
||||
}
|
||||
|
||||
// 【修改点1】改为外部存储,方便你查看文件,确认是否生成
|
||||
// 改为外部存储
|
||||
private val ttsFolderPath: String by lazy {
|
||||
val baseDir = externalCacheDir ?: cacheDir
|
||||
baseDir.absolutePath + File.separator + "httpTTS" + File.separator
|
||||
@@ -454,13 +452,10 @@ class HttpReadAloudService : BaseReadAloudService(),
|
||||
}
|
||||
|
||||
/**
|
||||
* 【核心修复点】生成音频文件名
|
||||
* 1. 之前的问题:textChapter.title 可能是 "第一章 内容" (带格式),而数据库里是 "第一章 内容" (不带格式)。
|
||||
* 2. 现在的做法:强制使用 textChapter.chapter.title (数据库原始标题)。
|
||||
* 3. 结果:前台 (播放) 和后台 (下载) 用的标题来源完全一致,MD5 绝对匹配,不会再重复下载了!
|
||||
* 生成音频文件名
|
||||
*/
|
||||
private fun md5SpeakFileName(content: String, textChapter: TextChapter? = this.textChapter): String {
|
||||
val titleToUse = textChapter?.chapter?.title ?: "" // 强制取“核芯”标题
|
||||
val titleToUse = textChapter?.chapter?.title ?: ""
|
||||
return MD5Utils.md5Encode16(titleToUse) + "_" +
|
||||
MD5Utils.md5Encode16("${ReadAloud.httpTTS?.url}-|-$speechRate-|-$content")
|
||||
}
|
||||
@@ -492,7 +487,7 @@ class HttpReadAloudService : BaseReadAloudService(),
|
||||
|
||||
/**
|
||||
* 移除缓存文件
|
||||
* 修复逻辑:如果时间设置为0,则不再保护当前章节,退出即全删。
|
||||
* 如果时间设置为0,则不再保护当前章节,退出即全删。
|
||||
*/
|
||||
private fun removeCacheFile() {
|
||||
val keepTime = AppConfig.audioCacheCleanTime
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.legado.app.service
|
||||
|
||||
// ——————【新增引用】——————
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
@@ -21,6 +22,7 @@ import io.legado.app.utils.getPrefBoolean
|
||||
import io.legado.app.utils.getPrefInt
|
||||
import io.legado.app.utils.postEvent
|
||||
import io.legado.app.utils.printOnDebug
|
||||
import io.legado.app.utils.putPrefBoolean
|
||||
import io.legado.app.utils.sendToClip
|
||||
import io.legado.app.utils.servicePendingIntent
|
||||
import io.legado.app.utils.startForegroundServiceCompat
|
||||
@@ -33,8 +35,6 @@ import splitties.init.appCtx
|
||||
import splitties.systemservices.powerManager
|
||||
import splitties.systemservices.wifiManager
|
||||
import java.io.IOException
|
||||
// ——————【新增引用】——————
|
||||
import io.legado.app.utils.putPrefBoolean
|
||||
|
||||
class WebService : BaseService() {
|
||||
|
||||
@@ -43,9 +43,6 @@ class WebService : BaseService() {
|
||||
var hostAddress = ""
|
||||
|
||||
fun start(context: Context) {
|
||||
// ——————【修改开始】记录开启状态——————
|
||||
appCtx.putPrefBoolean("web_service_auto", true)
|
||||
// ——————【修改结束】——————
|
||||
context.startService<WebService>()
|
||||
}
|
||||
|
||||
@@ -55,9 +52,6 @@ class WebService : BaseService() {
|
||||
}
|
||||
|
||||
fun stop(context: Context) {
|
||||
// ——————【修改开始】记录关闭状态——————
|
||||
appCtx.putPrefBoolean("web_service_auto", false)
|
||||
// ——————【修改结束】——————
|
||||
context.stopService<WebService>()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package io.legado.app.ui.book.read.config
|
||||
|
||||
//import io.legado.app.lib.theme.backgroundColor
|
||||
//import io.legado.app.lib.theme.primaryColor
|
||||
// 【新增引用】为了显示清理成功的提示
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
@@ -18,16 +21,16 @@ import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.lib.dialogs.SelectItem
|
||||
import io.legado.app.lib.prefs.SwitchPreference
|
||||
import io.legado.app.lib.prefs.fragment.PreferenceFragment
|
||||
//import io.legado.app.lib.theme.backgroundColor
|
||||
//import io.legado.app.lib.theme.primaryColor
|
||||
import io.legado.app.model.ReadAloud
|
||||
import io.legado.app.service.BaseReadAloudService
|
||||
import io.legado.app.ui.widget.number.NumberPickerDialog
|
||||
import io.legado.app.utils.GSON
|
||||
import io.legado.app.utils.StringUtils
|
||||
import io.legado.app.utils.TTSCacheUtils
|
||||
import io.legado.app.utils.fromJsonObject
|
||||
import io.legado.app.utils.postEvent
|
||||
import io.legado.app.utils.putPrefInt
|
||||
import io.legado.app.utils.showDialogFragment
|
||||
// 【新增引用】为了显示清理成功的提示
|
||||
import io.legado.app.utils.toastOnUi
|
||||
|
||||
class ReadAloudConfigDialog : BasePrefDialogFragment() {
|
||||
@@ -73,17 +76,16 @@ class ReadAloudConfigDialog : BasePrefDialogFragment() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
addPreferencesFromResource(R.xml.pref_config_aloud)
|
||||
upSpeakEngineSummary()
|
||||
upPreferenceSummary(PreferKey.audioPreDownloadNum)
|
||||
upPreferenceSummary(PreferKey.audioCacheCleanTime)
|
||||
findPreference<SwitchPreference>(PreferKey.pauseReadAloudWhilePhoneCalls)?.let {
|
||||
it.isEnabled = AppConfig.ignoreAudioFocus
|
||||
}
|
||||
|
||||
// 【新增代码】绑定清理缓存按钮事件
|
||||
findPreference<Preference>("clear_cache")?.let {
|
||||
it.summary = getString(R.string.clear_cache)
|
||||
it.setOnPreferenceClickListener {
|
||||
// 调用 AppConfig 中的万能清理函数 (自动处理外部存储)
|
||||
AppConfig.clearTtsCache()
|
||||
// 弹出提示
|
||||
TTSCacheUtils.clearTtsCache()
|
||||
toastOnUi("音频缓存已清理")
|
||||
true
|
||||
}
|
||||
@@ -107,6 +109,38 @@ class ReadAloudConfigDialog : BasePrefDialogFragment() {
|
||||
|
||||
override fun onPreferenceTreeClick(preference: Preference): Boolean {
|
||||
when (preference.key) {
|
||||
PreferKey.audioPreDownloadNum -> {
|
||||
NumberPickerDialog(requireContext())
|
||||
.setTitle(getString(R.string.read_aloud_preload))
|
||||
.setMaxValue(50)
|
||||
.setMinValue(0)
|
||||
.setValue(10)
|
||||
.setCustomButton((R.string.btn_default_s)) {
|
||||
putPrefInt(PreferKey.audioPreDownloadNum, 10)
|
||||
upPreferenceSummary(PreferKey.audioPreDownloadNum)
|
||||
}
|
||||
.show {
|
||||
putPrefInt(PreferKey.audioPreDownloadNum, it)
|
||||
upPreferenceSummary(PreferKey.audioPreDownloadNum)
|
||||
}
|
||||
}
|
||||
|
||||
PreferKey.audioCacheCleanTime -> {
|
||||
NumberPickerDialog(requireContext())
|
||||
.setTitle(getString(R.string.audio_cache_clean_time))
|
||||
.setMaxValue(50)
|
||||
.setMinValue(0)
|
||||
.setValue(1)
|
||||
.setCustomButton((R.string.btn_default_s)) {
|
||||
putPrefInt(PreferKey.audioCacheCleanTime, 10)
|
||||
upPreferenceSummary(PreferKey.audioCacheCleanTime)
|
||||
}
|
||||
.show {
|
||||
putPrefInt(PreferKey.audioCacheCleanTime, it)
|
||||
upPreferenceSummary(PreferKey.audioCacheCleanTime)
|
||||
}
|
||||
}
|
||||
|
||||
PreferKey.ttsEngine -> showDialogFragment(SpeakEngineDialog())
|
||||
"sysTtsConfig" -> IntentHelp.openTTSSetting()
|
||||
}
|
||||
@@ -139,12 +173,34 @@ class ReadAloudConfigDialog : BasePrefDialogFragment() {
|
||||
preference.summary = if (index >= 0) preference.entries[index] else null
|
||||
}
|
||||
|
||||
|
||||
else -> {
|
||||
preference?.summary = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun upPreferenceSummary(preferenceKey: String, value: String? = null) {
|
||||
val preference = findPreference<Preference>(preferenceKey) ?: return
|
||||
when (preferenceKey) {
|
||||
PreferKey.audioPreDownloadNum -> {
|
||||
preference.summary = getString(
|
||||
R.string.read_aloud_preload_summary,
|
||||
AppConfig.audioPreDownloadNum
|
||||
)
|
||||
}
|
||||
|
||||
PreferKey.audioCacheCleanTime -> {
|
||||
preference.summary = getString(
|
||||
R.string.audio_cache_clean_time_summary,
|
||||
AppConfig.audioCacheCleanTimeOrgin
|
||||
)
|
||||
}
|
||||
|
||||
else -> preference.summary = value
|
||||
}
|
||||
}
|
||||
|
||||
override fun upSpeakEngineSummary() {
|
||||
upPreferenceSummary(
|
||||
findPreference(PreferKey.ttsEngine),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.legado.app.ui.book.read.config
|
||||
|
||||
//import io.legado.app.lib.theme.primaryColor
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
@@ -24,15 +25,14 @@ import io.legado.app.help.DirectLinkUpload
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.lib.dialogs.SelectItem
|
||||
import io.legado.app.lib.dialogs.alert
|
||||
//import io.legado.app.lib.theme.primaryColor
|
||||
import io.legado.app.model.ReadAloud
|
||||
import io.legado.app.model.ReadBook
|
||||
import io.legado.app.ui.association.ImportHttpTtsDialog
|
||||
import io.legado.app.ui.file.HandleFileContract
|
||||
import io.legado.app.ui.login.SourceLoginActivity
|
||||
import io.legado.app.utils.ACache
|
||||
import io.legado.app.utils.FileUtils
|
||||
import io.legado.app.utils.GSON
|
||||
import io.legado.app.utils.TTSCacheUtils
|
||||
import io.legado.app.utils.fromJsonObject
|
||||
import io.legado.app.utils.gone
|
||||
import io.legado.app.utils.isAbsUrl
|
||||
@@ -49,7 +49,6 @@ import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* tts引擎管理
|
||||
@@ -236,19 +235,10 @@ class SpeakEngineDialog() : BaseBottomSheetDialogFragment(R.layout.dialog_recycl
|
||||
adapter.notifyItemRangeChanged(adapter.getHeaderCount(), adapter.itemCount)
|
||||
}
|
||||
|
||||
/**
|
||||
* 【核心修改点】清理缓存方法
|
||||
* 原来:只删除 cacheDir (内部存储)
|
||||
* 现在:调用 AppConfig.clearTtsCache(),自动处理 externalCacheDir (外部存储)
|
||||
*/
|
||||
fun clearCache() {
|
||||
execute {
|
||||
ReadAloud.upReadAloudClass()
|
||||
|
||||
// 调用万能清理函数
|
||||
AppConfig.clearTtsCache()
|
||||
|
||||
// 显示成功提示
|
||||
TTSCacheUtils.clearTtsCache()
|
||||
toastOnUi(R.string.clear_cache_success)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ import io.legado.app.help.coroutine.Coroutine
|
||||
import io.legado.app.help.storage.Backup
|
||||
import io.legado.app.help.update.AppUpdateGitHub
|
||||
import io.legado.app.lib.dialogs.alert
|
||||
import io.legado.app.service.WebService
|
||||
import io.legado.app.ui.about.CrashLogsDialog
|
||||
import io.legado.app.ui.about.UpdateDialog
|
||||
import io.legado.app.ui.book.read.ReadBookActivity
|
||||
@@ -71,7 +72,6 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
import io.legado.app.service.WebService
|
||||
|
||||
/**
|
||||
* 主界面
|
||||
@@ -135,13 +135,11 @@ open class MainActivity : VMBaseActivity<ActivityMainBinding, MainViewModel>(),
|
||||
binding.viewPagerMain.fitsSystemWindows = true
|
||||
// 其他初始化逻辑
|
||||
setupBackCallback()
|
||||
|
||||
// ——————【修改开始】——————
|
||||
|
||||
// 智能自启:如果上次是手动开启状态(web_service_auto 为 true),则自启
|
||||
if (getPrefBoolean("web_service_auto", false)) {
|
||||
if (AppConfig.webServiceAutoStart) {
|
||||
WebService.startForeground(this)
|
||||
}
|
||||
// ——————【修改结束】——————
|
||||
|
||||
upBottomMenu()
|
||||
initView()
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package io.legado.app.utils
|
||||
|
||||
import splitties.init.appCtx
|
||||
import java.io.File
|
||||
|
||||
object TTSCacheUtils {
|
||||
|
||||
fun clearTtsCache() {
|
||||
val baseDir = appCtx.externalCacheDir ?: appCtx.cacheDir
|
||||
// 清理音频文件
|
||||
FileUtils.delete(baseDir.absolutePath + File.separator + "httpTTS")
|
||||
// 清理数据库索引 (可选,建议一起清,防止索引还在但文件没了)
|
||||
FileUtils.delete(baseDir.absolutePath + File.separator + "httpTTS_cache")
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user