优化目录并发访问

pull/909/head
gedoor 4 years ago
parent 4024028923
commit 66fe4b017b
  1. 206
      app/src/main/java/io/legado/app/model/webBook/BookChapterList.kt

@ -6,16 +6,16 @@ import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookChapter
import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.BookSource
import io.legado.app.data.entities.rule.TocRule import io.legado.app.data.entities.rule.TocRule
import io.legado.app.help.coroutine.Coroutine
import io.legado.app.model.Debug import io.legado.app.model.Debug
import io.legado.app.model.analyzeRule.AnalyzeRule import io.legado.app.model.analyzeRule.AnalyzeRule
import io.legado.app.model.analyzeRule.AnalyzeUrl import io.legado.app.model.analyzeRule.AnalyzeUrl
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.async
import kotlinx.coroutines.ensureActive import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withContext
import splitties.init.appCtx import splitties.init.appCtx
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
object BookChapterList { object BookChapterList {
@ -26,153 +26,81 @@ object BookChapterList {
bookSource: BookSource, bookSource: BookSource,
baseUrl: String, baseUrl: String,
redirectUrl: String redirectUrl: String
): List<BookChapter> = suspendCancellableCoroutine { block -> ): List<BookChapter> {
kotlin.runCatching { val chapterList = ArrayList<BookChapter>()
val chapterList = ArrayList<BookChapter>() body ?: throw Exception(
body ?: throw Exception( appCtx.getString(R.string.error_get_web_content, baseUrl)
appCtx.getString(R.string.error_get_web_content, baseUrl) )
) Debug.log(bookSource.bookSourceUrl, "≡获取成功:${baseUrl}")
Debug.log(bookSource.bookSourceUrl, "≡获取成功:${baseUrl}")
val tocRule = bookSource.getTocRule() val tocRule = bookSource.getTocRule()
val nextUrlList = arrayListOf(baseUrl) val nextUrlList = arrayListOf(baseUrl)
var reverse = false var reverse = false
var listRule = tocRule.chapterList ?: "" var listRule = tocRule.chapterList ?: ""
if (listRule.startsWith("-")) { if (listRule.startsWith("-")) {
reverse = true reverse = true
listRule = listRule.substring(1) listRule = listRule.substring(1)
} }
if (listRule.startsWith("+")) { if (listRule.startsWith("+")) {
listRule = listRule.substring(1) listRule = listRule.substring(1)
} }
var chapterData = var chapterData =
analyzeChapterList( analyzeChapterList(
scope, book, baseUrl, redirectUrl, body, scope, book, baseUrl, redirectUrl, body,
tocRule, listRule, bookSource, log = true tocRule, listRule, bookSource, log = true
) )
chapterData.chapterList?.let { chapterData.chapterList?.let {
chapterList.addAll(it) chapterList.addAll(it)
} }
when (chapterData.nextUrl.size) { when (chapterData.nextUrl.size) {
0 -> { 0 -> Unit
block.resume(finish(book, chapterList, reverse)) 1 -> {
} var nextUrl = chapterData.nextUrl[0]
1 -> { while (nextUrl.isNotEmpty() && !nextUrlList.contains(nextUrl)) {
Coroutine.async(scope = scope) { nextUrlList.add(nextUrl)
var nextUrl = chapterData.nextUrl[0] AnalyzeUrl(
while (nextUrl.isNotEmpty() && !nextUrlList.contains(nextUrl)) { ruleUrl = nextUrl,
nextUrlList.add(nextUrl) book = book,
AnalyzeUrl( headerMapF = bookSource.getHeaderMap()
ruleUrl = nextUrl, ).getStrResponse(bookSource.bookSourceUrl).body?.let { nextBody ->
book = book, chapterData = analyzeChapterList(
headerMapF = bookSource.getHeaderMap() scope, book, nextUrl, nextUrl,
).getStrResponse(bookSource.bookSourceUrl).body?.let { nextBody -> nextBody, tocRule, listRule, bookSource
chapterData = analyzeChapterList( )
this, book, nextUrl, nextUrl, nextUrl = chapterData.nextUrl.firstOrNull() ?: ""
nextBody, tocRule, listRule, bookSource chapterData.chapterList?.let {
) chapterList.addAll(it)
nextUrl = chapterData.nextUrl.firstOrNull() ?: ""
chapterData.chapterList?.let {
chapterList.addAll(it)
}
}
} }
Debug.log(bookSource.bookSourceUrl, "◇目录总页数:${nextUrlList.size}")
block.resume(finish(book, chapterList, reverse))
}.onError {
block.resumeWithException(it)
} }
} }
else -> { Debug.log(bookSource.bookSourceUrl, "◇目录总页数:${nextUrlList.size}")
val chapterDataList = arrayListOf<ChapterData<String>>() }
for (item in chapterData.nextUrl) { else -> {
if (!nextUrlList.contains(item)) { Debug.log(bookSource.bookSourceUrl, "◇目录总页数:${nextUrlList.size}")
val data = ChapterData(nextUrl = item) withContext(IO) {
chapterDataList.add(data) val asyncArray = Array(chapterData.nextUrl.size) {
nextUrlList.add(item) async {
} val urlStr = chapterData.nextUrl[it]
} val analyzeUrl = AnalyzeUrl(
Debug.log(bookSource.bookSourceUrl, "◇目录总页数:${nextUrlList.size}") ruleUrl = urlStr,
for (item in chapterDataList) { book = book,
downloadToc( headerMapF = bookSource.getHeaderMap()
scope, item, book, bookSource, )
tocRule, listRule, chapterList, chapterDataList, val res = analyzeUrl.getStrResponse(bookSource.bookSourceUrl)
{ analyzeChapterList(
block.resume(finish(book, chapterList, reverse)) this, book, urlStr, res.url,
} res.body!!, tocRule, listRule, bookSource, false
) { ).chapterList
block.cancel(it)
} }
} }
} asyncArray.forEach { coroutine ->
} coroutine.await()?.let {
}.onFailure {
block.cancel(it)
}
}
private fun downloadToc(
scope: CoroutineScope,
chapterData: ChapterData<String>,
book: Book,
bookSource: BookSource,
tocRule: TocRule,
listRule: String,
chapterList: ArrayList<BookChapter>,
chapterDataList: ArrayList<ChapterData<String>>,
onFinish: () -> Unit,
onError: (error: Throwable) -> Unit
) {
Coroutine.async(scope = scope) {
val nextBody = AnalyzeUrl(
ruleUrl = chapterData.nextUrl,
book = book,
headerMapF = bookSource.getHeaderMap()
).getStrResponse(bookSource.bookSourceUrl).body
?: throw Exception("${chapterData.nextUrl}, 下载失败")
val nextChapterData = analyzeChapterList(
this, book, chapterData.nextUrl, chapterData.nextUrl,
nextBody, tocRule, listRule, bookSource, false
)
synchronized(chapterDataList) {
val isFinished = addChapterListIsFinish(
chapterDataList,
chapterData,
nextChapterData.chapterList
)
if (isFinished) {
chapterDataList.forEach { item ->
item.chapterList?.let {
chapterList.addAll(it) chapterList.addAll(it)
} }
} }
onFinish()
} }
} }
}.onError {
onError.invoke(it)
} }
}
private fun addChapterListIsFinish(
chapterDataList: ArrayList<ChapterData<String>>,
chapterData: ChapterData<String>,
chapterList: List<BookChapter>?
): Boolean {
chapterData.chapterList = chapterList
chapterDataList.forEach {
if (it.chapterList == null) {
return false
}
}
return true
}
private fun finish(
book: Book,
chapterList: ArrayList<BookChapter>,
reverse: Boolean
): ArrayList<BookChapter> {
//去重 //去重
if (!reverse) { if (!reverse) {
chapterList.reverse() chapterList.reverse()

Loading…
Cancel
Save