优化
This commit is contained in:
@@ -21,6 +21,7 @@ import io.legado.app.utils.NetworkUtils
|
||||
import io.legado.app.utils.StringUtils
|
||||
import io.legado.app.utils.SvgUtils
|
||||
import io.legado.app.utils.UrlUtil
|
||||
import io.legado.app.utils.createFileIfNotExist
|
||||
import io.legado.app.utils.exists
|
||||
import io.legado.app.utils.externalFiles
|
||||
import io.legado.app.utils.getFile
|
||||
@@ -29,10 +30,10 @@ import io.legado.app.utils.onEachParallel
|
||||
import io.legado.app.utils.postEvent
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.ensureActive
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.apache.commons.text.similarity.JaccardSimilarity
|
||||
import splitties.init.appCtx
|
||||
@@ -55,7 +56,7 @@ object BookHelp {
|
||||
private const val cacheFolderName = "book_cache"
|
||||
private const val cacheImageFolderName = "images"
|
||||
private const val cacheEpubFolderName = "epub"
|
||||
private val downloadImages = ConcurrentHashMap.newKeySet<String>()
|
||||
private val downloadImages = ConcurrentHashMap<String, Mutex>()
|
||||
|
||||
val cachePath = FileUtils.getPath(downloadDir, cacheFolderName)
|
||||
|
||||
@@ -173,15 +174,18 @@ object BookHelp {
|
||||
src: String,
|
||||
chapter: BookChapter? = null
|
||||
) {
|
||||
while (downloadImages.contains(src)) {
|
||||
delay(100)
|
||||
}
|
||||
if (getImage(book, src).exists()) {
|
||||
if (isImageExist(book, src)) {
|
||||
return
|
||||
}
|
||||
downloadImages.add(src)
|
||||
val analyzeUrl = AnalyzeUrl(src, source = bookSource)
|
||||
val mutex = synchronized(this) {
|
||||
downloadImages.getOrPut(src) { Mutex() }
|
||||
}
|
||||
mutex.lock()
|
||||
try {
|
||||
if (isImageExist(book, src)) {
|
||||
return
|
||||
}
|
||||
val analyzeUrl = AnalyzeUrl(src, source = bookSource)
|
||||
val bytes = analyzeUrl.getByteArrayAwait()
|
||||
//某些图片被加密,需要进一步解密
|
||||
ImageUtils.decode(
|
||||
@@ -193,13 +197,7 @@ object BookHelp {
|
||||
// throw NoStackTraceException("数据异常")
|
||||
AppLog.put("${book.name} ${chapter?.title} 图片 $src 下载错误 数据异常")
|
||||
}
|
||||
FileUtils.createFileIfNotExist(
|
||||
downloadDir,
|
||||
cacheFolderName,
|
||||
book.getFolderName(),
|
||||
cacheImageFolderName,
|
||||
"${MD5Utils.md5Encode16(src)}.${getImageSuffix(src)}"
|
||||
).writeBytes(it)
|
||||
writeImage(book, src, it)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
coroutineContext.ensureActive()
|
||||
@@ -207,6 +205,7 @@ object BookHelp {
|
||||
AppLog.put(msg, e)
|
||||
} finally {
|
||||
downloadImages.remove(src)
|
||||
mutex.unlock()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,6 +218,16 @@ object BookHelp {
|
||||
)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun writeImage(book: Book, src: String, bytes: ByteArray) {
|
||||
getImage(book, src).createFileIfNotExist().writeBytes(bytes)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun isImageExist(book: Book, src: String): Boolean {
|
||||
return getImage(book, src).exists()
|
||||
}
|
||||
|
||||
fun getImageSuffix(src: String): String {
|
||||
return UrlUtil.getSuffix(src, "jpg")
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ object ImageProvider {
|
||||
): File {
|
||||
return withContext(IO) {
|
||||
val vFile = BookHelp.getImage(book, src)
|
||||
if (!vFile.exists()) {
|
||||
if (!BookHelp.isImageExist(book, src)) {
|
||||
val inputStream = when {
|
||||
book.isEpub -> EpubFile.getImage(book, src)
|
||||
book.isPdf -> PdfFile.getImage(book, src)
|
||||
|
||||
@@ -8,6 +8,7 @@ import androidx.media3.common.C
|
||||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.common.PlaybackException
|
||||
import androidx.media3.common.Player
|
||||
import androidx.media3.common.Timeline
|
||||
import androidx.media3.database.StandaloneDatabaseProvider
|
||||
import androidx.media3.datasource.DataSource
|
||||
import androidx.media3.datasource.cache.CacheDataSink
|
||||
@@ -75,7 +76,7 @@ class HttpReadAloudService : BaseReadAloudService(),
|
||||
private val cache by lazy {
|
||||
SimpleCache(
|
||||
File(cacheDir, "httpTTS_cache"),
|
||||
LeastRecentlyUsedCacheEvictor((50 * 1024 * 1024).toLong()),
|
||||
LeastRecentlyUsedCacheEvictor(128 * 1024 * 1024),
|
||||
StandaloneDatabaseProvider(appCtx)
|
||||
)
|
||||
}
|
||||
@@ -182,15 +183,7 @@ class HttpReadAloudService : BaseReadAloudService(),
|
||||
val file = getSpeakFileAsMd5(fileName)
|
||||
val mediaItem = MediaItem.fromUri(Uri.fromFile(file))
|
||||
launch(Main) {
|
||||
if (exoPlayer.playbackState == Player.STATE_ENDED) {
|
||||
exoPlayer.stop()
|
||||
exoPlayer.clearMediaItems()
|
||||
}
|
||||
exoPlayer.addMediaItem(mediaItem)
|
||||
if (!exoPlayer.isPlaying) {
|
||||
exoPlayer.playWhenReady = !pause
|
||||
exoPlayer.prepare()
|
||||
}
|
||||
}
|
||||
}
|
||||
preDownloadAudios(httpTts)
|
||||
@@ -256,15 +249,7 @@ class HttpReadAloudService : BaseReadAloudService(),
|
||||
downloaderChannel.send(downloader)
|
||||
val mediaSource = createMediaSource(dataSourceFactory, fileName)
|
||||
launch(Main) {
|
||||
if (exoPlayer.playbackState == Player.STATE_ENDED) {
|
||||
exoPlayer.stop()
|
||||
exoPlayer.clearMediaItems()
|
||||
}
|
||||
exoPlayer.addMediaSource(mediaSource)
|
||||
if (!exoPlayer.isPlaying) {
|
||||
exoPlayer.playWhenReady = !pause
|
||||
exoPlayer.prepare()
|
||||
}
|
||||
}
|
||||
}
|
||||
preDownloadAudiosStream(httpTts, downloaderChannel)
|
||||
@@ -540,10 +525,24 @@ class HttpReadAloudService : BaseReadAloudService(),
|
||||
// 结束
|
||||
playErrorNo = 0
|
||||
updateNextPos()
|
||||
exoPlayer.stop()
|
||||
exoPlayer.clearMediaItems()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTimelineChanged(timeline: Timeline, reason: Int) {
|
||||
when (reason) {
|
||||
Player.TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED -> {
|
||||
if (!timeline.isEmpty && exoPlayer.playbackState == Player.STATE_IDLE) {
|
||||
exoPlayer.prepare()
|
||||
}
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
|
||||
if (reason == Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED) return
|
||||
if (reason == Player.MEDIA_ITEM_TRANSITION_REASON_AUTO) {
|
||||
|
||||
@@ -35,7 +35,7 @@ fun File.listFileDocs(filter: FileDocFilter? = null): ArrayList<FileDoc> {
|
||||
|
||||
fun File.createFileIfNotExist(): File {
|
||||
if (!exists()) {
|
||||
parentFile?.createFileIfNotExist()
|
||||
parentFile?.createFolderIfNotExist()
|
||||
createNewFile()
|
||||
}
|
||||
return this
|
||||
|
||||
Reference in New Issue
Block a user