章节增加字数统计字段,网络书籍增加字数统计 (#4437)

This commit is contained in:
niuhb
2024-12-15 16:20:44 +08:00
committed by GitHub
parent e784e22c5c
commit 4865a72409
8 changed files with 1977 additions and 20 deletions
File diff suppressed because it is too large Load Diff
@@ -63,7 +63,7 @@ val appDb by lazy {
} }
@Database( @Database(
version = 72, version = 73,
exportSchema = true, exportSchema = true,
entities = [Book::class, BookGroup::class, BookSource::class, BookChapter::class, entities = [Book::class, BookGroup::class, BookSource::class, BookChapter::class,
ReplaceRule::class, SearchBook::class, SearchKeyword::class, Cookie::class, ReplaceRule::class, SearchBook::class, SearchKeyword::class, Cookie::class,
@@ -100,6 +100,7 @@ val appDb by lazy {
AutoMigration(from = 69, to = 70), AutoMigration(from = 69, to = 70),
AutoMigration(from = 70, to = 71), AutoMigration(from = 70, to = 71),
AutoMigration(from = 71, to = 72), AutoMigration(from = 71, to = 72),
AutoMigration(from = 72, to = 73),
] ]
) )
abstract class AppDatabase : RoomDatabase() { abstract class AppDatabase : RoomDatabase() {
@@ -51,6 +51,7 @@ data class BookChapter(
var isPay: Boolean = false, // 是否已购买 var isPay: Boolean = false, // 是否已购买
var resourceUrl: String? = null, // 音频真实URL var resourceUrl: String? = null, // 音频真实URL
var tag: String? = null, // 更新时间或其他章节附加信息 var tag: String? = null, // 更新时间或其他章节附加信息
var wordCount: String? = null, // 本章节字数
var start: Long? = null, // 章节起始位置 var start: Long? = null, // 章节起始位置
var end: Long? = null, // 章节终止位置 var end: Long? = null, // 章节终止位置
var startFragmentId: String? = null, //EPUB书籍当前章节的fragmentId var startFragmentId: String? = null, //EPUB书籍当前章节的fragmentId
@@ -148,6 +148,8 @@ object BookHelp {
book.getFolderName(), book.getFolderName(),
bookChapter.getFileName(), bookChapter.getFileName(),
).writeText(content) ).writeText(content)
bookChapter.wordCount = StringUtils.wordCountFormat(content.length)
appDb.bookChapterDao.update(bookChapter)
} }
suspend fun saveImages( suspend fun saveImages(
@@ -142,7 +142,7 @@ class TextFile(private var book: Book) {
* 按规则解析目录 * 按规则解析目录
*/ */
private fun analyze(pattern: Pattern?): Pair<ArrayList<BookChapter>, Int> { private fun analyze(pattern: Pattern?): Pair<ArrayList<BookChapter>, Int> {
if (pattern?.pattern().isNullOrEmpty()) { if (pattern == null || pattern.pattern().isNullOrEmpty()) {
return analyze() return analyze()
} }
val toc = arrayListOf<BookChapter>() val toc = arrayListOf<BookChapter>()
@@ -227,7 +227,7 @@ class TextFile(private var book: Book) {
qyChapter.title = "前言" qyChapter.title = "前言"
qyChapter.start = curOffset qyChapter.start = curOffset
qyChapter.end = curOffset + chapterLength qyChapter.end = curOffset + chapterLength
qyChapter.tag = StringUtils.wordCountFormat(chapterContent.length) qyChapter.wordCount = StringUtils.wordCountFormat(chapterContent.length)
toc.add(qyChapter) toc.add(qyChapter)
book.intro = if (chapterContent.length <= 500) { book.intro = if (chapterContent.length <= 500) {
chapterContent chapterContent
@@ -248,7 +248,7 @@ class TextFile(private var book: Book) {
//将当前段落添加上一章去 //将当前段落添加上一章去
lastChapter.end = lastChapter.end!! + chapterLength lastChapter.end = lastChapter.end!! + chapterLength
lastChapterWordCount += chapterContent.length lastChapterWordCount += chapterContent.length
lastChapter.tag = StringUtils.wordCountFormat(lastChapterWordCount) lastChapter.wordCount = StringUtils.wordCountFormat(lastChapterWordCount)
//创建当前章节 //创建当前章节
val curChapter = BookChapter() val curChapter = BookChapter()
curChapter.title = matcher.group() curChapter.title = matcher.group()
@@ -265,7 +265,7 @@ class TextFile(private var book: Book) {
chapterContent.substringAfter(lastChapter.title).isBlank() chapterContent.substringAfter(lastChapter.title).isBlank()
lastChapter.end = lastChapter.end =
lastChapter.start!! + chapterLength lastChapter.start!! + chapterLength
lastChapter.tag = StringUtils.wordCountFormat(chapterContent.length) lastChapter.wordCount = StringUtils.wordCountFormat(chapterContent.length)
//创建当前章节 //创建当前章节
val curChapter = BookChapter() val curChapter = BookChapter()
curChapter.title = matcher.group() curChapter.title = matcher.group()
@@ -276,7 +276,7 @@ class TextFile(private var book: Book) {
curChapter.title = matcher.group() curChapter.title = matcher.group()
curChapter.start = curOffset curChapter.start = curOffset
curChapter.end = curOffset curChapter.end = curOffset
curChapter.tag = StringUtils.wordCountFormat(chapterContent.length) curChapter.wordCount = StringUtils.wordCountFormat(chapterContent.length)
toc.add(curChapter) toc.add(curChapter)
} }
bookWordCount += chapterContent.length bookWordCount += chapterContent.length
@@ -293,7 +293,7 @@ class TextFile(private var book: Book) {
//设置上一章的结尾 //设置上一章的结尾
toc.lastOrNull()?.let { toc.lastOrNull()?.let {
it.end = curOffset it.end = curOffset
it.tag = StringUtils.wordCountFormat(lastChapterWordCount) it.wordCount = StringUtils.wordCountFormat(lastChapterWordCount)
} }
} }
toc.lastOrNull()?.let { chapter -> toc.lastOrNull()?.let { chapter ->
@@ -383,7 +383,7 @@ class TextFile(private var book: Book) {
chapter.title = "${blockPos}章($chapterPos)" chapter.title = "${blockPos}章($chapterPos)"
chapter.start = toc.lastOrNull()?.end ?: curOffset chapter.start = toc.lastOrNull()?.end ?: curOffset
chapter.end = chapter.start!! + end - chapterOffset chapter.end = chapter.start!! + end - chapterOffset
chapter.tag = StringUtils.wordCountFormat(content.length) chapter.wordCount = StringUtils.wordCountFormat(content.length)
toc.add(chapter) toc.add(chapter)
//减去已经被分配的长度 //减去已经被分配的长度
strLength -= (end - chapterOffset) strLength -= (end - chapterOffset)
@@ -407,13 +407,13 @@ class TextFile(private var book: Book) {
chapter.title = "${blockPos}章(${chapterPos})" chapter.title = "${blockPos}章(${chapterPos})"
chapter.start = toc.lastOrNull()?.end ?: curOffset chapter.start = toc.lastOrNull()?.end ?: curOffset
chapter.end = chapter.start!! + bufferStart chapter.end = chapter.start!! + bufferStart
chapter.tag = StringUtils.wordCountFormat(content.length) chapter.wordCount = StringUtils.wordCountFormat(content.length)
toc.add(chapter) toc.add(chapter)
} else { } else {
val wordCount = lastChapterWordCount + content.length val wordCount = lastChapterWordCount + content.length
toc.lastOrNull()?.let { toc.lastOrNull()?.let {
it.end = it.end!! + bufferStart it.end = it.end!! + bufferStart
it.tag = StringUtils.wordCountFormat(wordCount) it.wordCount = StringUtils.wordCountFormat(wordCount)
} }
} }
} }
@@ -4,6 +4,7 @@ import android.text.TextUtils
import com.script.ScriptBindings import com.script.ScriptBindings
import com.script.rhino.RhinoScriptEngine import com.script.rhino.RhinoScriptEngine
import io.legado.app.R import io.legado.app.R
import io.legado.app.data.appDb
import io.legado.app.data.entities.Book import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookChapter
import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.BookSource
@@ -162,6 +163,7 @@ object BookChapterList {
list.getOrElse(book.simulatedTotalChapterNum() - 1) { list.last() } list.getOrElse(book.simulatedTotalChapterNum() - 1) { list.last() }
.getDisplayTitle(replaceRules, book.getUseReplaceRule()) .getDisplayTitle(replaceRules, book.getUseReplaceRule())
coroutineContext.ensureActive() coroutineContext.ensureActive()
getWordCount(list, book)
return list return list
} }
@@ -267,4 +269,17 @@ object BookChapterList {
return Pair(chapterList, nextUrlList) return Pair(chapterList, nextUrlList)
} }
private fun getWordCount(list: ArrayList<BookChapter>, book: Book) {
val chapterList = appDb.bookChapterDao.getChapterList(book.bookUrl)
if (chapterList.isNotEmpty()){
val map = chapterList.associateBy({ it.getFileName() }, { it.wordCount })
for (bookChapter in list) {
val wordCount = map[bookChapter.getFileName()]
if(wordCount != null){
bookChapter.wordCount = wordCount
}
}
}
}
} }
@@ -138,13 +138,22 @@ class ChapterListAdapter(context: Context, val callback: Callback) :
//普通章节 保持不变 //普通章节 保持不变
tvChapterItem.background = tvChapterItem.background =
ThemeUtils.resolveDrawable(context, android.R.attr.selectableItemBackground) ThemeUtils.resolveDrawable(context, android.R.attr.selectableItemBackground)
}
if (!item.tag.isNullOrEmpty() && !item.isVolume) { //卷名不显示
//卷名不显示tag(更新时间规则) if (!item.tag.isNullOrEmpty()) {
tvTag.text = item.tag //更新时间规则
tvTag.visible() tvTag.text = item.tag
} else { tvTag.visible()
tvTag.gone() } else {
tvTag.gone()
}
if (!item.wordCount.isNullOrEmpty()) {
//章节字数
tvWordCount.text = item.wordCount
tvWordCount.visible()
} else {
tvWordCount.gone()
}
} }
upHasCache(binding, isDur, cached) upHasCache(binding, isDur, cached)
} else { } else {
+14 -3
View File
@@ -15,8 +15,19 @@
android:singleLine="true" android:singleLine="true"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/iv_checked" app:layout_constraintRight_toLeftOf="@+id/iv_checked" />
app:layout_constraintBottom_toTopOf="@id/tv_tag" />
<TextView
android:id="@+id/tv_word_count"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textSize="12sp"
android:visibility="gone"
android:singleLine="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_chapter_name"
app:layout_constraintRight_toLeftOf="@+id/tv_tag" />
<TextView <TextView
android:id="@+id/tv_tag" android:id="@+id/tv_tag"
@@ -27,7 +38,7 @@
android:singleLine="true" android:singleLine="true"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_chapter_name" app:layout_constraintTop_toBottomOf="@+id/tv_chapter_name"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toRightOf="@id/tv_word_count"
app:layout_constraintRight_toLeftOf="@+id/iv_checked" /> app:layout_constraintRight_toLeftOf="@+id/iv_checked" />
<ImageView <ImageView