|  |  |  | @ -22,9 +22,9 @@ import io.legado.app.help.AppWebDav | 
			
		
	
		
			
				
					|  |  |  |  | import io.legado.app.help.BookHelp | 
			
		
	
		
			
				
					|  |  |  |  | import io.legado.app.help.ContentProcessor | 
			
		
	
		
			
				
					|  |  |  |  | import io.legado.app.help.config.AppConfig | 
			
		
	
		
			
				
					|  |  |  |  | import io.legado.app.help.coroutine.OrderCoroutine | 
			
		
	
		
			
				
					|  |  |  |  | import io.legado.app.utils.* | 
			
		
	
		
			
				
					|  |  |  |  | import kotlinx.coroutines.delay | 
			
		
	
		
			
				
					|  |  |  |  | import kotlinx.coroutines.ensureActive | 
			
		
	
		
			
				
					|  |  |  |  | import kotlinx.coroutines.* | 
			
		
	
		
			
				
					|  |  |  |  | import kotlinx.coroutines.sync.Mutex | 
			
		
	
		
			
				
					|  |  |  |  | import kotlinx.coroutines.sync.withLock | 
			
		
	
		
			
				
					|  |  |  |  | import me.ag2s.epublib.domain.* | 
			
		
	
	
		
			
				
					|  |  |  | @ -104,10 +104,13 @@ class CacheViewModel(application: Application) : BaseViewModel(application) { | 
			
		
	
		
			
				
					|  |  |  |  |         val bookDoc = DocumentUtils.createFileIfNotExist(doc, filename) | 
			
		
	
		
			
				
					|  |  |  |  |             ?: throw NoStackTraceException("创建文档失败,请尝试重新设置导出文件夹") | 
			
		
	
		
			
				
					|  |  |  |  |         val stringBuilder = StringBuilder() | 
			
		
	
		
			
				
					|  |  |  |  |         val exportToWebDav = AppConfig.exportToWebDav | 
			
		
	
		
			
				
					|  |  |  |  |         context.contentResolver.openOutputStream(bookDoc.uri, "wa")?.use { bookOs -> | 
			
		
	
		
			
				
					|  |  |  |  |             getAllContents(book) { text, srcList -> | 
			
		
	
		
			
				
					|  |  |  |  |                 bookOs.write(text.toByteArray(Charset.forName(AppConfig.exportCharset))) | 
			
		
	
		
			
				
					|  |  |  |  |                 stringBuilder.append(text) | 
			
		
	
		
			
				
					|  |  |  |  |                 if (exportToWebDav) { | 
			
		
	
		
			
				
					|  |  |  |  |                     stringBuilder.append(text) | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |                 srcList?.forEach { | 
			
		
	
		
			
				
					|  |  |  |  |                     val vFile = BookHelp.getImage(book, it.third) | 
			
		
	
		
			
				
					|  |  |  |  |                     if (vFile.exists()) { | 
			
		
	
	
		
			
				
					|  |  |  | @ -133,9 +136,12 @@ class CacheViewModel(application: Application) : BaseViewModel(application) { | 
			
		
	
		
			
				
					|  |  |  |  |         val bookPath = FileUtils.getPath(file, filename) | 
			
		
	
		
			
				
					|  |  |  |  |         val bookFile = FileUtils.createFileWithReplace(bookPath) | 
			
		
	
		
			
				
					|  |  |  |  |         val stringBuilder = StringBuilder() | 
			
		
	
		
			
				
					|  |  |  |  |         val exportToWebDav = AppConfig.exportToWebDav | 
			
		
	
		
			
				
					|  |  |  |  |         getAllContents(book) { text, srcList -> | 
			
		
	
		
			
				
					|  |  |  |  |             bookFile.appendText(text, Charset.forName(AppConfig.exportCharset)) | 
			
		
	
		
			
				
					|  |  |  |  |             stringBuilder.append(text) | 
			
		
	
		
			
				
					|  |  |  |  |             if (exportToWebDav) { | 
			
		
	
		
			
				
					|  |  |  |  |                 stringBuilder.append(text) | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |             srcList?.forEach { | 
			
		
	
		
			
				
					|  |  |  |  |                 val vFile = BookHelp.getImage(book, it.third) | 
			
		
	
		
			
				
					|  |  |  |  |                 if (vFile.exists()) { | 
			
		
	
	
		
			
				
					|  |  |  | @ -171,37 +177,61 @@ class CacheViewModel(application: Application) : BaseViewModel(application) { | 
			
		
	
		
			
				
					|  |  |  |  |             ) | 
			
		
	
		
			
				
					|  |  |  |  |         }" | 
			
		
	
		
			
				
					|  |  |  |  |         append(qy, null) | 
			
		
	
		
			
				
					|  |  |  |  |         appDb.bookChapterDao.getChapterList(book.bookUrl).forEachIndexed { index, chapter -> | 
			
		
	
		
			
				
					|  |  |  |  |             coroutineContext.ensureActive() | 
			
		
	
		
			
				
					|  |  |  |  |             upAdapterLiveData.postValue(book.bookUrl) | 
			
		
	
		
			
				
					|  |  |  |  |             exportProgress[book.bookUrl] = index | 
			
		
	
		
			
				
					|  |  |  |  |             BookHelp.getContent(book, chapter).let { content -> | 
			
		
	
		
			
				
					|  |  |  |  |                 val content1 = contentProcessor | 
			
		
	
		
			
				
					|  |  |  |  |                     .getContent( | 
			
		
	
		
			
				
					|  |  |  |  |                         book, | 
			
		
	
		
			
				
					|  |  |  |  |                         chapter, | 
			
		
	
		
			
				
					|  |  |  |  |                         content ?: "null", | 
			
		
	
		
			
				
					|  |  |  |  |                         includeTitle = !AppConfig.exportNoChapterName, | 
			
		
	
		
			
				
					|  |  |  |  |                         useReplace = useReplace, | 
			
		
	
		
			
				
					|  |  |  |  |                         chineseConvert = false, | 
			
		
	
		
			
				
					|  |  |  |  |                         reSegment = false | 
			
		
	
		
			
				
					|  |  |  |  |                     ).joinToString("\n") | 
			
		
	
		
			
				
					|  |  |  |  |                 if (AppConfig.exportPictureFile) { | 
			
		
	
		
			
				
					|  |  |  |  |                     //txt导出图片文件 | 
			
		
	
		
			
				
					|  |  |  |  |                     val srcList = arrayListOf<Triple<String, Int, String>>() | 
			
		
	
		
			
				
					|  |  |  |  |                     content?.split("\n")?.forEachIndexed { index, text -> | 
			
		
	
		
			
				
					|  |  |  |  |                         val matcher = AppPattern.imgPattern.matcher(text) | 
			
		
	
		
			
				
					|  |  |  |  |                         while (matcher.find()) { | 
			
		
	
		
			
				
					|  |  |  |  |                             matcher.group(1)?.let { | 
			
		
	
		
			
				
					|  |  |  |  |                                 val src = NetworkUtils.getAbsoluteURL(chapter.url, it) | 
			
		
	
		
			
				
					|  |  |  |  |                                 srcList.add(Triple(chapter.title, index, src)) | 
			
		
	
		
			
				
					|  |  |  |  |                             } | 
			
		
	
		
			
				
					|  |  |  |  |         if (AppConfig.parallelExportBook) { | 
			
		
	
		
			
				
					|  |  |  |  |             val oc = | 
			
		
	
		
			
				
					|  |  |  |  |                 OrderCoroutine<Pair<String, ArrayList<Triple<String, Int, String>>?>>(AppConfig.threadCount) | 
			
		
	
		
			
				
					|  |  |  |  |             appDb.bookChapterDao.getChapterList(book.bookUrl).forEach { chapter -> | 
			
		
	
		
			
				
					|  |  |  |  |                 oc.submit { getExportData(book, chapter, contentProcessor, useReplace) } | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |             oc.collect { index, result -> | 
			
		
	
		
			
				
					|  |  |  |  |                 upAdapterLiveData.postValue(book.bookUrl) | 
			
		
	
		
			
				
					|  |  |  |  |                 exportProgress[book.bookUrl] = index | 
			
		
	
		
			
				
					|  |  |  |  |                 append.invoke(result.first, result.second) | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         } else { | 
			
		
	
		
			
				
					|  |  |  |  |             appDb.bookChapterDao.getChapterList(book.bookUrl).forEachIndexed { index, chapter -> | 
			
		
	
		
			
				
					|  |  |  |  |                 coroutineContext.ensureActive() | 
			
		
	
		
			
				
					|  |  |  |  |                 upAdapterLiveData.postValue(book.bookUrl) | 
			
		
	
		
			
				
					|  |  |  |  |                 exportProgress[book.bookUrl] = index | 
			
		
	
		
			
				
					|  |  |  |  |                 val result = getExportData(book, chapter, contentProcessor, useReplace) | 
			
		
	
		
			
				
					|  |  |  |  |                 append.invoke(result.first, result.second) | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     private suspend fun getExportData( | 
			
		
	
		
			
				
					|  |  |  |  |         book: Book, | 
			
		
	
		
			
				
					|  |  |  |  |         chapter: BookChapter, | 
			
		
	
		
			
				
					|  |  |  |  |         contentProcessor: ContentProcessor, | 
			
		
	
		
			
				
					|  |  |  |  |         useReplace: Boolean | 
			
		
	
		
			
				
					|  |  |  |  |     ): Pair<String, ArrayList<Triple<String, Int, String>>?> { | 
			
		
	
		
			
				
					|  |  |  |  |         BookHelp.getContent(book, chapter).let { content -> | 
			
		
	
		
			
				
					|  |  |  |  |             val content1 = contentProcessor | 
			
		
	
		
			
				
					|  |  |  |  |                 .getContent( | 
			
		
	
		
			
				
					|  |  |  |  |                     book, | 
			
		
	
		
			
				
					|  |  |  |  |                     chapter, | 
			
		
	
		
			
				
					|  |  |  |  |                     content ?: "null", | 
			
		
	
		
			
				
					|  |  |  |  |                     includeTitle = !AppConfig.exportNoChapterName, | 
			
		
	
		
			
				
					|  |  |  |  |                     useReplace = useReplace, | 
			
		
	
		
			
				
					|  |  |  |  |                     chineseConvert = false, | 
			
		
	
		
			
				
					|  |  |  |  |                     reSegment = false | 
			
		
	
		
			
				
					|  |  |  |  |                 ).joinToString("\n") | 
			
		
	
		
			
				
					|  |  |  |  |             if (AppConfig.exportPictureFile) { | 
			
		
	
		
			
				
					|  |  |  |  |                 //txt导出图片文件 | 
			
		
	
		
			
				
					|  |  |  |  |                 val srcList = arrayListOf<Triple<String, Int, String>>() | 
			
		
	
		
			
				
					|  |  |  |  |                 content?.split("\n")?.forEachIndexed { index, text -> | 
			
		
	
		
			
				
					|  |  |  |  |                     val matcher = AppPattern.imgPattern.matcher(text) | 
			
		
	
		
			
				
					|  |  |  |  |                     while (matcher.find()) { | 
			
		
	
		
			
				
					|  |  |  |  |                         matcher.group(1)?.let { | 
			
		
	
		
			
				
					|  |  |  |  |                             val src = NetworkUtils.getAbsoluteURL(chapter.url, it) | 
			
		
	
		
			
				
					|  |  |  |  |                             srcList.add(Triple(chapter.title, index, src)) | 
			
		
	
		
			
				
					|  |  |  |  |                         } | 
			
		
	
		
			
				
					|  |  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |  |                     append.invoke("\n\n$content1", srcList) | 
			
		
	
		
			
				
					|  |  |  |  |                 } else { | 
			
		
	
		
			
				
					|  |  |  |  |                     append.invoke("\n\n$content1", null) | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |                 return Pair("\n\n$content1", srcList) | 
			
		
	
		
			
				
					|  |  |  |  |             } else { | 
			
		
	
		
			
				
					|  |  |  |  |                 return Pair("\n\n$content1", null) | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
	
		
			
				
					|  |  |  | @ -422,7 +452,10 @@ class CacheViewModel(application: Application) : BaseViewModel(application) { | 
			
		
	
		
			
				
					|  |  |  |  |             .asBitmap() | 
			
		
	
		
			
				
					|  |  |  |  |             .load(book.getDisplayCover()) | 
			
		
	
		
			
				
					|  |  |  |  |             .into(object : CustomTarget<Bitmap>() { | 
			
		
	
		
			
				
					|  |  |  |  |                 override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) { | 
			
		
	
		
			
				
					|  |  |  |  |                 override fun onResourceReady( | 
			
		
	
		
			
				
					|  |  |  |  |                     resource: Bitmap, | 
			
		
	
		
			
				
					|  |  |  |  |                     transition: Transition<in Bitmap>? | 
			
		
	
		
			
				
					|  |  |  |  |                 ) { | 
			
		
	
		
			
				
					|  |  |  |  |                     val stream = ByteArrayOutputStream() | 
			
		
	
		
			
				
					|  |  |  |  |                     resource.compress(Bitmap.CompressFormat.JPEG, 100, stream) | 
			
		
	
		
			
				
					|  |  |  |  |                     val byteArray: ByteArray = stream.toByteArray() | 
			
		
	
	
		
			
				
					|  |  |  | @ -491,8 +524,10 @@ class CacheViewModel(application: Application) : BaseViewModel(application) { | 
			
		
	
		
			
				
					|  |  |  |  |             while (matcher.find()) { | 
			
		
	
		
			
				
					|  |  |  |  |                 matcher.group(1)?.let { | 
			
		
	
		
			
				
					|  |  |  |  |                     val src = NetworkUtils.getAbsoluteURL(chapter.url, it) | 
			
		
	
		
			
				
					|  |  |  |  |                     val originalHref = "${MD5Utils.md5Encode16(src)}.${BookHelp.getImageSuffix(src)}" | 
			
		
	
		
			
				
					|  |  |  |  |                     val href = "Images/${MD5Utils.md5Encode16(src)}.${BookHelp.getImageSuffix(src)}" | 
			
		
	
		
			
				
					|  |  |  |  |                     val originalHref = | 
			
		
	
		
			
				
					|  |  |  |  |                         "${MD5Utils.md5Encode16(src)}.${BookHelp.getImageSuffix(src)}" | 
			
		
	
		
			
				
					|  |  |  |  |                     val href = | 
			
		
	
		
			
				
					|  |  |  |  |                         "Images/${MD5Utils.md5Encode16(src)}.${BookHelp.getImageSuffix(src)}" | 
			
		
	
		
			
				
					|  |  |  |  |                     val vFile = BookHelp.getImage(book, src) | 
			
		
	
		
			
				
					|  |  |  |  |                     val fp = FileResourceProvider(vFile.parent) | 
			
		
	
		
			
				
					|  |  |  |  |                     if (vFile.exists()) { | 
			
		
	
	
		
			
				
					|  |  |  | 
 |