Merge pull request #1 from gedoor/master

merge
pull/42/head
Celeter 6 years ago committed by GitHub
commit 0cd13d7c0f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      app/src/main/java/io/legado/app/data/api/IHttpPostApi.kt
  2. 5
      app/src/main/java/io/legado/app/help/JsExtensions.kt
  3. 5
      app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt
  4. 3
      app/src/main/java/io/legado/app/service/BaseReadAloudService.kt
  5. 125
      app/src/main/java/io/legado/app/service/HttpReadAloudService.kt
  6. 20
      app/src/main/java/io/legado/app/ui/filechooser/FileChooserDialog.kt
  7. 4
      app/src/main/java/io/legado/app/utils/EncoderUtils.kt
  8. 37
      app/src/main/java/io/legado/app/utils/FileUtils.kt

@ -45,9 +45,9 @@ interface IHttpPostApi {
@FormUrlEncoded
@POST
fun postMapByte(
fun postMapByteAsync(
@Url url: String,
@FieldMap(encoded = true) fieldMap: Map<String, String>,
@HeaderMap headers: Map<String, String>
): Call<ByteArray>
): Deferred<Response<ByteArray>>
}

@ -1,5 +1,6 @@
package io.legado.app.help
import android.util.Base64
import io.legado.app.model.analyzeRule.AnalyzeUrl
import io.legado.app.utils.EncoderUtils
import io.legado.app.utils.MD5Utils
@ -33,6 +34,10 @@ object JsExtensions {
return EncoderUtils.base64Encode(str)
}
fun base64Encode(str: String, flags: Int = Base64.NO_WRAP): String? {
return EncoderUtils.base64Encode(str, flags)
}
fun strToMd5By32(str: String): String? {
return MD5Utils.strToMd5By32(str)
}

@ -1,6 +1,7 @@
package io.legado.app.model.analyzeRule
import android.text.TextUtils
import android.util.Base64
import androidx.annotation.Keep
import io.legado.app.constant.AppConst.SCRIPT_ENGINE
import io.legado.app.constant.Pattern.JS_PATTERN
@ -580,6 +581,10 @@ class AnalyzeRule(private var book: BaseBook? = null) {
return EncoderUtils.base64Encode(str)
}
fun base64Encode(str: String, flags: Int = Base64.NO_WRAP): String? {
return EncoderUtils.base64Encode(str, flags)
}
fun strToMd5By32(str: String): String? {
return MD5Utils.strToMd5By32(str)
}

@ -101,7 +101,8 @@ abstract class BaseReadAloudService : BaseService(),
return super.onStartCommand(intent, flags, startId)
}
private fun newReadAloud(dataKey: String?, play: Boolean) {
@CallSuper
open fun newReadAloud(dataKey: String?, play: Boolean) {
dataKey?.let {
textChapter = IntentDataHelp.getData(dataKey) as? TextChapter
textChapter?.let { textChapter ->

@ -7,15 +7,16 @@ import io.legado.app.data.api.IHttpPostApi
import io.legado.app.help.FileHelp
import io.legado.app.help.IntentHelp
import io.legado.app.help.http.HttpHelper
import io.legado.app.utils.LogUtils
import io.legado.app.utils.getPrefInt
import io.legado.app.utils.getPrefString
import io.legado.app.utils.postEvent
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.Job
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.jetbrains.anko.toast
import java.io.File
import java.io.FileDescriptor
import java.io.FileInputStream
import java.net.URLEncoder
@ -24,10 +25,14 @@ class HttpReadAloudService : BaseReadAloudService(),
MediaPlayer.OnErrorListener,
MediaPlayer.OnCompletionListener {
private var mediaPlayer = MediaPlayer()
private val mediaPlayer = MediaPlayer()
private lateinit var ttsFolder: String
private var job: Job? = null
private var playingIndex = -1
override fun onCreate() {
super.onCreate()
ttsFolder = cacheDir.absolutePath + File.separator + "bdTts"
mediaPlayer.setOnErrorListener(this)
mediaPlayer.setOnPreparedListener(this)
mediaPlayer.setOnCompletionListener(this)
@ -38,18 +43,72 @@ class HttpReadAloudService : BaseReadAloudService(),
mediaPlayer.release()
}
private fun getAudioBody(): Map<String, String> {
override fun newReadAloud(dataKey: String?, play: Boolean) {
mediaPlayer.reset()
job?.cancel()
playingIndex = -1
super.newReadAloud(dataKey, play)
}
override fun play() {
if (contentList.isEmpty()) return
if (nowSpeak == 0) {
downloadAudio()
} else {
val file = getSpeakFile(nowSpeak)
if (file.exists()) {
playAudio(FileInputStream(file).fd)
}
}
}
private fun downloadAudio() {
job = launch(IO) {
FileHelp.deleteFile(ttsFolder)
for (index in 0 until contentList.size) {
if (isActive) {
val bytes = HttpHelper.getByteRetrofit("http://tts.baidu.com")
.create(IHttpPostApi::class.java)
.postMapByteAsync(
"http://tts.baidu.com/text2audio",
getAudioBody(contentList[index]), mapOf()
).await()
.body()
if (bytes != null && isActive) {
val file = getSpeakFile(index)
file.writeBytes(bytes)
if (index == nowSpeak) {
playAudio(FileInputStream(file).fd)
}
}
} else {
break
}
}
}
}
@Synchronized
private fun playAudio(fd: FileDescriptor) {
if (playingIndex != nowSpeak) {
playingIndex = nowSpeak
try {
mediaPlayer.reset()
mediaPlayer.setDataSource(fd)
mediaPlayer.prepareAsync()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
private fun getSpeakFile(index: Int = nowSpeak): File {
return FileHelp.getFile("${ttsFolder}${File.separator}${index}.mp3")
}
private fun getAudioBody(content: String): Map<String, String> {
return mapOf(
Pair(
"tex",
URLEncoder.encode(
URLEncoder.encode(
contentList[nowSpeak],
"UTF-8"
),
"UTF-8"
)
),
Pair("tex", encodeTwo(content)),
Pair("spd", ((getPrefInt("ttsSpeechRate", 25) + 5) / 5).toString()),
Pair("per", getPrefString("ttsSpeechPer") ?: "0"),
Pair("cuid", "baidu_speech_demo"),
@ -64,27 +123,11 @@ class HttpReadAloudService : BaseReadAloudService(),
)
}
override fun play() {
if (contentList.isEmpty()) return
launch(IO) {
if (requestFocus()) {
val bytes = HttpHelper.getByteRetrofit("http://tts.baidu.com")
.create(IHttpPostApi::class.java)
.postMapByte("http://tts.baidu.com/text2audio", getAudioBody(), mapOf())
.execute().body()
if (bytes == null) {
withContext(Main) {
toast("访问失败")
}
} else {
val file =
FileHelp.getFile(cacheDir.absolutePath + File.separator + "bdTts.mp3")
file.writeBytes(bytes)
mediaPlayer.reset()
mediaPlayer.setDataSource(FileInputStream(file).fd)
mediaPlayer.prepareAsync()
}
}
private fun encodeTwo(content: String): String {
return try {
URLEncoder.encode(URLEncoder.encode(content, "UTF-8"), "UTF-8")
} catch (e: Exception) {
" "
}
}
@ -99,6 +142,13 @@ class HttpReadAloudService : BaseReadAloudService(),
}
override fun upSpeechRate(reset: Boolean) {
job?.cancel()
mediaPlayer.reset()
for (i in 0 until nowSpeak) {
contentList.removeAt(0)
}
nowSpeak = 0
playingIndex = -1
play()
}
@ -138,8 +188,9 @@ class HttpReadAloudService : BaseReadAloudService(),
}
override fun onCompletion(mp: MediaPlayer?) {
LogUtils.d("播放完成", contentList[nowSpeak])
readAloudNumber += contentList[nowSpeak].length + 1
if (nowSpeak < contentList.size) {
if (nowSpeak < contentList.lastIndex) {
nowSpeak++
play()
} else {

@ -0,0 +1,20 @@
package io.legado.app.ui.filechooser
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentManager
class FileChooserDialog : DialogFragment() {
companion object {
const val tag = "FileChooserDialog"
fun show(manager: FragmentManager) {
val fragment =
(manager.findFragmentByTag(tag) as? FileChooserDialog) ?: FileChooserDialog()
fragment.show(manager, tag)
}
}
}

@ -33,7 +33,7 @@ object EncoderUtils {
}
}
fun base64Encode(str: String): String? {
return Base64.encodeToString(str.toByteArray(), Base64.DEFAULT)
fun base64Encode(str: String, flags: Int = Base64.NO_WRAP): String? {
return Base64.encodeToString(str.toByteArray(), flags)
}
}

@ -48,8 +48,8 @@ object FileUtils {
val list = ArrayList<String>()
for (i in 0 until length) {
val storageValume = Array.get(invokeVolumeList, i)//得到StorageVolume对象
val path = getPath.invoke(storageValume) as String
val storageVolume = Array.get(invokeVolumeList, i)//得到StorageVolume对象
val path = getPath.invoke(storageVolume) as String
list.add(path)
}
@ -103,11 +103,8 @@ object FileUtils {
val id = DocumentsContract.getDocumentId(uri)
val split = id.split(":").dropLastWhile { it.isEmpty() }.toTypedArray()
val type = split[0]
if ("raw".equals(
type,
ignoreCase = true
)
) { //处理某些机型(比如Goole Pixel )ID是raw:/storage/emulated/0/Download/c20f8664da05ab6b4644913048ea8c83.mp4
if ("raw".equals(type, ignoreCase = true)) {
//处理某些机型(比如Google Pixel )ID是raw:/storage/emulated/0/Download/c20f8664da05ab6b4644913048ea8c83.mp4
return split[1]
}
@ -122,12 +119,10 @@ object FileUtils {
val type = split[0]
var contentUri: Uri? = null
if ("image" == type) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
} else if ("video" == type) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
} else if ("audio" == type) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
when (type) {
"image" -> contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
"video" -> contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
"audio" -> contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
}
val selection = "_id=?"
@ -136,21 +131,17 @@ object FileUtils {
return getDataColumn(context, contentUri, selection, selectionArgs)
}// MediaProvider
// DownloadsProvider
} else if ("content".equals(uri.scheme!!, ignoreCase = true)) {
} else if ("content".equals(uri.scheme, ignoreCase = true)) {
// Return the remote address
return if (isGooglePhotosUri(uri)) uri.lastPathSegment else getDataColumn(
context,
uri,
null,
null
)
return if (isGooglePhotosUri(uri))
uri.lastPathSegment
else
getDataColumn(context, uri, null, null)
} else if ("file".equals(uri.scheme!!, ignoreCase = true)) {
} else if ("file".equals(uri.scheme, ignoreCase = true)) {
return uri.path
}// File
// MediaStore (and general)
return null
}

Loading…
Cancel
Save