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-text:1.8'
//
implementation 'net.ricecode:string-similarity:1.0.0'
//MarkDown
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.delay
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 java.io.File
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
object BookHelp {
@ -202,54 +207,88 @@ object BookHelp {
}
/**
* 找到相似度最高的章节
* 根据目录名获取当前章节
*/
fun getDurChapterIndexByChapterTitle(
title: String?,
index: Int,
chapters: List<BookChapter>,
fun getDurChapter(
oldDurChapterIndex: Int,
oldChapterListSize: Int,
oldDurChapterName: String?,
newChapterList: List<BookChapter>
): Int {
if (title.isNullOrEmpty()) {
return min(index, chapters.lastIndex)
}
if (chapters.size > index && title == chapters[index].title) {
return index
}
if (oldChapterListSize == 0) return 0
val oldChapterNum = getChapterNum(oldDurChapterName)
val oldName = getPureChapterName(oldDurChapterName)
val newChapterSize = newChapterList.size
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
val jSimilarity = JaccardSimilarity()
var similarity = if (chapters.size > index) {
jSimilarity.apply(title, chapters[index].title)
} else 0.0
if (similarity == 1.0) {
return index
} else {
for (i in 1..50) {
if (index - i in chapters.indices) {
jSimilarity.apply(title, chapters[index - i].title).let {
if (it > similarity) {
similarity = it
newIndex = index - i
if (similarity == 1.0) {
return newIndex
}
}
}
var newNum = 0
if (oldName.isNotEmpty()) {
val service = StringSimilarityServiceImpl(JaroWinklerStrategy())
for (i in min..max) {
val newName = getPureChapterName(newChapterList[i].title)
val temp = service.score(oldName, newName)
if (temp > nameSim) {
nameSim = temp
newIndex = i
}
if (index + i in chapters.indices) {
jSimilarity.apply(title, chapters[index + i].title).let {
if (it > similarity) {
similarity = it
newIndex = index + i
if (similarity == 1.0) {
return newIndex
}
}
}
}
}
if (nameSim < 0.96 && oldChapterNum > 0) {
for (i in min..max) {
val temp = getChapterNum(newChapterList[i].title)
if (temp == oldChapterNum) {
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

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

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

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

Loading…
Cancel
Save