优化
This commit is contained in:
@@ -4,6 +4,7 @@ import android.content.Intent
|
|||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import androidx.annotation.CallSuper
|
import androidx.annotation.CallSuper
|
||||||
import androidx.lifecycle.LifecycleService
|
import androidx.lifecycle.LifecycleService
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import io.legado.app.R
|
import io.legado.app.R
|
||||||
import io.legado.app.help.LifecycleHelp
|
import io.legado.app.help.LifecycleHelp
|
||||||
import io.legado.app.help.coroutine.Coroutine
|
import io.legado.app.help.coroutine.Coroutine
|
||||||
@@ -12,15 +13,13 @@ import io.legado.app.lib.permission.PermissionsCompat
|
|||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.CoroutineStart
|
import kotlinx.coroutines.CoroutineStart
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.MainScope
|
|
||||||
import kotlinx.coroutines.cancel
|
|
||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
abstract class BaseService : LifecycleService(), CoroutineScope by MainScope() {
|
abstract class BaseService : LifecycleService() {
|
||||||
|
|
||||||
fun <T> execute(
|
fun <T> execute(
|
||||||
scope: CoroutineScope = this,
|
scope: CoroutineScope = lifecycleScope,
|
||||||
context: CoroutineContext = Dispatchers.IO,
|
context: CoroutineContext = Dispatchers.IO,
|
||||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||||
executeContext: CoroutineContext = Dispatchers.Main,
|
executeContext: CoroutineContext = Dispatchers.Main,
|
||||||
@@ -49,7 +48,6 @@ abstract class BaseService : LifecycleService(), CoroutineScope by MainScope() {
|
|||||||
@CallSuper
|
@CallSuper
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
cancel()
|
|
||||||
LifecycleHelp.onServiceDestroy(this)
|
LifecycleHelp.onServiceDestroy(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +66,7 @@ abstract class BaseService : LifecycleService(), CoroutineScope by MainScope() {
|
|||||||
.addPermissions(Permissions.POST_NOTIFICATIONS)
|
.addPermissions(Permissions.POST_NOTIFICATIONS)
|
||||||
.rationale(R.string.notification_permission_rationale)
|
.rationale(R.string.notification_permission_rationale)
|
||||||
.onGranted {
|
.onGranted {
|
||||||
if (isActive) {
|
if (lifecycleScope.isActive) {
|
||||||
upNotification()
|
upNotification()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import android.support.v4.media.MediaMetadataCompat
|
|||||||
import android.support.v4.media.session.MediaSessionCompat
|
import android.support.v4.media.session.MediaSessionCompat
|
||||||
import android.support.v4.media.session.PlaybackStateCompat
|
import android.support.v4.media.session.PlaybackStateCompat
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.media.AudioFocusRequestCompat
|
import androidx.media.AudioFocusRequestCompat
|
||||||
import androidx.media3.common.PlaybackException
|
import androidx.media3.common.PlaybackException
|
||||||
import androidx.media3.common.Player
|
import androidx.media3.common.Player
|
||||||
@@ -341,7 +342,7 @@ class AudioPlayService : BaseService(),
|
|||||||
postEvent(EventBus.AUDIO_DS, timeMinute)
|
postEvent(EventBus.AUDIO_DS, timeMinute)
|
||||||
upNotification()
|
upNotification()
|
||||||
dsJob?.cancel()
|
dsJob?.cancel()
|
||||||
dsJob = launch {
|
dsJob = lifecycleScope.launch {
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
delay(60000)
|
delay(60000)
|
||||||
if (!pause) {
|
if (!pause) {
|
||||||
@@ -363,7 +364,7 @@ class AudioPlayService : BaseService(),
|
|||||||
*/
|
*/
|
||||||
private fun upPlayProgress() {
|
private fun upPlayProgress() {
|
||||||
upPlayProgressJob?.cancel()
|
upPlayProgressJob?.cancel()
|
||||||
upPlayProgressJob = launch {
|
upPlayProgressJob = lifecycleScope.launch {
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
AudioPlay.book?.let {
|
AudioPlay.book?.let {
|
||||||
//更新buffer位置
|
//更新buffer位置
|
||||||
@@ -387,7 +388,7 @@ class AudioPlayService : BaseService(),
|
|||||||
val book = AudioPlay.book
|
val book = AudioPlay.book
|
||||||
val bookSource = AudioPlay.bookSource
|
val bookSource = AudioPlay.bookSource
|
||||||
if (book != null && bookSource != null) {
|
if (book != null && bookSource != null) {
|
||||||
WebBook.getContent(this@AudioPlayService, bookSource, book, chapter)
|
WebBook.getContent(lifecycleScope, bookSource, book, chapter)
|
||||||
.onSuccess { content ->
|
.onSuccess { content ->
|
||||||
if (content.isEmpty()) {
|
if (content.isEmpty()) {
|
||||||
toastOnUi("未获取到资源链接")
|
toastOnUi("未获取到资源链接")
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import android.support.v4.media.session.MediaSessionCompat
|
|||||||
import android.support.v4.media.session.PlaybackStateCompat
|
import android.support.v4.media.session.PlaybackStateCompat
|
||||||
import androidx.annotation.CallSuper
|
import androidx.annotation.CallSuper
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.media.AudioFocusRequestCompat
|
import androidx.media.AudioFocusRequestCompat
|
||||||
import androidx.media.AudioManagerCompat
|
import androidx.media.AudioManagerCompat
|
||||||
import io.legado.app.R
|
import io.legado.app.R
|
||||||
@@ -160,18 +161,20 @@ abstract class BaseReadAloudService : BaseService(),
|
|||||||
return super.onStartCommand(intent, flags, startId)
|
return super.onStartCommand(intent, flags, startId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun newReadAloud(play: Boolean, pageIndex: Int, startPos: Int) = launch(IO) {
|
private fun newReadAloud(play: Boolean, pageIndex: Int, startPos: Int) {
|
||||||
this@BaseReadAloudService.pageIndex = pageIndex
|
lifecycleScope.launch(IO) {
|
||||||
textChapter = ReadBook.curTextChapter
|
this@BaseReadAloudService.pageIndex = pageIndex
|
||||||
val textChapter = textChapter ?: return@launch
|
textChapter = ReadBook.curTextChapter
|
||||||
nowSpeak = 0
|
val textChapter = textChapter ?: return@launch
|
||||||
readAloudNumber = textChapter.getReadLength(pageIndex) + startPos
|
nowSpeak = 0
|
||||||
val readAloudByPage = getPrefBoolean(PreferKey.readAloudByPage)
|
readAloudNumber = textChapter.getReadLength(pageIndex) + startPos
|
||||||
contentList = textChapter.getNeedReadAloud(pageIndex, readAloudByPage, startPos)
|
val readAloudByPage = getPrefBoolean(PreferKey.readAloudByPage)
|
||||||
.split("\n")
|
contentList = textChapter.getNeedReadAloud(pageIndex, readAloudByPage, startPos)
|
||||||
.filter { it.isNotEmpty() }
|
.split("\n")
|
||||||
launch(Main) {
|
.filter { it.isNotEmpty() }
|
||||||
if (play) play() else pageChanged = true
|
launch(Main) {
|
||||||
|
if (play) play() else pageChanged = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,7 +259,7 @@ abstract class BaseReadAloudService : BaseService(),
|
|||||||
postEvent(EventBus.READ_ALOUD_DS, timeMinute)
|
postEvent(EventBus.READ_ALOUD_DS, timeMinute)
|
||||||
upNotification()
|
upNotification()
|
||||||
dsJob?.cancel()
|
dsJob?.cancel()
|
||||||
dsJob = launch {
|
dsJob = lifecycleScope.launch {
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
delay(60000)
|
delay(60000)
|
||||||
if (!pause) {
|
if (!pause) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package io.legado.app.service
|
|||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import io.legado.app.R
|
import io.legado.app.R
|
||||||
import io.legado.app.base.BaseService
|
import io.legado.app.base.BaseService
|
||||||
import io.legado.app.constant.AppConst
|
import io.legado.app.constant.AppConst
|
||||||
@@ -61,7 +62,7 @@ class CacheBookService : BaseService() {
|
|||||||
isRun = true
|
isRun = true
|
||||||
CacheBook.successDownloadSet.clear()
|
CacheBook.successDownloadSet.clear()
|
||||||
CacheBook.errorDownloadMap.clear()
|
CacheBook.errorDownloadMap.clear()
|
||||||
launch {
|
lifecycleScope.launch {
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
delay(1000)
|
delay(1000)
|
||||||
notificationContent = CacheBook.downloadSummary
|
notificationContent = CacheBook.downloadSummary
|
||||||
@@ -142,7 +143,7 @@ class CacheBookService : BaseService() {
|
|||||||
|
|
||||||
private fun download() {
|
private fun download() {
|
||||||
downloadJob?.cancel()
|
downloadJob?.cancel()
|
||||||
downloadJob = launch(cachePool) {
|
downloadJob = lifecycleScope.launch(cachePool) {
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
if (!CacheBook.isRun) {
|
if (!CacheBook.isRun) {
|
||||||
CacheBook.stop(this@CacheBookService)
|
CacheBook.stop(this@CacheBookService)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package io.legado.app.service
|
|||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.script.ScriptException
|
import com.script.ScriptException
|
||||||
import io.legado.app.R
|
import io.legado.app.R
|
||||||
import io.legado.app.base.BaseService
|
import io.legado.app.base.BaseService
|
||||||
@@ -109,7 +110,7 @@ class CheckSourceService : BaseService() {
|
|||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
processIndex++
|
processIndex++
|
||||||
}
|
}
|
||||||
launch(IO) {
|
lifecycleScope.launch(IO) {
|
||||||
if (index < allIds.size) {
|
if (index < allIds.size) {
|
||||||
val sourceUrl = allIds[index]
|
val sourceUrl = allIds[index]
|
||||||
appDb.bookSourceDao.getBookSource(sourceUrl)?.let { source ->
|
appDb.bookSourceDao.getBookSource(sourceUrl)?.let { source ->
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import android.content.IntentFilter
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import io.legado.app.R
|
import io.legado.app.R
|
||||||
import io.legado.app.base.BaseService
|
import io.legado.app.base.BaseService
|
||||||
import io.legado.app.constant.AppConst
|
import io.legado.app.constant.AppConst
|
||||||
@@ -147,7 +148,7 @@ class DownloadService : BaseService() {
|
|||||||
|
|
||||||
private fun checkDownloadState() {
|
private fun checkDownloadState() {
|
||||||
upStateJob?.cancel()
|
upStateJob?.cancel()
|
||||||
upStateJob = launch {
|
upStateJob = lifecycleScope.launch {
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
queryState()
|
queryState()
|
||||||
delay(1000)
|
delay(1000)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import android.os.Build
|
|||||||
import android.util.ArraySet
|
import android.util.ArraySet
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.documentfile.provider.DocumentFile
|
import androidx.documentfile.provider.DocumentFile
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.bumptech.glide.request.target.CustomTarget
|
import com.bumptech.glide.request.target.CustomTarget
|
||||||
import com.bumptech.glide.request.transition.Transition
|
import com.bumptech.glide.request.transition.Transition
|
||||||
@@ -53,6 +54,7 @@ import kotlinx.coroutines.Job
|
|||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.ensureActive
|
import kotlinx.coroutines.ensureActive
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import me.ag2s.epublib.domain.Author
|
import me.ag2s.epublib.domain.Author
|
||||||
import me.ag2s.epublib.domain.Date
|
import me.ag2s.epublib.domain.Date
|
||||||
import me.ag2s.epublib.domain.EpubBook
|
import me.ag2s.epublib.domain.EpubBook
|
||||||
@@ -171,7 +173,7 @@ class ExportBookService : BaseService() {
|
|||||||
if (exportProgress.contains(bookUrl)) return
|
if (exportProgress.contains(bookUrl)) return
|
||||||
exportProgress[bookUrl] = 0
|
exportProgress[bookUrl] = 0
|
||||||
waitExportBooks.remove(bookUrl)
|
waitExportBooks.remove(bookUrl)
|
||||||
exportJob = launch(IO) {
|
exportJob = lifecycleScope.launch(IO) {
|
||||||
val book = appDb.bookDao.getBook(bookUrl)
|
val book = appDb.bookDao.getBook(bookUrl)
|
||||||
try {
|
try {
|
||||||
book ?: throw NoStackTraceException("获取${bookUrl}书籍出错")
|
book ?: throw NoStackTraceException("获取${bookUrl}书籍出错")
|
||||||
@@ -205,6 +207,12 @@ class ExportBookService : BaseService() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private data class SrcData(
|
||||||
|
val chapterTitle: String,
|
||||||
|
val index: Int,
|
||||||
|
val src: String
|
||||||
|
)
|
||||||
|
|
||||||
private suspend fun export(path: String, book: Book) {
|
private suspend fun export(path: String, book: Book) {
|
||||||
exportMsg.remove(book.bookUrl)
|
exportMsg.remove(book.bookUrl)
|
||||||
postEvent(EventBus.EXPORT_BOOK, book.bookUrl)
|
postEvent(EventBus.EXPORT_BOOK, book.bookUrl)
|
||||||
@@ -227,12 +235,16 @@ class ExportBookService : BaseService() {
|
|||||||
getAllContents(book) { text, srcList ->
|
getAllContents(book) { text, srcList ->
|
||||||
bookOs.write(text.toByteArray(Charset.forName(AppConfig.exportCharset)))
|
bookOs.write(text.toByteArray(Charset.forName(AppConfig.exportCharset)))
|
||||||
srcList?.forEach {
|
srcList?.forEach {
|
||||||
val vFile = BookHelp.getImage(book, it.third)
|
val vFile = BookHelp.getImage(book, it.src)
|
||||||
if (vFile.exists()) {
|
if (vFile.exists()) {
|
||||||
DocumentUtils.createFileIfNotExist(
|
DocumentUtils.createFileIfNotExist(
|
||||||
doc,
|
doc,
|
||||||
"${it.second}-${MD5Utils.md5Encode16(it.third)}.jpg",
|
"${it.index}-${MD5Utils.md5Encode16(it.src)}.jpg",
|
||||||
subDirs = arrayOf("${book.name}_${book.author}", "images", it.first)
|
subDirs = arrayOf(
|
||||||
|
"${book.name}_${book.author}",
|
||||||
|
"images",
|
||||||
|
it.chapterTitle
|
||||||
|
)
|
||||||
)?.writeBytes(this, vFile.readBytes())
|
)?.writeBytes(this, vFile.readBytes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,14 +263,14 @@ class ExportBookService : BaseService() {
|
|||||||
getAllContents(book) { text, srcList ->
|
getAllContents(book) { text, srcList ->
|
||||||
bookFile.appendText(text, Charset.forName(AppConfig.exportCharset))
|
bookFile.appendText(text, Charset.forName(AppConfig.exportCharset))
|
||||||
srcList?.forEach {
|
srcList?.forEach {
|
||||||
val vFile = BookHelp.getImage(book, it.third)
|
val vFile = BookHelp.getImage(book, it.src)
|
||||||
if (vFile.exists()) {
|
if (vFile.exists()) {
|
||||||
FileUtils.createFileIfNotExist(
|
FileUtils.createFileIfNotExist(
|
||||||
file,
|
file,
|
||||||
"${book.name}_${book.author}",
|
"${book.name}_${book.author}",
|
||||||
"images",
|
"images",
|
||||||
it.first,
|
it.chapterTitle,
|
||||||
"${it.second}-${MD5Utils.md5Encode16(it.third)}.jpg"
|
"${it.index}-${MD5Utils.md5Encode16(it.src)}.jpg"
|
||||||
).writeBytes(vFile.readBytes())
|
).writeBytes(vFile.readBytes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -270,8 +282,8 @@ class ExportBookService : BaseService() {
|
|||||||
|
|
||||||
private suspend fun getAllContents(
|
private suspend fun getAllContents(
|
||||||
book: Book,
|
book: Book,
|
||||||
append: (text: String, srcList: ArrayList<Triple<String, Int, String>>?) -> Unit
|
append: (text: String, srcList: ArrayList<SrcData>?) -> Unit
|
||||||
) {
|
) = withContext(IO) {
|
||||||
val useReplace = AppConfig.exportUseReplace && book.getUseReplaceRule()
|
val useReplace = AppConfig.exportUseReplace && book.getUseReplaceRule()
|
||||||
val contentProcessor = ContentProcessor.get(book.name, book.origin)
|
val contentProcessor = ContentProcessor.get(book.name, book.origin)
|
||||||
val qy = "${book.name}\n${
|
val qy = "${book.name}\n${
|
||||||
@@ -285,7 +297,7 @@ class ExportBookService : BaseService() {
|
|||||||
append(qy, null)
|
append(qy, null)
|
||||||
if (AppConfig.parallelExportBook) {
|
if (AppConfig.parallelExportBook) {
|
||||||
val oc =
|
val oc =
|
||||||
OrderCoroutine<Pair<String, ArrayList<Triple<String, Int, String>>?>>(AppConfig.threadCount)
|
OrderCoroutine<Pair<String, ArrayList<SrcData>?>>(AppConfig.threadCount)
|
||||||
appDb.bookChapterDao.getChapterList(book.bookUrl).forEach { chapter ->
|
appDb.bookChapterDao.getChapterList(book.bookUrl).forEach { chapter ->
|
||||||
oc.submit { getExportData(book, chapter, contentProcessor, useReplace) }
|
oc.submit { getExportData(book, chapter, contentProcessor, useReplace) }
|
||||||
}
|
}
|
||||||
@@ -296,7 +308,7 @@ class ExportBookService : BaseService() {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
appDb.bookChapterDao.getChapterList(book.bookUrl).forEachIndexed { index, chapter ->
|
appDb.bookChapterDao.getChapterList(book.bookUrl).forEachIndexed { index, chapter ->
|
||||||
kotlin.coroutines.coroutineContext.ensureActive()
|
ensureActive()
|
||||||
postEvent(EventBus.EXPORT_BOOK, book.bookUrl)
|
postEvent(EventBus.EXPORT_BOOK, book.bookUrl)
|
||||||
exportProgress[book.bookUrl] = index
|
exportProgress[book.bookUrl] = index
|
||||||
val result = getExportData(book, chapter, contentProcessor, useReplace)
|
val result = getExportData(book, chapter, contentProcessor, useReplace)
|
||||||
@@ -311,7 +323,7 @@ class ExportBookService : BaseService() {
|
|||||||
chapter: BookChapter,
|
chapter: BookChapter,
|
||||||
contentProcessor: ContentProcessor,
|
contentProcessor: ContentProcessor,
|
||||||
useReplace: Boolean
|
useReplace: Boolean
|
||||||
): Pair<String, ArrayList<Triple<String, Int, String>>?> {
|
): Pair<String, ArrayList<SrcData>?> {
|
||||||
BookHelp.getContent(book, chapter).let { content ->
|
BookHelp.getContent(book, chapter).let { content ->
|
||||||
val content1 = contentProcessor
|
val content1 = contentProcessor
|
||||||
.getContent(
|
.getContent(
|
||||||
@@ -326,13 +338,13 @@ class ExportBookService : BaseService() {
|
|||||||
).toString()
|
).toString()
|
||||||
if (AppConfig.exportPictureFile) {
|
if (AppConfig.exportPictureFile) {
|
||||||
//txt导出图片文件
|
//txt导出图片文件
|
||||||
val srcList = arrayListOf<Triple<String, Int, String>>()
|
val srcList = arrayListOf<SrcData>()
|
||||||
content?.split("\n")?.forEachIndexed { index, text ->
|
content?.split("\n")?.forEachIndexed { index, text ->
|
||||||
val matcher = AppPattern.imgPattern.matcher(text)
|
val matcher = AppPattern.imgPattern.matcher(text)
|
||||||
while (matcher.find()) {
|
while (matcher.find()) {
|
||||||
matcher.group(1)?.let {
|
matcher.group(1)?.let {
|
||||||
val src = NetworkUtils.getAbsoluteURL(chapter.url, it)
|
val src = NetworkUtils.getAbsoluteURL(chapter.url, it)
|
||||||
srcList.add(Triple(chapter.title, index, src))
|
srcList.add(SrcData(chapter.title, index, src))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -594,12 +606,12 @@ class ExportBookService : BaseService() {
|
|||||||
contentModel: String,
|
contentModel: String,
|
||||||
book: Book,
|
book: Book,
|
||||||
epubBook: EpubBook
|
epubBook: EpubBook
|
||||||
) {
|
) = withContext(IO) {
|
||||||
//正文
|
//正文
|
||||||
val useReplace = AppConfig.exportUseReplace && book.getUseReplaceRule()
|
val useReplace = AppConfig.exportUseReplace && book.getUseReplaceRule()
|
||||||
val contentProcessor = ContentProcessor.get(book.name, book.origin)
|
val contentProcessor = ContentProcessor.get(book.name, book.origin)
|
||||||
appDb.bookChapterDao.getChapterList(book.bookUrl).forEachIndexed { index, chapter ->
|
appDb.bookChapterDao.getChapterList(book.bookUrl).forEachIndexed { index, chapter ->
|
||||||
kotlin.coroutines.coroutineContext.ensureActive()
|
ensureActive()
|
||||||
postEvent(EventBus.EXPORT_BOOK, book.bookUrl)
|
postEvent(EventBus.EXPORT_BOOK, book.bookUrl)
|
||||||
exportProgress[book.bookUrl] = index
|
exportProgress[book.bookUrl] = index
|
||||||
BookHelp.getContent(book, chapter).let { content ->
|
BookHelp.getContent(book, chapter).let { content ->
|
||||||
@@ -701,7 +713,7 @@ class ExportBookService : BaseService() {
|
|||||||
suspend fun export(
|
suspend fun export(
|
||||||
path: String,
|
path: String,
|
||||||
book: Book
|
book: Book
|
||||||
) {
|
) = withContext(IO) {
|
||||||
exportProgress[book.bookUrl] = 0
|
exportProgress[book.bookUrl] = 0
|
||||||
exportMsg.remove(book.bookUrl)
|
exportMsg.remove(book.bookUrl)
|
||||||
postEvent(EventBus.EXPORT_BOOK, book.bookUrl)
|
postEvent(EventBus.EXPORT_BOOK, book.bookUrl)
|
||||||
@@ -729,7 +741,7 @@ class ExportBookService : BaseService() {
|
|||||||
progressBar += book.totalChapterNum.toDouble() / scope.size / 2
|
progressBar += book.totalChapterNum.toDouble() / scope.size / 2
|
||||||
exportProgress[book.bookUrl] = progressBar.toInt()
|
exportProgress[book.bookUrl] = progressBar.toInt()
|
||||||
}
|
}
|
||||||
save2Drive(filename, epubBook, doc) { total, progress ->
|
save2Drive(filename, epubBook, doc) { total, _ ->
|
||||||
//写入硬盘时更新进度条
|
//写入硬盘时更新进度条
|
||||||
progressBar += book.totalChapterNum.toDouble() / epubList.size / total / 2
|
progressBar += book.totalChapterNum.toDouble() / epubList.size / total / 2
|
||||||
postEvent(EventBus.EXPORT_BOOK, book.bookUrl)
|
postEvent(EventBus.EXPORT_BOOK, book.bookUrl)
|
||||||
@@ -761,7 +773,7 @@ class ExportBookService : BaseService() {
|
|||||||
exportProgress[book.bookUrl]?.plus(book.totalChapterNum / scope.size)
|
exportProgress[book.bookUrl]?.plus(book.totalChapterNum / scope.size)
|
||||||
?: 1
|
?: 1
|
||||||
}
|
}
|
||||||
save2Drive(filename, epubBook, file) { total, progress ->
|
save2Drive(filename, epubBook, file) { total, _ ->
|
||||||
//设置进度
|
//设置进度
|
||||||
progressBar += book.totalChapterNum.toDouble() / epubList.size / total / 2
|
progressBar += book.totalChapterNum.toDouble() / epubList.size / total / 2
|
||||||
postEvent(EventBus.EXPORT_BOOK, book.bookUrl)
|
postEvent(EventBus.EXPORT_BOOK, book.bookUrl)
|
||||||
@@ -785,13 +797,13 @@ class ExportBookService : BaseService() {
|
|||||||
* @param epubBook 分割后的epub
|
* @param epubBook 分割后的epub
|
||||||
* @param epubBookIndex 分割后的epub序号
|
* @param epubBookIndex 分割后的epub序号
|
||||||
*/
|
*/
|
||||||
private fun setEpubContent(
|
private suspend fun setEpubContent(
|
||||||
contentModel: String,
|
contentModel: String,
|
||||||
book: Book,
|
book: Book,
|
||||||
epubBook: EpubBook,
|
epubBook: EpubBook,
|
||||||
epubBookIndex: Int,
|
epubBookIndex: Int,
|
||||||
updateProgress: (chapterList: MutableList<BookChapter>, index: Int) -> Unit
|
updateProgress: (chapterList: MutableList<BookChapter>, index: Int) -> Unit
|
||||||
) {
|
) = withContext(IO) {
|
||||||
//正文
|
//正文
|
||||||
val useReplace = AppConfig.exportUseReplace && book.getUseReplaceRule()
|
val useReplace = AppConfig.exportUseReplace && book.getUseReplaceRule()
|
||||||
val contentProcessor = ContentProcessor.get(book.name, book.origin)
|
val contentProcessor = ContentProcessor.get(book.name, book.origin)
|
||||||
@@ -813,7 +825,7 @@ class ExportBookService : BaseService() {
|
|||||||
if ((epubBookIndex + 1) * size > scope.size) scope.size else (epubBookIndex + 1) * size
|
if ((epubBookIndex + 1) * size > scope.size) scope.size else (epubBookIndex + 1) * size
|
||||||
)
|
)
|
||||||
chapterList.forEachIndexed { index, chapter ->
|
chapterList.forEachIndexed { index, chapter ->
|
||||||
coroutineContext.ensureActive()
|
ensureActive()
|
||||||
updateProgress(chapterList, index)
|
updateProgress(chapterList, index)
|
||||||
BookHelp.getContent(book, chapter).let { content ->
|
BookHelp.getContent(book, chapter).let { content ->
|
||||||
var content1 = fixPic(
|
var content1 = fixPic(
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package io.legado.app.service
|
|||||||
|
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.media3.common.MediaItem
|
import androidx.media3.common.MediaItem
|
||||||
import androidx.media3.common.PlaybackException
|
import androidx.media3.common.PlaybackException
|
||||||
import androidx.media3.common.Player
|
import androidx.media3.common.Player
|
||||||
@@ -26,6 +27,7 @@ import io.legado.app.utils.printOnDebug
|
|||||||
import io.legado.app.utils.servicePendingIntent
|
import io.legado.app.utils.servicePendingIntent
|
||||||
import io.legado.app.utils.toastOnUi
|
import io.legado.app.utils.toastOnUi
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.Dispatchers.Main
|
import kotlinx.coroutines.Dispatchers.Main
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
@@ -33,6 +35,7 @@ import kotlinx.coroutines.ensureActive
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import org.mozilla.javascript.WrappedException
|
import org.mozilla.javascript.WrappedException
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -151,7 +154,10 @@ class HttpReadAloudService : BaseReadAloudService(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getSpeakStream(httpTts: HttpTTS, speakText: String): InputStream? {
|
private suspend fun getSpeakStream(
|
||||||
|
httpTts: HttpTTS,
|
||||||
|
speakText: String
|
||||||
|
): InputStream? = withContext(IO) {
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
val analyzeUrl = AnalyzeUrl(
|
val analyzeUrl = AnalyzeUrl(
|
||||||
@@ -180,7 +186,7 @@ class HttpReadAloudService : BaseReadAloudService(),
|
|||||||
ensureActive()
|
ensureActive()
|
||||||
response.body!!.byteStream().let { stream ->
|
response.body!!.byteStream().let { stream ->
|
||||||
downloadErrorNo = 0
|
downloadErrorNo = 0
|
||||||
return stream
|
return@withContext stream
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
when (e) {
|
when (e) {
|
||||||
@@ -221,7 +227,7 @@ class HttpReadAloudService : BaseReadAloudService(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null
|
return@withContext null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun md5SpeakFileName(content: String): String {
|
private fun md5SpeakFileName(content: String): String {
|
||||||
@@ -294,7 +300,7 @@ class HttpReadAloudService : BaseReadAloudService(),
|
|||||||
private fun upPlayPos() {
|
private fun upPlayPos() {
|
||||||
playIndexJob?.cancel()
|
playIndexJob?.cancel()
|
||||||
val textChapter = textChapter ?: return
|
val textChapter = textChapter ?: return
|
||||||
playIndexJob = launch {
|
playIndexJob = lifecycleScope.launch {
|
||||||
postEvent(EventBus.TTS_PROGRESS, readAloudNumber + 1)
|
postEvent(EventBus.TTS_PROGRESS, readAloudNumber + 1)
|
||||||
if (exoPlayer.duration <= 0) {
|
if (exoPlayer.duration <= 0) {
|
||||||
return@launch
|
return@launch
|
||||||
|
|||||||
Reference in New Issue
Block a user