Merge branch 'gedoor:master' into cronet

pull/1120/head
ag2s20150909 3 years ago committed by GitHub
commit ad2f277675
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      app/src/main/assets/updateLog.md
  2. 2
      app/src/main/java/io/legado/app/help/BookHelp.kt
  3. 146
      app/src/main/java/io/legado/app/help/JsExtensions.kt
  4. 2
      app/src/main/java/io/legado/app/help/storage/BookWebDav.kt
  5. 4
      app/src/main/java/io/legado/app/model/localBook/EpubFile.kt
  6. 2
      app/src/main/java/io/legado/app/model/localBook/LocalBook.kt
  7. 7
      app/src/main/java/io/legado/app/model/localBook/UmdFile.kt
  8. 4
      app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditActivity.kt
  9. 18
      app/src/main/java/io/legado/app/ui/book/read/config/BgTextConfigDialog.kt
  10. 4
      app/src/main/java/io/legado/app/ui/config/OtherConfigFragment.kt
  11. 4
      app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt
  12. 2
      app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt
  13. 4
      app/src/main/java/io/legado/app/utils/ContextExtensions.kt
  14. 3
      app/src/main/java/io/legado/app/utils/FileUtils.kt

@ -8,6 +8,10 @@
* 正文出现缺字漏字、内容缺失、排版错乱等情况,有可能是净化规则出现问题。先关闭替换净化并刷新,再观察是否正常。如果正常说明净化规则存在误杀,如果关闭后仍然出现相关问题,请点击源链接查看原文与正文是否相同,如果不同,再进行反馈。
* 漫画源看书显示乱码,**阅读与其他软件的源并不通用**,请导入阅读的支持的漫画源!
**2021/07/16**
1. js扩展函数添加删除本地文件方法
2. js扩展函数对于文件的读写删操作都是相对路径,只能操作阅读缓存内的文件,/android/data/{package}/cache/...
**2021/07/15**
1. 添加js函数来修复开启js沙箱后某些书源失效。by ag2s20150909
```kotlin

@ -23,7 +23,7 @@ import kotlin.math.min
object BookHelp {
private const val cacheFolderName = "book_cache"
private const val cacheImageFolderName = "images"
private val downloadDir: File = appCtx.externalFilesDir
private val downloadDir: File = appCtx.externalFiles
private val downloadImages = CopyOnWriteArraySet<String>()
fun clearCache() {

@ -23,6 +23,11 @@ import java.util.*
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
/**
* js扩展类, 在js中通过java变量调用
* 所有对于文件的读写删操作都是相对路径,只能操作阅读缓存内的文件
* /android/data/{package}/cache/...
*/
@Keep
@Suppress("unused")
interface JsExtensions {
@ -80,6 +85,7 @@ interface JsExtensions {
/**
* 实现16进制字符串转文件
* @return 相对路径
*/
fun downloadFile(content: String, url: String): String {
val type = AnalyzeUrl(url).type ?: return ""
@ -94,45 +100,7 @@ interface JsExtensions {
zipFile.writeBytes(it)
}
}
return zipPath
}
/**
* js实现压缩文件解压
*/
fun unzipFile(zipPath: String): String {
if (zipPath.isEmpty()) return ""
val unzipPath = FileUtils.getPath(
FileUtils.createFolderIfNotExist(FileUtils.getCachePath()),
FileUtils.getNameExcludeExtension(zipPath)
)
FileUtils.deleteFile(unzipPath)
val zipFile = FileUtils.createFileIfNotExist(zipPath)
val unzipFolder = FileUtils.createFolderIfNotExist(unzipPath)
ZipUtils.unzipFile(zipFile, unzipFolder)
FileUtils.deleteFile(zipPath)
return unzipPath
}
/**
* js实现文件夹内所有文件读取
*/
fun getTxtInFolder(unzipPath: String): String {
if (unzipPath.isEmpty()) return ""
val unzipFolder = FileUtils.createFolderIfNotExist(unzipPath)
val contents = StringBuilder()
unzipFolder.listFiles().let {
if (it != null) {
for (f in it) {
val charsetName = EncodingDetect.getEncode(f)
contents.append(String(f.readBytes(), charset(charsetName)))
.append("\n")
}
contents.deleteCharAt(contents.length - 1)
}
}
FileUtils.deleteFile(unzipPath)
return contents.toString()
return zipPath.substring(FileUtils.getCachePath().length)
}
/**
@ -252,31 +220,94 @@ interface JsExtensions {
return HtmlFormatter.formatKeepImg(str)
}
//****************文件操作******************//
/**
* 读取本地文件
* 获取本地文件
* @param path 相对路径
* @return File
*/
fun readFile(path: String): ByteArray {
return File(path).readBytes()
fun getFile(path: String): File {
val cachePath = appCtx.externalCache.absolutePath
val aPath = if (path.startsWith(File.separator)) {
cachePath + path
} else {
cachePath + File.separator + path
}
return File(aPath)
}
fun readFile(path: String): ByteArray? {
val file = getFile(path)
if (file.exists()) {
return file.readBytes()
}
return null
}
fun readTxtFile(path: String): String {
val f = File(path)
val charsetName = EncodingDetect.getEncode(f)
return String(f.readBytes(), charset(charsetName))
val file = getFile(path)
if (file.exists()) {
val charsetName = EncodingDetect.getEncode(file)
return String(file.readBytes(), charset(charsetName))
}
return ""
}
fun readTxtFile(path: String, charsetName: String): String {
return String(File(path).readBytes(), charset(charsetName))
val file = getFile(path)
if (file.exists()) {
return String(file.readBytes(), charset(charsetName))
}
return ""
}
/**
* 解析字体,返回字体解析类
* 删除本地文件
*/
fun queryBase64TTF(base64: String?): QueryTTF? {
base64DecodeToByteArray(base64)?.let {
return QueryTTF(it)
fun deleteFile(path: String) {
val file = getFile(path)
FileUtils.delete(file, true)
}
/**
* js实现压缩文件解压
* @param zipPath 相对路径
* @return 相对路径
*/
fun unzipFile(zipPath: String): String {
if (zipPath.isEmpty()) return ""
val unzipPath = FileUtils.getPath(
FileUtils.createFolderIfNotExist(FileUtils.getCachePath()),
FileUtils.getNameExcludeExtension(zipPath)
)
FileUtils.deleteFile(unzipPath)
val zipFile = getFile(zipPath)
val unzipFolder = FileUtils.createFolderIfNotExist(unzipPath)
ZipUtils.unzipFile(zipFile, unzipFolder)
FileUtils.deleteFile(zipPath)
return unzipPath.substring(FileUtils.getCachePath().length)
}
/**
* js实现文件夹内所有文件读取
*/
fun getTxtInFolder(unzipPath: String): String {
if (unzipPath.isEmpty()) return ""
val unzipFolder = getFile(unzipPath)
val contents = StringBuilder()
unzipFolder.listFiles().let {
if (it != null) {
for (f in it) {
val charsetName = EncodingDetect.getEncode(f)
contents.append(String(f.readBytes(), charset(charsetName)))
.append("\n")
}
contents.deleteCharAt(contents.length - 1)
}
}
return null
FileUtils.deleteFile(unzipPath)
return contents.toString()
}
/**
@ -332,6 +363,18 @@ interface JsExtensions {
return null
}
//******************文件操作************************//
/**
* 解析字体,返回字体解析类
*/
fun queryBase64TTF(base64: String?): QueryTTF? {
base64DecodeToByteArray(base64)?.let {
return QueryTTF(it)
}
return null
}
/**
* 返回字体解析类
* @param str 支持url,本地文件,base64,自动判断,自动缓存
@ -405,7 +448,6 @@ interface JsExtensions {
transformation: String,
iv: String
): ByteArray? {
return EncoderUtils.decryptAES(
data = str.encodeToByteArray(),
key = key.encodeToByteArray(),

@ -23,7 +23,7 @@ import java.util.*
object BookWebDav {
private const val defaultWebDavUrl = "https://dav.jianguoyun.com/dav/"
private val bookProgressUrl = "${rootWebDavUrl}bookProgress/"
private val zipFilePath = "${FileUtils.getCachePath()}${File.separator}backup.zip"
private val zipFilePath = "${appCtx.externalFiles.absolutePath}${File.separator}backup.zip"
private val rootWebDavUrl: String
get() {

@ -9,7 +9,7 @@ import io.legado.app.help.BookHelp
import io.legado.app.utils.FileUtils
import io.legado.app.utils.HtmlFormatter
import io.legado.app.utils.MD5Utils
import io.legado.app.utils.externalFilesDir
import io.legado.app.utils.externalFiles
import me.ag2s.epublib.domain.EpubBook
import me.ag2s.epublib.epub.EpubReader
import org.jsoup.Jsoup
@ -80,7 +80,7 @@ class EpubFile(var book: Book) {
epubBook?.let {
if (book.coverUrl.isNullOrEmpty()) {
book.coverUrl = FileUtils.getPath(
appCtx.externalFilesDir,
appCtx.externalFiles,
"covers",
"${MD5Utils.md5Encode16(book.bookUrl)}.jpg"
)

@ -119,7 +119,7 @@ object LocalBook {
author = author,
originName = fileName,
coverUrl = FileUtils.getPath(
appCtx.externalFilesDir,
appCtx.externalFiles,
"covers",
"${MD5Utils.md5Encode16(path)}.jpg"
)

@ -4,17 +4,16 @@ import android.net.Uri
import android.util.Log
import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookChapter
import io.legado.app.utils.FileUtils
import io.legado.app.utils.MD5Utils
import io.legado.app.utils.externalFilesDir
import io.legado.app.utils.externalFiles
import io.legado.app.utils.isContentScheme
import me.ag2s.umdlib.domain.UmdBook
import me.ag2s.umdlib.umd.UmdReader
import splitties.init.appCtx
import java.io.File
import java.io.InputStream
import java.util.ArrayList
import java.util.*
class UmdFile(var book: Book) {
companion object {
@ -74,7 +73,7 @@ class UmdFile(var book: Book) {
umdBook?.let {
if (book.coverUrl.isNullOrEmpty()) {
book.coverUrl = FileUtils.getPath(
appCtx.externalFilesDir,
appCtx.externalFiles,
"covers",
"${MD5Utils.md5Encode16(book.bookUrl)}.jpg"
)

@ -108,7 +108,7 @@ class BookInfoEditActivity :
if (uri.isContentScheme()) {
val doc = DocumentFile.fromSingleUri(this, uri)
doc?.name?.let {
var file = this.externalFilesDir
var file = this.externalFiles
file = FileUtils.createFileIfNotExist(file, "covers", it)
kotlin.runCatching {
DocumentUtils.readBytes(this, doc.uri)
@ -128,7 +128,7 @@ class BookInfoEditActivity :
RealPathUtil.getPath(this, uri)?.let { path ->
val imgFile = File(path)
if (imgFile.exists()) {
var file = this.externalFilesDir
var file = this.externalFiles
file = FileUtils.createFileIfNotExist(file, "covers", imgFile.name)
file.writeBytes(imgFile.readBytes())
coverChangeTo(file.absolutePath)

@ -224,7 +224,7 @@ class BgTextConfigDialog : BaseDialogFragment() {
}
execute {
val exportFiles = arrayListOf<File>()
val configDirPath = FileUtils.getPath(requireContext().eCacheDir, "readConfig")
val configDirPath = FileUtils.getPath(requireContext().externalCache, "readConfig")
FileUtils.deleteFile(configDirPath)
val configDir = FileUtils.createFolderIfNotExist(configDirPath)
val configExportPath = FileUtils.getPath(configDir, "readConfig.json")
@ -269,7 +269,7 @@ class BgTextConfigDialog : BaseDialogFragment() {
exportFiles.add(bgExportFile)
}
}
val configZipPath = FileUtils.getPath(requireContext().eCacheDir, configFileName)
val configZipPath = FileUtils.getPath(requireContext().externalCache, configFileName)
if (ZipUtils.zipFiles(exportFiles, File(configZipPath))) {
if (uri.isContentScheme()) {
DocumentFile.fromTreeUri(requireContext(), uri)?.let { treeDoc ->
@ -331,11 +331,11 @@ class BgTextConfigDialog : BaseDialogFragment() {
@Suppress("BlockingMethodInNonBlockingContext")
private fun importConfig(byteArray: ByteArray) {
execute {
val configZipPath = FileUtils.getPath(requireContext().eCacheDir, configFileName)
val configZipPath = FileUtils.getPath(requireContext().externalCache, configFileName)
FileUtils.deleteFile(configZipPath)
val zipFile = FileUtils.createFileIfNotExist(configZipPath)
zipFile.writeBytes(byteArray)
val configDirPath = FileUtils.getPath(requireContext().eCacheDir, "readConfig")
val configDirPath = FileUtils.getPath(requireContext().externalCache, "readConfig")
FileUtils.deleteFile(configDirPath)
ZipUtils.unzipFile(zipFile, FileUtils.createFolderIfNotExist(configDirPath))
val configDir = FileUtils.createFolderIfNotExist(configDirPath)
@ -344,7 +344,7 @@ class BgTextConfigDialog : BaseDialogFragment() {
if (config.textFont.isNotEmpty()) {
val fontName = FileUtils.getName(config.textFont)
val fontPath =
FileUtils.getPath(requireContext().externalFilesDir, "font", fontName)
FileUtils.getPath(requireContext().externalFiles, "font", fontName)
if (!FileUtils.exist(fontPath)) {
FileUtils.getFile(configDir, fontName).copyTo(File(fontPath))
}
@ -352,7 +352,7 @@ class BgTextConfigDialog : BaseDialogFragment() {
}
if (config.bgType == 2) {
val bgName = FileUtils.getName(config.bgStr)
val bgPath = FileUtils.getPath(requireContext().externalFilesDir, "bg", bgName)
val bgPath = FileUtils.getPath(requireContext().externalFiles, "bg", bgName)
if (!FileUtils.exist(bgPath)) {
val bgFile = FileUtils.getFile(configDir, bgName)
if (bgFile.exists()) {
@ -362,7 +362,7 @@ class BgTextConfigDialog : BaseDialogFragment() {
}
if (config.bgTypeNight == 2) {
val bgName = FileUtils.getName(config.bgStrNight)
val bgPath = FileUtils.getPath(requireContext().externalFilesDir, "bg", bgName)
val bgPath = FileUtils.getPath(requireContext().externalFiles, "bg", bgName)
if (!FileUtils.exist(bgPath)) {
val bgFile = FileUtils.getFile(configDir, bgName)
if (bgFile.exists()) {
@ -372,7 +372,7 @@ class BgTextConfigDialog : BaseDialogFragment() {
}
if (config.bgTypeEInk == 2) {
val bgName = FileUtils.getName(config.bgStrEInk)
val bgPath = FileUtils.getPath(requireContext().externalFilesDir, "bg", bgName)
val bgPath = FileUtils.getPath(requireContext().externalFiles, "bg", bgName)
if (!FileUtils.exist(bgPath)) {
val bgFile = FileUtils.getFile(configDir, bgName)
if (bgFile.exists()) {
@ -395,7 +395,7 @@ class BgTextConfigDialog : BaseDialogFragment() {
val doc = DocumentFile.fromSingleUri(requireContext(), uri)
doc?.name?.let {
val file =
FileUtils.createFileIfNotExist(requireContext().externalFilesDir, "bg", it)
FileUtils.createFileIfNotExist(requireContext().externalFiles, "bg", it)
kotlin.runCatching {
DocumentUtils.readBytes(requireContext(), doc.uri)
}.getOrNull()?.let { byteArray ->

@ -226,7 +226,7 @@ class OtherConfigFragment : BasePreferenceFragment(),
if (uri.isContentScheme()) {
val doc = DocumentFile.fromSingleUri(requireContext(), uri)
doc?.name?.let {
var file = requireContext().externalFilesDir
var file = requireContext().externalFiles
file = FileUtils.createFileIfNotExist(file, "covers", it)
kotlin.runCatching {
DocumentUtils.readBytes(requireContext(), doc.uri)
@ -247,7 +247,7 @@ class OtherConfigFragment : BasePreferenceFragment(),
RealPathUtil.getPath(requireContext(), uri)?.let { path ->
val imgFile = File(path)
if (imgFile.exists()) {
var file = requireContext().externalFilesDir
var file = requireContext().externalFiles
file = FileUtils.createFileIfNotExist(file, "covers", imgFile.name)
file.writeBytes(imgFile.readBytes())
putPrefString(PreferKey.defaultCover, file.absolutePath)

@ -225,7 +225,7 @@ class ThemeConfigFragment : BasePreferenceFragment(),
if (uri.isContentScheme()) {
val doc = DocumentFile.fromSingleUri(requireContext(), uri)
doc?.name?.let {
var file = requireContext().externalFilesDir
var file = requireContext().externalFiles
file = FileUtils.createFileIfNotExist(file, preferenceKey, it)
kotlin.runCatching {
DocumentUtils.readBytes(requireContext(), doc.uri)
@ -247,7 +247,7 @@ class ThemeConfigFragment : BasePreferenceFragment(),
RealPathUtil.getPath(requireContext(), uri)?.let { path ->
val imgFile = File(path)
if (imgFile.exists()) {
var file = requireContext().externalFilesDir
var file = requireContext().externalFiles
file = FileUtils.createFileIfNotExist(file, preferenceKey, imgFile.name)
file.writeBytes(imgFile.readBytes())
putPrefString(preferenceKey, file.absolutePath)

@ -139,7 +139,7 @@ class FontSelectDialog : BaseDialogFragment(),
private fun getLocalFonts(): ArrayList<DocItem> {
val fontItems = arrayListOf<DocItem>()
val fontDir =
FileUtils.createFolderIfNotExist(requireContext().externalFilesDir, "font")
FileUtils.createFolderIfNotExist(requireContext().externalFiles, "font")
fontDir.listFiles { pathName ->
pathName.name.lowercase(Locale.getDefault()).matches(fontRegex)
}?.forEach {

@ -224,10 +224,10 @@ val Context.sysBattery: Int
return batteryStatus?.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) ?: -1
}
val Context.externalFilesDir: File
val Context.externalFiles: File
get() = this.getExternalFilesDir(null) ?: this.filesDir
val Context.eCacheDir: File
val Context.externalCache: File
get() = this.externalCacheDir ?: this.cacheDir
fun Context.openUrl(url: String) {

@ -105,8 +105,7 @@ object FileUtils {
}
fun getCachePath(): String {
return appCtx.externalCacheDir?.absolutePath
?: appCtx.cacheDir.absolutePath
return appCtx.externalCache.absolutePath
}
fun getSdCardPath(): String {

Loading…
Cancel
Save