pull/783/head
gedoor 5 years ago
parent 95f2f1f9a4
commit f07a291a96
  1. 53
      app/src/main/java/io/legado/app/model/webBook/BookChapterList.kt
  2. 4
      app/src/main/java/io/legado/app/model/webBook/BookContent.kt
  3. 11
      app/src/main/java/io/legado/app/model/webBook/BookInfo.kt
  4. 39
      app/src/main/java/io/legado/app/model/webBook/BookList.kt

@ -12,6 +12,7 @@ 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 kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
@ -19,13 +20,13 @@ import kotlin.coroutines.resumeWithException
object BookChapterList {
suspend fun analyzeChapterList(
coroutineScope: CoroutineScope,
scope: CoroutineScope,
book: Book,
body: String?,
bookSource: BookSource,
baseUrl: String
): List<BookChapter> = suspendCancellableCoroutine { block ->
try {
kotlin.runCatching {
val chapterList = ArrayList<BookChapter>()
body ?: throw Exception(
App.INSTANCE.getString(R.string.error_get_web_content, baseUrl)
@ -45,7 +46,7 @@ object BookChapterList {
}
var chapterData =
analyzeChapterList(
book, baseUrl, body, tocRule, listRule, bookSource, log = true
scope, book, baseUrl, body, tocRule, listRule, bookSource, log = true
)
chapterData.chapterList?.let {
chapterList.addAll(it)
@ -55,7 +56,7 @@ object BookChapterList {
block.resume(finish(book, chapterList, reverse))
}
1 -> {
Coroutine.async(scope = coroutineScope) {
Coroutine.async(scope = scope) {
var nextUrl = chapterData.nextUrl[0]
while (nextUrl.isNotEmpty() && !nextUrlList.contains(nextUrl)) {
nextUrlList.add(nextUrl)
@ -63,14 +64,11 @@ object BookChapterList {
ruleUrl = nextUrl,
book = book,
headerMapF = bookSource.getHeaderMap()
).getStrResponse(bookSource.bookSourceUrl)
.body?.let { nextBody ->
).getStrResponse(bookSource.bookSourceUrl).body?.let { nextBody ->
chapterData = analyzeChapterList(
book, nextUrl, nextBody, tocRule, listRule, bookSource
this, book, nextUrl, nextBody, tocRule, listRule, bookSource
)
nextUrl = if (chapterData.nextUrl.isNotEmpty()) {
chapterData.nextUrl[0]
} else ""
nextUrl = chapterData.nextUrl.firstOrNull() ?: ""
chapterData.chapterList?.let {
chapterList.addAll(it)
}
@ -94,29 +92,21 @@ object BookChapterList {
Debug.log(bookSource.bookSourceUrl, "◇目录总页数:${nextUrlList.size}")
for (item in chapterDataList) {
downloadToc(
coroutineScope,
item,
book,
bookSource,
tocRule,
listRule,
chapterList,
chapterDataList,
{
scope, item, book, bookSource,
tocRule, listRule, chapterList, chapterDataList
) {
block.resume(finish(book, chapterList, reverse))
}, {
block.cancel(it)
})
}
}
}
} catch (e: Exception) {
block.resumeWithException(e)
}
}.onFailure {
block.resumeWithException(it)
}
}
private fun downloadToc(
coroutineScope: CoroutineScope,
scope: CoroutineScope,
chapterData: ChapterData<String>,
book: Book,
bookSource: BookSource,
@ -124,10 +114,9 @@ object BookChapterList {
listRule: String,
chapterList: ArrayList<BookChapter>,
chapterDataList: ArrayList<ChapterData<String>>,
onFinish: () -> Unit,
onError: (e: Throwable) -> Unit
onFinish: () -> Unit
) {
Coroutine.async(scope = coroutineScope) {
Coroutine.async(scope = scope) {
val nextBody = AnalyzeUrl(
ruleUrl = chapterData.nextUrl,
book = book,
@ -135,8 +124,7 @@ object BookChapterList {
).getStrResponse(bookSource.bookSourceUrl).body
?: throw Exception("${chapterData.nextUrl}, 下载失败")
val nextChapterData = analyzeChapterList(
book, chapterData.nextUrl, nextBody, tocRule, listRule, bookSource,
false
this, book, chapterData.nextUrl, nextBody, tocRule, listRule, bookSource, false
)
synchronized(chapterDataList) {
val isFinished = addChapterListIsFinish(
@ -154,7 +142,7 @@ object BookChapterList {
}
}
}.onError {
onError(it)
throw it
}
}
@ -200,6 +188,7 @@ object BookChapterList {
}
private fun analyzeChapterList(
scope: CoroutineScope,
book: Book,
baseUrl: String,
body: String,
@ -232,6 +221,7 @@ object BookChapterList {
Debug.log(bookSource.bookSourceUrl, "┌获取目录列表", log)
val elements = analyzeRule.getElements(listRule)
Debug.log(bookSource.bookSourceUrl, "└列表大小:${elements.size}", log)
scope.ensureActive()
if (elements.isNotEmpty()) {
val nameRule = analyzeRule.splitSourceRule(tocRule.chapterName)
val urlRule = analyzeRule.splitSourceRule(tocRule.chapterUrl)
@ -239,6 +229,7 @@ object BookChapterList {
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

@ -19,7 +19,7 @@ object BookContent {
@Throws(Exception::class)
suspend fun analyzeContent(
coroutineScope: CoroutineScope,
scope: CoroutineScope,
body: String?,
book: Book,
bookChapter: BookChapter,
@ -73,7 +73,7 @@ object BookContent {
contentDataList.add(ContentData(nextUrl = item))
}
for (item in contentDataList) {
withContext(coroutineScope.coroutineContext) {
withContext(scope.coroutineContext) {
AnalyzeUrl(
ruleUrl = item.nextUrl,
book = book,

@ -11,6 +11,7 @@ import io.legado.app.utils.NetworkUtils
import io.legado.app.utils.StringUtils.wordCountFormat
import io.legado.app.utils.htmlFormat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ensureActive
object BookInfo {
@ -32,11 +33,13 @@ object BookInfo {
analyzeRule.setContent(body).setBaseUrl(baseUrl)
infoRule.init?.let {
if (it.isNotBlank()) {
scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "≡执行详情页初始化规则")
analyzeRule.setContent(analyzeRule.getElement(it))
}
}
val mCanReName = canReName && !infoRule.canReName.isNullOrBlank()
scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "┌获取书名")
BookHelp.formatBookName(analyzeRule.getString(infoRule.name)).let {
if (it.isNotEmpty() && (mCanReName || book.name.isEmpty())) {
@ -44,6 +47,7 @@ object BookInfo {
}
Debug.log(bookSource.bookSourceUrl, "${it}")
}
scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "┌获取作者")
BookHelp.formatBookAuthor(analyzeRule.getString(infoRule.author)).let {
if (it.isNotEmpty() && (mCanReName || book.author.isEmpty())) {
@ -51,6 +55,7 @@ object BookInfo {
}
Debug.log(bookSource.bookSourceUrl, "${it}")
}
scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "┌获取分类")
analyzeRule.getStringList(infoRule.kind)
?.joinToString(",")
@ -58,27 +63,31 @@ object BookInfo {
if (it.isNotEmpty()) book.kind = it
}
Debug.log(bookSource.bookSourceUrl, "${book.kind}")
scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "┌获取字数")
wordCountFormat(analyzeRule.getString(infoRule.wordCount)).let {
if (it.isNotEmpty()) book.wordCount = it
}
Debug.log(bookSource.bookSourceUrl, "${book.wordCount}")
scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "┌获取最新章节")
analyzeRule.getString(infoRule.lastChapter).let {
if (it.isNotEmpty()) book.latestChapterTitle = it
}
Debug.log(bookSource.bookSourceUrl, "${book.latestChapterTitle}")
scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "┌获取简介")
analyzeRule.getString(infoRule.intro).let {
if (it.isNotEmpty()) book.intro = it.htmlFormat()
}
Debug.log(bookSource.bookSourceUrl, "${book.intro}")
scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "┌获取封面链接")
analyzeRule.getString(infoRule.coverUrl).let {
if (it.isNotEmpty()) book.coverUrl = NetworkUtils.getAbsoluteURL(baseUrl, it)
}
Debug.log(bookSource.bookSourceUrl, "${book.coverUrl}")
scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "┌获取目录链接")
book.tocUrl = analyzeRule.getString(infoRule.tocUrl, true)
if (book.tocUrl.isEmpty()) book.tocUrl = baseUrl

@ -12,9 +12,8 @@ import io.legado.app.model.analyzeRule.AnalyzeUrl
import io.legado.app.utils.NetworkUtils
import io.legado.app.utils.StringUtils.wordCountFormat
import io.legado.app.utils.htmlFormat
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.isActive
import kotlinx.coroutines.ensureActive
object BookList {
@ -36,10 +35,10 @@ object BookList {
)
)
Debug.log(bookSource.bookSourceUrl, "≡获取成功:${analyzeUrl.ruleUrl}")
if (!scope.isActive) throw CancellationException()
val analyzeRule = AnalyzeRule(variableBook)
analyzeRule.setContent(body).setBaseUrl(baseUrl)
bookSource.bookUrlPattern?.let {
scope.ensureActive()
if (baseUrl.matches(it.toRegex())) {
Debug.log(bookSource.bookSourceUrl, "≡链接为详情页")
getInfoItem(scope, analyzeRule, bookSource, baseUrl, variableBook.variable)
@ -67,6 +66,7 @@ object BookList {
}
Debug.log(bookSource.bookSourceUrl, "┌获取书籍列表")
collections = analyzeRule.getElements(ruleList)
scope.ensureActive()
if (collections.isEmpty() && bookSource.bookUrlPattern.isNullOrEmpty()) {
Debug.log(bookSource.bookSourceUrl, "└列表为空,按详情页解析")
getInfoItem(scope, analyzeRule, bookSource, baseUrl, variableBook.variable)
@ -85,7 +85,6 @@ object BookList {
val ruleWordCount = analyzeRule.splitSourceRule(bookListRule.wordCount)
Debug.log(bookSource.bookSourceUrl, "└列表大小:${collections.size}")
for ((index, item) in collections.withIndex()) {
if (!scope.isActive) throw CancellationException()
getSearchItem(
scope,
item,
@ -134,37 +133,37 @@ object BookList {
with(bookSource.getBookInfoRule()) {
init?.let {
if (it.isNotEmpty()) {
if (!scope.isActive) throw CancellationException()
scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "≡执行详情页初始化规则")
analyzeRule.setContent(analyzeRule.getElement(it))
}
}
if (!scope.isActive) throw CancellationException()
scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "┌获取书名")
searchBook.name = BookHelp.formatBookName(analyzeRule.getString(name))
Debug.log(bookSource.bookSourceUrl, "${searchBook.name}")
if (searchBook.name.isNotEmpty()) {
if (!scope.isActive) throw CancellationException()
scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "┌获取作者")
searchBook.author = BookHelp.formatBookAuthor(analyzeRule.getString(author))
Debug.log(bookSource.bookSourceUrl, "${searchBook.author}")
if (!scope.isActive) throw CancellationException()
scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "┌获取分类")
searchBook.kind = analyzeRule.getStringList(kind)?.joinToString(",")
Debug.log(bookSource.bookSourceUrl, "${searchBook.kind}")
if (!scope.isActive) throw CancellationException()
scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "┌获取字数")
searchBook.wordCount = wordCountFormat(analyzeRule.getString(wordCount))
Debug.log(bookSource.bookSourceUrl, "${searchBook.wordCount}")
if (!scope.isActive) throw CancellationException()
scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "┌获取最新章节")
searchBook.latestChapterTitle = analyzeRule.getString(lastChapter)
Debug.log(bookSource.bookSourceUrl, "${searchBook.latestChapterTitle}")
if (!scope.isActive) throw CancellationException()
scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "┌获取简介")
searchBook.intro = analyzeRule.getString(intro).htmlFormat()
Debug.log(bookSource.bookSourceUrl, "${searchBook.intro}")
if (!scope.isActive) throw CancellationException()
scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "┌获取封面链接")
searchBook.coverUrl = analyzeRule.getString(coverUrl, true)
Debug.log(bookSource.bookSourceUrl, "${searchBook.coverUrl}")
@ -199,38 +198,38 @@ object BookList {
searchBook.originOrder = bookSource.customOrder
analyzeRule.book = searchBook
analyzeRule.setContent(item)
if (!scope.isActive) throw CancellationException()
scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "┌获取书名", log)
searchBook.name = BookHelp.formatBookName(analyzeRule.getString(ruleName))
Debug.log(bookSource.bookSourceUrl, "${searchBook.name}", log)
if (searchBook.name.isNotEmpty()) {
if (!scope.isActive) throw CancellationException()
scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "┌获取作者", log)
searchBook.author = BookHelp.formatBookAuthor(analyzeRule.getString(ruleAuthor))
Debug.log(bookSource.bookSourceUrl, "${searchBook.author}", log)
if (!scope.isActive) throw CancellationException()
scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "┌获取分类", log)
searchBook.kind = analyzeRule.getStringList(ruleKind)?.joinToString(",")
Debug.log(bookSource.bookSourceUrl, "${searchBook.kind}", log)
if (!scope.isActive) throw CancellationException()
scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "┌获取字数", log)
searchBook.wordCount = wordCountFormat(analyzeRule.getString(ruleWordCount))
Debug.log(bookSource.bookSourceUrl, "${searchBook.wordCount}", log)
if (!scope.isActive) throw CancellationException()
scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "┌获取最新章节", log)
searchBook.latestChapterTitle = analyzeRule.getString(ruleLastChapter)
Debug.log(bookSource.bookSourceUrl, "${searchBook.latestChapterTitle}", log)
if (!scope.isActive) throw CancellationException()
scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "┌获取简介", log)
searchBook.intro = analyzeRule.getString(ruleIntro).htmlFormat()
Debug.log(bookSource.bookSourceUrl, "${searchBook.intro}", log)
if (!scope.isActive) throw CancellationException()
scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "┌获取封面链接", log)
analyzeRule.getString(ruleCoverUrl).let {
if (it.isNotEmpty()) searchBook.coverUrl = NetworkUtils.getAbsoluteURL(baseUrl, it)
}
Debug.log(bookSource.bookSourceUrl, "${searchBook.coverUrl}", log)
if (!scope.isActive) throw CancellationException()
scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "┌获取详情页链接", log)
searchBook.bookUrl = analyzeRule.getString(ruleBookUrl, true)
if (searchBook.bookUrl.isEmpty()) {

Loading…
Cancel
Save