@@ -21,6 +21,7 @@ import io.legado.app.utils.NetworkUtils
21
21
import io.legado.app.utils.StringUtils
22
22
import io.legado.app.utils.SvgUtils
23
23
import io.legado.app.utils.UrlUtil
24
+ import io.legado.app.utils.createFileIfNotExist
24
25
import io.legado.app.utils.exists
25
26
import io.legado.app.utils.externalFiles
26
27
import io.legado.app.utils.getFile
@@ -29,10 +30,10 @@ import io.legado.app.utils.onEachParallel
29
30
import io.legado.app.utils.postEvent
30
31
import kotlinx.coroutines.Dispatchers.IO
31
32
import kotlinx.coroutines.coroutineScope
32
- import kotlinx.coroutines.delay
33
33
import kotlinx.coroutines.ensureActive
34
34
import kotlinx.coroutines.flow.collect
35
35
import kotlinx.coroutines.flow.flow
36
+ import kotlinx.coroutines.sync.Mutex
36
37
import kotlinx.coroutines.withContext
37
38
import org.apache.commons.text.similarity.JaccardSimilarity
38
39
import splitties.init.appCtx
@@ -55,7 +56,7 @@ object BookHelp {
55
56
private const val cacheFolderName = " book_cache"
56
57
private const val cacheImageFolderName = " images"
57
58
private const val cacheEpubFolderName = " epub"
58
- private val downloadImages = ConcurrentHashMap .newKeySet <String >()
59
+ private val downloadImages = ConcurrentHashMap <String , Mutex >()
59
60
60
61
val cachePath = FileUtils .getPath(downloadDir, cacheFolderName)
61
62
@@ -173,15 +174,18 @@ object BookHelp {
173
174
src : String ,
174
175
chapter : BookChapter ? = null
175
176
) {
176
- while (downloadImages.contains(src)) {
177
- delay(100 )
178
- }
179
- if (getImage(book, src).exists()) {
177
+ if (isImageExist(book, src)) {
180
178
return
181
179
}
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()
184
184
try {
185
+ if (isImageExist(book, src)) {
186
+ return
187
+ }
188
+ val analyzeUrl = AnalyzeUrl (src, source = bookSource)
185
189
val bytes = analyzeUrl.getByteArrayAwait()
186
190
// 某些图片被加密,需要进一步解密
187
191
ImageUtils .decode(
@@ -193,20 +197,15 @@ object BookHelp {
193
197
// throw NoStackTraceException("数据异常")
194
198
AppLog .put(" ${book.name} ${chapter?.title} 图片 $src 下载错误 数据异常" )
195
199
}
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)
203
201
}
204
202
} catch (e: Exception ) {
205
203
coroutineContext.ensureActive()
206
204
val msg = " ${book.name} ${chapter?.title} 图片 $src 下载失败\n ${e.localizedMessage} "
207
205
AppLog .put(msg, e)
208
206
} finally {
209
207
downloadImages.remove(src)
208
+ mutex.unlock()
210
209
}
211
210
}
212
211
@@ -219,6 +218,16 @@ object BookHelp {
219
218
)
220
219
}
221
220
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
+
222
231
fun getImageSuffix (src : String ): String {
223
232
return UrlUtil .getSuffix(src, " jpg" )
224
233
}
0 commit comments