pull/1282/head
gedoor 3 years ago
parent 0a2d903899
commit 7c08da40ba
  1. 10
      app/src/main/java/io/legado/app/api/controller/BookController.kt
  2. 60
      app/src/main/java/io/legado/app/model/Debug.kt
  3. 14
      app/src/main/java/io/legado/app/model/ReadBook.kt
  4. 9
      app/src/main/java/io/legado/app/model/webBook/BookChapterList.kt
  5. 7
      app/src/main/java/io/legado/app/model/webBook/BookContent.kt
  6. 7
      app/src/main/java/io/legado/app/model/webBook/BookInfo.kt
  7. 9
      app/src/main/java/io/legado/app/model/webBook/BookList.kt
  8. 5
      app/src/main/java/io/legado/app/model/webBook/PreciseSearch.kt
  9. 3
      app/src/main/java/io/legado/app/model/webBook/SearchBookModel.kt
  10. 100
      app/src/main/java/io/legado/app/model/webBook/WebBook.kt
  11. 7
      app/src/main/java/io/legado/app/service/AudioPlayService.kt
  12. 27
      app/src/main/java/io/legado/app/service/CacheBookService.kt
  13. 15
      app/src/main/java/io/legado/app/service/CheckSourceService.kt
  14. 6
      app/src/main/java/io/legado/app/service/help/AudioPlay.kt
  15. 5
      app/src/main/java/io/legado/app/service/help/CacheBook.kt
  16. 42
      app/src/main/java/io/legado/app/ui/book/audio/AudioPlayViewModel.kt
  17. 4
      app/src/main/java/io/legado/app/ui/book/changecover/ChangeCoverViewModel.kt
  18. 17
      app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceViewModel.kt
  19. 2
      app/src/main/java/io/legado/app/ui/book/explore/ExploreShowViewModel.kt
  20. 4
      app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt
  21. 6
      app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt
  22. 52
      app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt
  23. 2
      app/src/main/java/io/legado/app/ui/book/read/ReadMenu.kt
  24. 9
      app/src/main/java/io/legado/app/ui/book/source/debug/BookSourceDebugModel.kt
  25. 12
      app/src/main/java/io/legado/app/ui/main/MainViewModel.kt
  26. 2
      app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt
  27. 3
      app/src/main/java/io/legado/app/web/SourceDebugWebSocket.kt

@ -81,12 +81,11 @@ object BookController {
} else { } else {
val bookSource = appDb.bookSourceDao.getBookSource(book.origin) val bookSource = appDb.bookSourceDao.getBookSource(book.origin)
?: return returnData.setErrorMsg("未找到对应书源,请换源") ?: return returnData.setErrorMsg("未找到对应书源,请换源")
val webBook = WebBook(bookSource)
val toc = runBlocking { val toc = runBlocking {
if (book.tocUrl.isBlank()) { if (book.tocUrl.isBlank()) {
webBook.getBookInfoAwait(this, book) WebBook.getBookInfoAwait(this, bookSource, book)
} }
webBook.getChapterListAwait(this, book) WebBook.getChapterListAwait(this, bookSource, book)
} }
appDb.bookChapterDao.delByBook(book.bookUrl) appDb.bookChapterDao.delByBook(book.bookUrl)
appDb.bookChapterDao.insert(*toc.toTypedArray()) appDb.bookChapterDao.insert(*toc.toTypedArray())
@ -149,13 +148,12 @@ object BookController {
?: return returnData.setErrorMsg("未找到书源") ?: return returnData.setErrorMsg("未找到书源")
try { try {
content = runBlocking { content = runBlocking {
WebBook(bookSource).getContentAwait(this, book, chapter) WebBook.getContentAwait(this, bookSource, book, chapter)
} }
val contentProcessor = ContentProcessor.get(book.name, book.origin) val contentProcessor = ContentProcessor.get(book.name, book.origin)
saveBookReadIndex(book, index) saveBookReadIndex(book, index)
returnData.setData( returnData.setData(
contentProcessor.getContent(book, chapter.title, content) contentProcessor.getContent(book, chapter.title, content).joinToString("\n")
.joinToString("\n")
) )
} catch (e: Exception) { } catch (e: Exception) {
returnData.setErrorMsg(e.msg) returnData.setErrorMsg(e.msg)

@ -143,56 +143,56 @@ object Debug {
} }
} }
fun startDebug(scope: CoroutineScope, webBook: WebBook, key: String) { fun startDebug(scope: CoroutineScope, bookSource: BookSource, key: String) {
cancelDebug() cancelDebug()
debugSource = webBook.sourceUrl debugSource = bookSource.bookSourceUrl
startTime = System.currentTimeMillis() startTime = System.currentTimeMillis()
when { when {
key.isAbsUrl() -> { key.isAbsUrl() -> {
val book = Book() val book = Book()
book.origin = webBook.sourceUrl book.origin = bookSource.bookSourceUrl
book.bookUrl = key book.bookUrl = key
log(webBook.sourceUrl, "⇒开始访问详情页:$key") log(bookSource.bookSourceUrl, "⇒开始访问详情页:$key")
infoDebug(scope, webBook, book) infoDebug(scope, bookSource, book)
} }
key.contains("::") -> { key.contains("::") -> {
val url = key.substringAfter("::") val url = key.substringAfter("::")
log(webBook.sourceUrl, "⇒开始访问发现页:$url") log(bookSource.bookSourceUrl, "⇒开始访问发现页:$url")
exploreDebug(scope, webBook, url) exploreDebug(scope, bookSource, url)
} }
key.startsWith("++") -> { key.startsWith("++") -> {
val url = key.substring(2) val url = key.substring(2)
val book = Book() val book = Book()
book.origin = webBook.sourceUrl book.origin = bookSource.bookSourceUrl
book.tocUrl = url book.tocUrl = url
log(webBook.sourceUrl, "⇒开始访目录页:$url") log(bookSource.bookSourceUrl, "⇒开始访目录页:$url")
tocDebug(scope, webBook, book) tocDebug(scope, bookSource, book)
} }
key.startsWith("--") -> { key.startsWith("--") -> {
val url = key.substring(2) val url = key.substring(2)
val book = Book() val book = Book()
book.origin = webBook.sourceUrl book.origin = bookSource.bookSourceUrl
log(webBook.sourceUrl, "⇒开始访正文页:$url") log(bookSource.bookSourceUrl, "⇒开始访正文页:$url")
val chapter = BookChapter() val chapter = BookChapter()
chapter.title = "调试" chapter.title = "调试"
chapter.url = url chapter.url = url
contentDebug(scope, webBook, book, chapter, null) contentDebug(scope, bookSource, book, chapter, null)
} }
else -> { else -> {
log(webBook.sourceUrl, "⇒开始搜索关键字:$key") log(bookSource.bookSourceUrl, "⇒开始搜索关键字:$key")
searchDebug(scope, webBook, key) searchDebug(scope, bookSource, key)
} }
} }
} }
private fun exploreDebug(scope: CoroutineScope, webBook: WebBook, url: String) { private fun exploreDebug(scope: CoroutineScope, bookSource: BookSource, url: String) {
log(debugSource, "︾开始解析发现页") log(debugSource, "︾开始解析发现页")
val explore = webBook.exploreBook(scope, url, 1) val explore = WebBook.exploreBook(scope, bookSource, url, 1)
.onSuccess { exploreBooks -> .onSuccess { exploreBooks ->
if (exploreBooks.isNotEmpty()) { if (exploreBooks.isNotEmpty()) {
log(debugSource, "︽发现页解析完成") log(debugSource, "︽发现页解析完成")
log(debugSource, showTime = false) log(debugSource, showTime = false)
infoDebug(scope, webBook, exploreBooks[0].toBook()) infoDebug(scope, bookSource, exploreBooks[0].toBook())
} else { } else {
log(debugSource, "︽未获取到书籍", state = -1) log(debugSource, "︽未获取到书籍", state = -1)
} }
@ -203,14 +203,14 @@ object Debug {
tasks.add(explore) tasks.add(explore)
} }
private fun searchDebug(scope: CoroutineScope, webBook: WebBook, key: String) { private fun searchDebug(scope: CoroutineScope, bookSource: BookSource, key: String) {
log(debugSource, "︾开始解析搜索页") log(debugSource, "︾开始解析搜索页")
val search = webBook.searchBook(scope, key, 1) val search = WebBook.searchBook(scope, bookSource, key, 1)
.onSuccess { searchBooks -> .onSuccess { searchBooks ->
if (searchBooks.isNotEmpty()) { if (searchBooks.isNotEmpty()) {
log(debugSource, "︽搜索页解析完成") log(debugSource, "︽搜索页解析完成")
log(debugSource, showTime = false) log(debugSource, showTime = false)
infoDebug(scope, webBook, searchBooks[0].toBook()) infoDebug(scope, bookSource, searchBooks[0].toBook())
} else { } else {
log(debugSource, "︽未获取到书籍", state = -1) log(debugSource, "︽未获取到书籍", state = -1)
} }
@ -221,19 +221,19 @@ object Debug {
tasks.add(search) tasks.add(search)
} }
private fun infoDebug(scope: CoroutineScope, webBook: WebBook, book: Book) { private fun infoDebug(scope: CoroutineScope, bookSource: BookSource, book: Book) {
if (book.tocUrl.isNotBlank()) { if (book.tocUrl.isNotBlank()) {
log(debugSource, "≡已获取目录链接,跳过详情页") log(debugSource, "≡已获取目录链接,跳过详情页")
log(debugSource, showTime = false) log(debugSource, showTime = false)
tocDebug(scope, webBook, book) tocDebug(scope, bookSource, book)
return return
} }
log(debugSource, "︾开始解析详情页") log(debugSource, "︾开始解析详情页")
val info = webBook.getBookInfo(scope, book) val info = WebBook.getBookInfo(scope, bookSource, book)
.onSuccess { .onSuccess {
log(debugSource, "︽详情页解析完成") log(debugSource, "︽详情页解析完成")
log(debugSource, showTime = false) log(debugSource, showTime = false)
tocDebug(scope, webBook, book) tocDebug(scope, bookSource, book)
} }
.onError { .onError {
log(debugSource, it.msg, state = -1) log(debugSource, it.msg, state = -1)
@ -241,15 +241,15 @@ object Debug {
tasks.add(info) tasks.add(info)
} }
private fun tocDebug(scope: CoroutineScope, webBook: WebBook, book: Book) { private fun tocDebug(scope: CoroutineScope, bookSource: BookSource, book: Book) {
log(debugSource, "︾开始解析目录页") log(debugSource, "︾开始解析目录页")
val chapterList = webBook.getChapterList(scope, book) val chapterList = WebBook.getChapterList(scope, bookSource, book)
.onSuccess { .onSuccess {
if (it.isNotEmpty()) { if (it.isNotEmpty()) {
log(debugSource, "︽目录页解析完成") log(debugSource, "︽目录页解析完成")
log(debugSource, showTime = false) log(debugSource, showTime = false)
val nextChapterUrl = it.getOrNull(1)?.url val nextChapterUrl = it.getOrNull(1)?.url
contentDebug(scope, webBook, book, it[0], nextChapterUrl) contentDebug(scope, bookSource, book, it[0], nextChapterUrl)
} else { } else {
log(debugSource, "︽目录列表为空", state = -1) log(debugSource, "︽目录列表为空", state = -1)
} }
@ -262,13 +262,13 @@ object Debug {
private fun contentDebug( private fun contentDebug(
scope: CoroutineScope, scope: CoroutineScope,
webBook: WebBook, bookSource: BookSource,
book: Book, book: Book,
bookChapter: BookChapter, bookChapter: BookChapter,
nextChapterUrl: String? nextChapterUrl: String?
) { ) {
log(debugSource, "︾开始解析正文页") log(debugSource, "︾开始解析正文页")
val content = webBook.getContent(scope, book, bookChapter, nextChapterUrl) val content = WebBook.getContent(scope, bookSource, book, bookChapter, nextChapterUrl)
.onSuccess { .onSuccess {
log(debugSource, "︽正文页解析完成", state = 1000) log(debugSource, "︽正文页解析完成", state = 1000)
} }

@ -38,7 +38,6 @@ object ReadBook : CoroutineScope by MainScope() {
var curTextChapter: TextChapter? = null var curTextChapter: TextChapter? = null
var nextTextChapter: TextChapter? = null var nextTextChapter: TextChapter? = null
var bookSource: BookSource? = null var bookSource: BookSource? = null
var webBook: WebBook? = null
var msg: String? = null var msg: String? = null
private val loadingChapters = arrayListOf<Int>() private val loadingChapters = arrayListOf<Int>()
private val readRecord = ReadRecord() private val readRecord = ReadRecord()
@ -65,17 +64,14 @@ object ReadBook : CoroutineScope by MainScope() {
fun upWebBook(book: Book) { fun upWebBook(book: Book) {
if (book.origin == BookType.local) { if (book.origin == BookType.local) {
bookSource = null bookSource = null
webBook = null
} else { } else {
appDb.bookSourceDao.getBookSource(book.origin)?.let { appDb.bookSourceDao.getBookSource(book.origin)?.let {
bookSource = it bookSource = it
webBook = WebBook(it)
if (book.getImageStyle().isNullOrBlank()) { if (book.getImageStyle().isNullOrBlank()) {
book.setImageStyle(it.getContentRule().imageStyle) book.setImageStyle(it.getContentRule().imageStyle)
} }
} ?: let { } ?: let {
bookSource = null bookSource = null
webBook = null
} }
} }
} }
@ -314,9 +310,9 @@ object ReadBook : CoroutineScope by MainScope() {
success: (() -> Unit)? = null success: (() -> Unit)? = null
) { ) {
val book = book val book = book
val webBook = webBook val bookSource = bookSource
if (book != null && webBook != null) { if (book != null && bookSource != null) {
CacheBook.download(scope, webBook, book, chapter) CacheBook.download(scope, bookSource, book, chapter)
} else if (book != null) { } else if (book != null) {
contentLoadFinish( contentLoadFinish(
book, chapter, "没有书源", resetPageOffset = resetPageOffset book, chapter, "没有书源", resetPageOffset = resetPageOffset
@ -394,11 +390,11 @@ object ReadBook : CoroutineScope by MainScope() {
@Synchronized @Synchronized
fun upToc() { fun upToc() {
val webBook = webBook ?: return val bookSource = bookSource ?: return
val book = book ?: return val book = book ?: return
if (System.currentTimeMillis() - book.lastCheckTime < 600000) return if (System.currentTimeMillis() - book.lastCheckTime < 600000) return
book.lastCheckTime = System.currentTimeMillis() book.lastCheckTime = System.currentTimeMillis()
webBook.getChapterList(this, book).onSuccess(IO) { cList -> WebBook.getChapterList(this, bookSource, book).onSuccess(IO) { cList ->
if (book.bookUrl == ReadBook.book?.bookUrl if (book.bookUrl == ReadBook.book?.bookUrl
&& cList.size > chapterSize && cList.size > chapterSize
) { ) {

@ -6,7 +6,6 @@ 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.http.StrResponse
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
@ -16,20 +15,18 @@ 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 java.net.URLDecoder
@Suppress("BlockingMethodInNonBlockingContext") @Suppress("BlockingMethodInNonBlockingContext")
object BookChapterList { object BookChapterList {
suspend fun analyzeChapterList( suspend fun analyzeChapterList(
scope: CoroutineScope, scope: CoroutineScope,
strResponse: StrResponse,
bookSource: BookSource, bookSource: BookSource,
book: Book, book: Book,
redirectUrl: String redirectUrl: String,
baseUrl: String,
body: String?
): List<BookChapter> { ): List<BookChapter> {
val baseUrl = URLDecoder.decode(strResponse.url, "utf-8")
val body = strResponse.body
body ?: throw Exception( body ?: throw Exception(
appCtx.getString(R.string.error_get_web_content, baseUrl) appCtx.getString(R.string.error_get_web_content, baseUrl)
) )

@ -7,7 +7,6 @@ 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.ContentRule import io.legado.app.data.entities.rule.ContentRule
import io.legado.app.help.BookHelp import io.legado.app.help.BookHelp
import io.legado.app.help.http.StrResponse
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
@ -19,7 +18,6 @@ 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 java.net.URLDecoder
@Suppress("BlockingMethodInNonBlockingContext") @Suppress("BlockingMethodInNonBlockingContext")
object BookContent { object BookContent {
@ -27,15 +25,14 @@ object BookContent {
@Throws(Exception::class) @Throws(Exception::class)
suspend fun analyzeContent( suspend fun analyzeContent(
scope: CoroutineScope, scope: CoroutineScope,
strResponse: StrResponse,
bookSource: BookSource, bookSource: BookSource,
book: Book, book: Book,
bookChapter: BookChapter, bookChapter: BookChapter,
redirectUrl: String, redirectUrl: String,
baseUrl: String,
body: String?,
nextChapterUrl: String? = null nextChapterUrl: String? = null
): String { ): String {
val baseUrl = URLDecoder.decode(strResponse.url, "utf-8")
val body = strResponse.body
body ?: throw Exception( body ?: throw Exception(
appCtx.getString(R.string.error_get_web_content, baseUrl) appCtx.getString(R.string.error_get_web_content, baseUrl)
) )

@ -4,7 +4,6 @@ import io.legado.app.R
import io.legado.app.data.entities.Book import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.BookSource
import io.legado.app.help.BookHelp import io.legado.app.help.BookHelp
import io.legado.app.help.http.StrResponse
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.utils.HtmlFormatter import io.legado.app.utils.HtmlFormatter
@ -13,21 +12,19 @@ import io.legado.app.utils.StringUtils.wordCountFormat
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ensureActive import kotlinx.coroutines.ensureActive
import splitties.init.appCtx import splitties.init.appCtx
import java.net.URLDecoder
object BookInfo { object BookInfo {
@Throws(Exception::class) @Throws(Exception::class)
fun analyzeBookInfo( fun analyzeBookInfo(
scope: CoroutineScope, scope: CoroutineScope,
strResponse: StrResponse,
bookSource: BookSource, bookSource: BookSource,
book: Book, book: Book,
redirectUrl: String, redirectUrl: String,
baseUrl: String,
body: String?,
canReName: Boolean, canReName: Boolean,
) { ) {
val baseUrl = URLDecoder.decode(strResponse.url, "utf-8")
val body = strResponse.body
body ?: throw Exception( body ?: throw Exception(
appCtx.getString(R.string.error_get_web_content, baseUrl) appCtx.getString(R.string.error_get_web_content, baseUrl)
) )

@ -6,7 +6,6 @@ import io.legado.app.data.entities.BookSource
import io.legado.app.data.entities.SearchBook import io.legado.app.data.entities.SearchBook
import io.legado.app.data.entities.rule.BookListRule import io.legado.app.data.entities.rule.BookListRule
import io.legado.app.help.BookHelp import io.legado.app.help.BookHelp
import io.legado.app.help.http.StrResponse
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
@ -16,21 +15,19 @@ import io.legado.app.utils.StringUtils.wordCountFormat
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ensureActive import kotlinx.coroutines.ensureActive
import splitties.init.appCtx import splitties.init.appCtx
import java.net.URLDecoder
object BookList { object BookList {
@Throws(Exception::class) @Throws(Exception::class)
fun analyzeBookList( fun analyzeBookList(
scope: CoroutineScope, scope: CoroutineScope,
strResponse: StrResponse,
bookSource: BookSource, bookSource: BookSource,
analyzeUrl: AnalyzeUrl,
variableBook: SearchBook, variableBook: SearchBook,
analyzeUrl: AnalyzeUrl,
baseUrl: String,
body: String?,
isSearch: Boolean = true, isSearch: Boolean = true,
): ArrayList<SearchBook> { ): ArrayList<SearchBook> {
val baseUrl = URLDecoder.decode(strResponse.url, "utf-8")
val body = strResponse.body
body ?: throw Exception( body ?: throw Exception(
appCtx.getString( appCtx.getString(
R.string.error_get_web_content, R.string.error_get_web_content,

@ -17,15 +17,14 @@ object PreciseSearch {
author: String author: String
): Book? { ): Book? {
bookSources.forEach { bookSource -> bookSources.forEach { bookSource ->
val webBook = WebBook(bookSource)
kotlin.runCatching { kotlin.runCatching {
if (!scope.isActive) return null if (!scope.isActive) return null
webBook.searchBookAwait(scope, name).firstOrNull { WebBook.searchBookAwait(scope, bookSource, name).firstOrNull {
it.name == name && it.author == author it.name == name && it.author == author
}?.let { }?.let {
return if (it.tocUrl.isBlank()) { return if (it.tocUrl.isBlank()) {
if (!scope.isActive) return null if (!scope.isActive) return null
webBook.getBookInfoAwait(scope, it.toBook()) WebBook.getBookInfoAwait(scope, bookSource, it.toBook())
} else { } else {
it.toBook() it.toBook()
} }

@ -67,8 +67,9 @@ class SearchBookModel(private val scope: CoroutineScope, private val callBack: C
} }
searchIndex++ searchIndex++
val source = bookSourceList[searchIndex] val source = bookSourceList[searchIndex]
val task = WebBook(source).searchBook( val task = WebBook.searchBook(
scope, scope,
source,
searchKey, searchKey,
searchPage, searchPage,
context = searchPool!! context = searchPool!!

@ -13,27 +13,26 @@ import kotlinx.coroutines.Dispatchers
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
@Suppress("MemberVisibilityCanBePrivate") @Suppress("MemberVisibilityCanBePrivate")
class WebBook(val bookSource: BookSource) { object WebBook {
val sourceUrl: String
get() = bookSource.bookSourceUrl
/** /**
* 搜索 * 搜索
*/ */
fun searchBook( fun searchBook(
scope: CoroutineScope, scope: CoroutineScope,
bookSource: BookSource,
key: String, key: String,
page: Int? = 1, page: Int? = 1,
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, key, page) searchBookAwait(scope, bookSource, key, page)
} }
} }
suspend fun searchBookAwait( suspend fun searchBookAwait(
scope: CoroutineScope, scope: CoroutineScope,
bookSource: BookSource,
key: String, key: String,
page: Int? = 1, page: Int? = 1,
): ArrayList<SearchBook> { ): ArrayList<SearchBook> {
@ -43,7 +42,7 @@ class WebBook(val bookSource: BookSource) {
ruleUrl = searchUrl, ruleUrl = searchUrl,
key = key, key = key,
page = page, page = page,
baseUrl = sourceUrl, baseUrl = bookSource.bookSourceUrl,
headerMapF = bookSource.getHeaderMap(true), headerMapF = bookSource.getHeaderMap(true),
book = variableBook, book = variableBook,
source = bookSource source = bookSource
@ -55,7 +54,15 @@ class WebBook(val bookSource: BookSource) {
res = analyzeUrl.evalJS(checkJs) as StrResponse res = analyzeUrl.evalJS(checkJs) as StrResponse
} }
} }
return BookList.analyzeBookList(scope, res, bookSource, analyzeUrl, variableBook, true) return BookList.analyzeBookList(
scope,
bookSource,
variableBook,
analyzeUrl,
res.url,
res.body,
true
)
} }
return arrayListOf() return arrayListOf()
} }
@ -65,17 +72,19 @@ class WebBook(val bookSource: BookSource) {
*/ */
fun exploreBook( fun exploreBook(
scope: CoroutineScope, scope: CoroutineScope,
bookSource: BookSource,
url: String, url: String,
page: Int? = 1, page: Int? = 1,
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, url, page) exploreBookAwait(scope, bookSource, url, page)
} }
} }
suspend fun exploreBookAwait( suspend fun exploreBookAwait(
scope: CoroutineScope, scope: CoroutineScope,
bookSource: BookSource,
url: String, url: String,
page: Int? = 1, page: Int? = 1,
): ArrayList<SearchBook> { ): ArrayList<SearchBook> {
@ -83,7 +92,7 @@ class WebBook(val bookSource: BookSource) {
val analyzeUrl = AnalyzeUrl( val analyzeUrl = AnalyzeUrl(
ruleUrl = url, ruleUrl = url,
page = page, page = page,
baseUrl = sourceUrl, baseUrl = bookSource.bookSourceUrl,
book = variableBook, book = variableBook,
source = bookSource, source = bookSource,
headerMapF = bookSource.getHeaderMap(true) headerMapF = bookSource.getHeaderMap(true)
@ -95,7 +104,15 @@ class WebBook(val bookSource: BookSource) {
res = analyzeUrl.evalJS(checkJs) as StrResponse res = analyzeUrl.evalJS(checkJs) as StrResponse
} }
} }
return BookList.analyzeBookList(scope, res, bookSource, analyzeUrl, variableBook, false) return BookList.analyzeBookList(
scope,
bookSource,
variableBook,
analyzeUrl,
res.url,
res.body,
false
)
} }
/** /**
@ -103,28 +120,37 @@ class WebBook(val bookSource: BookSource) {
*/ */
fun getBookInfo( fun getBookInfo(
scope: CoroutineScope, scope: CoroutineScope,
bookSource: BookSource,
book: Book, book: Book,
context: CoroutineContext = Dispatchers.IO, context: CoroutineContext = Dispatchers.IO,
canReName: Boolean = true, canReName: Boolean = true,
): Coroutine<Book> { ): Coroutine<Book> {
return Coroutine.async(scope, context) { return Coroutine.async(scope, context) {
getBookInfoAwait(scope, book, canReName) getBookInfoAwait(scope, bookSource, book, canReName)
} }
} }
suspend fun getBookInfoAwait( suspend fun getBookInfoAwait(
scope: CoroutineScope, scope: CoroutineScope,
bookSource: BookSource,
book: Book, book: Book,
canReName: Boolean = true, canReName: Boolean = true,
): Book { ): Book {
book.type = bookSource.bookSourceType book.type = bookSource.bookSourceType
if (!book.infoHtml.isNullOrEmpty()) { if (!book.infoHtml.isNullOrEmpty()) {
val strResponse = StrResponse(book.bookUrl, book.infoHtml) BookInfo.analyzeBookInfo(
BookInfo.analyzeBookInfo(scope, strResponse, bookSource, book, book.bookUrl, canReName) scope,
bookSource,
book,
book.bookUrl,
book.bookUrl,
book.infoHtml,
canReName
)
} else { } else {
val analyzeUrl = AnalyzeUrl( val analyzeUrl = AnalyzeUrl(
ruleUrl = book.bookUrl, ruleUrl = book.bookUrl,
baseUrl = sourceUrl, baseUrl = bookSource.bookSourceUrl,
book = book, book = book,
source = bookSource, source = bookSource,
headerMapF = bookSource.getHeaderMap(true) headerMapF = bookSource.getHeaderMap(true)
@ -136,7 +162,15 @@ class WebBook(val bookSource: BookSource) {
res = analyzeUrl.evalJS(checkJs) as StrResponse res = analyzeUrl.evalJS(checkJs) as StrResponse
} }
} }
BookInfo.analyzeBookInfo(scope, res, bookSource, book, book.bookUrl, canReName) BookInfo.analyzeBookInfo(
scope,
bookSource,
book,
book.bookUrl,
res.url,
res.body,
canReName
)
} }
return book return book
} }
@ -146,22 +180,30 @@ class WebBook(val bookSource: BookSource) {
*/ */
fun getChapterList( fun getChapterList(
scope: CoroutineScope, scope: CoroutineScope,
bookSource: BookSource,
book: Book, book: Book,
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, book) getChapterListAwait(scope, bookSource, book)
} }
} }
suspend fun getChapterListAwait( suspend fun getChapterListAwait(
scope: CoroutineScope, scope: CoroutineScope,
bookSource: BookSource,
book: Book, book: Book,
): List<BookChapter> { ): List<BookChapter> {
book.type = bookSource.bookSourceType book.type = bookSource.bookSourceType
return if (book.bookUrl == book.tocUrl && !book.tocHtml.isNullOrEmpty()) { return if (book.bookUrl == book.tocUrl && !book.tocHtml.isNullOrEmpty()) {
val strResponse = StrResponse(book.tocUrl, book.tocHtml) BookChapterList.analyzeChapterList(
BookChapterList.analyzeChapterList(scope, strResponse, bookSource, book, book.tocUrl) scope,
bookSource,
book,
book.tocUrl,
book.tocUrl,
book.tocHtml
)
} else { } else {
val analyzeUrl = AnalyzeUrl( val analyzeUrl = AnalyzeUrl(
ruleUrl = book.tocUrl, ruleUrl = book.tocUrl,
@ -177,7 +219,14 @@ class WebBook(val bookSource: BookSource) {
res = analyzeUrl.evalJS(checkJs) as StrResponse res = analyzeUrl.evalJS(checkJs) as StrResponse
} }
} }
BookChapterList.analyzeChapterList(scope, res, bookSource, book, book.tocUrl) BookChapterList.analyzeChapterList(
scope,
bookSource,
book,
book.tocUrl,
res.url,
res.body
)
} }
} }
@ -186,35 +235,37 @@ class WebBook(val bookSource: BookSource) {
*/ */
fun getContent( fun getContent(
scope: CoroutineScope, scope: CoroutineScope,
bookSource: BookSource,
book: Book, book: Book,
bookChapter: BookChapter, bookChapter: BookChapter,
nextChapterUrl: String? = null, nextChapterUrl: String? = null,
context: CoroutineContext = Dispatchers.IO context: CoroutineContext = Dispatchers.IO
): Coroutine<String> { ): Coroutine<String> {
return Coroutine.async(scope, context) { return Coroutine.async(scope, context) {
getContentAwait(scope, book, bookChapter, nextChapterUrl) getContentAwait(scope, bookSource, book, bookChapter, nextChapterUrl)
} }
} }
suspend fun getContentAwait( suspend fun getContentAwait(
scope: CoroutineScope, scope: CoroutineScope,
bookSource: BookSource,
book: Book, book: Book,
bookChapter: BookChapter, bookChapter: BookChapter,
nextChapterUrl: String? = null, nextChapterUrl: String? = null,
): String { ): String {
if (bookSource.getContentRule().content.isNullOrEmpty()) { if (bookSource.getContentRule().content.isNullOrEmpty()) {
Debug.log(sourceUrl, "⇒正文规则为空,使用章节链接:${bookChapter.url}") Debug.log(bookSource.bookSourceUrl, "⇒正文规则为空,使用章节链接:${bookChapter.url}")
return bookChapter.url return bookChapter.url
} }
return if (bookChapter.url == book.bookUrl && !book.tocHtml.isNullOrEmpty()) { return if (bookChapter.url == book.bookUrl && !book.tocHtml.isNullOrEmpty()) {
val strResponse = StrResponse(bookChapter.getAbsoluteURL(), book.tocHtml)
BookContent.analyzeContent( BookContent.analyzeContent(
scope, scope,
strResponse,
bookSource, bookSource,
book, book,
bookChapter, bookChapter,
bookChapter.getAbsoluteURL(), bookChapter.getAbsoluteURL(),
bookChapter.getAbsoluteURL(),
book.tocHtml,
nextChapterUrl nextChapterUrl
) )
} else { } else {
@ -239,11 +290,12 @@ class WebBook(val bookSource: BookSource) {
} }
BookContent.analyzeContent( BookContent.analyzeContent(
scope, scope,
res,
bookSource, bookSource,
book, book,
bookChapter, bookChapter,
bookChapter.getAbsoluteURL(), bookChapter.getAbsoluteURL(),
res.url,
res.body,
nextChapterUrl nextChapterUrl
) )
} }

@ -26,6 +26,7 @@ import io.legado.app.data.entities.BookChapter
import io.legado.app.help.IntentHelp import io.legado.app.help.IntentHelp
import io.legado.app.help.MediaHelp import io.legado.app.help.MediaHelp
import io.legado.app.model.analyzeRule.AnalyzeUrl import io.legado.app.model.analyzeRule.AnalyzeUrl
import io.legado.app.model.webBook.WebBook
import io.legado.app.receiver.MediaButtonReceiver import io.legado.app.receiver.MediaButtonReceiver
import io.legado.app.service.help.AudioPlay import io.legado.app.service.help.AudioPlay
import io.legado.app.service.help.ReadAloud import io.legado.app.service.help.ReadAloud
@ -288,9 +289,9 @@ class AudioPlayService : BaseService(),
durChapter?.let { chapter -> durChapter?.let { chapter ->
if (addLoading(durChapterIndex)) { if (addLoading(durChapterIndex)) {
val book = AudioPlay.book val book = AudioPlay.book
val webBook = AudioPlay.webBook val bookSource = AudioPlay.bookSource
if (book != null && webBook != null) { if (book != null && bookSource != null) {
webBook.getContent(this@AudioPlayService, book, chapter) WebBook.getContent(this@AudioPlayService, bookSource, book, chapter)
.onSuccess { content -> .onSuccess { content ->
if (content.isEmpty()) { if (content.isEmpty()) {
withContext(Main) { withContext(Main) {

@ -10,6 +10,7 @@ import io.legado.app.constant.IntentAction
import io.legado.app.data.appDb import io.legado.app.data.appDb
import io.legado.app.data.entities.Book 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.help.AppConfig import io.legado.app.help.AppConfig
import io.legado.app.help.BookHelp import io.legado.app.help.BookHelp
import io.legado.app.help.IntentHelp import io.legado.app.help.IntentHelp
@ -35,7 +36,7 @@ class CacheBookService : BaseService() {
Executors.newFixedThreadPool(min(threadCount, 8)).asCoroutineDispatcher() Executors.newFixedThreadPool(min(threadCount, 8)).asCoroutineDispatcher()
private var tasks = CompositeCoroutine() private var tasks = CompositeCoroutine()
private val bookMap = ConcurrentHashMap<String, Book>() private val bookMap = ConcurrentHashMap<String, Book>()
private val webBookMap = ConcurrentHashMap<String, WebBook>() private val bookSourceMap = ConcurrentHashMap<String, BookSource>()
private val downloadMap = ConcurrentHashMap<String, CopyOnWriteArraySet<BookChapter>>() private val downloadMap = ConcurrentHashMap<String, CopyOnWriteArraySet<BookChapter>>()
private val downloadCount = ConcurrentHashMap<String, DownloadCount>() private val downloadCount = ConcurrentHashMap<String, DownloadCount>()
private val finalMap = ConcurrentHashMap<String, CopyOnWriteArraySet<BookChapter>>() private val finalMap = ConcurrentHashMap<String, CopyOnWriteArraySet<BookChapter>>()
@ -110,22 +111,20 @@ class CacheBookService : BaseService() {
return book return book
} }
private fun getWebBook(bookUrl: String, origin: String): WebBook? { private fun getBookSource(bookUrl: String, origin: String): BookSource? {
var webBook = webBookMap[origin] var bookSource = bookSourceMap[origin]
if (webBook == null) { if (bookSource == null) {
synchronized(this) { synchronized(this) {
webBook = webBookMap[origin] bookSource = bookSourceMap[origin]
if (webBook == null) { if (bookSource == null) {
appDb.bookSourceDao.getBookSource(origin)?.let { bookSource = appDb.bookSourceDao.getBookSource(origin)
webBook = WebBook(it) if (bookSource == null) {
}
if (webBook == null) {
removeDownload(bookUrl) removeDownload(bookUrl)
} }
} }
} }
} }
return webBook return bookSource
} }
private fun addDownloadData(bookUrl: String?, start: Int, end: Int) { private fun addDownloadData(bookUrl: String?, start: Int, end: Int) {
@ -183,13 +182,13 @@ class CacheBookService : BaseService() {
postDownloading(true) postDownloading(true)
return@async return@async
} }
val webBook = getWebBook(bookChapter.bookUrl, book.origin) val bookSource = getBookSource(bookChapter.bookUrl, book.origin)
if (webBook == null) { if (bookSource == null) {
postDownloading(true) postDownloading(true)
return@async return@async
} }
if (!BookHelp.hasImageContent(book, bookChapter)) { if (!BookHelp.hasImageContent(book, bookChapter)) {
webBook.getContent(this, book, bookChapter, context = cachePool) WebBook.getContent(this, bookSource, book, bookChapter, context = cachePool)
.timeout(60000L) .timeout(60000L)
.onError(cachePool) { .onError(cachePool) {
synchronized(this) { synchronized(this) {

@ -24,7 +24,8 @@ import kotlin.math.min
class CheckSourceService : BaseService() { class CheckSourceService : BaseService() {
private var threadCount = AppConfig.threadCount private var threadCount = AppConfig.threadCount
private var searchCoroutine = Executors.newFixedThreadPool(min(threadCount,8)).asCoroutineDispatcher() private var searchCoroutine =
Executors.newFixedThreadPool(min(threadCount, 8)).asCoroutineDispatcher()
private var tasks = CompositeCoroutine() private var tasks = CompositeCoroutine()
private val allIds = ArrayList<String>() private val allIds = ArrayList<String>()
private val checkedIds = ArrayList<String>() private val checkedIds = ArrayList<String>()
@ -109,8 +110,7 @@ class CheckSourceService : BaseService() {
fun check(source: BookSource) { fun check(source: BookSource) {
execute(context = searchCoroutine) { execute(context = searchCoroutine) {
Debug.startChecking(source) Debug.startChecking(source)
val webBook = WebBook(source) var books = WebBook.searchBookAwait(this, source, CheckSource.keyword)
var books = webBook.searchBookAwait(this, CheckSource.keyword)
if (books.isEmpty()) { if (books.isEmpty()) {
val exs = source.exploreKinds val exs = source.exploreKinds
var url: String? = null var url: String? = null
@ -123,11 +123,12 @@ class CheckSourceService : BaseService() {
if (url.isNullOrBlank()) { if (url.isNullOrBlank()) {
throw Exception("搜索内容为空并且没有发现") throw Exception("搜索内容为空并且没有发现")
} }
books = webBook.exploreBookAwait(this, url) books = WebBook.exploreBookAwait(this, source, url)
} }
val book = webBook.getBookInfoAwait(this, books.first().toBook()) val book = WebBook.getBookInfoAwait(this, source, books.first().toBook())
val toc = webBook.getChapterListAwait(this, book) val toc = WebBook.getChapterListAwait(this, source, book)
val content = webBook.getContentAwait(this, book, toc.first(), toc.getOrNull(2)?.url) val content =
WebBook.getContentAwait(this, source, book, toc.first(), toc.getOrNull(1)?.url)
if (content.isBlank()) { if (content.isBlank()) {
throw Exception("正文内容为空") throw Exception("正文内容为空")
} }

@ -9,8 +9,8 @@ import io.legado.app.constant.Status
import io.legado.app.data.appDb import io.legado.app.data.appDb
import io.legado.app.data.entities.Book 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.help.coroutine.Coroutine import io.legado.app.help.coroutine.Coroutine
import io.legado.app.model.webBook.WebBook
import io.legado.app.service.AudioPlayService import io.legado.app.service.AudioPlayService
import io.legado.app.utils.postEvent import io.legado.app.utils.postEvent
import io.legado.app.utils.startService import io.legado.app.utils.startService
@ -24,11 +24,11 @@ object AudioPlay {
var inBookshelf = false var inBookshelf = false
var durChapterIndex = 0 var durChapterIndex = 0
var durChapterPos = 0 var durChapterPos = 0
var webBook: WebBook? = null var bookSource: BookSource? = null
val loadingChapters = arrayListOf<Int>() val loadingChapters = arrayListOf<Int>()
fun headers(): Map<String, String>? { fun headers(): Map<String, String>? {
return webBook?.bookSource?.getHeaderMap() return bookSource?.getHeaderMap()
} }
fun play(context: Context) { fun play(context: Context) {

@ -5,6 +5,7 @@ import io.legado.app.R
import io.legado.app.constant.IntentAction import io.legado.app.constant.IntentAction
import io.legado.app.data.entities.Book 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.model.ReadBook import io.legado.app.model.ReadBook
import io.legado.app.model.webBook.WebBook import io.legado.app.model.webBook.WebBook
import io.legado.app.service.CacheBookService import io.legado.app.service.CacheBookService
@ -61,7 +62,7 @@ object CacheBook {
fun download( fun download(
scope: CoroutineScope, scope: CoroutineScope,
webBook: WebBook, bookSource: BookSource,
book: Book, book: Book,
chapter: BookChapter, chapter: BookChapter,
resetPageOffset: Boolean = false resetPageOffset: Boolean = false
@ -73,7 +74,7 @@ object CacheBook {
downloadMap[book.bookUrl] = CopyOnWriteArraySet() downloadMap[book.bookUrl] = CopyOnWriteArraySet()
} }
downloadMap[book.bookUrl]?.add(chapter.index) downloadMap[book.bookUrl]?.add(chapter.index)
webBook.getContent(scope, book, chapter) WebBook.getContent(scope, bookSource, book, chapter)
.onSuccess { content -> .onSuccess { content ->
if (ReadBook.book?.bookUrl == book.bookUrl) { if (ReadBook.book?.bookUrl == book.bookUrl) {
ReadBook.contentLoadFinish( ReadBook.contentLoadFinish(

@ -31,9 +31,7 @@ class AudioPlayViewModel(application: Application) : BaseViewModel(application)
durChapterPos = book.durChapterPos durChapterPos = book.durChapterPos
durChapter = appDb.bookChapterDao.getChapter(book.bookUrl, durChapterIndex) durChapter = appDb.bookChapterDao.getChapter(book.bookUrl, durChapterIndex)
upDurChapter(book) upDurChapter(book)
appDb.bookSourceDao.getBookSource(book.origin)?.let { bookSource = appDb.bookSourceDao.getBookSource(book.origin)
webBook = WebBook(it)
}
if (durChapter == null) { if (durChapter == null) {
if (book.tocUrl.isEmpty()) { if (book.tocUrl.isEmpty()) {
loadBookInfo(book) loadBookInfo(book)
@ -52,10 +50,12 @@ class AudioPlayViewModel(application: Application) : BaseViewModel(application)
changeDruChapterIndex: ((chapters: List<BookChapter>) -> Unit)? = null changeDruChapterIndex: ((chapters: List<BookChapter>) -> Unit)? = null
) { ) {
execute { execute {
AudioPlay.webBook?.getBookInfo(this, book) AudioPlay.bookSource?.let {
?.onSuccess { WebBook.getBookInfo(this, it, book)
loadChapterList(book, changeDruChapterIndex) .onSuccess {
} loadChapterList(book, changeDruChapterIndex)
}
}
} }
} }
@ -64,21 +64,23 @@ class AudioPlayViewModel(application: Application) : BaseViewModel(application)
changeDruChapterIndex: ((chapters: List<BookChapter>) -> Unit)? = null changeDruChapterIndex: ((chapters: List<BookChapter>) -> Unit)? = null
) { ) {
execute { execute {
AudioPlay.webBook?.getChapterList(this, book) AudioPlay.bookSource?.let {
?.onSuccess(Dispatchers.IO) { cList -> WebBook.getChapterList(this, it, book)
if (cList.isNotEmpty()) { .onSuccess(Dispatchers.IO) { cList ->
if (changeDruChapterIndex == null) { if (cList.isNotEmpty()) {
appDb.bookChapterDao.insert(*cList.toTypedArray()) if (changeDruChapterIndex == null) {
appDb.bookChapterDao.insert(*cList.toTypedArray())
} else {
changeDruChapterIndex(cList)
}
AudioPlay.upDurChapter(book)
} else { } else {
changeDruChapterIndex(cList) context.toastOnUi(R.string.error_load_toc)
} }
AudioPlay.upDurChapter(book) }.onError {
} else {
context.toastOnUi(R.string.error_load_toc) context.toastOnUi(R.string.error_load_toc)
} }
}?.onError { }
context.toastOnUi(R.string.error_load_toc)
}
} }
} }
@ -92,9 +94,7 @@ class AudioPlayViewModel(application: Application) : BaseViewModel(application)
} }
appDb.bookDao.insert(book1) appDb.bookDao.insert(book1)
AudioPlay.book = book1 AudioPlay.book = book1
appDb.bookSourceDao.getBookSource(book1.origin)?.let { AudioPlay.bookSource = appDb.bookSourceDao.getBookSource(book1.origin)
AudioPlay.webBook = WebBook(it)
}
if (book1.tocUrl.isEmpty()) { if (book1.tocUrl.isEmpty()) {
loadBookInfo(book1) { upChangeDurChapterIndex(book1, oldTocSize, it) } loadBookInfo(book1) { upChangeDurChapterIndex(book1, oldTocSize, it) }
} else { } else {

@ -100,8 +100,8 @@ class ChangeCoverViewModel(application: Application) : BaseViewModel(application
searchNext() searchNext()
return return
} }
val task = WebBook(source) val task = WebBook
.searchBook(viewModelScope, name, context = searchPool!!) .searchBook(viewModelScope, source, name, context = searchPool!!)
.timeout(60000L) .timeout(60000L)
.onSuccess(searchPool) { .onSuccess(searchPool) {
if (it.isNotEmpty()) { if (it.isNotEmpty()) {

@ -128,9 +128,8 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio
searchIndex++ searchIndex++
} }
val source = bookSourceList[searchIndex] val source = bookSourceList[searchIndex]
val webBook = WebBook(source) val task = WebBook
val task = webBook .searchBook(viewModelScope, source, name, context = searchPool!!)
.searchBook(viewModelScope, name, context = searchPool!!)
.timeout(60000L) .timeout(60000L)
.onSuccess(searchPool) { .onSuccess(searchPool) {
it.forEach { searchBook -> it.forEach { searchBook ->
@ -140,7 +139,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio
) { ) {
if (searchBook.latestChapterTitle.isNullOrEmpty()) { if (searchBook.latestChapterTitle.isNullOrEmpty()) {
if (AppConfig.changeSourceLoadInfo || AppConfig.changeSourceLoadToc) { if (AppConfig.changeSourceLoadInfo || AppConfig.changeSourceLoadToc) {
loadBookInfo(webBook, searchBook.toBook()) loadBookInfo(source, searchBook.toBook())
} else { } else {
searchFinish(searchBook) searchFinish(searchBook)
} }
@ -171,11 +170,11 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio
} }
private fun loadBookInfo(webBook: WebBook, book: Book) { private fun loadBookInfo(source: BookSource, book: Book) {
webBook.getBookInfo(viewModelScope, book) WebBook.getBookInfo(viewModelScope, source, book)
.onSuccess { .onSuccess {
if (context.getPrefBoolean(PreferKey.changeSourceLoadToc)) { if (context.getPrefBoolean(PreferKey.changeSourceLoadToc)) {
loadBookToc(webBook, book) loadBookToc(source, book)
} else { } else {
//从详情页里获取最新章节 //从详情页里获取最新章节
book.latestChapterTitle = it.latestChapterTitle book.latestChapterTitle = it.latestChapterTitle
@ -187,8 +186,8 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio
} }
} }
private fun loadBookToc(webBook: WebBook, book: Book) { private fun loadBookToc(source: BookSource, book: Book) {
webBook.getChapterList(viewModelScope, book) WebBook.getChapterList(viewModelScope, source, book)
.onSuccess(IO) { chapters -> .onSuccess(IO) { chapters ->
if (chapters.isNotEmpty()) { if (chapters.isNotEmpty()) {
book.latestChapterTitle = chapters.last().title book.latestChapterTitle = chapters.last().title

@ -35,7 +35,7 @@ class ExploreShowViewModel(application: Application) : BaseViewModel(application
val source = bookSource val source = bookSource
val url = exploreUrl val url = exploreUrl
if (source != null && url != null) { if (source != null && url != null) {
WebBook(source).exploreBook(viewModelScope, url, page) WebBook.exploreBook(viewModelScope, source, url, page)
.timeout(30000L) .timeout(30000L)
.onSuccess(IO) { searchBooks -> .onSuccess(IO) { searchBooks ->
booksData.postValue(searchBooks) booksData.postValue(searchBooks)

@ -81,7 +81,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
loadChapter(book, changeDruChapterIndex) loadChapter(book, changeDruChapterIndex)
} else { } else {
bookSource?.let { bookSource -> bookSource?.let { bookSource ->
WebBook(bookSource).getBookInfo(this, book, canReName = canReName) WebBook.getBookInfo(this, bookSource, book, canReName = canReName)
.onSuccess(IO) { .onSuccess(IO) {
bookData.postValue(book) bookData.postValue(book)
if (inBookshelf) { if (inBookshelf) {
@ -112,7 +112,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
} }
} else { } else {
bookSource?.let { bookSource -> bookSource?.let { bookSource ->
WebBook(bookSource).getChapterList(this, book) WebBook.getChapterList(this, bookSource, book)
.onSuccess(IO) { .onSuccess(IO) {
if (it.isNotEmpty()) { if (it.isNotEmpty()) {
if (inBookshelf) { if (inBookshelf) {

@ -727,9 +727,9 @@ class ReadBookActivity : ReadBookBaseActivity(),
} }
override fun openSourceEditActivity() { override fun openSourceEditActivity() {
ReadBook.webBook?.let { ReadBook.bookSource?.let {
sourceEditActivity.launch(Intent(this, BookSourceEditActivity::class.java).apply { sourceEditActivity.launch(Intent(this, BookSourceEditActivity::class.java).apply {
putExtra("data", it.bookSource.bookSourceUrl) putExtra("data", it.bookSourceUrl)
}) })
} }
} }
@ -785,7 +785,7 @@ class ReadBookActivity : ReadBookBaseActivity(),
} }
override fun showLogin() { override fun showLogin() {
ReadBook.webBook?.bookSource?.let { ReadBook.bookSource?.let {
startActivity<SourceLoginActivity> { startActivity<SourceLoginActivity> {
putExtra("sourceUrl", it.bookSourceUrl) putExtra("sourceUrl", it.bookSourceUrl)
} }

@ -53,7 +53,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
if (ReadBook.book?.bookUrl != book.bookUrl) { if (ReadBook.book?.bookUrl != book.bookUrl) {
ReadBook.resetData(book) ReadBook.resetData(book)
isInitFinish = true isInitFinish = true
if (!book.isLocalBook() && ReadBook.webBook == null) { if (!book.isLocalBook() && ReadBook.bookSource == null) {
autoChangeSource(book.name, book.author) autoChangeSource(book.name, book.author)
return return
} }
@ -81,7 +81,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
ReadBook.titleDate.postValue(book.name) ReadBook.titleDate.postValue(book.name)
ReadBook.upWebBook(book) ReadBook.upWebBook(book)
isInitFinish = true isInitFinish = true
if (!book.isLocalBook() && ReadBook.webBook == null) { if (!book.isLocalBook() && ReadBook.bookSource == null) {
autoChangeSource(book.name, book.author) autoChangeSource(book.name, book.author)
return return
} }
@ -112,10 +112,12 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
if (book.isLocalBook()) { if (book.isLocalBook()) {
loadChapterList(book, changeDruChapterIndex) loadChapterList(book, changeDruChapterIndex)
} else { } else {
ReadBook.webBook?.getBookInfo(viewModelScope, book, canReName = false) ReadBook.bookSource?.let {
?.onSuccess { WebBook.getBookInfo(viewModelScope, it, book, canReName = false)
loadChapterList(book, changeDruChapterIndex) .onSuccess {
} loadChapterList(book, changeDruChapterIndex)
}
}
} }
} }
@ -141,24 +143,26 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
ReadBook.upMsg("LoadTocError:${it.localizedMessage}") ReadBook.upMsg("LoadTocError:${it.localizedMessage}")
} }
} else { } else {
ReadBook.webBook?.getChapterList(viewModelScope, book) ReadBook.bookSource?.let {
?.onSuccess(IO) { cList -> WebBook.getChapterList(viewModelScope, it, book)
if (cList.isNotEmpty()) { .onSuccess(IO) { cList ->
if (changeDruChapterIndex == null) { if (cList.isNotEmpty()) {
appDb.bookChapterDao.insert(*cList.toTypedArray()) if (changeDruChapterIndex == null) {
appDb.bookDao.update(book) appDb.bookChapterDao.insert(*cList.toTypedArray())
ReadBook.chapterSize = cList.size appDb.bookDao.update(book)
ReadBook.upMsg(null) ReadBook.chapterSize = cList.size
ReadBook.loadContent(resetPageOffset = true) ReadBook.upMsg(null)
ReadBook.loadContent(resetPageOffset = true)
} else {
changeDruChapterIndex(cList)
}
} else { } else {
changeDruChapterIndex(cList) ReadBook.upMsg(context.getString(R.string.error_load_toc))
} }
} else { }.onError {
ReadBook.upMsg(context.getString(R.string.error_load_toc)) ReadBook.upMsg(context.getString(R.string.error_load_toc))
} }
}?.onError { }
ReadBook.upMsg(context.getString(R.string.error_load_toc))
}
} }
} }
@ -192,9 +196,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
it.changeTo(newBook) it.changeTo(newBook)
} }
ReadBook.book = newBook ReadBook.book = newBook
appDb.bookSourceDao.getBookSource(newBook.origin)?.let { ReadBook.bookSource = appDb.bookSourceDao.getBookSource(newBook.origin)
ReadBook.webBook = WebBook(it)
}
ReadBook.prevTextChapter = null ReadBook.prevTextChapter = null
ReadBook.curTextChapter = null ReadBook.curTextChapter = null
ReadBook.nextTextChapter = null ReadBook.nextTextChapter = null
@ -277,9 +279,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
fun upBookSource(success: (() -> Unit)?) { fun upBookSource(success: (() -> Unit)?) {
execute { execute {
ReadBook.book?.let { book -> ReadBook.book?.let { book ->
appDb.bookSourceDao.getBookSource(book.origin)?.let { ReadBook.bookSource = appDb.bookSourceDao.getBookSource(book.origin)
ReadBook.webBook = WebBook(it)
}
} }
}.onSuccess { }.onSuccess {
success?.invoke() success?.invoke()

@ -284,7 +284,7 @@ class ReadMenu @JvmOverloads constructor(
} }
fun upBookView() { fun upBookView() {
binding.tvLogin.isGone = ReadBook.webBook?.bookSource?.loginUrl.isNullOrEmpty() binding.tvLogin.isGone = ReadBook.bookSource?.loginUrl.isNullOrEmpty()
ReadBook.curTextChapter?.let { ReadBook.curTextChapter?.let {
binding.tvChapterName.text = it.title binding.tvChapterName.text = it.title
binding.tvChapterName.visible() binding.tvChapterName.visible()

@ -3,13 +3,13 @@ package io.legado.app.ui.book.source.debug
import android.app.Application import android.app.Application
import io.legado.app.base.BaseViewModel import io.legado.app.base.BaseViewModel
import io.legado.app.data.appDb import io.legado.app.data.appDb
import io.legado.app.data.entities.BookSource
import io.legado.app.model.Debug import io.legado.app.model.Debug
import io.legado.app.model.webBook.WebBook
class BookSourceDebugModel(application: Application) : BaseViewModel(application), class BookSourceDebugModel(application: Application) : BaseViewModel(application),
Debug.Callback { Debug.Callback {
private var webBook: WebBook? = null private var bookSource: BookSource? = null
private var callback: ((Int, String) -> Unit)? = null private var callback: ((Int, String) -> Unit)? = null
var searchSrc: String? = null var searchSrc: String? = null
var bookSrc: String? = null var bookSrc: String? = null
@ -20,8 +20,7 @@ class BookSourceDebugModel(application: Application) : BaseViewModel(application
sourceUrl?.let { sourceUrl?.let {
//优先使用这个,不会抛出异常 //优先使用这个,不会抛出异常
execute { execute {
val bookSource = appDb.bookSourceDao.getBookSource(sourceUrl) bookSource = appDb.bookSourceDao.getBookSource(sourceUrl)
bookSource?.let { webBook = WebBook(it) }
} }
} }
} }
@ -33,7 +32,7 @@ class BookSourceDebugModel(application: Application) : BaseViewModel(application
fun startDebug(key: String, start: (() -> Unit)? = null, error: (() -> Unit)? = null) { fun startDebug(key: String, start: (() -> Unit)? = null, error: (() -> Unit)? = null) {
execute { execute {
Debug.callback = this@BookSourceDebugModel Debug.callback = this@BookSourceDebugModel
Debug.startDebug(this, webBook!!, key) Debug.startDebug(this, bookSource!!, key)
}.onStart { }.onStart {
start?.invoke() start?.invoke()
}.onError { }.onError {

@ -6,6 +6,7 @@ import io.legado.app.constant.BookType
import io.legado.app.constant.EventBus import io.legado.app.constant.EventBus
import io.legado.app.data.appDb import io.legado.app.data.appDb
import io.legado.app.data.entities.Book import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookSource
import io.legado.app.help.AppConfig import io.legado.app.help.AppConfig
import io.legado.app.help.BookHelp import io.legado.app.help.BookHelp
import io.legado.app.help.DefaultData import io.legado.app.help.DefaultData
@ -75,15 +76,14 @@ class MainViewModel(application: Application) : BaseViewModel(application) {
} }
appDb.bookSourceDao.getBookSource(book.origin)?.let { bookSource -> appDb.bookSourceDao.getBookSource(book.origin)?.let { bookSource ->
execute(context = upTocPool) { execute(context = upTocPool) {
val webBook = WebBook(bookSource)
if (book.tocUrl.isBlank()) { if (book.tocUrl.isBlank()) {
webBook.getBookInfoAwait(this, book) WebBook.getBookInfoAwait(this, bookSource, book)
} }
val toc = webBook.getChapterListAwait(this, book) val toc = WebBook.getChapterListAwait(this, bookSource, book)
appDb.bookDao.update(book) appDb.bookDao.update(book)
appDb.bookChapterDao.delByBook(book.bookUrl) appDb.bookChapterDao.delByBook(book.bookUrl)
appDb.bookChapterDao.insert(*toc.toTypedArray()) appDb.bookChapterDao.insert(*toc.toTypedArray())
cacheBook(webBook, book) cacheBook(bookSource, book)
}.onError(upTocPool) { }.onError(upTocPool) {
it.printStackTrace() it.printStackTrace()
}.onFinally(upTocPool) { }.onFinally(upTocPool) {
@ -108,7 +108,7 @@ class MainViewModel(application: Application) : BaseViewModel(application) {
} }
} }
private fun cacheBook(webBook: WebBook, book: Book) { private fun cacheBook(bookSource: BookSource, book: Book) {
execute { execute {
if (book.totalChapterNum > book.durChapterIndex) { if (book.totalChapterNum > book.durChapterIndex) {
val downloadToIndex = val downloadToIndex =
@ -119,7 +119,7 @@ class MainViewModel(application: Application) : BaseViewModel(application) {
var addToCache = false var addToCache = false
while (!addToCache) { while (!addToCache) {
if (CacheBook.downloadCount() < 10) { if (CacheBook.downloadCount() < 10) {
CacheBook.download(this, webBook, book, chapter) CacheBook.download(this, bookSource, book, chapter)
addToCache = true addToCache = true
} else { } else {
delay(100) delay(100)

@ -46,7 +46,7 @@ class BookshelfViewModel(application: Application) : BaseViewModel(application)
origin = bookSource.bookSourceUrl, origin = bookSource.bookSourceUrl,
originName = bookSource.bookSourceName originName = bookSource.bookSourceName
) )
WebBook(bookSource).getBookInfo(this, book) WebBook.getBookInfo(this, bookSource, book)
.onSuccess(IO) { .onSuccess(IO) {
it.order = appDb.bookDao.maxOrder + 1 it.order = appDb.bookDao.maxOrder + 1
it.save() it.save()

@ -6,7 +6,6 @@ import fi.iki.elonen.NanoWSD
import io.legado.app.R import io.legado.app.R
import io.legado.app.data.appDb import io.legado.app.data.appDb
import io.legado.app.model.Debug import io.legado.app.model.Debug
import io.legado.app.model.webBook.WebBook
import io.legado.app.utils.GSON import io.legado.app.utils.GSON
import io.legado.app.utils.fromJsonObject import io.legado.app.utils.fromJsonObject
import io.legado.app.utils.isJson import io.legado.app.utils.isJson
@ -63,7 +62,7 @@ class SourceDebugWebSocket(handshakeRequest: NanoHTTPD.IHTTPSession) :
} }
appDb.bookSourceDao.getBookSource(tag)?.let { appDb.bookSourceDao.getBookSource(tag)?.let {
Debug.callback = this@SourceDebugWebSocket Debug.callback = this@SourceDebugWebSocket
Debug.startDebug(this, WebBook(it), key) Debug.startDebug(this, it, key)
} }
} }
} }

Loading…
Cancel
Save