Skip to content

Commit 8a9cc6b

Browse files
authored
Merge branch 'gedoor:master' into main
2 parents 9658b1b + beb561a commit 8a9cc6b

File tree

7 files changed

+62
-62
lines changed

7 files changed

+62
-62
lines changed

app/src/main/java/io/legado/app/help/book/BookHelp.kt

+24-15
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import io.legado.app.utils.NetworkUtils
2121
import io.legado.app.utils.StringUtils
2222
import io.legado.app.utils.SvgUtils
2323
import io.legado.app.utils.UrlUtil
24+
import io.legado.app.utils.createFileIfNotExist
2425
import io.legado.app.utils.exists
2526
import io.legado.app.utils.externalFiles
2627
import io.legado.app.utils.getFile
@@ -29,10 +30,10 @@ import io.legado.app.utils.onEachParallel
2930
import io.legado.app.utils.postEvent
3031
import kotlinx.coroutines.Dispatchers.IO
3132
import kotlinx.coroutines.coroutineScope
32-
import kotlinx.coroutines.delay
3333
import kotlinx.coroutines.ensureActive
3434
import kotlinx.coroutines.flow.collect
3535
import kotlinx.coroutines.flow.flow
36+
import kotlinx.coroutines.sync.Mutex
3637
import kotlinx.coroutines.withContext
3738
import org.apache.commons.text.similarity.JaccardSimilarity
3839
import splitties.init.appCtx
@@ -55,7 +56,7 @@ object BookHelp {
5556
private const val cacheFolderName = "book_cache"
5657
private const val cacheImageFolderName = "images"
5758
private const val cacheEpubFolderName = "epub"
58-
private val downloadImages = ConcurrentHashMap.newKeySet<String>()
59+
private val downloadImages = ConcurrentHashMap<String, Mutex>()
5960

6061
val cachePath = FileUtils.getPath(downloadDir, cacheFolderName)
6162

@@ -173,15 +174,18 @@ object BookHelp {
173174
src: String,
174175
chapter: BookChapter? = null
175176
) {
176-
while (downloadImages.contains(src)) {
177-
delay(100)
178-
}
179-
if (getImage(book, src).exists()) {
177+
if (isImageExist(book, src)) {
180178
return
181179
}
182-
downloadImages.add(src)
183-
val analyzeUrl = AnalyzeUrl(src, source = bookSource)
180+
val mutex = synchronized(this) {
181+
downloadImages.getOrPut(src) { Mutex() }
182+
}
183+
mutex.lock()
184184
try {
185+
if (isImageExist(book, src)) {
186+
return
187+
}
188+
val analyzeUrl = AnalyzeUrl(src, source = bookSource)
185189
val bytes = analyzeUrl.getByteArrayAwait()
186190
//某些图片被加密,需要进一步解密
187191
ImageUtils.decode(
@@ -193,20 +197,15 @@ object BookHelp {
193197
// throw NoStackTraceException("数据异常")
194198
AppLog.put("${book.name} ${chapter?.title} 图片 $src 下载错误 数据异常")
195199
}
196-
FileUtils.createFileIfNotExist(
197-
downloadDir,
198-
cacheFolderName,
199-
book.getFolderName(),
200-
cacheImageFolderName,
201-
"${MD5Utils.md5Encode16(src)}.${getImageSuffix(src)}"
202-
).writeBytes(it)
200+
writeImage(book, src, it)
203201
}
204202
} catch (e: Exception) {
205203
coroutineContext.ensureActive()
206204
val msg = "${book.name} ${chapter?.title} 图片 $src 下载失败\n${e.localizedMessage}"
207205
AppLog.put(msg, e)
208206
} finally {
209207
downloadImages.remove(src)
208+
mutex.unlock()
210209
}
211210
}
212211

@@ -219,6 +218,16 @@ object BookHelp {
219218
)
220219
}
221220

221+
@Synchronized
222+
fun writeImage(book: Book, src: String, bytes: ByteArray) {
223+
getImage(book, src).createFileIfNotExist().writeBytes(bytes)
224+
}
225+
226+
@Synchronized
227+
fun isImageExist(book: Book, src: String): Boolean {
228+
return getImage(book, src).exists()
229+
}
230+
222231
fun getImageSuffix(src: String): String {
223232
return UrlUtil.getSuffix(src, "jpg")
224233
}

app/src/main/java/io/legado/app/model/ImageProvider.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ object ImageProvider {
9494
): File {
9595
return withContext(IO) {
9696
val vFile = BookHelp.getImage(book, src)
97-
if (!vFile.exists()) {
97+
if (!BookHelp.isImageExist(book, src)) {
9898
val inputStream = when {
9999
book.isEpub -> EpubFile.getImage(book, src)
100100
book.isPdf -> PdfFile.getImage(book, src)

app/src/main/java/io/legado/app/service/HttpReadAloudService.kt

+16-17
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import androidx.media3.common.C
88
import androidx.media3.common.MediaItem
99
import androidx.media3.common.PlaybackException
1010
import androidx.media3.common.Player
11+
import androidx.media3.common.Timeline
1112
import androidx.media3.database.StandaloneDatabaseProvider
1213
import androidx.media3.datasource.DataSource
1314
import androidx.media3.datasource.cache.CacheDataSink
@@ -75,7 +76,7 @@ class HttpReadAloudService : BaseReadAloudService(),
7576
private val cache by lazy {
7677
SimpleCache(
7778
File(cacheDir, "httpTTS_cache"),
78-
LeastRecentlyUsedCacheEvictor((50 * 1024 * 1024).toLong()),
79+
LeastRecentlyUsedCacheEvictor(128 * 1024 * 1024),
7980
StandaloneDatabaseProvider(appCtx)
8081
)
8182
}
@@ -182,15 +183,7 @@ class HttpReadAloudService : BaseReadAloudService(),
182183
val file = getSpeakFileAsMd5(fileName)
183184
val mediaItem = MediaItem.fromUri(Uri.fromFile(file))
184185
launch(Main) {
185-
if (exoPlayer.playbackState == Player.STATE_ENDED) {
186-
exoPlayer.stop()
187-
exoPlayer.clearMediaItems()
188-
}
189186
exoPlayer.addMediaItem(mediaItem)
190-
if (!exoPlayer.isPlaying) {
191-
exoPlayer.playWhenReady = !pause
192-
exoPlayer.prepare()
193-
}
194187
}
195188
}
196189
preDownloadAudios(httpTts)
@@ -256,15 +249,7 @@ class HttpReadAloudService : BaseReadAloudService(),
256249
downloaderChannel.send(downloader)
257250
val mediaSource = createMediaSource(dataSourceFactory, fileName)
258251
launch(Main) {
259-
if (exoPlayer.playbackState == Player.STATE_ENDED) {
260-
exoPlayer.stop()
261-
exoPlayer.clearMediaItems()
262-
}
263252
exoPlayer.addMediaSource(mediaSource)
264-
if (!exoPlayer.isPlaying) {
265-
exoPlayer.playWhenReady = !pause
266-
exoPlayer.prepare()
267-
}
268253
}
269254
}
270255
preDownloadAudiosStream(httpTts, downloaderChannel)
@@ -540,10 +525,24 @@ class HttpReadAloudService : BaseReadAloudService(),
540525
// 结束
541526
playErrorNo = 0
542527
updateNextPos()
528+
exoPlayer.stop()
529+
exoPlayer.clearMediaItems()
543530
}
544531
}
545532
}
546533

534+
override fun onTimelineChanged(timeline: Timeline, reason: Int) {
535+
when (reason) {
536+
Player.TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED -> {
537+
if (!timeline.isEmpty && exoPlayer.playbackState == Player.STATE_IDLE) {
538+
exoPlayer.prepare()
539+
}
540+
}
541+
542+
else -> {}
543+
}
544+
}
545+
547546
override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
548547
if (reason == Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED) return
549548
if (reason == Player.MEDIA_ITEM_TRANSITION_REASON_AUTO) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package io.legado.app.utils
2+
3+
import io.legado.app.help.globalExecutor
4+
import java.util.logging.FileHandler
5+
import java.util.logging.LogRecord
6+
7+
class AsyncFileHandler(pattern: String) : FileHandler(pattern) {
8+
9+
override fun publish(record: LogRecord?) {
10+
if (!isLoggable(record)) {
11+
return
12+
}
13+
globalExecutor.execute {
14+
super.publish(record)
15+
}
16+
}
17+
18+
}

app/src/main/java/io/legado/app/utils/AsyncHandler.kt

-25
This file was deleted.

app/src/main/java/io/legado/app/utils/FileExtensions.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ fun File.listFileDocs(filter: FileDocFilter? = null): ArrayList<FileDoc> {
3535

3636
fun File.createFileIfNotExist(): File {
3737
if (!exists()) {
38-
parentFile?.createFileIfNotExist()
38+
parentFile?.createFolderIfNotExist()
3939
createNewFile()
4040
}
4141
return this

app/src/main/java/io/legado/app/utils/LogUtils.kt

+2-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import io.legado.app.help.config.AppConfig
1111
import splitties.init.appCtx
1212
import java.text.SimpleDateFormat
1313
import java.util.Date
14-
import java.util.logging.FileHandler
1514
import java.util.logging.Level
1615
import java.util.logging.LogRecord
1716
import java.util.logging.Logger
@@ -58,7 +57,7 @@ object LogUtils {
5857
}
5958
val date = getCurrentDateStr(TIME_PATTERN)
6059
val logPath = FileUtils.getPath(root = logFolder, "appLog-$date.txt")
61-
FileHandler(logPath).apply {
60+
AsyncFileHandler(logPath).apply {
6261
formatter = object : java.util.logging.Formatter() {
6362
override fun format(record: LogRecord): String {
6463
// 设置文件输出格式
@@ -70,7 +69,7 @@ object LogUtils {
7069
} else {
7170
Level.OFF
7271
}
73-
}.asynchronous()
72+
}
7473
}
7574

7675
fun upLevel() {

0 commit comments

Comments
 (0)