Skip to content

Commit

Permalink
优化
Browse files Browse the repository at this point in the history
  • Loading branch information
821938089 committed Jan 1, 2024
1 parent 73dc85e commit 8f07d73
Show file tree
Hide file tree
Showing 15 changed files with 80 additions and 259 deletions.
8 changes: 6 additions & 2 deletions app/src/main/java/io/legado/app/model/ReadBook.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ package io.legado.app.model

import io.legado.app.constant.AppLog
import io.legado.app.data.appDb
import io.legado.app.data.entities.*
import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookChapter
import io.legado.app.data.entities.BookProgress
import io.legado.app.data.entities.BookSource
import io.legado.app.data.entities.ReadRecord
import io.legado.app.help.AppWebDav
import io.legado.app.help.book.BookHelp
import io.legado.app.help.book.ContentProcessor
Expand Down Expand Up @@ -88,7 +92,7 @@ object ReadBook : CoroutineScope by MainScope() {
upWebBook(book)
lastBookPress = null
webBookProgress = null
TextFile.txtBuffer = null
TextFile.clear()
synchronized(this) {
loadingChapters.clear()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ object LocalBook {
}
}

@Throws(Exception::class)
@Throws(TocEmptyException::class)
fun getChapterList(book: Book): ArrayList<BookChapter> {
val chapters = when {
book.isEpub -> {
Expand Down
117 changes: 72 additions & 45 deletions app/src/main/java/io/legado/app/model/localBook/TextFile.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,56 +16,37 @@ import java.util.regex.Matcher
import java.util.regex.Pattern
import kotlin.math.min

class TextFile(private val book: Book) {
class TextFile(private var book: Book) {

@Suppress("ConstPropertyName")
companion object {
private val padRegex = "^[\\n\\s]+".toRegex()
private const val bufferSize = 8 * 1024 * 1024
private var bufferStart = -1
private var bufferEnd = -1
var txtBuffer: ByteArray? = null
var bookUrl = ""
private const val txtBufferSize = 8 * 1024 * 1024
private var textFile: TextFile? = null

@Synchronized
private fun getTextFile(book: Book): TextFile {
if (textFile == null || textFile?.book?.bookUrl != book.bookUrl) {
textFile = TextFile(book)
return textFile!!
}
textFile?.book = book
return textFile!!
}

@Throws(FileNotFoundException::class)
fun getChapterList(book: Book): ArrayList<BookChapter> {
return TextFile(book).getChapterList()
return getTextFile(book).getChapterList()
}

@Synchronized
@Throws(FileNotFoundException::class)
fun getContent(book: Book, bookChapter: BookChapter): String {
if (txtBuffer == null || bookUrl != book.bookUrl || bookChapter.start!! > bufferEnd || bookChapter.end!! < bufferStart) {
bookUrl = book.bookUrl
LocalBook.getBookInputStream(book).use { bis ->
bufferStart = bufferSize * (bookChapter.start!! / bufferSize).toInt()
txtBuffer = ByteArray(min(bufferSize, bis.available() - bufferStart))
bufferEnd = bufferStart + txtBuffer!!.size
bis.skip(bufferStart.toLong())
bis.read(txtBuffer)
}
}

val count = (bookChapter.end!! - bookChapter.start!!).toInt()
val buffer = ByteArray(count)

if (bookChapter.start!! < bufferEnd && bookChapter.end!! > bufferEnd || bookChapter.start!! < bufferStart && bookChapter.end!! > bufferStart) {
/** 章节内容在缓冲区交界处 */
LocalBook.getBookInputStream(book).use { bis ->
bis.skip(bookChapter.start!!)
bis.read(buffer)
}
} else {
/** 章节内容在缓冲区内 */
txtBuffer!!.copyInto(
buffer,
0,
(bookChapter.start!! - bufferStart).toInt(),
(bookChapter.end!! - bufferStart).toInt()
)
}
return getTextFile(book).getContent(bookChapter)
}

return String(buffer, book.fileCharset()).substringAfter(bookChapter.title)
.replace(padRegex, "  ")
fun clear() {
textFile = null
}

}
Expand All @@ -83,10 +64,14 @@ class TextFile(private val book: Book) {

private var charset: Charset = book.fileCharset()

private var txtBuffer: ByteArray? = null
private var bufferStart = -1L
private var bufferEnd = -1L

/**
* 获取目录
*/
@Throws(FileNotFoundException::class)
@Throws(FileNotFoundException::class, SecurityException::class, EmptyFileException::class)
fun getChapterList(): ArrayList<BookChapter> {
if (book.charset == null || book.tocUrl.isBlank()) {
LocalBook.getBookInputStream(book).use { bis ->
Expand All @@ -112,6 +97,43 @@ class TextFile(private val book: Book) {
return toc
}

fun getContent(chapter: BookChapter): String {
val start = chapter.start!!
val end = chapter.end!!
if (txtBuffer == null || start > bufferEnd || end < bufferStart) {
LocalBook.getBookInputStream(book).use { bis ->
bufferStart = txtBufferSize * (start / txtBufferSize)
txtBuffer = ByteArray(min(txtBufferSize, bis.available() - bufferStart.toInt()))
bufferEnd = bufferStart + txtBuffer!!.size
bis.skip(bufferStart)
bis.read(txtBuffer)
}
}

val count = (end - start).toInt()
val buffer = ByteArray(count)

if (bufferEnd in start..end || bufferStart in start..end) {
/** 章节内容在缓冲区交界处 */
LocalBook.getBookInputStream(book).use { bis ->
bis.skip(start)
bis.read(buffer)
}
} else {
/** 章节内容在缓冲区内 */
txtBuffer!!.copyInto(
buffer,
0,
(start - bufferStart).toInt(),
(end - bufferStart).toInt()
)
}

return String(buffer, charset)
.substringAfter(chapter.title)
.replace(padRegex, "  ")
}

/**
* 按规则解析目录
*/
Expand Down Expand Up @@ -162,7 +184,7 @@ class TextFile(private val book: Book) {
val chapterStart = matcher.start()
//获取章节内容
val chapterContent = blockContent.substring(seekPos, chapterStart)
val chapterLength = chapterContent.toByteArray(charset).size
val chapterLength = chapterContent.toByteArray(charset).size.toLong()
val lastStart = toc.lastOrNull()?.start ?: curOffset
if (book.getSplitLongChapter() && curOffset + chapterLength - lastStart > maxLengthWithToc) {
toc.lastOrNull()?.let {
Expand All @@ -186,7 +208,7 @@ class TextFile(private val book: Book) {
curChapter.start = curOffset + chapterLength
toc.add(curChapter)
} else if (seekPos == 0 && chapterStart != 0) {
/*
/**
* 如果 seekPos == 0 && chapterStart != 0 表示当前block处前面有一段内容
* 第一种情况一定是序章 第二种情况是上一个章节的内容
*/
Expand All @@ -196,21 +218,26 @@ class TextFile(private val book: Book) {
val qyChapter = BookChapter()
qyChapter.title = "前言"
qyChapter.start = curOffset
qyChapter.end = curOffset + chapterLength.toLong()
qyChapter.end = curOffset + chapterLength
toc.add(qyChapter)
book.intro = if (chapterContent.length <= 500) {
chapterContent
} else {
chapterContent.substring(0, 500)
}
}
//创建当前章节
val curChapter = BookChapter()
curChapter.title = matcher.group()
curChapter.start = curOffset + chapterLength.toLong()
curChapter.start = curOffset + chapterLength
toc.add(curChapter)
} else { //否则就block分割之后,上一个章节的剩余内容
//获取上一章节
val lastChapter = toc.last()
lastChapter.isVolume =
chapterContent.substringAfter(lastChapter.title).isBlank()
//将当前段落添加上一章去
lastChapter.end = lastChapter.end!! + chapterLength.toLong()
lastChapter.end = lastChapter.end!! + chapterLength
//创建当前章节
val curChapter = BookChapter()
curChapter.title = matcher.group()
Expand All @@ -224,7 +251,7 @@ class TextFile(private val book: Book) {
lastChapter.isVolume =
chapterContent.substringAfter(lastChapter.title).isBlank()
lastChapter.end =
lastChapter.start!! + chapterContent.toByteArray(charset).size.toLong()
lastChapter.start!! + chapterLength
//创建当前章节
val curChapter = BookChapter()
curChapter.title = matcher.group()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,45 +1,27 @@
package io.legado.app.ui.book.explore

import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import androidx.activity.viewModels
import androidx.recyclerview.widget.RecyclerView
import io.legado.app.R
import io.legado.app.base.VMBaseActivity
import io.legado.app.constant.AppLog
import io.legado.app.data.appDb
import io.legado.app.data.entities.Book
import io.legado.app.data.entities.SearchBook
import io.legado.app.databinding.ActivityExploreShowBinding
import io.legado.app.databinding.DialogPageChoiceBinding
import io.legado.app.databinding.ViewLoadMoreBinding
import io.legado.app.help.coroutine.Coroutine
import io.legado.app.lib.dialogs.alert
import io.legado.app.lib.theme.backgroundColor
import io.legado.app.model.webBook.WebBook
import io.legado.app.ui.book.group.GroupSelectDialog
import io.legado.app.ui.book.info.BookInfoActivity
import io.legado.app.ui.widget.dialog.WaitDialog
import io.legado.app.ui.widget.recycler.LoadMoreView
import io.legado.app.ui.widget.recycler.VerticalDivider
import io.legado.app.utils.showDialogFragment
import io.legado.app.utils.startActivity
import io.legado.app.utils.viewbindingdelegate.viewBinding
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.launch

class ExploreShowActivity : VMBaseActivity<ActivityExploreShowBinding, ExploreShowViewModel>(),
ExploreShowAdapter.CallBack,
GroupSelectDialog.CallBack {
ExploreShowAdapter.CallBack {
override val binding by viewBinding(ActivityExploreShowBinding::inflate)
override val viewModel by viewModels<ExploreShowViewModel>()

private val adapter by lazy { ExploreShowAdapter(this, this) }
private val loadMoreView by lazy { LoadMoreView(this) }
private val waitDialog by lazy {
WaitDialog(this)
}

override fun onActivityCreated(savedInstanceState: Bundle?) {
binding.titleBar.title = intent.getStringExtra("exploreName")
Expand Down Expand Up @@ -116,84 +98,4 @@ class ExploreShowActivity : VMBaseActivity<ActivityExploreShowBinding, ExploreSh
putExtra("bookUrl", book.bookUrl)
}
}

override fun onCompatCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.explore_show, menu)
return super.onCompatCreateOptionsMenu(menu)
}

override fun onCompatOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.menu_add_all_to_bookshelf -> addAllToBookshelf()
}
return super.onCompatOptionsItemSelected(item)
}

private fun addAllToBookshelf() {
showDialogFragment(GroupSelectDialog(0))
}

override fun upGroup(requestCode: Int, groupId: Long) {

alert("选择页数范围") {
val alertBinding = DialogPageChoiceBinding.inflate(layoutInflater).apply {
root.setBackgroundColor(root.context.backgroundColor)
}
customView { alertBinding.root }
yesButton {
alertBinding.run {
val start = editStart.text
.runCatching {
toString().toInt()
}.getOrDefault(1)
val end = editEnd.text
.runCatching {
toString().toInt()
}.getOrDefault(9)
addAllToBookshelf(start, end, groupId)
}
}
noButton()
}

}

private fun addAllToBookshelf(start: Int, end: Int, groupId: Long) {
val job = Coroutine.async {
launch(Main) {
waitDialog.setText("加载列表中...")
waitDialog.show()
}
val searchBooks = viewModel.loadExploreBooks(start, end)
val books = searchBooks.map {
it.toBook()
}
launch(Main) {
waitDialog.setText("添加书架中...")
}
books.forEach {
appDb.bookDao.getBook(it.bookUrl)?.let { book ->
book.group = book.group or groupId
it.order = appDb.bookDao.minOrder - 1
book.save()
return@forEach
}
if (it.tocUrl.isEmpty()) {
val source = appDb.bookSourceDao.getBookSource(it.origin)!!
WebBook.getBookInfoAwait(source, it)
}
it.order = appDb.bookDao.minOrder - 1
it.group = groupId
it.save()
}
}.onError {
AppLog.put("添加书架出错\n${it.localizedMessage}", it)
}.onFinally {
waitDialog.dismiss()
}
waitDialog.setOnCancelListener {
job.cancel()
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -70,18 +70,4 @@ class ExploreShowViewModel(application: Application) : BaseViewModel(application
}
}

suspend fun loadExploreBooks(start: Int, end: Int): List<SearchBook> {
val source = bookSource
val url = exploreUrl
if (source == null || url == null) return emptyList()
val searchBooks = arrayListOf<SearchBook>()
for (page in start..end) {
val books = WebBook.exploreBookAwait(source, url, page)
if (books.isEmpty()) break
searchBooks.addAll(books)
}
searchBooks.reverse()
return searchBooks
}

}
Loading

0 comments on commit 8f07d73

Please sign in to comment.