|
|
@ -43,6 +43,7 @@ class HttpReadAloudService : BaseReadAloudService(), |
|
|
|
private val cacheFiles = hashSetOf<String>() |
|
|
|
private val cacheFiles = hashSetOf<String>() |
|
|
|
private var downloadTask: Coroutine<*>? = null |
|
|
|
private var downloadTask: Coroutine<*>? = null |
|
|
|
private var playIndexJob: Job? = null |
|
|
|
private var playIndexJob: Job? = null |
|
|
|
|
|
|
|
private var downloadTaskIsActive = false |
|
|
|
private var downloadErrorNo: Int = 0 |
|
|
|
private var downloadErrorNo: Int = 0 |
|
|
|
private var playErrorNo = 0 |
|
|
|
private var playErrorNo = 0 |
|
|
|
|
|
|
|
|
|
|
@ -103,104 +104,114 @@ class HttpReadAloudService : BaseReadAloudService(), |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private fun downloadAudio() { |
|
|
|
private fun downloadAudio() { |
|
|
|
downloadTask?.cancel() |
|
|
|
launch { |
|
|
|
downloadTask = execute { |
|
|
|
downloadTask?.cancel() |
|
|
|
clearSpeakCache() |
|
|
|
while (downloadTaskIsActive) { |
|
|
|
removeCacheFile() |
|
|
|
//在线tts大部分只能单线程,等待上次访问结束 |
|
|
|
val httpTts = ReadAloud.httpTTS ?: return@execute |
|
|
|
delay(100) |
|
|
|
contentList.forEachIndexed { index, content -> |
|
|
|
} |
|
|
|
ensureActive() |
|
|
|
downloadTask = execute { |
|
|
|
val fileName = |
|
|
|
clearSpeakCache() |
|
|
|
md5SpeakFileName(httpTts.url, speechRate.toString(), content) |
|
|
|
removeCacheFile() |
|
|
|
val speakText = content.replace(AppPattern.notReadAloudRegex, "") |
|
|
|
val httpTts = ReadAloud.httpTTS ?: return@execute |
|
|
|
if (hasSpeakFile(fileName)) { //已经下载好的语音缓存 |
|
|
|
contentList.forEachIndexed { index, content -> |
|
|
|
if (index == nowSpeak) { |
|
|
|
ensureActive() |
|
|
|
val file = getSpeakFileAsMd5(fileName) |
|
|
|
val fileName = |
|
|
|
playAudio(file) |
|
|
|
md5SpeakFileName(httpTts.url, speechRate.toString(), content) |
|
|
|
} |
|
|
|
val speakText = content.replace(AppPattern.notReadAloudRegex, "") |
|
|
|
} else if (hasSpeakCache(fileName)) { //缓存文件还在,可能还没下载完 |
|
|
|
if (hasSpeakFile(fileName)) { //已经下载好的语音缓存 |
|
|
|
return@forEachIndexed |
|
|
|
if (index == nowSpeak) { |
|
|
|
} else if (speakText.isEmpty()) { |
|
|
|
val file = getSpeakFileAsMd5(fileName) |
|
|
|
createSilentSound(fileName) |
|
|
|
playAudio(file) |
|
|
|
return@forEachIndexed |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
runCatching { |
|
|
|
|
|
|
|
createSpeakCache(fileName) |
|
|
|
|
|
|
|
val analyzeUrl = AnalyzeUrl( |
|
|
|
|
|
|
|
httpTts.url, |
|
|
|
|
|
|
|
speakText = speakText, |
|
|
|
|
|
|
|
speakSpeed = speechRate, |
|
|
|
|
|
|
|
source = httpTts, |
|
|
|
|
|
|
|
headerMapF = httpTts.getHeaderMap(true) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
var response = analyzeUrl.getResponseAwait() |
|
|
|
|
|
|
|
ensureActive() |
|
|
|
|
|
|
|
httpTts.loginCheckJs?.takeIf { checkJs -> |
|
|
|
|
|
|
|
checkJs.isNotBlank() |
|
|
|
|
|
|
|
}?.let { checkJs -> |
|
|
|
|
|
|
|
response = analyzeUrl.evalJS(checkJs, response) as Response |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
httpTts.contentType?.takeIf { ct -> |
|
|
|
} else if (hasSpeakCache(fileName)) { //缓存文件还在,可能还没下载完 |
|
|
|
ct.isNotBlank() |
|
|
|
return@forEachIndexed |
|
|
|
}?.let { ct -> |
|
|
|
} else if (speakText.isEmpty()) { |
|
|
|
response.headers["Content-Type"]?.let { contentType -> |
|
|
|
createSilentSound(fileName) |
|
|
|
if (!contentType.matches(ct.toRegex())) { |
|
|
|
return@forEachIndexed |
|
|
|
throw NoStackTraceException(response.body!!.string()) |
|
|
|
} else { |
|
|
|
} |
|
|
|
runCatching { |
|
|
|
|
|
|
|
createSpeakCache(fileName) |
|
|
|
|
|
|
|
val analyzeUrl = AnalyzeUrl( |
|
|
|
|
|
|
|
httpTts.url, |
|
|
|
|
|
|
|
speakText = speakText, |
|
|
|
|
|
|
|
speakSpeed = speechRate, |
|
|
|
|
|
|
|
source = httpTts, |
|
|
|
|
|
|
|
headerMapF = httpTts.getHeaderMap(true) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
var response = analyzeUrl.getResponseAwait() |
|
|
|
|
|
|
|
ensureActive() |
|
|
|
|
|
|
|
httpTts.loginCheckJs?.takeIf { checkJs -> |
|
|
|
|
|
|
|
checkJs.isNotBlank() |
|
|
|
|
|
|
|
}?.let { checkJs -> |
|
|
|
|
|
|
|
response = analyzeUrl.evalJS(checkJs, response) as Response |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
httpTts.contentType?.takeIf { ct -> |
|
|
|
ensureActive() |
|
|
|
ct.isNotBlank() |
|
|
|
response.body!!.bytes().let { bytes -> |
|
|
|
}?.let { ct -> |
|
|
|
val file = createSpeakFileAsMd5IfNotExist(fileName) |
|
|
|
response.headers["Content-Type"]?.let { contentType -> |
|
|
|
file.writeBytes(bytes) |
|
|
|
if (!contentType.matches(ct.toRegex())) { |
|
|
|
removeSpeakCache(fileName) |
|
|
|
throw NoStackTraceException(response.body!!.string()) |
|
|
|
if (index == nowSpeak) { |
|
|
|
} |
|
|
|
playAudio(file) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
ensureActive() |
|
|
|
downloadErrorNo = 0 |
|
|
|
response.body!!.bytes().let { bytes -> |
|
|
|
}.onFailure { |
|
|
|
val file = createSpeakFileAsMd5IfNotExist(fileName) |
|
|
|
when (it) { |
|
|
|
file.writeBytes(bytes) |
|
|
|
is CancellationException -> removeSpeakCache(fileName) |
|
|
|
|
|
|
|
is ConcurrentException -> { |
|
|
|
|
|
|
|
removeSpeakCache(fileName) |
|
|
|
removeSpeakCache(fileName) |
|
|
|
delay(it.waitTime.toLong()) |
|
|
|
if (index == nowSpeak) { |
|
|
|
downloadAudio() |
|
|
|
playAudio(file) |
|
|
|
} |
|
|
|
} |
|
|
|
is ScriptException, is WrappedException -> { |
|
|
|
|
|
|
|
AppLog.put("js错误\n${it.localizedMessage}", it) |
|
|
|
|
|
|
|
toastOnUi("js错误\n${it.localizedMessage}") |
|
|
|
|
|
|
|
it.printOnDebug() |
|
|
|
|
|
|
|
cancel() |
|
|
|
|
|
|
|
pauseReadAloud(true) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
is SocketTimeoutException, is ConnectException -> { |
|
|
|
downloadErrorNo = 0 |
|
|
|
removeSpeakCache(fileName) |
|
|
|
}.onFailure { |
|
|
|
downloadErrorNo++ |
|
|
|
when (it) { |
|
|
|
if (downloadErrorNo > 5) { |
|
|
|
is CancellationException -> removeSpeakCache(fileName) |
|
|
|
val msg = "tts超时或连接错误超过5次\n${it.localizedMessage}" |
|
|
|
is ConcurrentException -> { |
|
|
|
AppLog.put(msg, it) |
|
|
|
removeSpeakCache(fileName) |
|
|
|
toastOnUi(msg) |
|
|
|
delay(it.waitTime.toLong()) |
|
|
|
pauseReadAloud(true) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
downloadAudio() |
|
|
|
downloadAudio() |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
is ScriptException, is WrappedException -> { |
|
|
|
else -> { |
|
|
|
AppLog.put("js错误\n${it.localizedMessage}", it) |
|
|
|
removeSpeakCache(fileName) |
|
|
|
toastOnUi("js错误\n${it.localizedMessage}") |
|
|
|
downloadErrorNo++ |
|
|
|
it.printOnDebug() |
|
|
|
val msg = "tts下载错误\n${it.localizedMessage}" |
|
|
|
cancel() |
|
|
|
AppLog.put(msg, it) |
|
|
|
|
|
|
|
it.printOnDebug() |
|
|
|
|
|
|
|
if (downloadErrorNo > 5) { |
|
|
|
|
|
|
|
pauseReadAloud(true) |
|
|
|
pauseReadAloud(true) |
|
|
|
} else { |
|
|
|
} |
|
|
|
createSilentSound(fileName) |
|
|
|
is SocketTimeoutException, is ConnectException -> { |
|
|
|
|
|
|
|
removeSpeakCache(fileName) |
|
|
|
|
|
|
|
downloadErrorNo++ |
|
|
|
|
|
|
|
if (downloadErrorNo > 5) { |
|
|
|
|
|
|
|
val msg = "tts超时或连接错误超过5次\n${it.localizedMessage}" |
|
|
|
|
|
|
|
AppLog.put(msg, it) |
|
|
|
|
|
|
|
toastOnUi(msg) |
|
|
|
|
|
|
|
pauseReadAloud(true) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
downloadAudio() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else -> { |
|
|
|
|
|
|
|
removeSpeakCache(fileName) |
|
|
|
|
|
|
|
downloadErrorNo++ |
|
|
|
|
|
|
|
val msg = "tts下载错误\n${it.localizedMessage}" |
|
|
|
|
|
|
|
AppLog.put(msg, it) |
|
|
|
|
|
|
|
it.printOnDebug() |
|
|
|
|
|
|
|
if (downloadErrorNo > 5) { |
|
|
|
|
|
|
|
pauseReadAloud(true) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
createSilentSound(fileName) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
}.onStart { |
|
|
|
|
|
|
|
downloadTaskIsActive = true |
|
|
|
|
|
|
|
}.onFinally { |
|
|
|
|
|
|
|
downloadTaskIsActive = false |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|