From 452925f41943012858a6b6a4ad9b3dd34060bcef Mon Sep 17 00:00:00 2001 From: Horis <8674809+821938089@users.noreply.github.com> Date: Tue, 30 Jul 2024 12:39:04 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/io/legado/app/help/book/BookHelp.kt | 39 ++++++++++++------- .../java/io/legado/app/model/ImageProvider.kt | 2 +- .../app/service/HttpReadAloudService.kt | 33 ++++++++-------- .../io/legado/app/utils/FileExtensions.kt | 2 +- 4 files changed, 42 insertions(+), 34 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/book/BookHelp.kt b/app/src/main/java/io/legado/app/help/book/BookHelp.kt index 40f47f3a0..0d57e1ed2 100644 --- a/app/src/main/java/io/legado/app/help/book/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/book/BookHelp.kt @@ -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() + private val downloadImages = ConcurrentHashMap() 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") } diff --git a/app/src/main/java/io/legado/app/model/ImageProvider.kt b/app/src/main/java/io/legado/app/model/ImageProvider.kt index c86aa6dc9..eb23262a3 100644 --- a/app/src/main/java/io/legado/app/model/ImageProvider.kt +++ b/app/src/main/java/io/legado/app/model/ImageProvider.kt @@ -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) diff --git a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt index 3bfa6fcc6..ccab60d98 100644 --- a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt @@ -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) { diff --git a/app/src/main/java/io/legado/app/utils/FileExtensions.kt b/app/src/main/java/io/legado/app/utils/FileExtensions.kt index 018497276..6bc60568a 100644 --- a/app/src/main/java/io/legado/app/utils/FileExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/FileExtensions.kt @@ -35,7 +35,7 @@ fun File.listFileDocs(filter: FileDocFilter? = null): ArrayList { fun File.createFileIfNotExist(): File { if (!exists()) { - parentFile?.createFileIfNotExist() + parentFile?.createFolderIfNotExist() createNewFile() } return this