pull/433/head
gedoor 4 years ago
parent 70ce0535b6
commit 8bc251c105
  1. 3
      app/build.gradle
  2. 123
      app/src/main/java/io/legado/app/help/BookHelp.kt
  3. 17
      app/src/main/java/io/legado/app/ui/audio/AudioPlayViewModel.kt
  4. 25
      app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt
  5. 17
      app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt

@ -193,6 +193,9 @@ dependencies {
implementation 'org.apache.commons:commons-lang3:3.11' implementation 'org.apache.commons:commons-lang3:3.11'
implementation 'org.apache.commons:commons-text:1.8' implementation 'org.apache.commons:commons-text:1.8'
//
implementation 'net.ricecode:string-similarity:1.0.0'
//MarkDown //MarkDown
implementation 'ru.noties.markwon:core:3.1.0' implementation 'ru.noties.markwon:core:3.1.0'

@ -15,10 +15,15 @@ import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.apache.commons.text.similarity.JaccardSimilarity import net.ricecode.similarity.JaroWinklerStrategy
import net.ricecode.similarity.StringSimilarityServiceImpl
import org.jetbrains.anko.toast import org.jetbrains.anko.toast
import java.io.File import java.io.File
import java.util.concurrent.CopyOnWriteArraySet import java.util.concurrent.CopyOnWriteArraySet
import java.util.regex.Matcher
import java.util.regex.Pattern
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min import kotlin.math.min
object BookHelp { object BookHelp {
@ -202,54 +207,88 @@ object BookHelp {
} }
/** /**
* 找到相似度最高的章节 * 根据目录名获取当前章节
*/ */
fun getDurChapterIndexByChapterTitle( fun getDurChapter(
title: String?, oldDurChapterIndex: Int,
index: Int, oldChapterListSize: Int,
chapters: List<BookChapter>, oldDurChapterName: String?,
newChapterList: List<BookChapter>
): Int { ): Int {
if (title.isNullOrEmpty()) { if (oldChapterListSize == 0) return 0
return min(index, chapters.lastIndex) val oldChapterNum = getChapterNum(oldDurChapterName)
} val oldName = getPureChapterName(oldDurChapterName)
if (chapters.size > index && title == chapters[index].title) { val newChapterSize = newChapterList.size
return index val min = max(
} 0,
min(
oldDurChapterIndex,
oldDurChapterIndex - oldChapterListSize + newChapterSize
) - 10
)
val max = min(
newChapterSize - 1,
max(
oldDurChapterIndex,
oldDurChapterIndex - oldChapterListSize + newChapterSize
) + 10
)
var nameSim = 0.0
var newIndex = 0 var newIndex = 0
val jSimilarity = JaccardSimilarity() var newNum = 0
var similarity = if (chapters.size > index) { if (oldName.isNotEmpty()) {
jSimilarity.apply(title, chapters[index].title) val service = StringSimilarityServiceImpl(JaroWinklerStrategy())
} else 0.0 for (i in min..max) {
if (similarity == 1.0) { val newName = getPureChapterName(newChapterList[i].title)
return index val temp = service.score(oldName, newName)
} else { if (temp > nameSim) {
for (i in 1..50) { nameSim = temp
if (index - i in chapters.indices) { newIndex = i
jSimilarity.apply(title, chapters[index - i].title).let {
if (it > similarity) {
similarity = it
newIndex = index - i
if (similarity == 1.0) {
return newIndex
}
}
}
} }
if (index + i in chapters.indices) { }
jSimilarity.apply(title, chapters[index + i].title).let { }
if (it > similarity) { if (nameSim < 0.96 && oldChapterNum > 0) {
similarity = it for (i in min..max) {
newIndex = index + i val temp = getChapterNum(newChapterList[i].title)
if (similarity == 1.0) { if (temp == oldChapterNum) {
return newIndex newNum = temp
} newIndex = i
} break
} } else if (abs(temp - oldChapterNum) < abs(newNum - oldChapterNum)) {
newNum = temp
newIndex = i
} }
} }
} }
return newIndex return if (nameSim > 0.96 || abs(newNum - oldChapterNum) < 1) {
newIndex
} else {
min(max(0, newChapterList.size - 1), oldDurChapterIndex)
}
}
private val chapterNamePattern =
Pattern.compile("^(.*?第([\\d零〇一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟0-9\\s]+)[章节篇回集])[、,。 ::.\\s]*")
private fun getChapterNum(chapterName: String?): Int {
if (chapterName != null) {
val matcher: Matcher = chapterNamePattern.matcher(chapterName)
if (matcher.find()) {
return StringUtils.stringToInt(matcher.group(2))
}
}
return -1
}
private fun getPureChapterName(chapterName: String?): String {
// 所有非字母数字中日韩文字 CJK区+扩展A-F区
return if (chapterName == null) "" else StringUtils.fullToHalf(chapterName)
.replace("\\s".toRegex(), "")
.replace("^第.*?章|[(\\[][^()\\[\\]]{2,}[)\\]]$".toRegex(), "")
.replace(
"[^\\w\\u4E00-\\u9FEF〇\\u3400-\\u4DBF\\u20000-\\u2A6DF\\u2A700-\\u2EBEF]".toRegex(),
""
)
} }
private var bookName: String? = null private var bookName: String? = null

@ -89,7 +89,9 @@ class AudioPlayViewModel(application: Application) : BaseViewModel(application)
fun changeTo(book1: Book) { fun changeTo(book1: Book) {
execute { execute {
var oldTocSize: Int = book1.totalChapterNum
AudioPlay.book?.let { AudioPlay.book?.let {
oldTocSize = it.totalChapterNum
book1.order = it.order book1.order = it.order
App.db.bookDao().delete(it) App.db.bookDao().delete(it)
} }
@ -99,18 +101,23 @@ class AudioPlayViewModel(application: Application) : BaseViewModel(application)
AudioPlay.webBook = WebBook(it) AudioPlay.webBook = WebBook(it)
} }
if (book1.tocUrl.isEmpty()) { if (book1.tocUrl.isEmpty()) {
loadBookInfo(book1) { upChangeDurChapterIndex(book1, it) } loadBookInfo(book1) { upChangeDurChapterIndex(book1, oldTocSize, it) }
} else { } else {
loadChapterList(book1) { upChangeDurChapterIndex(book1, it) } loadChapterList(book1) { upChangeDurChapterIndex(book1, oldTocSize, it) }
} }
} }
} }
private fun upChangeDurChapterIndex(book: Book, chapters: List<BookChapter>) { private fun upChangeDurChapterIndex(
book: Book,
oldTocSize: Int,
chapters: List<BookChapter>
) {
execute { execute {
AudioPlay.durChapterIndex = BookHelp.getDurChapterIndexByChapterTitle( AudioPlay.durChapterIndex = BookHelp.getDurChapter(
book.durChapterTitle,
book.durChapterIndex, book.durChapterIndex,
oldTocSize,
book.durChapterTitle,
chapters chapters
) )
book.durChapterIndex = AudioPlay.durChapterIndex book.durChapterIndex = AudioPlay.durChapterIndex

@ -133,23 +133,36 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
fun changeTo(newBook: Book) { fun changeTo(newBook: Book) {
execute { execute {
var oldTocSize: Int = newBook.totalChapterNum
if (inBookshelf) { if (inBookshelf) {
bookData.value?.changeTo(newBook) bookData.value?.let {
oldTocSize = it.totalChapterNum
it.changeTo(newBook)
}
} }
bookData.postValue(newBook) bookData.postValue(newBook)
if (newBook.tocUrl.isEmpty()) { if (newBook.tocUrl.isEmpty()) {
loadBookInfo(newBook, false) { upChangeDurChapterIndex(newBook, it) } loadBookInfo(newBook, false) {
upChangeDurChapterIndex(newBook, oldTocSize, it)
}
} else { } else {
loadChapter(newBook) { upChangeDurChapterIndex(newBook, it) } loadChapter(newBook) {
upChangeDurChapterIndex(newBook, oldTocSize, it)
}
} }
} }
} }
private fun upChangeDurChapterIndex(book: Book, chapters: List<BookChapter>) { private fun upChangeDurChapterIndex(
book: Book,
oldTocSize: Int,
chapters: List<BookChapter>
) {
execute { execute {
book.durChapterIndex = BookHelp.getDurChapterIndexByChapterTitle( book.durChapterIndex = BookHelp.getDurChapter(
book.durChapterTitle,
book.durChapterIndex, book.durChapterIndex,
oldTocSize,
book.durChapterTitle,
chapters chapters
) )
book.durChapterTitle = chapters[book.durChapterIndex].title book.durChapterTitle = chapters[book.durChapterIndex].title

@ -157,8 +157,12 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
fun changeTo(newBook: Book) { fun changeTo(newBook: Book) {
execute { execute {
var oldTocSize: Int = newBook.totalChapterNum
ReadBook.upMsg(null) ReadBook.upMsg(null)
ReadBook.book?.changeTo(newBook) ReadBook.book?.let {
oldTocSize = it.totalChapterNum
it.changeTo(newBook)
}
ReadBook.book = newBook ReadBook.book = newBook
App.db.bookSourceDao().getBookSource(newBook.origin)?.let { App.db.bookSourceDao().getBookSource(newBook.origin)?.let {
ReadBook.webBook = WebBook(it) ReadBook.webBook = WebBook(it)
@ -171,11 +175,11 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
} }
if (newBook.tocUrl.isEmpty()) { if (newBook.tocUrl.isEmpty()) {
loadBookInfo(newBook) { loadBookInfo(newBook) {
upChangeDurChapterIndex(newBook, it) upChangeDurChapterIndex(newBook, oldTocSize, it)
} }
} else { } else {
loadChapterList(newBook) { loadChapterList(newBook) {
upChangeDurChapterIndex(newBook, it) upChangeDurChapterIndex(newBook, oldTocSize, it)
} }
} }
} }
@ -208,11 +212,12 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
} }
} }
private fun upChangeDurChapterIndex(book: Book, chapters: List<BookChapter>) { private fun upChangeDurChapterIndex(book: Book, oldTocSize: Int, chapters: List<BookChapter>) {
execute { execute {
ReadBook.durChapterIndex = BookHelp.getDurChapterIndexByChapterTitle( ReadBook.durChapterIndex = BookHelp.getDurChapter(
book.durChapterTitle,
book.durChapterIndex, book.durChapterIndex,
oldTocSize,
book.durChapterTitle,
chapters chapters
) )
book.durChapterIndex = ReadBook.durChapterIndex book.durChapterIndex = ReadBook.durChapterIndex

Loading…
Cancel
Save