diff --git a/app/src/main/java/io/legado/app/model/webBook/BookChapterList.kt b/app/src/main/java/io/legado/app/model/webBook/BookChapterList.kt deleted file mode 100644 index 30b3fc1b9..000000000 --- a/app/src/main/java/io/legado/app/model/webBook/BookChapterList.kt +++ /dev/null @@ -1,274 +0,0 @@ -package io.legado.app.model.webBook - -import android.text.TextUtils -import io.legado.app.R -import io.legado.app.data.entities.Book -import io.legado.app.data.entities.BookChapter -import io.legado.app.data.entities.BookSource -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.analyzeRule.AnalyzeRule -import io.legado.app.model.analyzeRule.AnalyzeUrl -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.ensureActive -import kotlinx.coroutines.suspendCancellableCoroutine -import splitties.init.appCtx -import kotlin.coroutines.resume -import kotlin.coroutines.resumeWithException - -object BookChapterList { - - suspend fun analyzeChapterList( - scope: CoroutineScope, - book: Book, - body: String?, - bookSource: BookSource, - baseUrl: String, - redirectUrl: String - ): List = suspendCancellableCoroutine { block -> - kotlin.runCatching { - val chapterList = ArrayList() - body ?: throw Exception( - appCtx.getString(R.string.error_get_web_content, baseUrl) - ) - Debug.log(bookSource.bookSourceUrl, "≡获取成功:${baseUrl}") - - val tocRule = bookSource.getTocRule() - val nextUrlList = arrayListOf(baseUrl) - var reverse = AnalyzeRule.userReverse - var listRule = tocRule.chapterList ?: "" - if (listRule.startsWith("-")) { - reverse = true - listRule = listRule.substring(1) - } - if (listRule.startsWith("+")) { - listRule = listRule.substring(1) - } - var chapterData = - analyzeChapterList( - scope, book, baseUrl, redirectUrl, body, - tocRule, listRule, bookSource, log = true - ) - chapterData.chapterList?.let { - chapterList.addAll(it) - } - when (chapterData.nextUrl.size) { - 0 -> { - block.resume(finish(book, chapterList, reverse)) - } - 1 -> { - Coroutine.async(scope = scope) { - var nextUrl = chapterData.nextUrl[0] - while (nextUrl.isNotEmpty() && !nextUrlList.contains(nextUrl)) { - nextUrlList.add(nextUrl) - AnalyzeUrl( - ruleUrl = nextUrl, - book = book, - headerMapF = bookSource.getHeaderMap() - ).getStrResponse(bookSource.bookSourceUrl).body?.let { nextBody -> - chapterData = analyzeChapterList( - this, book, nextUrl, nextUrl, - nextBody, tocRule, listRule, bookSource - ) - 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 -> { - val chapterDataList = arrayListOf>() - for (item in chapterData.nextUrl) { - if (!nextUrlList.contains(item)) { - val data = ChapterData(nextUrl = item) - chapterDataList.add(data) - nextUrlList.add(item) - } - } - Debug.log(bookSource.bookSourceUrl, "◇目录总页数:${nextUrlList.size}") - for (item in chapterDataList) { - downloadToc( - scope, item, book, bookSource, - tocRule, listRule, chapterList, chapterDataList, - { - block.resume(finish(book, chapterList, reverse)) - } - ) { - block.cancel(it) - } - } - } - } - }.onFailure { - block.cancel(it) - } - } - - private fun downloadToc( - scope: CoroutineScope, - chapterData: ChapterData, - book: Book, - bookSource: BookSource, - tocRule: TocRule, - listRule: String, - chapterList: ArrayList, - chapterDataList: ArrayList>, - 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) - } - } - onFinish() - } - } - }.onError { - onError.invoke(it) - } - } - - private fun addChapterListIsFinish( - chapterDataList: ArrayList>, - chapterData: ChapterData, - chapterList: List? - ): Boolean { - chapterData.chapterList = chapterList - chapterDataList.forEach { - if (it.chapterList == null) { - return false - } - } - return true - } - - private fun finish( - book: Book, - chapterList: ArrayList, - reverse: Boolean - ): ArrayList { - //去重 - if (!reverse) { - chapterList.reverse() - } - val lh = LinkedHashSet(chapterList) - val list = ArrayList(lh) - list.reverse() - Debug.log(book.origin, "◇目录总数:${list.size}") - for ((index, item) in list.withIndex()) { - item.index = index - } - book.latestChapterTitle = list.last().title - book.durChapterTitle = - list.getOrNull(book.durChapterIndex)?.title ?: book.latestChapterTitle - if (book.totalChapterNum < list.size) { - book.lastCheckCount = list.size - book.totalChapterNum - book.latestChapterTime = System.currentTimeMillis() - } - book.totalChapterNum = list.size - return list - } - - private fun analyzeChapterList( - scope: CoroutineScope, - book: Book, - baseUrl: String, - redirectUrl: String, - body: String, - tocRule: TocRule, - listRule: String, - bookSource: BookSource, - getNextUrl: Boolean = true, - log: Boolean = false - ): ChapterData> { - val analyzeRule = AnalyzeRule(book) - analyzeRule.setContent(body).setBaseUrl(baseUrl) - analyzeRule.setRedirectUrl(redirectUrl) - //获取目录列表 - val chapterList = arrayListOf() - Debug.log(bookSource.bookSourceUrl, "┌获取目录列表", log) - val elements = analyzeRule.getElements(listRule) - Debug.log(bookSource.bookSourceUrl, "└列表大小:${elements.size}", log) - //获取下一页链接 - val nextUrlList = arrayListOf() - val nextTocRule = tocRule.nextTocUrl - if (getNextUrl && !nextTocRule.isNullOrEmpty()) { - Debug.log(bookSource.bookSourceUrl, "┌获取目录下一页列表", log) - analyzeRule.getStringList(nextTocRule, true)?.let { - for (item in it) { - if (item != baseUrl) { - nextUrlList.add(item) - } - } - } - Debug.log( - bookSource.bookSourceUrl, - "└" + TextUtils.join(",\n", nextUrlList), - log - ) - } - scope.ensureActive() - if (elements.isNotEmpty()) { - Debug.log(bookSource.bookSourceUrl, "┌解析目录列表", log) - val nameRule = analyzeRule.splitSourceRule(tocRule.chapterName) - val urlRule = analyzeRule.splitSourceRule(tocRule.chapterUrl) - val vipRule = analyzeRule.splitSourceRule(tocRule.isVip) - val update = analyzeRule.splitSourceRule(tocRule.updateTime) - var isVip: String? - for (item in elements) { - scope.ensureActive() - analyzeRule.setContent(item) - val bookChapter = BookChapter(bookUrl = book.bookUrl, baseUrl = baseUrl) - analyzeRule.chapter = bookChapter - bookChapter.title = analyzeRule.getString(nameRule) - bookChapter.url = analyzeRule.getString(urlRule) - bookChapter.tag = analyzeRule.getString(update) - isVip = analyzeRule.getString(vipRule) - if (bookChapter.url.isEmpty()) { - bookChapter.url = baseUrl - } - if (bookChapter.title.isNotEmpty()) { - if (isVip.isNotEmpty() && isVip != "null" && isVip != "false" && isVip != "0") { - bookChapter.title = "\uD83D\uDD12" + bookChapter.title - } - chapterList.add(bookChapter) - } - } - Debug.log(bookSource.bookSourceUrl, "└解析目录列表完成", log) - Debug.log(bookSource.bookSourceUrl, "┌首章名称", log) - Debug.log(bookSource.bookSourceUrl, "└${chapterList[0].title}", log) - Debug.log(bookSource.bookSourceUrl, "┌首章链接", log) - Debug.log(bookSource.bookSourceUrl, "└${chapterList[0].url}", log) - Debug.log(bookSource.bookSourceUrl, "┌首章信息", log) - Debug.log(bookSource.bookSourceUrl, "└${chapterList[0].tag}", log) - } - return ChapterData(chapterList, nextUrlList) - } - -}