From dc4f1e03d7d916bf064c8ddee56ff9a7de3bb166 Mon Sep 17 00:00:00 2001 From: Discut Date: Tue, 23 May 2023 14:01:21 +0800 Subject: [PATCH] =?UTF-8?q?feat(CustomExport):=20=E2=9C=A8=20=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E5=AF=BC=E5=87=BA=E6=96=B0=E5=A2=9E=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=8F=98=E9=87=8F=20epubIndex?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../legado/app/ui/book/cache/CacheActivity.kt | 6 +- .../app/ui/book/cache/CacheViewModel.kt | 83 +++++++++++++++++-- 2 files changed, 81 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/cache/CacheActivity.kt b/app/src/main/java/io/legado/app/ui/book/cache/CacheActivity.kt index 16246645c..499c144c6 100644 --- a/app/src/main/java/io/legado/app/ui/book/cache/CacheActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/cache/CacheActivity.kt @@ -398,7 +398,11 @@ class CacheActivity : VMBaseActivity() @SuppressLint("SetTextI18n") private fun alertExportFileName() { alert(R.string.export_file_name) { - setMessage("js内有name和author变量,返回书名") + var message = "js内有name和author变量,返回书名\n启用自定义epub导出章节时包含额外变量[epubIndex]" + if (AppConfig.bookExportFileName.isNullOrBlank()) { + message += "\n例如:\nname+\"-\"+author+(epubIndex?\"(\"+epubIndex+\")\":\"\")" + } + setMessage(message) val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply { editView.hint = "file name js" editView.setText(AppConfig.bookExportFileName) diff --git a/app/src/main/java/io/legado/app/ui/book/cache/CacheViewModel.kt b/app/src/main/java/io/legado/app/ui/book/cache/CacheViewModel.kt index 8d13e2176..6b4072e61 100644 --- a/app/src/main/java/io/legado/app/ui/book/cache/CacheViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/cache/CacheViewModel.kt @@ -281,13 +281,12 @@ class CacheViewModel(application: Application) : BaseViewModel(application) { //////////////////Start EPUB /** - * 导出Epub 自定义导出范围 + * 导出Epub 根据自定义导出范围 * * @param path 导出路径 * @param book 书籍 * @param size 每本Epub包含的章节 * @param scope 导出范围 - * @author Discut * @since 2023/5/22 */ fun exportEPUBs(path: String, book: Book, size: Int = 1, scope: String) { @@ -295,7 +294,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) { CustomExporter(this).let { it.scope = paresScope(scope) it.size = size - it.exportEPUB(path, book) + it.export(path, book) } } @@ -644,7 +643,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) { * @param path 导出的路径 * @param book 书籍 */ - fun exportEPUB( + fun export( path: String, book: Book ) { @@ -662,10 +661,9 @@ class CacheViewModel(application: Application) : BaseViewModel(application) { val uri = Uri.parse(path) val doc = DocumentFile.fromTreeUri(context.context, uri) ?: throw NoStackTraceException("获取导出文档失败") - book.totalChapterNum exportEpub(doc, book) } else { - context.exportEpub(File(path).createFolderIfNotExist(), book) + exportEpub(File(path).createFolderIfNotExist(), book) } }.onError { context.exportProgress.remove(book.bookUrl) @@ -682,6 +680,22 @@ class CacheViewModel(application: Application) : BaseViewModel(application) { } } + /** + * 导出 epub + * + * from [io.legado.app.ui.book.cache.CacheViewModel.exportEpub] + */ + private suspend fun exportEpub(file: File, book: Book) { + val (contentModel, epubList) = createEpubs(book) + epubList.forEachIndexed { index, ep -> + val (filename, epubBook) = ep + //设置正文 + this.setEpubContent(contentModel, book, epubBook, index) + save2Drive(filename, epubBook, file) + } + + } + /** * 导出 epub * @@ -698,10 +712,16 @@ class CacheViewModel(application: Application) : BaseViewModel(application) { } + /** * 设置epub正文 * * from [io.legado.app.ui.book.cache.CacheViewModel.setEpubContent] + * + * @param contentModel 正文模板 + * @param book 书籍 + * @param epubBook 分割后的epub + * @param epubBookIndex 分割后的epub序号 */ private suspend fun setEpubContent( contentModel: String, @@ -709,7 +729,6 @@ class CacheViewModel(application: Application) : BaseViewModel(application) { epubBook: EpubBook, epubBookIndex: Int ) { - //正文 val useReplace = AppConfig.exportUseReplace && book.getUseReplaceRule() val contentProcessor = ContentProcessor.get(book.name, book.origin) @@ -770,6 +789,8 @@ class CacheViewModel(application: Application) : BaseViewModel(application) { /** * 创建多个epub 对象 * + * 分割epub时,一个书籍需要创建多个epub对象 + * * @param doc 导出文档 * @param book 书籍 * @@ -800,6 +821,38 @@ class CacheViewModel(application: Application) : BaseViewModel(application) { return Pair(contentModel, result) } + /** + * 创建多个epub 对象 + * + * 分割epub时,一个书籍需要创建多个epub对象 + * + * @param book 书籍 + * + * @return <内容模板字符串, > + */ + private fun createEpubs( + book: Book + ): Pair>> { + val paresNumOfEpub = paresNumOfEpub(scope.size, size) + val result: MutableList> = ArrayList(paresNumOfEpub) + var contentModel = "" + for (i in 1..paresNumOfEpub) { + val filename = book.getExportFileName("epub", i) + val epubBook = EpubBook() + epubBook.version = "2.0" + //set metadata + context.setEpubMetadata(book, epubBook) + //set cover + context.setCover(book, epubBook) + //set css + contentModel = context.setAssets(book, epubBook) + + // add epubBook + result.add(Pair(filename, epubBook)) + } + return Pair(contentModel, result) + } + /** * 保存文件到 设备 */ @@ -813,11 +866,27 @@ class CacheViewModel(application: Application) : BaseViewModel(application) { AppWebDav.exportWebDav(bookDoc.uri, filename) } } + } + /** + * 保存文件到 设备 + */ + private suspend fun save2Drive(filename: String, epubBook: EpubBook, file: File) { + val bookPath = FileUtils.getPath(file, filename) + val bookFile = FileUtils.createFileWithReplace(bookPath) + @Suppress("BlockingMethodInNonBlockingContext") + EpubWriter().write(epubBook, FileOutputStream(bookFile)) + if (AppConfig.exportToWebDav) { + // 导出到webdav + AppWebDav.exportWebDav(Uri.fromFile(bookFile), filename) + } } /** * 解析 分割epub后的数量 + * + * @param total 章节总数 + * @param size 每个epub文件包含多少章节 */ private fun paresNumOfEpub(total: Int, size: Int): Int { val i = total % size