HapeLee 4 mesi fa
parent
commit
ac8a1d426a

+ 30 - 0
app/src/main/java/io/legado/app/domain/usecase/SearchBooksUseCase.kt

@@ -234,12 +234,16 @@ class SearchBooksUseCase(
         private val tagsBooks = LinkedHashMap<SearchBookKey, SearchBook>()
         private val containsBooks = LinkedHashMap<SearchBookKey, SearchBook>()
         private val otherBooks = LinkedHashMap<SearchBookKey, SearchBook>()
+        private val bookUrlIndex = HashMap<String, SearchBookKey>()
         var resultLimitReached = false
             private set
 
         val count: Int
             get() = equalBooks.size + tagsBooks.size + containsBooks.size + otherBooks.size
 
+        private fun allBuckets(): Sequence<Map.Entry<SearchBookKey, SearchBook>> =
+            sequenceOf(equalBooks, tagsBooks, containsBooks, otherBooks).flatMap { it.entries }
+
         suspend fun merge(newBooks: List<SearchBook>): SearchBookChange {
             if (newBooks.isEmpty()) return SearchBookChange()
 
@@ -248,11 +252,26 @@ class SearchBooksUseCase(
             val touchedBuckets = linkedSetOf<LinkedHashMap<SearchBookKey, SearchBook>>()
             newBooks.forEach { newBook ->
                 coroutineContext.ensureActive()
+                val existingKey = bookUrlIndex[newBook.bookUrl]
+                if (existingKey != null) {
+                    val existingEntry = allBuckets().firstOrNull { it.key == existingKey }
+                    val existingBook = existingEntry?.value
+                    if (existingBook != null) {
+                        existingBook.addOrigin(newBook.origin)
+                        upsertBooks.add(existingBook)
+                        val existingBucket = findBucket(existingKey)
+                        if (existingBucket != null) {
+                            touchedBuckets.add(existingBucket)
+                        }
+                        return@forEach
+                    }
+                }
                 val bucket = classifyBucket(newBook) ?: return@forEach
                 val key = SearchBookKey(newBook.name, newBook.author)
                 val currentBook = bucket[key]
                 if (currentBook == null) {
                     bucket[key] = newBook
+                    bookUrlIndex[newBook.bookUrl] = key
                     upsertBooks.add(newBook)
                 } else {
                     currentBook.addOrigin(newBook.origin)
@@ -261,6 +280,7 @@ class SearchBooksUseCase(
                 touchedBuckets.add(bucket)
                 trimSearchBooks()?.let { removed ->
                     removedBookUrls.add(removed.bookUrl)
+                    bookUrlIndex.remove(removed.bookUrl)
                     upsertBooks.removeAll { it.bookUrl == removed.bookUrl }
                 }
             }
@@ -294,6 +314,16 @@ class SearchBooksUseCase(
             }
         }
 
+        private fun findBucket(key: SearchBookKey): LinkedHashMap<SearchBookKey, SearchBook>? {
+            return when {
+                key in equalBooks -> equalBooks
+                key in tagsBooks -> tagsBooks
+                key in containsBooks -> containsBooks
+                key in otherBooks -> otherBooks
+                else -> null
+            }
+        }
+
         /**
          * 按 origins.size 降序重新排列桶内元素。
          * 使用 sortedEntries 重建 LinkedHashMap 以保持排序后的迭代顺序。

+ 13 - 0
app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt

@@ -849,11 +849,24 @@ class SearchViewModel(
     }
 
     private fun mergeSearchResults(books: List<SearchBook>) {
+        val bookUrlIndex = HashMap<String, SearchResultKey>()
+        searchResultBooks.forEach { (key, book) ->
+            bookUrlIndex[book.bookUrl] = key
+        }
         books.forEach { book ->
             val key = SearchResultKey(book.name, book.author)
+            val existingUrlKey = bookUrlIndex[book.bookUrl]
+            if (existingUrlKey != null && existingUrlKey != key) {
+                val existingBook = searchResultBooks[existingUrlKey]
+                if (existingBook != null) {
+                    existingBook.addOrigin(book.origin)
+                    return@forEach
+                }
+            }
             val currentBook = searchResultBooks[key]
             if (currentBook == null) {
                 searchResultBooks[key] = book
+                bookUrlIndex[book.bookUrl] = key
             } else {
                 book.origins.forEach { origin -> currentBook.addOrigin(origin) }
             }