优化
This commit is contained in:
@@ -110,9 +110,9 @@ object BookController {
|
|||||||
?: return returnData.setErrorMsg("未找到对应书源,请换源")
|
?: return returnData.setErrorMsg("未找到对应书源,请换源")
|
||||||
val toc = runBlocking {
|
val toc = runBlocking {
|
||||||
if (book.tocUrl.isBlank()) {
|
if (book.tocUrl.isBlank()) {
|
||||||
WebBook.getBookInfoAwait(this, bookSource, book)
|
WebBook.getBookInfoAwait(bookSource, book)
|
||||||
}
|
}
|
||||||
WebBook.getChapterListAwait(this, bookSource, book).getOrThrow()
|
WebBook.getChapterListAwait(bookSource, book).getOrThrow()
|
||||||
}
|
}
|
||||||
appDb.bookChapterDao.delByBook(book.bookUrl)
|
appDb.bookChapterDao.delByBook(book.bookUrl)
|
||||||
appDb.bookChapterDao.insert(*toc.toTypedArray())
|
appDb.bookChapterDao.insert(*toc.toTypedArray())
|
||||||
|
|||||||
@@ -68,14 +68,13 @@ object BookHelp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
suspend fun saveContent(
|
suspend fun saveContent(
|
||||||
scope: CoroutineScope,
|
|
||||||
bookSource: BookSource,
|
bookSource: BookSource,
|
||||||
book: Book,
|
book: Book,
|
||||||
bookChapter: BookChapter,
|
bookChapter: BookChapter,
|
||||||
content: String
|
content: String
|
||||||
) {
|
) {
|
||||||
saveText(book, bookChapter, content)
|
saveText(book, bookChapter, content)
|
||||||
saveImages(scope, bookSource, book, bookChapter, content)
|
saveImages(bookSource, book, bookChapter, content)
|
||||||
postEvent(EventBus.SAVE_CONTENT, bookChapter)
|
postEvent(EventBus.SAVE_CONTENT, bookChapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +94,6 @@ object BookHelp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun saveImages(
|
private suspend fun saveImages(
|
||||||
scope: CoroutineScope,
|
|
||||||
bookSource: BookSource,
|
bookSource: BookSource,
|
||||||
book: Book,
|
book: Book,
|
||||||
bookChapter: BookChapter,
|
bookChapter: BookChapter,
|
||||||
@@ -107,8 +105,10 @@ object BookHelp {
|
|||||||
if (matcher.find()) {
|
if (matcher.find()) {
|
||||||
matcher.group(1)?.let { src ->
|
matcher.group(1)?.let { src ->
|
||||||
val mSrc = NetworkUtils.getAbsoluteURL(bookChapter.url, src)
|
val mSrc = NetworkUtils.getAbsoluteURL(bookChapter.url, src)
|
||||||
awaitList.add(scope.async {
|
awaitList.add(coroutineScope {
|
||||||
saveImage(bookSource, book, mSrc)
|
async {
|
||||||
|
saveImage(bookSource, book, mSrc)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ object CacheBook {
|
|||||||
val chapterCount = appDb.bookChapterDao.getChapterCount(book.bookUrl)
|
val chapterCount = appDb.bookChapterDao.getChapterCount(book.bookUrl)
|
||||||
if (chapterCount == 0) {
|
if (chapterCount == 0) {
|
||||||
runBlocking {
|
runBlocking {
|
||||||
WebBook.getChapterListAwait(this, bookSource, book)
|
WebBook.getChapterListAwait(bookSource, book)
|
||||||
.onFailure {
|
.onFailure {
|
||||||
AppLog.put("缓存书籍没有目录且加载目录失败\n${it.localizedMessage}", it)
|
AppLog.put("缓存书籍没有目录且加载目录失败\n${it.localizedMessage}", it)
|
||||||
appCtx.toastOnUi("缓存书籍没有目录且加载目录失败\n${it.localizedMessage}")
|
appCtx.toastOnUi("缓存书籍没有目录且加载目录失败\n${it.localizedMessage}")
|
||||||
|
|||||||
@@ -700,7 +700,7 @@ class AnalyzeRule(
|
|||||||
book.putVariable(entry.key, entry.value)
|
book.putVariable(entry.key, entry.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WebBook.getBookInfoAwait(this, bookSource, book, false)
|
WebBook.getBookInfoAwait(bookSource, book, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -714,7 +714,7 @@ class AnalyzeRule(
|
|||||||
if (bookSource == null || book == null) return
|
if (bookSource == null || book == null) return
|
||||||
runBlocking {
|
runBlocking {
|
||||||
withTimeout(1800000) {
|
withTimeout(1800000) {
|
||||||
WebBook.getBookInfoAwait(this, bookSource, book)
|
WebBook.getBookInfoAwait(bookSource, book)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -728,7 +728,7 @@ class AnalyzeRule(
|
|||||||
if (bookSource == null || book == null) return
|
if (bookSource == null || book == null) return
|
||||||
runBlocking {
|
runBlocking {
|
||||||
withTimeout(1800000) {
|
withTimeout(1800000) {
|
||||||
WebBook.getBookInfoAwait(this, bookSource, book)
|
WebBook.getBookInfoAwait(bookSource, book)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ 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 io.legado.app.utils.isTrue
|
import io.legado.app.utils.isTrue
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.ensureActive
|
import kotlinx.coroutines.ensureActive
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
|
import kotlin.coroutines.coroutineContext
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取目录
|
* 获取目录
|
||||||
@@ -26,7 +26,6 @@ import splitties.init.appCtx
|
|||||||
object BookChapterList {
|
object BookChapterList {
|
||||||
|
|
||||||
suspend fun analyzeChapterList(
|
suspend fun analyzeChapterList(
|
||||||
scope: CoroutineScope,
|
|
||||||
bookSource: BookSource,
|
bookSource: BookSource,
|
||||||
book: Book,
|
book: Book,
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
@@ -52,7 +51,7 @@ object BookChapterList {
|
|||||||
}
|
}
|
||||||
var chapterData =
|
var chapterData =
|
||||||
analyzeChapterList(
|
analyzeChapterList(
|
||||||
scope, book, baseUrl, redirectUrl, body,
|
book, baseUrl, redirectUrl, body,
|
||||||
tocRule, listRule, bookSource, log = true
|
tocRule, listRule, bookSource, log = true
|
||||||
)
|
)
|
||||||
chapterList.addAll(chapterData.first)
|
chapterList.addAll(chapterData.first)
|
||||||
@@ -69,7 +68,7 @@ object BookChapterList {
|
|||||||
headerMapF = bookSource.getHeaderMap()
|
headerMapF = bookSource.getHeaderMap()
|
||||||
).getStrResponseAwait().body?.let { nextBody ->
|
).getStrResponseAwait().body?.let { nextBody ->
|
||||||
chapterData = analyzeChapterList(
|
chapterData = analyzeChapterList(
|
||||||
scope, book, nextUrl, nextUrl,
|
book, nextUrl, nextUrl,
|
||||||
nextBody, tocRule, listRule, bookSource
|
nextBody, tocRule, listRule, bookSource
|
||||||
)
|
)
|
||||||
nextUrl = chapterData.second.firstOrNull() ?: ""
|
nextUrl = chapterData.second.firstOrNull() ?: ""
|
||||||
@@ -92,7 +91,7 @@ object BookChapterList {
|
|||||||
)
|
)
|
||||||
val res = analyzeUrl.getStrResponseAwait()
|
val res = analyzeUrl.getStrResponseAwait()
|
||||||
analyzeChapterList(
|
analyzeChapterList(
|
||||||
this, book, urlStr, res.url,
|
book, urlStr, res.url,
|
||||||
res.body!!, tocRule, listRule, bookSource, false
|
res.body!!, tocRule, listRule, bookSource, false
|
||||||
).first
|
).first
|
||||||
}
|
}
|
||||||
@@ -110,14 +109,14 @@ object BookChapterList {
|
|||||||
if (!reverse) {
|
if (!reverse) {
|
||||||
chapterList.reverse()
|
chapterList.reverse()
|
||||||
}
|
}
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
val lh = LinkedHashSet(chapterList)
|
val lh = LinkedHashSet(chapterList)
|
||||||
val list = ArrayList(lh)
|
val list = ArrayList(lh)
|
||||||
if (!book.getReverseToc()) {
|
if (!book.getReverseToc()) {
|
||||||
list.reverse()
|
list.reverse()
|
||||||
}
|
}
|
||||||
Debug.log(book.origin, "◇目录总数:${list.size}")
|
Debug.log(book.origin, "◇目录总数:${list.size}")
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
list.forEachIndexed { index, bookChapter ->
|
list.forEachIndexed { index, bookChapter ->
|
||||||
bookChapter.index = index
|
bookChapter.index = index
|
||||||
}
|
}
|
||||||
@@ -131,12 +130,11 @@ object BookChapterList {
|
|||||||
}
|
}
|
||||||
book.lastCheckTime = System.currentTimeMillis()
|
book.lastCheckTime = System.currentTimeMillis()
|
||||||
book.totalChapterNum = list.size
|
book.totalChapterNum = list.size
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun analyzeChapterList(
|
private suspend fun analyzeChapterList(
|
||||||
scope: CoroutineScope,
|
|
||||||
book: Book,
|
book: Book,
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
redirectUrl: String,
|
redirectUrl: String,
|
||||||
@@ -173,7 +171,7 @@ object BookChapterList {
|
|||||||
log
|
log
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
if (elements.isNotEmpty()) {
|
if (elements.isNotEmpty()) {
|
||||||
Debug.log(bookSource.bookSourceUrl, "┌解析目录列表", log)
|
Debug.log(bookSource.bookSourceUrl, "┌解析目录列表", log)
|
||||||
val nameRule = analyzeRule.splitSourceRule(tocRule.chapterName)
|
val nameRule = analyzeRule.splitSourceRule(tocRule.chapterName)
|
||||||
@@ -183,7 +181,7 @@ object BookChapterList {
|
|||||||
val upTimeRule = analyzeRule.splitSourceRule(tocRule.updateTime)
|
val upTimeRule = analyzeRule.splitSourceRule(tocRule.updateTime)
|
||||||
val isVolumeRule = analyzeRule.splitSourceRule(tocRule.isVolume)
|
val isVolumeRule = analyzeRule.splitSourceRule(tocRule.isVolume)
|
||||||
elements.forEachIndexed { index, item ->
|
elements.forEachIndexed { index, item ->
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
analyzeRule.setContent(item)
|
analyzeRule.setContent(item)
|
||||||
val bookChapter = BookChapter(bookUrl = book.bookUrl, baseUrl = redirectUrl)
|
val bookChapter = BookChapter(bookUrl = book.bookUrl, baseUrl = redirectUrl)
|
||||||
analyzeRule.chapter = bookChapter
|
analyzeRule.chapter = bookChapter
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ import io.legado.app.model.analyzeRule.AnalyzeRule
|
|||||||
import io.legado.app.model.analyzeRule.AnalyzeUrl
|
import io.legado.app.model.analyzeRule.AnalyzeUrl
|
||||||
import io.legado.app.utils.HtmlFormatter
|
import io.legado.app.utils.HtmlFormatter
|
||||||
import io.legado.app.utils.NetworkUtils
|
import io.legado.app.utils.NetworkUtils
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.ensureActive
|
import kotlinx.coroutines.ensureActive
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
|
import kotlin.coroutines.coroutineContext
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取正文
|
* 获取正文
|
||||||
@@ -28,7 +28,6 @@ object BookContent {
|
|||||||
|
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
suspend fun analyzeContent(
|
suspend fun analyzeContent(
|
||||||
scope: CoroutineScope,
|
|
||||||
bookSource: BookSource,
|
bookSource: BookSource,
|
||||||
book: Book,
|
book: Book,
|
||||||
bookChapter: BookChapter,
|
bookChapter: BookChapter,
|
||||||
@@ -55,7 +54,7 @@ object BookContent {
|
|||||||
val analyzeRule = AnalyzeRule(book, bookSource).setContent(body, baseUrl)
|
val analyzeRule = AnalyzeRule(book, bookSource).setContent(body, baseUrl)
|
||||||
analyzeRule.setRedirectUrl(redirectUrl)
|
analyzeRule.setRedirectUrl(redirectUrl)
|
||||||
analyzeRule.nextChapterUrl = mNextChapterUrl
|
analyzeRule.nextChapterUrl = mNextChapterUrl
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
var contentData = analyzeContent(
|
var contentData = analyzeContent(
|
||||||
book, baseUrl, redirectUrl, body, contentRule, bookChapter, bookSource, mNextChapterUrl
|
book, baseUrl, redirectUrl, body, contentRule, bookChapter, bookSource, mNextChapterUrl
|
||||||
)
|
)
|
||||||
@@ -68,7 +67,7 @@ object BookContent {
|
|||||||
== NetworkUtils.getAbsoluteURL(redirectUrl, mNextChapterUrl)
|
== NetworkUtils.getAbsoluteURL(redirectUrl, mNextChapterUrl)
|
||||||
) break
|
) break
|
||||||
nextUrlList.add(nextUrl)
|
nextUrlList.add(nextUrl)
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
val res = AnalyzeUrl(
|
val res = AnalyzeUrl(
|
||||||
mUrl = nextUrl,
|
mUrl = nextUrl,
|
||||||
source = bookSource,
|
source = bookSource,
|
||||||
@@ -106,7 +105,7 @@ object BookContent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
asyncArray.forEach { coroutine ->
|
asyncArray.forEach { coroutine ->
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
content.append("\n").append(coroutine.await())
|
content.append("\n").append(coroutine.await())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -124,7 +123,7 @@ object BookContent {
|
|||||||
throw ContentEmptyException("内容为空")
|
throw ContentEmptyException("内容为空")
|
||||||
}
|
}
|
||||||
if (needSave) {
|
if (needSave) {
|
||||||
BookHelp.saveContent(scope, bookSource, book, bookChapter, contentStr)
|
BookHelp.saveContent(bookSource, book, bookChapter, contentStr)
|
||||||
}
|
}
|
||||||
return contentStr
|
return contentStr
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ import io.legado.app.utils.DebugLog
|
|||||||
import io.legado.app.utils.HtmlFormatter
|
import io.legado.app.utils.HtmlFormatter
|
||||||
import io.legado.app.utils.NetworkUtils
|
import io.legado.app.utils.NetworkUtils
|
||||||
import io.legado.app.utils.StringUtils.wordCountFormat
|
import io.legado.app.utils.StringUtils.wordCountFormat
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.ensureActive
|
import kotlinx.coroutines.ensureActive
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
|
import kotlin.coroutines.coroutineContext
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -24,8 +24,7 @@ import splitties.init.appCtx
|
|||||||
object BookInfo {
|
object BookInfo {
|
||||||
|
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
fun analyzeBookInfo(
|
suspend fun analyzeBookInfo(
|
||||||
scope: CoroutineScope,
|
|
||||||
bookSource: BookSource,
|
bookSource: BookSource,
|
||||||
book: Book,
|
book: Book,
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
@@ -41,11 +40,10 @@ object BookInfo {
|
|||||||
val analyzeRule = AnalyzeRule(book, bookSource)
|
val analyzeRule = AnalyzeRule(book, bookSource)
|
||||||
analyzeRule.setContent(body).setBaseUrl(baseUrl)
|
analyzeRule.setContent(body).setBaseUrl(baseUrl)
|
||||||
analyzeRule.setRedirectUrl(redirectUrl)
|
analyzeRule.setRedirectUrl(redirectUrl)
|
||||||
analyzeBookInfo(scope, book, body, analyzeRule, bookSource, baseUrl, redirectUrl, canReName)
|
analyzeBookInfo(book, body, analyzeRule, bookSource, baseUrl, redirectUrl, canReName)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun analyzeBookInfo(
|
suspend fun analyzeBookInfo(
|
||||||
scope: CoroutineScope,
|
|
||||||
book: Book,
|
book: Book,
|
||||||
body: String,
|
body: String,
|
||||||
analyzeRule: AnalyzeRule,
|
analyzeRule: AnalyzeRule,
|
||||||
@@ -57,13 +55,13 @@ object BookInfo {
|
|||||||
val infoRule = bookSource.getBookInfoRule()
|
val infoRule = bookSource.getBookInfoRule()
|
||||||
infoRule.init?.let {
|
infoRule.init?.let {
|
||||||
if (it.isNotBlank()) {
|
if (it.isNotBlank()) {
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
Debug.log(bookSource.bookSourceUrl, "≡执行详情页初始化规则")
|
Debug.log(bookSource.bookSourceUrl, "≡执行详情页初始化规则")
|
||||||
analyzeRule.setContent(analyzeRule.getElement(it))
|
analyzeRule.setContent(analyzeRule.getElement(it))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val mCanReName = canReName && !infoRule.canReName.isNullOrBlank()
|
val mCanReName = canReName && !infoRule.canReName.isNullOrBlank()
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
Debug.log(bookSource.bookSourceUrl, "┌获取书名")
|
Debug.log(bookSource.bookSourceUrl, "┌获取书名")
|
||||||
BookHelp.formatBookName(analyzeRule.getString(infoRule.name)).let {
|
BookHelp.formatBookName(analyzeRule.getString(infoRule.name)).let {
|
||||||
if (it.isNotEmpty() && (mCanReName || book.name.isEmpty())) {
|
if (it.isNotEmpty() && (mCanReName || book.name.isEmpty())) {
|
||||||
@@ -71,7 +69,7 @@ object BookInfo {
|
|||||||
}
|
}
|
||||||
Debug.log(bookSource.bookSourceUrl, "└${it}")
|
Debug.log(bookSource.bookSourceUrl, "└${it}")
|
||||||
}
|
}
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
Debug.log(bookSource.bookSourceUrl, "┌获取作者")
|
Debug.log(bookSource.bookSourceUrl, "┌获取作者")
|
||||||
BookHelp.formatBookAuthor(analyzeRule.getString(infoRule.author)).let {
|
BookHelp.formatBookAuthor(analyzeRule.getString(infoRule.author)).let {
|
||||||
if (it.isNotEmpty() && (mCanReName || book.author.isEmpty())) {
|
if (it.isNotEmpty() && (mCanReName || book.author.isEmpty())) {
|
||||||
@@ -79,7 +77,7 @@ object BookInfo {
|
|||||||
}
|
}
|
||||||
Debug.log(bookSource.bookSourceUrl, "└${it}")
|
Debug.log(bookSource.bookSourceUrl, "└${it}")
|
||||||
}
|
}
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
Debug.log(bookSource.bookSourceUrl, "┌获取分类")
|
Debug.log(bookSource.bookSourceUrl, "┌获取分类")
|
||||||
try {
|
try {
|
||||||
analyzeRule.getStringList(infoRule.kind)
|
analyzeRule.getStringList(infoRule.kind)
|
||||||
@@ -92,7 +90,7 @@ object BookInfo {
|
|||||||
Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}")
|
Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}")
|
||||||
DebugLog.e("获取分类出错", e)
|
DebugLog.e("获取分类出错", e)
|
||||||
}
|
}
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
Debug.log(bookSource.bookSourceUrl, "┌获取字数")
|
Debug.log(bookSource.bookSourceUrl, "┌获取字数")
|
||||||
try {
|
try {
|
||||||
wordCountFormat(analyzeRule.getString(infoRule.wordCount)).let {
|
wordCountFormat(analyzeRule.getString(infoRule.wordCount)).let {
|
||||||
@@ -103,7 +101,7 @@ object BookInfo {
|
|||||||
Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}")
|
Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}")
|
||||||
DebugLog.e("获取字数出错", e)
|
DebugLog.e("获取字数出错", e)
|
||||||
}
|
}
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
Debug.log(bookSource.bookSourceUrl, "┌获取最新章节")
|
Debug.log(bookSource.bookSourceUrl, "┌获取最新章节")
|
||||||
try {
|
try {
|
||||||
analyzeRule.getString(infoRule.lastChapter).let {
|
analyzeRule.getString(infoRule.lastChapter).let {
|
||||||
@@ -114,7 +112,7 @@ object BookInfo {
|
|||||||
Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}")
|
Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}")
|
||||||
DebugLog.e("获取最新章节出错", e)
|
DebugLog.e("获取最新章节出错", e)
|
||||||
}
|
}
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
Debug.log(bookSource.bookSourceUrl, "┌获取简介")
|
Debug.log(bookSource.bookSourceUrl, "┌获取简介")
|
||||||
try {
|
try {
|
||||||
HtmlFormatter.format(analyzeRule.getString(infoRule.intro)).let {
|
HtmlFormatter.format(analyzeRule.getString(infoRule.intro)).let {
|
||||||
@@ -125,7 +123,7 @@ object BookInfo {
|
|||||||
Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}")
|
Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}")
|
||||||
DebugLog.e("获取简介出错", e)
|
DebugLog.e("获取简介出错", e)
|
||||||
}
|
}
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
Debug.log(bookSource.bookSourceUrl, "┌获取封面链接")
|
Debug.log(bookSource.bookSourceUrl, "┌获取封面链接")
|
||||||
try {
|
try {
|
||||||
analyzeRule.getString(infoRule.coverUrl).let {
|
analyzeRule.getString(infoRule.coverUrl).let {
|
||||||
@@ -140,7 +138,7 @@ object BookInfo {
|
|||||||
DebugLog.e("获取封面出错", e)
|
DebugLog.e("获取封面出错", e)
|
||||||
}
|
}
|
||||||
if (book.type != BookType.file) {
|
if (book.type != BookType.file) {
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
Debug.log(bookSource.bookSourceUrl, "┌获取目录链接")
|
Debug.log(bookSource.bookSourceUrl, "┌获取目录链接")
|
||||||
book.tocUrl = analyzeRule.getString(infoRule.tocUrl, isUrl = true)
|
book.tocUrl = analyzeRule.getString(infoRule.tocUrl, isUrl = true)
|
||||||
if (book.tocUrl.isEmpty()) book.tocUrl = baseUrl
|
if (book.tocUrl.isEmpty()) book.tocUrl = baseUrl
|
||||||
@@ -149,7 +147,7 @@ object BookInfo {
|
|||||||
}
|
}
|
||||||
Debug.log(bookSource.bookSourceUrl, "└${book.tocUrl}")
|
Debug.log(bookSource.bookSourceUrl, "└${book.tocUrl}")
|
||||||
} else {
|
} else {
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
Debug.log(bookSource.bookSourceUrl, "┌获取文件下载链接")
|
Debug.log(bookSource.bookSourceUrl, "┌获取文件下载链接")
|
||||||
book.downloadUrls = analyzeRule.getStringList(infoRule.downloadUrls, isUrl = true)
|
book.downloadUrls = analyzeRule.getStringList(infoRule.downloadUrls, isUrl = true)
|
||||||
if (book.downloadUrls == null) {
|
if (book.downloadUrls == null) {
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ import io.legado.app.model.analyzeRule.RuleData
|
|||||||
import io.legado.app.utils.HtmlFormatter
|
import io.legado.app.utils.HtmlFormatter
|
||||||
import io.legado.app.utils.NetworkUtils
|
import io.legado.app.utils.NetworkUtils
|
||||||
import io.legado.app.utils.StringUtils.wordCountFormat
|
import io.legado.app.utils.StringUtils.wordCountFormat
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.ensureActive
|
import kotlinx.coroutines.ensureActive
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
|
import kotlin.coroutines.coroutineContext
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取书籍列表
|
* 获取书籍列表
|
||||||
@@ -24,8 +24,7 @@ import splitties.init.appCtx
|
|||||||
object BookList {
|
object BookList {
|
||||||
|
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
fun analyzeBookList(
|
suspend fun analyzeBookList(
|
||||||
scope: CoroutineScope,
|
|
||||||
bookSource: BookSource,
|
bookSource: BookSource,
|
||||||
ruleData: RuleData,
|
ruleData: RuleData,
|
||||||
analyzeUrl: AnalyzeUrl,
|
analyzeUrl: AnalyzeUrl,
|
||||||
@@ -46,11 +45,10 @@ object BookList {
|
|||||||
analyzeRule.setContent(body).setBaseUrl(baseUrl)
|
analyzeRule.setContent(body).setBaseUrl(baseUrl)
|
||||||
analyzeRule.setRedirectUrl(baseUrl)
|
analyzeRule.setRedirectUrl(baseUrl)
|
||||||
bookSource.bookUrlPattern?.let {
|
bookSource.bookUrlPattern?.let {
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
if (baseUrl.matches(it.toRegex())) {
|
if (baseUrl.matches(it.toRegex())) {
|
||||||
Debug.log(bookSource.bookSourceUrl, "≡链接为详情页")
|
Debug.log(bookSource.bookSourceUrl, "≡链接为详情页")
|
||||||
getInfoItem(
|
getInfoItem(
|
||||||
scope,
|
|
||||||
bookSource,
|
bookSource,
|
||||||
analyzeRule,
|
analyzeRule,
|
||||||
analyzeUrl,
|
analyzeUrl,
|
||||||
@@ -81,11 +79,11 @@ object BookList {
|
|||||||
}
|
}
|
||||||
Debug.log(bookSource.bookSourceUrl, "┌获取书籍列表")
|
Debug.log(bookSource.bookSourceUrl, "┌获取书籍列表")
|
||||||
collections = analyzeRule.getElements(ruleList)
|
collections = analyzeRule.getElements(ruleList)
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
if (collections.isEmpty() && bookSource.bookUrlPattern.isNullOrEmpty()) {
|
if (collections.isEmpty() && bookSource.bookUrlPattern.isNullOrEmpty()) {
|
||||||
Debug.log(bookSource.bookSourceUrl, "└列表为空,按详情页解析")
|
Debug.log(bookSource.bookSourceUrl, "└列表为空,按详情页解析")
|
||||||
getInfoItem(
|
getInfoItem(
|
||||||
scope, bookSource, analyzeRule, analyzeUrl, body, baseUrl, ruleData.getVariable()
|
bookSource, analyzeRule, analyzeUrl, body, baseUrl, ruleData.getVariable()
|
||||||
)?.let { searchBook ->
|
)?.let { searchBook ->
|
||||||
searchBook.infoHtml = body
|
searchBook.infoHtml = body
|
||||||
bookList.add(searchBook)
|
bookList.add(searchBook)
|
||||||
@@ -102,7 +100,7 @@ object BookList {
|
|||||||
Debug.log(bookSource.bookSourceUrl, "└列表大小:${collections.size}")
|
Debug.log(bookSource.bookSourceUrl, "└列表大小:${collections.size}")
|
||||||
for ((index, item) in collections.withIndex()) {
|
for ((index, item) in collections.withIndex()) {
|
||||||
getSearchItem(
|
getSearchItem(
|
||||||
scope, bookSource, analyzeRule, item, baseUrl, ruleData.getVariable(),
|
bookSource, analyzeRule, item, baseUrl, ruleData.getVariable(),
|
||||||
index == 0,
|
index == 0,
|
||||||
ruleName = ruleName,
|
ruleName = ruleName,
|
||||||
ruleBookUrl = ruleBookUrl,
|
ruleBookUrl = ruleBookUrl,
|
||||||
@@ -127,8 +125,7 @@ object BookList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
private fun getInfoItem(
|
private suspend fun getInfoItem(
|
||||||
scope: CoroutineScope,
|
|
||||||
bookSource: BookSource,
|
bookSource: BookSource,
|
||||||
analyzeRule: AnalyzeRule,
|
analyzeRule: AnalyzeRule,
|
||||||
analyzeUrl: AnalyzeUrl,
|
analyzeUrl: AnalyzeUrl,
|
||||||
@@ -144,7 +141,6 @@ object BookList {
|
|||||||
book.type = bookSource.bookSourceType
|
book.type = bookSource.bookSourceType
|
||||||
analyzeRule.ruleData = book
|
analyzeRule.ruleData = book
|
||||||
BookInfo.analyzeBookInfo(
|
BookInfo.analyzeBookInfo(
|
||||||
scope,
|
|
||||||
book,
|
book,
|
||||||
body,
|
body,
|
||||||
analyzeRule,
|
analyzeRule,
|
||||||
@@ -160,8 +156,7 @@ object BookList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
private fun getSearchItem(
|
private suspend fun getSearchItem(
|
||||||
scope: CoroutineScope,
|
|
||||||
bookSource: BookSource,
|
bookSource: BookSource,
|
||||||
analyzeRule: AnalyzeRule,
|
analyzeRule: AnalyzeRule,
|
||||||
item: Any,
|
item: Any,
|
||||||
@@ -184,16 +179,16 @@ object BookList {
|
|||||||
searchBook.originOrder = bookSource.customOrder
|
searchBook.originOrder = bookSource.customOrder
|
||||||
analyzeRule.ruleData = searchBook
|
analyzeRule.ruleData = searchBook
|
||||||
analyzeRule.setContent(item)
|
analyzeRule.setContent(item)
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
Debug.log(bookSource.bookSourceUrl, "┌获取书名", log)
|
Debug.log(bookSource.bookSourceUrl, "┌获取书名", log)
|
||||||
searchBook.name = BookHelp.formatBookName(analyzeRule.getString(ruleName))
|
searchBook.name = BookHelp.formatBookName(analyzeRule.getString(ruleName))
|
||||||
Debug.log(bookSource.bookSourceUrl, "└${searchBook.name}", log)
|
Debug.log(bookSource.bookSourceUrl, "└${searchBook.name}", log)
|
||||||
if (searchBook.name.isNotEmpty()) {
|
if (searchBook.name.isNotEmpty()) {
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
Debug.log(bookSource.bookSourceUrl, "┌获取作者", log)
|
Debug.log(bookSource.bookSourceUrl, "┌获取作者", log)
|
||||||
searchBook.author = BookHelp.formatBookAuthor(analyzeRule.getString(ruleAuthor))
|
searchBook.author = BookHelp.formatBookAuthor(analyzeRule.getString(ruleAuthor))
|
||||||
Debug.log(bookSource.bookSourceUrl, "└${searchBook.author}", log)
|
Debug.log(bookSource.bookSourceUrl, "└${searchBook.author}", log)
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
Debug.log(bookSource.bookSourceUrl, "┌获取分类", log)
|
Debug.log(bookSource.bookSourceUrl, "┌获取分类", log)
|
||||||
try {
|
try {
|
||||||
searchBook.kind = analyzeRule.getStringList(ruleKind)?.joinToString(",")
|
searchBook.kind = analyzeRule.getStringList(ruleKind)?.joinToString(",")
|
||||||
@@ -201,7 +196,7 @@ object BookList {
|
|||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}", log)
|
Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}", log)
|
||||||
}
|
}
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
Debug.log(bookSource.bookSourceUrl, "┌获取字数", log)
|
Debug.log(bookSource.bookSourceUrl, "┌获取字数", log)
|
||||||
try {
|
try {
|
||||||
searchBook.wordCount = wordCountFormat(analyzeRule.getString(ruleWordCount))
|
searchBook.wordCount = wordCountFormat(analyzeRule.getString(ruleWordCount))
|
||||||
@@ -209,7 +204,7 @@ object BookList {
|
|||||||
} catch (e: java.lang.Exception) {
|
} catch (e: java.lang.Exception) {
|
||||||
Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}", log)
|
Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}", log)
|
||||||
}
|
}
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
Debug.log(bookSource.bookSourceUrl, "┌获取最新章节", log)
|
Debug.log(bookSource.bookSourceUrl, "┌获取最新章节", log)
|
||||||
try {
|
try {
|
||||||
searchBook.latestChapterTitle = analyzeRule.getString(ruleLastChapter)
|
searchBook.latestChapterTitle = analyzeRule.getString(ruleLastChapter)
|
||||||
@@ -217,7 +212,7 @@ object BookList {
|
|||||||
} catch (e: java.lang.Exception) {
|
} catch (e: java.lang.Exception) {
|
||||||
Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}", log)
|
Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}", log)
|
||||||
}
|
}
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
Debug.log(bookSource.bookSourceUrl, "┌获取简介", log)
|
Debug.log(bookSource.bookSourceUrl, "┌获取简介", log)
|
||||||
try {
|
try {
|
||||||
searchBook.intro = HtmlFormatter.format(analyzeRule.getString(ruleIntro))
|
searchBook.intro = HtmlFormatter.format(analyzeRule.getString(ruleIntro))
|
||||||
@@ -225,7 +220,7 @@ object BookList {
|
|||||||
} catch (e: java.lang.Exception) {
|
} catch (e: java.lang.Exception) {
|
||||||
Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}", log)
|
Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}", log)
|
||||||
}
|
}
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
Debug.log(bookSource.bookSourceUrl, "┌获取封面链接", log)
|
Debug.log(bookSource.bookSourceUrl, "┌获取封面链接", log)
|
||||||
try {
|
try {
|
||||||
analyzeRule.getString(ruleCoverUrl).let {
|
analyzeRule.getString(ruleCoverUrl).let {
|
||||||
@@ -237,7 +232,7 @@ object BookList {
|
|||||||
} catch (e: java.lang.Exception) {
|
} catch (e: java.lang.Exception) {
|
||||||
Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}", log)
|
Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}", log)
|
||||||
}
|
}
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
Debug.log(bookSource.bookSourceUrl, "┌获取详情页链接", log)
|
Debug.log(bookSource.bookSourceUrl, "┌获取详情页链接", log)
|
||||||
searchBook.bookUrl = analyzeRule.getString(ruleBookUrl, isUrl = true)
|
searchBook.bookUrl = analyzeRule.getString(ruleBookUrl, isUrl = true)
|
||||||
if (searchBook.bookUrl.isEmpty()) {
|
if (searchBook.bookUrl.isEmpty()) {
|
||||||
|
|||||||
@@ -29,12 +29,11 @@ object WebBook {
|
|||||||
context: CoroutineContext = Dispatchers.IO,
|
context: CoroutineContext = Dispatchers.IO,
|
||||||
): Coroutine<ArrayList<SearchBook>> {
|
): Coroutine<ArrayList<SearchBook>> {
|
||||||
return Coroutine.async(scope, context) {
|
return Coroutine.async(scope, context) {
|
||||||
searchBookAwait(scope, bookSource, key, page)
|
searchBookAwait(bookSource, key, page)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun searchBookAwait(
|
suspend fun searchBookAwait(
|
||||||
scope: CoroutineScope,
|
|
||||||
bookSource: BookSource,
|
bookSource: BookSource,
|
||||||
key: String,
|
key: String,
|
||||||
page: Int? = 1,
|
page: Int? = 1,
|
||||||
@@ -58,7 +57,6 @@ object WebBook {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return BookList.analyzeBookList(
|
return BookList.analyzeBookList(
|
||||||
scope = scope,
|
|
||||||
bookSource = bookSource,
|
bookSource = bookSource,
|
||||||
ruleData = ruleData,
|
ruleData = ruleData,
|
||||||
analyzeUrl = analyzeUrl,
|
analyzeUrl = analyzeUrl,
|
||||||
@@ -81,12 +79,11 @@ object WebBook {
|
|||||||
context: CoroutineContext = Dispatchers.IO,
|
context: CoroutineContext = Dispatchers.IO,
|
||||||
): Coroutine<List<SearchBook>> {
|
): Coroutine<List<SearchBook>> {
|
||||||
return Coroutine.async(scope, context) {
|
return Coroutine.async(scope, context) {
|
||||||
exploreBookAwait(scope, bookSource, url, page)
|
exploreBookAwait(bookSource, url, page)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun exploreBookAwait(
|
suspend fun exploreBookAwait(
|
||||||
scope: CoroutineScope,
|
|
||||||
bookSource: BookSource,
|
bookSource: BookSource,
|
||||||
url: String,
|
url: String,
|
||||||
page: Int? = 1,
|
page: Int? = 1,
|
||||||
@@ -108,7 +105,6 @@ object WebBook {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return BookList.analyzeBookList(
|
return BookList.analyzeBookList(
|
||||||
scope = scope,
|
|
||||||
bookSource = bookSource,
|
bookSource = bookSource,
|
||||||
ruleData = ruleData,
|
ruleData = ruleData,
|
||||||
analyzeUrl = analyzeUrl,
|
analyzeUrl = analyzeUrl,
|
||||||
@@ -129,12 +125,11 @@ object WebBook {
|
|||||||
canReName: Boolean = true,
|
canReName: Boolean = true,
|
||||||
): Coroutine<Book> {
|
): Coroutine<Book> {
|
||||||
return Coroutine.async(scope, context) {
|
return Coroutine.async(scope, context) {
|
||||||
getBookInfoAwait(scope, bookSource, book, canReName)
|
getBookInfoAwait(bookSource, book, canReName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getBookInfoAwait(
|
suspend fun getBookInfoAwait(
|
||||||
scope: CoroutineScope,
|
|
||||||
bookSource: BookSource,
|
bookSource: BookSource,
|
||||||
book: Book,
|
book: Book,
|
||||||
canReName: Boolean = true,
|
canReName: Boolean = true,
|
||||||
@@ -142,7 +137,6 @@ object WebBook {
|
|||||||
book.type = bookSource.bookSourceType
|
book.type = bookSource.bookSourceType
|
||||||
if (!book.infoHtml.isNullOrEmpty()) {
|
if (!book.infoHtml.isNullOrEmpty()) {
|
||||||
BookInfo.analyzeBookInfo(
|
BookInfo.analyzeBookInfo(
|
||||||
scope = scope,
|
|
||||||
bookSource = bookSource,
|
bookSource = bookSource,
|
||||||
book = book,
|
book = book,
|
||||||
baseUrl = book.bookUrl,
|
baseUrl = book.bookUrl,
|
||||||
@@ -166,7 +160,6 @@ object WebBook {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
BookInfo.analyzeBookInfo(
|
BookInfo.analyzeBookInfo(
|
||||||
scope = scope,
|
|
||||||
bookSource = bookSource,
|
bookSource = bookSource,
|
||||||
book = book,
|
book = book,
|
||||||
baseUrl = book.bookUrl,
|
baseUrl = book.bookUrl,
|
||||||
@@ -188,12 +181,11 @@ object WebBook {
|
|||||||
context: CoroutineContext = Dispatchers.IO
|
context: CoroutineContext = Dispatchers.IO
|
||||||
): Coroutine<List<BookChapter>> {
|
): Coroutine<List<BookChapter>> {
|
||||||
return Coroutine.async(scope, context) {
|
return Coroutine.async(scope, context) {
|
||||||
getChapterListAwait(scope, bookSource, book).getOrThrow()
|
getChapterListAwait(bookSource, book).getOrThrow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getChapterListAwait(
|
suspend fun getChapterListAwait(
|
||||||
scope: CoroutineScope,
|
|
||||||
bookSource: BookSource,
|
bookSource: BookSource,
|
||||||
book: Book,
|
book: Book,
|
||||||
): Result<List<BookChapter>> {
|
): Result<List<BookChapter>> {
|
||||||
@@ -201,7 +193,6 @@ object WebBook {
|
|||||||
return kotlin.runCatching {
|
return kotlin.runCatching {
|
||||||
if (book.bookUrl == book.tocUrl && !book.tocHtml.isNullOrEmpty()) {
|
if (book.bookUrl == book.tocUrl && !book.tocHtml.isNullOrEmpty()) {
|
||||||
BookChapterList.analyzeChapterList(
|
BookChapterList.analyzeChapterList(
|
||||||
scope = scope,
|
|
||||||
bookSource = bookSource,
|
bookSource = bookSource,
|
||||||
book = book,
|
book = book,
|
||||||
baseUrl = book.tocUrl,
|
baseUrl = book.tocUrl,
|
||||||
@@ -224,7 +215,6 @@ object WebBook {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
BookChapterList.analyzeChapterList(
|
BookChapterList.analyzeChapterList(
|
||||||
scope = scope,
|
|
||||||
bookSource = bookSource,
|
bookSource = bookSource,
|
||||||
book = book,
|
book = book,
|
||||||
baseUrl = book.tocUrl,
|
baseUrl = book.tocUrl,
|
||||||
@@ -270,7 +260,6 @@ object WebBook {
|
|||||||
}
|
}
|
||||||
return if (bookChapter.url == book.bookUrl && !book.tocHtml.isNullOrEmpty()) {
|
return if (bookChapter.url == book.bookUrl && !book.tocHtml.isNullOrEmpty()) {
|
||||||
BookContent.analyzeContent(
|
BookContent.analyzeContent(
|
||||||
scope = scope,
|
|
||||||
bookSource = bookSource,
|
bookSource = bookSource,
|
||||||
book = book,
|
book = book,
|
||||||
bookChapter = bookChapter,
|
bookChapter = bookChapter,
|
||||||
@@ -300,7 +289,6 @@ object WebBook {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
BookContent.analyzeContent(
|
BookContent.analyzeContent(
|
||||||
scope = scope,
|
|
||||||
bookSource = bookSource,
|
bookSource = bookSource,
|
||||||
book = book,
|
book = book,
|
||||||
bookChapter = bookChapter,
|
bookChapter = bookChapter,
|
||||||
@@ -342,13 +330,13 @@ object WebBook {
|
|||||||
): Result<Book> {
|
): Result<Book> {
|
||||||
return kotlin.runCatching {
|
return kotlin.runCatching {
|
||||||
scope.isActive
|
scope.isActive
|
||||||
searchBookAwait(scope, bookSource, name).firstOrNull {
|
searchBookAwait(bookSource, name).firstOrNull {
|
||||||
it.name == name && it.author == author
|
it.name == name && it.author == author
|
||||||
}?.let { searchBook ->
|
}?.let { searchBook ->
|
||||||
scope.isActive
|
scope.isActive
|
||||||
var book = searchBook.toBook()
|
var book = searchBook.toBook()
|
||||||
if (book.tocUrl.isBlank()) {
|
if (book.tocUrl.isBlank()) {
|
||||||
book = getBookInfoAwait(scope, bookSource, book)
|
book = getBookInfoAwait(bookSource, book)
|
||||||
}
|
}
|
||||||
return@runCatching book
|
return@runCatching book
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,8 +24,11 @@ import io.legado.app.utils.activityPendingIntent
|
|||||||
import io.legado.app.utils.postEvent
|
import io.legado.app.utils.postEvent
|
||||||
import io.legado.app.utils.servicePendingIntent
|
import io.legado.app.utils.servicePendingIntent
|
||||||
import io.legado.app.utils.toastOnUi
|
import io.legado.app.utils.toastOnUi
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.CoroutineStart
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
|
import kotlinx.coroutines.TimeoutCancellationException
|
||||||
|
import kotlinx.coroutines.asCoroutineDispatcher
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.mozilla.javascript.WrappedException
|
import org.mozilla.javascript.WrappedException
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
@@ -139,7 +142,7 @@ class CheckSourceService : BaseService() {
|
|||||||
if (CheckSource.checkSearch) {
|
if (CheckSource.checkSearch) {
|
||||||
if (!source.searchUrl.isNullOrBlank()) {
|
if (!source.searchUrl.isNullOrBlank()) {
|
||||||
source.removeGroup("搜索链接规则为空")
|
source.removeGroup("搜索链接规则为空")
|
||||||
val searchBooks = WebBook.searchBookAwait(this, source, searchWord)
|
val searchBooks = WebBook.searchBookAwait(source, searchWord)
|
||||||
if (searchBooks.isEmpty()) {
|
if (searchBooks.isEmpty()) {
|
||||||
source.addGroup("搜索失效")
|
source.addGroup("搜索失效")
|
||||||
} else {
|
} else {
|
||||||
@@ -164,7 +167,7 @@ class CheckSourceService : BaseService() {
|
|||||||
source.addGroup("发现规则为空")
|
source.addGroup("发现规则为空")
|
||||||
} else {
|
} else {
|
||||||
source.removeGroup("发现规则为空")
|
source.removeGroup("发现规则为空")
|
||||||
val exploreBooks = WebBook.exploreBookAwait(this, source, url)
|
val exploreBooks = WebBook.exploreBookAwait(source, url)
|
||||||
if (exploreBooks.isEmpty()) {
|
if (exploreBooks.isEmpty()) {
|
||||||
source.addGroup("发现失效")
|
source.addGroup("发现失效")
|
||||||
} else {
|
} else {
|
||||||
@@ -205,13 +208,13 @@ class CheckSourceService : BaseService() {
|
|||||||
//校验详情
|
//校验详情
|
||||||
if (CheckSource.checkInfo) {
|
if (CheckSource.checkInfo) {
|
||||||
if (mBook.tocUrl.isBlank()) {
|
if (mBook.tocUrl.isBlank()) {
|
||||||
mBook = WebBook.getBookInfoAwait(this, source, mBook)
|
mBook = WebBook.getBookInfoAwait(source, mBook)
|
||||||
}
|
}
|
||||||
//校验目录
|
//校验目录
|
||||||
if (CheckSource.checkCategory &&
|
if (CheckSource.checkCategory &&
|
||||||
source.bookSourceType != BookType.file
|
source.bookSourceType != BookType.file
|
||||||
) {
|
) {
|
||||||
val toc = WebBook.getChapterListAwait(this, source, mBook).getOrThrow()
|
val toc = WebBook.getChapterListAwait(source, mBook).getOrThrow()
|
||||||
val nextChapterUrl = toc.getOrNull(1)?.url ?: toc.first().url
|
val nextChapterUrl = toc.getOrNull(1)?.url ?: toc.first().url
|
||||||
//校验正文
|
//校验正文
|
||||||
if (CheckSource.checkContent) {
|
if (CheckSource.checkContent) {
|
||||||
|
|||||||
+15
-17
@@ -23,7 +23,6 @@ import io.legado.app.help.BookHelp
|
|||||||
import io.legado.app.help.ContentProcessor
|
import io.legado.app.help.ContentProcessor
|
||||||
import io.legado.app.help.config.AppConfig
|
import io.legado.app.help.config.AppConfig
|
||||||
import io.legado.app.utils.*
|
import io.legado.app.utils.*
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.ensureActive
|
import kotlinx.coroutines.ensureActive
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
@@ -37,6 +36,7 @@ import java.io.File
|
|||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.nio.charset.Charset
|
import java.nio.charset.Charset
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
import kotlin.coroutines.coroutineContext
|
||||||
|
|
||||||
|
|
||||||
class CacheViewModel(application: Application) : BaseViewModel(application) {
|
class CacheViewModel(application: Application) : BaseViewModel(application) {
|
||||||
@@ -79,9 +79,9 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
val uri = Uri.parse(path)
|
val uri = Uri.parse(path)
|
||||||
val doc = DocumentFile.fromTreeUri(context, uri)
|
val doc = DocumentFile.fromTreeUri(context, uri)
|
||||||
?: throw NoStackTraceException("获取导出文档失败")
|
?: throw NoStackTraceException("获取导出文档失败")
|
||||||
export(this, doc, book)
|
export(doc, book)
|
||||||
} else {
|
} else {
|
||||||
export(this, FileUtils.createFolderIfNotExist(path), book)
|
export(FileUtils.createFolderIfNotExist(path), book)
|
||||||
}
|
}
|
||||||
}.onError {
|
}.onError {
|
||||||
exportProgress.remove(book.bookUrl)
|
exportProgress.remove(book.bookUrl)
|
||||||
@@ -98,14 +98,14 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("BlockingMethodInNonBlockingContext")
|
@Suppress("BlockingMethodInNonBlockingContext")
|
||||||
private suspend fun export(scope: CoroutineScope, doc: DocumentFile, book: Book) {
|
private suspend fun export(doc: DocumentFile, book: Book) {
|
||||||
val filename = "${getExportFileName(book)}.txt"
|
val filename = "${getExportFileName(book)}.txt"
|
||||||
DocumentUtils.delete(doc, filename)
|
DocumentUtils.delete(doc, filename)
|
||||||
val bookDoc = DocumentUtils.createFileIfNotExist(doc, filename)
|
val bookDoc = DocumentUtils.createFileIfNotExist(doc, filename)
|
||||||
?: throw NoStackTraceException("创建文档失败,请尝试重新设置导出文件夹")
|
?: throw NoStackTraceException("创建文档失败,请尝试重新设置导出文件夹")
|
||||||
val stringBuilder = StringBuilder()
|
val stringBuilder = StringBuilder()
|
||||||
context.contentResolver.openOutputStream(bookDoc.uri, "wa")?.use { bookOs ->
|
context.contentResolver.openOutputStream(bookDoc.uri, "wa")?.use { bookOs ->
|
||||||
getAllContents(scope, book) { text, srcList ->
|
getAllContents(book) { text, srcList ->
|
||||||
bookOs.write(text.toByteArray(Charset.forName(AppConfig.exportCharset)))
|
bookOs.write(text.toByteArray(Charset.forName(AppConfig.exportCharset)))
|
||||||
stringBuilder.append(text)
|
stringBuilder.append(text)
|
||||||
srcList?.forEach {
|
srcList?.forEach {
|
||||||
@@ -128,12 +128,12 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun export(scope: CoroutineScope, file: File, book: Book) {
|
private suspend fun export(file: File, book: Book) {
|
||||||
val filename = "${getExportFileName(book)}.txt"
|
val filename = "${getExportFileName(book)}.txt"
|
||||||
val bookPath = FileUtils.getPath(file, filename)
|
val bookPath = FileUtils.getPath(file, filename)
|
||||||
val bookFile = FileUtils.createFileWithReplace(bookPath)
|
val bookFile = FileUtils.createFileWithReplace(bookPath)
|
||||||
val stringBuilder = StringBuilder()
|
val stringBuilder = StringBuilder()
|
||||||
getAllContents(scope, book) { text, srcList ->
|
getAllContents(book) { text, srcList ->
|
||||||
bookFile.appendText(text, Charset.forName(AppConfig.exportCharset))
|
bookFile.appendText(text, Charset.forName(AppConfig.exportCharset))
|
||||||
stringBuilder.append(text)
|
stringBuilder.append(text)
|
||||||
srcList?.forEach {
|
srcList?.forEach {
|
||||||
@@ -157,7 +157,6 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getAllContents(
|
private suspend fun getAllContents(
|
||||||
scope: CoroutineScope,
|
|
||||||
book: Book,
|
book: Book,
|
||||||
append: (text: String, srcList: ArrayList<Triple<String, Int, String>>?) -> Unit
|
append: (text: String, srcList: ArrayList<Triple<String, Int, String>>?) -> Unit
|
||||||
) {
|
) {
|
||||||
@@ -173,7 +172,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
}"
|
}"
|
||||||
append(qy, null)
|
append(qy, null)
|
||||||
appDb.bookChapterDao.getChapterList(book.bookUrl).forEachIndexed { index, chapter ->
|
appDb.bookChapterDao.getChapterList(book.bookUrl).forEachIndexed { index, chapter ->
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
upAdapterLiveData.postValue(book.bookUrl)
|
upAdapterLiveData.postValue(book.bookUrl)
|
||||||
exportProgress[book.bookUrl] = index
|
exportProgress[book.bookUrl] = index
|
||||||
BookHelp.getContent(book, chapter).let { content ->
|
BookHelp.getContent(book, chapter).let { content ->
|
||||||
@@ -227,9 +226,9 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
val uri = Uri.parse(path)
|
val uri = Uri.parse(path)
|
||||||
val doc = DocumentFile.fromTreeUri(context, uri)
|
val doc = DocumentFile.fromTreeUri(context, uri)
|
||||||
?: throw NoStackTraceException("获取导出文档失败")
|
?: throw NoStackTraceException("获取导出文档失败")
|
||||||
exportEpub(this, doc, book)
|
exportEpub(doc, book)
|
||||||
} else {
|
} else {
|
||||||
exportEpub(this, FileUtils.createFolderIfNotExist(path), book)
|
exportEpub(FileUtils.createFolderIfNotExist(path), book)
|
||||||
}
|
}
|
||||||
}.onError {
|
}.onError {
|
||||||
exportProgress.remove(book.bookUrl)
|
exportProgress.remove(book.bookUrl)
|
||||||
@@ -246,7 +245,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("BlockingMethodInNonBlockingContext")
|
@Suppress("BlockingMethodInNonBlockingContext")
|
||||||
private suspend fun exportEpub(scope: CoroutineScope, doc: DocumentFile, book: Book) {
|
private suspend fun exportEpub(doc: DocumentFile, book: Book) {
|
||||||
val filename = "${getExportFileName(book)}.epub"
|
val filename = "${getExportFileName(book)}.epub"
|
||||||
DocumentUtils.delete(doc, filename)
|
DocumentUtils.delete(doc, filename)
|
||||||
val epubBook = EpubBook()
|
val epubBook = EpubBook()
|
||||||
@@ -259,7 +258,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
val contentModel = setAssets(doc, book, epubBook)
|
val contentModel = setAssets(doc, book, epubBook)
|
||||||
|
|
||||||
//设置正文
|
//设置正文
|
||||||
setEpubContent(scope, contentModel, book, epubBook)
|
setEpubContent(contentModel, book, epubBook)
|
||||||
DocumentUtils.createFileIfNotExist(doc, filename)?.let { bookDoc ->
|
DocumentUtils.createFileIfNotExist(doc, filename)?.let { bookDoc ->
|
||||||
context.contentResolver.openOutputStream(bookDoc.uri, "wa")?.use { bookOs ->
|
context.contentResolver.openOutputStream(bookDoc.uri, "wa")?.use { bookOs ->
|
||||||
EpubWriter().write(epubBook, bookOs)
|
EpubWriter().write(epubBook, bookOs)
|
||||||
@@ -269,7 +268,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private suspend fun exportEpub(scope: CoroutineScope, file: File, book: Book) {
|
private suspend fun exportEpub(file: File, book: Book) {
|
||||||
val filename = "${getExportFileName(book)}.epub"
|
val filename = "${getExportFileName(book)}.epub"
|
||||||
val epubBook = EpubBook()
|
val epubBook = EpubBook()
|
||||||
epubBook.version = "2.0"
|
epubBook.version = "2.0"
|
||||||
@@ -283,7 +282,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
val bookPath = FileUtils.getPath(file, filename)
|
val bookPath = FileUtils.getPath(file, filename)
|
||||||
val bookFile = FileUtils.createFileWithReplace(bookPath)
|
val bookFile = FileUtils.createFileWithReplace(bookPath)
|
||||||
//设置正文
|
//设置正文
|
||||||
setEpubContent(scope, contentModel, book, epubBook)
|
setEpubContent(contentModel, book, epubBook)
|
||||||
@Suppress("BlockingMethodInNonBlockingContext")
|
@Suppress("BlockingMethodInNonBlockingContext")
|
||||||
EpubWriter().write(epubBook, FileOutputStream(bookFile))
|
EpubWriter().write(epubBook, FileOutputStream(bookFile))
|
||||||
}
|
}
|
||||||
@@ -438,7 +437,6 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun setEpubContent(
|
private suspend fun setEpubContent(
|
||||||
scope: CoroutineScope,
|
|
||||||
contentModel: String,
|
contentModel: String,
|
||||||
book: Book,
|
book: Book,
|
||||||
epubBook: EpubBook
|
epubBook: EpubBook
|
||||||
@@ -447,7 +445,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
val useReplace = AppConfig.exportUseReplace && book.getUseReplaceRule()
|
val useReplace = AppConfig.exportUseReplace && book.getUseReplaceRule()
|
||||||
val contentProcessor = ContentProcessor.get(book.name, book.origin)
|
val contentProcessor = ContentProcessor.get(book.name, book.origin)
|
||||||
appDb.bookChapterDao.getChapterList(book.bookUrl).forEachIndexed { index, chapter ->
|
appDb.bookChapterDao.getChapterList(book.bookUrl).forEachIndexed { index, chapter ->
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
upAdapterLiveData.postValue(book.bookUrl)
|
upAdapterLiveData.postValue(book.bookUrl)
|
||||||
exportProgress[book.bookUrl] = index
|
exportProgress[book.bookUrl] = index
|
||||||
BookHelp.getContent(book, chapter).let { content ->
|
BookHelp.getContent(book, chapter).let { content ->
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import io.legado.app.help.coroutine.Coroutine
|
|||||||
import io.legado.app.model.webBook.WebBook
|
import io.legado.app.model.webBook.WebBook
|
||||||
import io.legado.app.utils.getPrefBoolean
|
import io.legado.app.utils.getPrefBoolean
|
||||||
import io.legado.app.utils.toastOnUi
|
import io.legado.app.utils.toastOnUi
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.ExecutorCoroutineDispatcher
|
import kotlinx.coroutines.ExecutorCoroutineDispatcher
|
||||||
import kotlinx.coroutines.asCoroutineDispatcher
|
import kotlinx.coroutines.asCoroutineDispatcher
|
||||||
@@ -155,7 +154,7 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
|
|||||||
}
|
}
|
||||||
val source = bookSourceList[searchIndex]
|
val source = bookSourceList[searchIndex]
|
||||||
val task = Coroutine.async(scope = viewModelScope, context = searchPool!!) {
|
val task = Coroutine.async(scope = viewModelScope, context = searchPool!!) {
|
||||||
val resultBooks = WebBook.searchBookAwait(this, source, name)
|
val resultBooks = WebBook.searchBookAwait(source, name)
|
||||||
resultBooks.forEach { searchBook ->
|
resultBooks.forEach { searchBook ->
|
||||||
if (searchBook.name == name) {
|
if (searchBook.name == name) {
|
||||||
if ((AppConfig.changeSourceCheckAuthor && searchBook.author.contains(author))
|
if ((AppConfig.changeSourceCheckAuthor && searchBook.author.contains(author))
|
||||||
@@ -163,7 +162,7 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
|
|||||||
) {
|
) {
|
||||||
if (searchBook.latestChapterTitle.isNullOrEmpty()) {
|
if (searchBook.latestChapterTitle.isNullOrEmpty()) {
|
||||||
if (AppConfig.changeSourceLoadInfo || AppConfig.changeSourceLoadToc) {
|
if (AppConfig.changeSourceLoadInfo || AppConfig.changeSourceLoadToc) {
|
||||||
loadBookInfo(this, source, searchBook.toBook())
|
loadBookInfo(source, searchBook.toBook())
|
||||||
} else {
|
} else {
|
||||||
searchCallback?.searchSuccess(searchBook)
|
searchCallback?.searchSuccess(searchBook)
|
||||||
}
|
}
|
||||||
@@ -183,10 +182,10 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
|
|||||||
tasks.add(task)
|
tasks.add(task)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun loadBookInfo(scope: CoroutineScope, source: BookSource, book: Book) {
|
private suspend fun loadBookInfo(source: BookSource, book: Book) {
|
||||||
WebBook.getBookInfoAwait(scope, source, book)
|
WebBook.getBookInfoAwait(source, book)
|
||||||
if (context.getPrefBoolean(PreferKey.changeSourceLoadToc)) {
|
if (context.getPrefBoolean(PreferKey.changeSourceLoadToc)) {
|
||||||
loadBookToc(scope, source, book)
|
loadBookToc(source, book)
|
||||||
} else {
|
} else {
|
||||||
//从详情页里获取最新章节
|
//从详情页里获取最新章节
|
||||||
val searchBook = book.toSearchBook()
|
val searchBook = book.toSearchBook()
|
||||||
@@ -194,8 +193,8 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun loadBookToc(scope: CoroutineScope, source: BookSource, book: Book) {
|
private suspend fun loadBookToc(source: BookSource, book: Book) {
|
||||||
val chapters = WebBook.getChapterListAwait(scope, source, book).getOrThrow()
|
val chapters = WebBook.getChapterListAwait(source, book).getOrThrow()
|
||||||
tocMap[book.bookUrl] = chapters
|
tocMap[book.bookUrl] = chapters
|
||||||
book.latestChapterTitle = chapters.last().title
|
book.latestChapterTitle = chapters.last().title
|
||||||
val searchBook: SearchBook = book.toSearchBook()
|
val searchBook: SearchBook = book.toSearchBook()
|
||||||
@@ -298,9 +297,9 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
|
|||||||
val source = appDb.bookSourceDao.getBookSource(book.origin)
|
val source = appDb.bookSourceDao.getBookSource(book.origin)
|
||||||
?: throw NoStackTraceException("书源不存在")
|
?: throw NoStackTraceException("书源不存在")
|
||||||
if (book.tocUrl.isEmpty()) {
|
if (book.tocUrl.isEmpty()) {
|
||||||
WebBook.getBookInfoAwait(this, source, book)
|
WebBook.getBookInfoAwait(source, book)
|
||||||
}
|
}
|
||||||
val toc = WebBook.getChapterListAwait(this, source, book).getOrThrow()
|
val toc = WebBook.getChapterListAwait(source, book).getOrThrow()
|
||||||
Pair(toc, source)
|
Pair(toc, source)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class BookshelfManageViewModel(application: Application) : BaseViewModel(applica
|
|||||||
.onFailure {
|
.onFailure {
|
||||||
context.toastOnUi("获取书籍出错\n${it.localizedMessage}")
|
context.toastOnUi("获取书籍出错\n${it.localizedMessage}")
|
||||||
}.getOrNull()?.let { newBook ->
|
}.getOrNull()?.let { newBook ->
|
||||||
WebBook.getChapterListAwait(this, source, newBook)
|
WebBook.getChapterListAwait(source, newBook)
|
||||||
.onFailure {
|
.onFailure {
|
||||||
context.toastOnUi("获取目录出错\n${it.localizedMessage}")
|
context.toastOnUi("获取目录出错\n${it.localizedMessage}")
|
||||||
}.getOrNull()?.let { toc ->
|
}.getOrNull()?.let { toc ->
|
||||||
|
|||||||
@@ -245,9 +245,9 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
sources.forEach { source ->
|
sources.forEach { source ->
|
||||||
WebBook.preciseSearchAwait(this, source, name, author).getOrNull()?.let { book ->
|
WebBook.preciseSearchAwait(this, source, name, author).getOrNull()?.let { book ->
|
||||||
if (book.tocUrl.isEmpty()) {
|
if (book.tocUrl.isEmpty()) {
|
||||||
WebBook.getBookInfoAwait(this, source, book)
|
WebBook.getBookInfoAwait(source, book)
|
||||||
}
|
}
|
||||||
val toc = WebBook.getChapterListAwait(this, source, book).getOrThrow()
|
val toc = WebBook.getChapterListAwait(source, book).getOrThrow()
|
||||||
changeTo(source, book, toc)
|
changeTo(source, book, toc)
|
||||||
return@execute
|
return@execute
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ class SearchContentActivity :
|
|||||||
binding.fbStop.visible()
|
binding.fbStop.visible()
|
||||||
val searchResults = withContext(IO) {
|
val searchResults = withContext(IO) {
|
||||||
if (isLocalBook || viewModel.cacheChapterNames.contains(bookChapter.getFileName())) {
|
if (isLocalBook || viewModel.cacheChapterNames.contains(bookChapter.getFileName())) {
|
||||||
viewModel.searchChapter(this, query, bookChapter)
|
viewModel.searchChapter(query, bookChapter)
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ import io.legado.app.data.entities.BookChapter
|
|||||||
import io.legado.app.help.BookHelp
|
import io.legado.app.help.BookHelp
|
||||||
import io.legado.app.help.ContentProcessor
|
import io.legado.app.help.ContentProcessor
|
||||||
import io.legado.app.help.config.AppConfig
|
import io.legado.app.help.config.AppConfig
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.ensureActive
|
import kotlinx.coroutines.ensureActive
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import kotlin.coroutines.coroutineContext
|
||||||
|
|
||||||
class SearchContentViewModel(application: Application) : BaseViewModel(application) {
|
class SearchContentViewModel(application: Application) : BaseViewModel(application) {
|
||||||
var bookUrl: String = ""
|
var bookUrl: String = ""
|
||||||
@@ -38,7 +38,6 @@ class SearchContentViewModel(application: Application) : BaseViewModel(applicati
|
|||||||
}
|
}
|
||||||
|
|
||||||
suspend fun searchChapter(
|
suspend fun searchChapter(
|
||||||
scope: CoroutineScope,
|
|
||||||
query: String,
|
query: String,
|
||||||
chapter: BookChapter?
|
chapter: BookChapter?
|
||||||
): List<SearchResult> {
|
): List<SearchResult> {
|
||||||
@@ -46,7 +45,7 @@ class SearchContentViewModel(application: Application) : BaseViewModel(applicati
|
|||||||
if (chapter != null) {
|
if (chapter != null) {
|
||||||
book?.let { book ->
|
book?.let { book ->
|
||||||
val chapterContent = BookHelp.getContent(book, chapter)
|
val chapterContent = BookHelp.getContent(book, chapter)
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
if (chapterContent != null) {
|
if (chapterContent != null) {
|
||||||
//先搜索没有启用净化的正文
|
//先搜索没有启用净化的正文
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
@@ -55,7 +54,7 @@ class SearchContentViewModel(application: Application) : BaseViewModel(applicati
|
|||||||
2 -> ChineseUtils.s2t(chapter.title)
|
2 -> ChineseUtils.s2t(chapter.title)
|
||||||
else -> chapter.title
|
else -> chapter.title
|
||||||
}
|
}
|
||||||
scope.ensureActive()
|
kotlin.coroutines.coroutineContext.ensureActive()
|
||||||
mContent = contentProcessor!!.getContent(
|
mContent = contentProcessor!!.getContent(
|
||||||
book, chapter, chapterContent,
|
book, chapter, chapterContent,
|
||||||
chineseConvert = true,
|
chineseConvert = true,
|
||||||
@@ -63,9 +62,9 @@ class SearchContentViewModel(application: Application) : BaseViewModel(applicati
|
|||||||
useReplace = false
|
useReplace = false
|
||||||
).joinToString("")
|
).joinToString("")
|
||||||
}
|
}
|
||||||
val positions = searchPosition(scope, query)
|
val positions = searchPosition(query)
|
||||||
positions.forEachIndexed { index, position ->
|
positions.forEachIndexed { index, position ->
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
val construct = getResultAndQueryIndex(mContent, position, query)
|
val construct = getResultAndQueryIndex(mContent, position, query)
|
||||||
val result = SearchResult(
|
val result = SearchResult(
|
||||||
resultCountWithinChapter = index,
|
resultCountWithinChapter = index,
|
||||||
@@ -85,7 +84,7 @@ class SearchContentViewModel(application: Application) : BaseViewModel(applicati
|
|||||||
return searchResultsWithinChapter
|
return searchResultsWithinChapter
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun searchPosition(scope: CoroutineScope, pattern: String): List<Int> {
|
private suspend fun searchPosition(pattern: String): List<Int> {
|
||||||
val position: MutableList<Int> = mutableListOf()
|
val position: MutableList<Int> = mutableListOf()
|
||||||
var index = mContent.indexOf(pattern)
|
var index = mContent.indexOf(pattern)
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
@@ -95,7 +94,7 @@ class SearchContentViewModel(application: Application) : BaseViewModel(applicati
|
|||||||
index = mContent.indexOf(pattern)
|
index = mContent.indexOf(pattern)
|
||||||
}
|
}
|
||||||
while (index >= 0) {
|
while (index >= 0) {
|
||||||
scope.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
position.add(index)
|
position.add(index)
|
||||||
index = mContent.indexOf(pattern, index + pattern.length)
|
index = mContent.indexOf(pattern, index + pattern.length)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,9 +123,9 @@ class MainViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
AnalyzeRule(book, source).evalJS(preUpdateJs)
|
AnalyzeRule(book, source).evalJS(preUpdateJs)
|
||||||
}
|
}
|
||||||
if (book.tocUrl.isBlank()) {
|
if (book.tocUrl.isBlank()) {
|
||||||
WebBook.getBookInfoAwait(this, source, book)
|
WebBook.getBookInfoAwait(source, book)
|
||||||
}
|
}
|
||||||
val toc = WebBook.getChapterListAwait(this, source, book).getOrThrow()
|
val toc = WebBook.getChapterListAwait(source, book).getOrThrow()
|
||||||
if (book.bookUrl == bookUrl) {
|
if (book.bookUrl == bookUrl) {
|
||||||
appDb.bookDao.update(book)
|
appDb.bookDao.update(book)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user