From 8b76649226edddf7ecc32f34efd5f9204c252b22 Mon Sep 17 00:00:00 2001 From: gedoor Date: Thu, 9 Jul 2020 19:45:49 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=8F=E8=AF=B4=E9=98=85=E8=AF=BB=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=20=E4=BC=98=E5=8C=96=20=E6=B7=BB=E5=8A=A0=20epub=20?= =?UTF-8?q?=E6=9C=AA=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 6 + .../io/legado/app/model/localBook/EPUBFile.kt | 123 ++++++++++++++++++ .../app/ui/book/local/ImportBookActivity.kt | 9 +- .../app/web/controller/BookshelfController.kt | 25 +++- 4 files changed, 160 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/io/legado/app/model/localBook/EPUBFile.kt diff --git a/app/build.gradle b/app/build.gradle index b68424a9a..a14eb29bb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -194,6 +194,12 @@ dependencies { //转换繁体 implementation 'com.hankcs:hanlp:portable-1.7.7' + //epub + implementation('com.positiondev.epublib:epublib-core:3.1') { + exclude group: 'org.slf4j' + exclude group: 'xmlpull' + } + //E-Ink 有些手机会出现重影 //implementation 'fadeapp.widgets:scrollless-recyclerView:1.0.2' } diff --git a/app/src/main/java/io/legado/app/model/localBook/EPUBFile.kt b/app/src/main/java/io/legado/app/model/localBook/EPUBFile.kt new file mode 100644 index 000000000..8706b8ad6 --- /dev/null +++ b/app/src/main/java/io/legado/app/model/localBook/EPUBFile.kt @@ -0,0 +1,123 @@ +package io.legado.app.model.localBook + +import android.content.Context +import android.text.TextUtils +import io.legado.app.data.entities.BookChapter +import net.sf.jazzlib.ZipFile +import nl.siegmann.epublib.domain.Book +import nl.siegmann.epublib.domain.TOCReference +import nl.siegmann.epublib.epub.EpubReader +import nl.siegmann.epublib.service.MediatypeService +import org.jsoup.Jsoup +import java.io.File +import java.io.IOException +import java.nio.charset.Charset +import java.util.* + +class EPUBFile(context: Context, val book: io.legado.app.data.entities.Book) { + var epubBook: Book? = null + private lateinit var mCharset: Charset + + init { + + } + + fun readBook(file: File?): Book? { + return try { + val epubReader = EpubReader() + val lazyTypes = + arrayOf( + MediatypeService.CSS, + MediatypeService.GIF, + MediatypeService.JPG, + MediatypeService.PNG, + MediatypeService.MP3, + MediatypeService.MP4 + ) + val zipFile = ZipFile(file) + epubReader.readEpubLazy(zipFile, "utf-8", Arrays.asList(*lazyTypes)) + } catch (e: Exception) { + null + } + } + + fun getChapterList(epubBook: Book): ArrayList { + val metadata = epubBook.metadata + book.name = metadata.firstTitle + if (metadata.authors.size > 0) { + val author = + metadata.authors[0].toString().replace("^, |, $".toRegex(), "") + book.author = author + } + if (metadata.descriptions.size > 0) { + book.intro = Jsoup.parse(metadata.descriptions[0]).text() + } + val chapterList = ArrayList() + val refs = + epubBook.tableOfContents.tocReferences + if (refs == null || refs.isEmpty()) { + val spineReferences = + epubBook.spine.spineReferences + var i = 0 + val size = spineReferences.size + while (i < size) { + val resource = + spineReferences[i].resource + var title = resource.title + if (TextUtils.isEmpty(title)) { + try { + val doc = + Jsoup.parse(String(resource.data, mCharset)) + val elements = doc.getElementsByTag("title") + if (elements.size > 0) { + title = elements[0].text() + } + } catch (e: IOException) { + e.printStackTrace() + } + } + val chapter = BookChapter() + chapter.index = i + chapter.bookUrl = book.bookUrl + chapter.url = resource.href + if (i == 0 && title.isEmpty()) { + chapter.title = "封面" + } else { + chapter.title = title + } + chapterList.add(chapter) + i++ + } + } else { + parseMenu(chapterList, refs, 0) + for (i in chapterList.indices) { + chapterList[i].index = i + } + } + + return chapterList + } + + + private fun parseMenu( + chapterList: ArrayList, + refs: List?, + level: Int + ) { + if (refs == null) return + for (ref in refs) { + if (ref.resource != null) { + val chapter = BookChapter() + chapter.bookUrl = book.bookUrl + chapter.title = ref.title + chapter.url = ref.completeHref + chapterList.add(chapter) + } + if (ref.children != null && !ref.children.isEmpty()) { + parseMenu(chapterList, ref.children, level + 1) + } + } + } + + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/local/ImportBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/local/ImportBookActivity.kt index 3ce47ee99..af8871548 100644 --- a/app/src/main/java/io/legado/app/ui/book/local/ImportBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/local/ImportBookActivity.kt @@ -172,7 +172,10 @@ class ImportBookActivity : VMBaseActivity(R.layout.activity val item = docList[i] if (item.name.startsWith(".")) { docList.removeAt(i) - } else if (!item.isDir && !item.name.endsWith(".txt", true)) { + } else if (!item.isDir + && !item.name.endsWith(".txt", true) + && !item.name.endsWith(".epub", true) + ) { docList.removeAt(i) } } @@ -196,7 +199,9 @@ class ImportBookActivity : VMBaseActivity(R.layout.activity Uri.parse(it.absolutePath) ) ) - } else if (it.name.endsWith(".txt", true)) { + } else if (it.name.endsWith(".txt", true) + || it.name.endsWith(".epub", true) + ) { docList.add( DocItem( it.name, diff --git a/app/src/main/java/io/legado/app/web/controller/BookshelfController.kt b/app/src/main/java/io/legado/app/web/controller/BookshelfController.kt index 6bae8f8aa..9347ee1bb 100644 --- a/app/src/main/java/io/legado/app/web/controller/BookshelfController.kt +++ b/app/src/main/java/io/legado/app/web/controller/BookshelfController.kt @@ -1,11 +1,13 @@ package io.legado.app.web.controller import io.legado.app.App +import io.legado.app.constant.PreferKey import io.legado.app.data.entities.Book import io.legado.app.help.BookHelp import io.legado.app.model.WebBook import io.legado.app.utils.GSON import io.legado.app.utils.fromJsonObject +import io.legado.app.utils.getPrefInt import io.legado.app.web.utils.ReturnData import kotlinx.coroutines.runBlocking @@ -17,7 +19,15 @@ class BookshelfController { val returnData = ReturnData() return if (books.isEmpty()) { returnData.setErrorMsg("还没有添加小说") - } else returnData.setData(books) + } else { + val data = when (App.INSTANCE.getPrefInt(PreferKey.bookshelfSort)) { + 1 -> books.sortedByDescending { it.latestChapterTime } + 2 -> books.sortedBy { it.name } + 3 -> books.sortedBy { it.order } + else -> books.sortedByDescending { it.durChapterTime } + } + returnData.setData(data) + } } fun getChapterList(parameters: Map>): ReturnData { @@ -47,12 +57,14 @@ class BookshelfController { } else { val content: String? = BookHelp.getContent(book, chapter) if (content != null) { + saveBookReadIndex(book, index) returnData.setData(content) } else { App.db.bookSourceDao().getBookSource(book.origin)?.let { source -> runBlocking { WebBook(source).getContentSuspend(book, chapter) }.let { + saveBookReadIndex(book, index) returnData.setData(it) } } ?: returnData.setErrorMsg("未找到书源") @@ -71,4 +83,15 @@ class BookshelfController { return returnData.setErrorMsg("格式不对") } + private fun saveBookReadIndex(book: Book, index: Int) { + if (index > book.durChapterIndex) { + book.durChapterIndex = index + book.durChapterTime = System.currentTimeMillis() + App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { + book.durChapterTitle = it.title + } + App.db.bookDao().update(book) + } + } + }