|
|
@@ -16,6 +16,7 @@ import io.legado.app.data.entities.BookSource
|
|
|
import io.legado.app.data.entities.SearchBook
|
|
|
import io.legado.app.exception.NoStackTraceException
|
|
|
import io.legado.app.help.book.BookHelp
|
|
|
+import io.legado.app.help.book.ContentProcessor
|
|
|
import io.legado.app.help.config.AppConfig
|
|
|
import io.legado.app.help.config.SourceConfig
|
|
|
import io.legado.app.help.coroutine.CompositeCoroutine
|
|
|
@@ -50,8 +51,25 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
|
|
|
private var searchBookList = arrayListOf<SearchBook>()
|
|
|
private val searchBooks = Collections.synchronizedList(arrayListOf<SearchBook>())
|
|
|
private val tocMap = ConcurrentHashMap<String, List<BookChapter>>()
|
|
|
+ private val contentProcessor by lazy {
|
|
|
+ ContentProcessor.get(oldBook!!)
|
|
|
+ }
|
|
|
private var searchCallback: SourceCallback? = null
|
|
|
private val emptyBookSource = BookSource()
|
|
|
+ private val chapterNumRegex = "^\\[(\\d+)]".toRegex()
|
|
|
+ private val comparatorBase by lazy {
|
|
|
+ compareByDescending<SearchBook> { getBookScore(it) }
|
|
|
+ .thenByDescending { SourceConfig.getSourceScore(it.origin) }
|
|
|
+ }
|
|
|
+ private val defaultComparator by lazy {
|
|
|
+ comparatorBase.thenBy { it.originOrder }
|
|
|
+ }
|
|
|
+ private val wordCountComparator by lazy {
|
|
|
+ comparatorBase.thenByDescending { it.chapterWordCount > 1000 }
|
|
|
+ .thenByDescending { getChapterNum(it.chapterWordCountText) }
|
|
|
+ .thenByDescending { it.chapterWordCount }
|
|
|
+ .thenBy { it.originOrder }
|
|
|
+ }
|
|
|
val bookMap = ConcurrentHashMap<String, Book>()
|
|
|
val searchDataFlow = callbackFlow {
|
|
|
|
|
|
@@ -88,26 +106,12 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
|
|
|
}
|
|
|
}.map {
|
|
|
kotlin.runCatching {
|
|
|
- searchBooks.sortedWith { o1, o2 ->
|
|
|
- val o1bs = SourceConfig.getBookScore(o1.origin, o1.name, o1.author)
|
|
|
- val o2bs = SourceConfig.getBookScore(o2.origin, o2.name, o2.author)
|
|
|
- when {
|
|
|
- o1bs - o2bs > 0 -> -1
|
|
|
- o1bs - o2bs < 0 -> 1
|
|
|
- else -> {
|
|
|
- val o1ss = SourceConfig.getSourceScore(o1.origin)
|
|
|
- val o2ss = SourceConfig.getSourceScore(o2.origin)
|
|
|
- when {
|
|
|
- o1ss - o2ss > 0 -> -1
|
|
|
- o1ss - o2ss < 0 -> 1
|
|
|
- else -> {
|
|
|
- val n = o1.originOrder - o2.originOrder
|
|
|
- if (n == 0) -1 else n
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ val comparator = if (AppConfig.changeSourceLoadWordCount) {
|
|
|
+ wordCountComparator
|
|
|
+ } else {
|
|
|
+ defaultComparator
|
|
|
}
|
|
|
+ searchBooks.sortedWith(comparator)
|
|
|
}.onFailure {
|
|
|
AppLog.put("换源排序出错\n${it.localizedMessage}", it)
|
|
|
}.getOrDefault(searchBooks)
|
|
|
@@ -153,9 +157,18 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
|
|
|
/**
|
|
|
* 搜索书籍
|
|
|
*/
|
|
|
- fun startSearch() {
|
|
|
+ fun startSearch(origin: String? = null) {
|
|
|
execute {
|
|
|
stopSearch()
|
|
|
+ origin?.let {
|
|
|
+ bookSourceList.clear()
|
|
|
+ bookSourceList.add(appDb.bookSourceDao.getBookSource(origin)!!)
|
|
|
+ searchStateData.postValue(true)
|
|
|
+ searchBooks.removeIf { it.origin == origin }
|
|
|
+ initSearchPool()
|
|
|
+ search()
|
|
|
+ return@execute
|
|
|
+ }
|
|
|
appDb.searchBookDao.clear(name, author)
|
|
|
searchBooks.clear()
|
|
|
searchCallback?.upAdapter()
|
|
|
@@ -182,7 +195,7 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
|
|
|
|
|
|
private fun search() {
|
|
|
val searchIndex = synchronized(this) {
|
|
|
- if (searchIndex >= bookSourceList.lastIndex) {
|
|
|
+ if (searchIndex > bookSourceList.lastIndex) {
|
|
|
return
|
|
|
}
|
|
|
searchIndex++
|
|
|
@@ -256,17 +269,18 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
|
|
|
)
|
|
|
} ?: chapters.lastIndex
|
|
|
} else chapters.lastIndex
|
|
|
- val bookChapter = chapters.getOrNull(chapterIndex)
|
|
|
+ val bookChapter = chapters[chapterIndex]
|
|
|
+ val title = bookChapter.title.trim()
|
|
|
val startTime = System.currentTimeMillis()
|
|
|
val pair = try {
|
|
|
- if (bookChapter == null) throw NoStackTraceException("章节缺失,总章节数${chapters.size}")
|
|
|
val nextChapterUrl = chapters.getOrNull(chapterIndex + 1)?.url
|
|
|
- WebBook.getContentAwait(source, book, bookChapter, nextChapterUrl, false).length.let {
|
|
|
- it to "第${chapterIndex + 1}章 字数:${it}"
|
|
|
- }
|
|
|
+ var content = WebBook.getContentAwait(source, book, bookChapter, nextChapterUrl, false)
|
|
|
+ content = contentProcessor.getContent(oldBook!!, bookChapter, content, false).toString()
|
|
|
+ val len = content.length
|
|
|
+ len to "[${chapterIndex + 1}] ${title}\n字数:${len}"
|
|
|
} catch (t: Throwable) {
|
|
|
if (t is CancellationException) throw t
|
|
|
- -1 to "第${chapterIndex + 1}章 获取字数失败:${t.localizedMessage}"
|
|
|
+ -1 to "[${chapterIndex + 1}] ${title}\n获取字数失败:${t.localizedMessage}"
|
|
|
}
|
|
|
val endTime = System.currentTimeMillis()
|
|
|
val searchBook = book.toSearchBook().apply {
|
|
|
@@ -526,6 +540,11 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
|
|
|
return SourceConfig.getBookScore(searchBook.origin, searchBook.name, searchBook.author)
|
|
|
}
|
|
|
|
|
|
+ private fun getChapterNum(wordCountText: String?): Int {
|
|
|
+ wordCountText ?: return -1
|
|
|
+ return chapterNumRegex.find(wordCountText)?.groupValues?.get(1)?.toIntOrNull() ?: -1
|
|
|
+ }
|
|
|
+
|
|
|
interface SourceCallback {
|
|
|
|
|
|
fun searchSuccess(searchBook: SearchBook)
|